package main import ( "encoding/json" "errors" "fmt" "log" "os" "strconv" "github.com/go-resty/resty/v2" "github.com/joho/godotenv" ) type Response struct { Success bool `json:"success"` } type Endpoint string const ( RECTANGLE Endpoint = "rectangle" UPDATE Endpoint = "update" COLOR Endpoint = "color" ) type Update struct { Endpoint Endpoint `json:"endpoint"` } type Color struct { R int `json:"r"` G int `json:"g"` B int `json:"b"` Endpoint Endpoint `json:"endpoint"` } type Rectangle struct { X int `json:"x"` Y int `json:"y"` W int `json:"w"` H int `json:"h"` Endpoint Endpoint `json:"endpoint"` } func GetEnvFallback(key string, fallback ...string) (string, error) { // Check for function fallback signature length := len(fallback) if length > 1 { return "", errors.New("Invalid signature: Too many fallback values provided!") } // Try to get environment variable value, exists := os.LookupEnv(key) if exists { return value, nil } // Try using fallback value instead if length == 1 { return fallback[0], nil } else if length == 0 { // No fallback value provided return "", errors.New("Panic: No fallback value provided!") } // Could not get environment variable return "", errors.New("Could not get environment variable: " + key) } func ConvertFallback(input string, fallback ...int) (int, error) { // Check for function fallback signature length := len(fallback) if length > 1 { return 0, errors.New("Invalid signature: Too many fallback values provided!") } // Try to convert input to int value, err := strconv.Atoi(input) if err == nil { return value, nil } // Try using fallback value instead if length == 1 { return fallback[0], nil } else if length == 0 { // No fallback value provided return 0, errors.New("Panic: No fallback value provided!") } // Could not convert input return 0, err } func LoadMatrixData() (string, int, int) { // Remote server info API_SERVER_IP, _ := GetEnvFallback("API_SERVER_IP", "localhost") API_SERVER_PORT, _ := GetEnvFallback("API_SERVER_PORT", "8080") // LED panel info PUBLIC_LED_WIDTH, _ := ConvertFallback(os.Getenv("PUBLIC_LED_WIDTH"), 64) PUBLIC_LED_HEIGHT, _ := ConvertFallback(os.Getenv("PUBLIC_LED_HEIGHT"), 64) // Matrix arrangement info PUBLIC_LED_CHAIN, _ := ConvertFallback(os.Getenv("PUBLIC_LED_CHAIN"), 1) PUBLIC_LED_PARALLEL, _ := ConvertFallback(os.Getenv("PUBLIC_LED_PARALLEL"), 1) // Prepare remote server url url := fmt.Sprintf("http://%s:%s", API_SERVER_IP, API_SERVER_PORT) // Calculate combined resolution width := PUBLIC_LED_WIDTH * PUBLIC_LED_CHAIN height := PUBLIC_LED_HEIGHT * PUBLIC_LED_PARALLEL return url, width, height } func SendRequest(client *resty.Client, url string, ins []interface{}) { // Manually marshal instructions marshal, err := json.Marshal(ins) if err != nil { log.Fatal(err) return } // Debug log json data log.Printf("Request: %s\n", string(marshal)) // Build and send request resp, err := client.R(). SetHeader("Content-Type", "application/json"). SetBody(ins). Post(fmt.Sprintf("%s/instructions", url)) // Error handling if err != nil { log.Fatal(err) return } // Print response status log.Printf("Response Status: %s\n", resp.Status()) // Unmarshal response var data Response err = json.Unmarshal(resp.Body(), &data) if err != nil { log.Fatal(err) return } // Print response log.Printf("Success: %t\n", data.Success) } func main() { // Load .env file if it exists err := godotenv.Load(".env") if err != nil { log.Fatal("Error loading .env file") } // Load env server data url, width, height := LoadMatrixData() log.Printf("At '%s': %d x %d\n", url, width, height) // Initialize resty client client := resty.New() // Initialize custom matrix data col := Color{R: 255, G: 0, B: 255, Endpoint: COLOR} rct := Rectangle{X: 0, Y: 0, W: 10, H: 10, Endpoint: RECTANGLE} upd := Update{Endpoint: UPDATE} // Send request to remote server SendRequest(client, url, []interface{}{col, rct, upd}) }