package read import ( "log" "sync" "time" "git.tek.govt.hu/dowerx/place/api/structs" "git.tek.govt.hu/dowerx/place/config" "git.tek.govt.hu/dowerx/place/storage" "github.com/gin-gonic/gin" "github.com/gorilla/websocket" ) var upgrader = websocket.Upgrader{ ReadBufferSize: 1024, WriteBufferSize: 1024, } type ConnectionsMap struct { sync.Mutex Items map[*websocket.Conn]chan structs.Pixel } func (c *ConnectionsMap) Send(pixel structs.Pixel) { c.Lock() for _, v := range c.Items { v <- pixel } c.Unlock() } var Connections ConnectionsMap = ConnectionsMap{Items: make(map[*websocket.Conn]chan structs.Pixel)} func Info(c *gin.Context) { conf := config.GetConfig() c.JSON(200, gin.H{ "tileSize": conf.TileSize, "canvasSize": conf.CanvasSize, "timeout": conf.Timeout, }) } func Tile(c *gin.Context) { var coords structs.Coordinates if c.ShouldBind(&coords) != nil { c.AbortWithStatus(400) return } buffer, err := storage.GetTile(coords.X, coords.Y) if err != nil { c.AbortWithError(500, err) return } c.Status(200) c.Header("Content-Type", "image/png") c.Writer.Write(buffer.Bytes()) } func Continuous(c *gin.Context) { conn, err := upgrader.Upgrade(c.Writer, c.Request, nil) if err != nil { return } Connections.Lock() Connections.Items[conn] = make(chan structs.Pixel) Connections.Unlock() conn.SetReadDeadline(time.Now().Add(time.Second * 60)) conn.SetPongHandler(func(string) error { conn.SetReadDeadline(time.Now().Add(time.Second * 60)) return nil }) // send pings go func() { ticker := time.NewTicker(30 * time.Second) defer ticker.Stop() for range ticker.C { if err := conn.WriteControl(websocket.PingMessage, nil, time.Now().Add(10*time.Second)); err != nil { return } } }() // defer: close connection, remove channel defer func() { Connections.Lock() for k, v := range Connections.Items { if k == conn { close(v) delete(Connections.Items, k) break } } Connections.Unlock() conn.Close() log.Println("removed connection") }() // send updates go func() { for pixel := range Connections.Items[conn] { conn.WriteJSON(pixel) } }() // read loop to keep the connetion alive for { _, _, err := conn.ReadMessage() if err != nil { break } } }