// line_notify — 發送 LINE Notify 訊息 // 透過 host function 呼叫 LINE Notify API // //go:build tinygo package main import ( "encoding/json" "io" "os" "strings" "unsafe" ) //go:wasmimport u6u http_request func hostHttpRequest( urlPtr uintptr, urlLen uint32, methodPtr uintptr, methodLen uint32, headersPtr uintptr, headersLen uint32, bodyPtr uintptr, bodyLen uint32, outPtr uintptr, outLenPtr uintptr, ) uint32 type Input struct { Message string `json:"message"` Token string `json:"token"` } func main() { raw, err := io.ReadAll(os.Stdin) if err != nil { writeError("failed to read stdin: " + err.Error()) return } var input Input if err := json.Unmarshal(raw, &input); err != nil { writeError("invalid input JSON: " + err.Error()) return } if input.Message == "" { writeError("message 必填") return } if input.Token == "" { writeError("token 必填") return } apiURL := "https://notify-api.line.me/api/notify" method := "POST" headers := map[string]string{ "Authorization": "Bearer " + input.Token, "Content-Type": "application/x-www-form-urlencoded", } headersJSON, _ := json.Marshal(headers) // form-encoded body body := "message=" + urlEncode(input.Message) urlBytes := []byte(apiURL) methodBytes := []byte(method) bodyBytes := []byte(body) outBuf := make([]byte, 4096) var outLen uint32 result := hostHttpRequest( uintptr(unsafe.Pointer(&urlBytes[0])), uint32(len(urlBytes)), uintptr(unsafe.Pointer(&methodBytes[0])), uint32(len(methodBytes)), uintptr(unsafe.Pointer(&headersJSON[0])), uint32(len(headersJSON)), uintptr(unsafe.Pointer(&bodyBytes[0])), uint32(len(bodyBytes)), uintptr(unsafe.Pointer(&outBuf[0])), uintptr(unsafe.Pointer(&outLen)), ) if result != 0 { writeError("LINE Notify API 呼叫失敗") return } out, _ := json.Marshal(map[string]interface{}{ "success": true, "data": map[string]interface{}{"status": 200}, }) os.Stdout.Write(out) } // urlEncode — 簡易 URL 編碼(只處理常見字元) func urlEncode(s string) string { var sb strings.Builder for _, c := range s { switch { case c >= 'A' && c <= 'Z', c >= 'a' && c <= 'z', c >= '0' && c <= '9', c == '-', c == '_', c == '.', c == '~': sb.WriteRune(c) case c == ' ': sb.WriteByte('+') default: // UTF-8 encode buf := []byte(string(c)) for _, b := range buf { sb.WriteByte('%') sb.WriteByte("0123456789ABCDEF"[b>>4]) sb.WriteByte("0123456789ABCDEF"[b&0xf]) } } } return sb.String() } func writeError(msg string) { out, _ := json.Marshal(map[string]interface{}{"success": false, "error": msg}) os.Stdout.Write(out) }