package main import ( "errors" "fmt" "image" "image/png" "net" "net/http" "os" "sync" "time" ) var ( fetchClient = &http.Client{ Timeout: 500 * time.Millisecond, } submitClient = &http.Client{ Timeout: 50 * time.Millisecond, } ) func main() { f, err := os.Open("img.png") if err != nil { panic(err) } img, err := png.Decode(f) if err != nil { panic(err) } for { if err := draw(img); err != nil { fmt.Println(err) } <-time.After(100 * time.Millisecond) } } func draw(img image.Image) error { fmt.Println("redraw") req, err := http.NewRequest("GET", "https://cqql.site/chaosbtn", nil) if err != nil { return err } res, err := fetchClient.Do(req) if err != nil { return err } defer res.Body.Close() if res.StatusCode != 200 { return errors.New("could not fetch current button state") } currentState, err := png.Decode(res.Body) if err != nil { return err } wg := &sync.WaitGroup{} for x := 0; x < 88; x++ { wg.Add(1) go drawCol(wg, x, img, currentState) } wg.Wait() return nil } func drawCol(wg *sync.WaitGroup, x int, img image.Image, currentState image.Image) error { defer wg.Done() for y := 0; y < 31; y++ { r, g, b, _ := img.At(x, y).RGBA() curR, curG, curB, _ := currentState.At(x, y).RGBA() if r == curR && g == curG && b == curB { continue } uri := fmt.Sprintf("https://cqql.site/chaosbtn/draw?x=%d&y=%d&r=%d&g=%d&b=%d", x, y, r/257, g/257, b/257) fmt.Printf("send [%02d,%02d] [%03d %03d %03d]\n", x, y, r/257, g/257, b/257) req, err := http.NewRequest("GET", uri, nil) if err != nil { return err } _, err = submitClient.Do(req) if err != nil { var netErr net.Error if errors.As(err, &netErr) && netErr.Timeout() { continue } return err } } return nil }