// google_sheets — 讀取或寫入 Google 試算表 // 透過 host function 呼叫 Google Sheets API // //go:build tinygo package main import ( "encoding/json" "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 type Input struct { SpreadsheetID string `json:"spreadsheet_id"` Range string `json:"range"` Action string `json:"action"` Values [][]json.RawMessage `json:"values"` AccessToken string `json:"access_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.SpreadsheetID == "" { writeError("spreadsheet_id 必填") return } if input.Range == "" { writeError("range 必填") return } if input.AccessToken == "" { writeError("access_token 必填") return } action := input.Action if action == "" { action = "read" } headers := map[string]string{ "Authorization": "Bearer " + input.AccessToken, "Content-Type": "application/json", } headersJSON, _ := json.Marshal(headers) var apiURL, method, bodyStr string switch action { case "read": apiURL = "https://sheets.googleapis.com/v4/spreadsheets/" + input.SpreadsheetID + "/values/" + input.Range method = "GET" bodyStr = "" case "write": apiURL = "https://sheets.googleapis.com/v4/spreadsheets/" + input.SpreadsheetID + "/values/" + input.Range + "?valueInputOption=RAW" method = "PUT" bodyData, _ := json.Marshal(map[string]interface{}{ "range": input.Range, "majorDimension": "ROWS", "values": input.Values, }) bodyStr = string(bodyData) default: writeError("不支援的 action: " + action) return } urlBytes := []byte(apiURL) methodBytes := []byte(method) bodyBytes := []byte(bodyStr) if len(bodyBytes) == 0 { bodyBytes = []byte{} } outBuf := make([]byte, 65536) var outLen uint32 var bodyPtr uintptr if len(bodyBytes) > 0 { bodyPtr = uintptr(unsafe.Pointer(&bodyBytes[0])) } 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)), bodyPtr, uint32(len(bodyBytes)), uintptr(unsafe.Pointer(&outBuf[0])), uintptr(unsafe.Pointer(&outLen)), ) if result != 0 { writeError("Google Sheets API 呼叫失敗") return } responseStr := string(outBuf[:outLen]) var responseData interface{} if err := json.Unmarshal([]byte(responseStr), &responseData); err != nil { responseData = responseStr } out, _ := json.Marshal(map[string]interface{}{ "success": true, "data": map[string]interface{}{ "values": responseData, "range": input.Range, }, }) os.Stdout.Write(out) } func writeError(msg string) { out, _ := json.Marshal(map[string]interface{}{"success": false, "error": msg}) os.Stdout.Write(out) }