// km_writer — 讀寫 Mira leo-graph(journals + pages) // 透過 host function 呼叫 Mira /km/* API // //go:build tinygo package main import ( "encoding/json" "fmt" "io" "os" "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 // Input actions: // read_journal — GET today's journal (requires: mira_url, token) // read_journal_date — GET journal by date (requires: mira_url, token, date) // append_journal — POST append entry (requires: mira_url, token, content; optional: timestamp) // list_pages — GET all pages (requires: mira_url, token) // read_page — GET page by name (requires: mira_url, token, name) // write_page — PUT write page (requires: mira_url, token, name, content) type Input struct { Action string `json:"action"` MiraURL string `json:"mira_url"` Token string `json:"token"` Content string `json:"content"` Timestamp string `json:"timestamp"` Date string `json:"date"` Name string `json:"name"` } func main() { raw, err := io.ReadAll(os.Stdin) if err != nil { writeError("failed to read stdin: " + err.Error()) return } var inp Input if err := json.Unmarshal(raw, &inp); err != nil { writeError("invalid input JSON: " + err.Error()) return } if inp.Action == "" { writeError("action 必填") return } if inp.MiraURL == "" { writeError("mira_url 必填") return } if inp.Token == "" { writeError("token 必填") return } authHeader := fmt.Sprintf(`{"Authorization":"Bearer %s","Content-Type":"application/json"}`, inp.Token) switch inp.Action { case "read_journal": result := doRequest(inp.MiraURL+"/km/journal", "GET", authHeader, "") os.Stdout.Write(result) case "read_journal_date": if inp.Date == "" { writeError("date 必填(格式 YYYY-MM-DD)") return } result := doRequest(inp.MiraURL+"/km/journal/"+inp.Date, "GET", authHeader, "") os.Stdout.Write(result) case "append_journal": if inp.Content == "" { writeError("content 必填") return } bodyMap := map[string]string{"content": inp.Content} if inp.Timestamp != "" { bodyMap["timestamp"] = inp.Timestamp } bodyBytes, _ := json.Marshal(bodyMap) result := doRequest(inp.MiraURL+"/km/journal", "POST", authHeader, string(bodyBytes)) os.Stdout.Write(result) case "list_pages": result := doRequest(inp.MiraURL+"/km/pages", "GET", authHeader, "") os.Stdout.Write(result) case "read_page": if inp.Name == "" { writeError("name 必填") return } result := doRequest(inp.MiraURL+"/km/page/"+inp.Name, "GET", authHeader, "") os.Stdout.Write(result) case "write_page": if inp.Name == "" { writeError("name 必填") return } if inp.Content == "" { writeError("content 必填") return } bodyMap := map[string]string{"content": inp.Content} bodyBytes, _ := json.Marshal(bodyMap) result := doRequest(inp.MiraURL+"/km/page/"+inp.Name, "PUT", authHeader, string(bodyBytes)) os.Stdout.Write(result) default: writeError("未知 action: " + inp.Action) } } func doRequest(url, method, headersJSON, body string) []byte { urlBytes := []byte(url) methodBytes := []byte(method) headersBytes := []byte(headersJSON) bodyBytes := []byte(body) outBuf := make([]byte, 131072) // 128KB var outLen uint32 if len(bodyBytes) == 0 { bodyBytes = []byte{} } var bodyPtr uintptr var bodyLen uint32 if len(bodyBytes) > 0 { bodyPtr = uintptr(unsafe.Pointer(&bodyBytes[0])) bodyLen = uint32(len(bodyBytes)) } code := hostHttpRequest( uintptr(unsafe.Pointer(&urlBytes[0])), uint32(len(urlBytes)), uintptr(unsafe.Pointer(&methodBytes[0])), uint32(len(methodBytes)), uintptr(unsafe.Pointer(&headersBytes[0])), uint32(len(headersBytes)), bodyPtr, bodyLen, uintptr(unsafe.Pointer(&outBuf[0])), uintptr(unsafe.Pointer(&outLen)), ) if code != 0 { out, _ := json.Marshal(map[string]interface{}{"success": false, "error": "HTTP request failed"}) return out } responseStr := string(outBuf[:outLen]) // Try to parse the response as JSON to forward it var parsed interface{} if err := json.Unmarshal([]byte(responseStr), &parsed); err != nil { // Not JSON — wrap it out, _ := json.Marshal(map[string]interface{}{"success": true, "data": responseStr}) return out } // Forward the parsed response as-is, wrapped in success out, _ := json.Marshal(map[string]interface{}{"success": true, "data": parsed}) return out } func writeError(msg string) { out, _ := json.Marshal(map[string]interface{}{"success": false, "error": msg}) os.Stdout.Write(out) }