package main import ( "fmt" "net/http" "os" "syscall" "time" "github.com/google/uuid" "github.com/gorilla/websocket" "github.com/labstack/echo/v4" "github.com/labstack/gommon/log" ) func keys(c echo.Context) error { ws, err := upgrader.Upgrade(c.Response(), c.Request(), nil) if err != nil { return err } defer ws.Close() id := uuid.New() idRaw := c.QueryParam("id") if idRaw != "" { updatedId, err := uuid.Parse(idRaw) if err != nil { log.Errorf("failed to parse id: %s", id) } else { id = updatedId } } now := time.Now() client := Client{ ID: id, Name: "Dummy", Connected: true, ConnectedAt: now, DisconnectedAt: now, CreatedAt: now, UpdatedAt: now, ExitWanted: false, conn: ws, } clients = append(clients, &client) fmt.Printf("%s client %s connected\n", time.Now().Format(TimeFormat), client.ID.String()) err = ws.WriteMessage(websocket.TextMessage, []byte("welcome")) if err != nil { log.Error(err) } f, err := os.OpenFile(filename(dataDir, client.ID.String(), now.Format(DateFormat)), syscall.O_CREAT|syscall.O_APPEND|syscall.O_WRONLY, 0644) if err != nil { log.Error(err) fmt.Printf("%s client %s crashed (couldn't open file)\n", time.Now().Format(TimeFormat), client.ID) now = time.Now() client.Connected = false client.DisconnectedAt = now client.UpdatedAt = now return c.NoContent(http.StatusInternalServerError) } defer f.Close() close := func() { _ = ws.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, "")) _ = ws.Close() now = time.Now() client.ExitWanted = true client.Connected = false client.DisconnectedAt = now client.UpdatedAt = now } for { if client.ExitWanted { close() fmt.Printf("%s client %s disconnected\n", time.Now().Format(TimeFormat), client.ID.String()) break } _, msg, err := ws.ReadMessage() if err != nil { log.Error(err) close() fmt.Printf("%s client %s crashed (websocket error)\n", time.Now().Format(TimeFormat), client.ID.String()) return c.NoContent(http.StatusInternalServerError) } _, err = f.Write(msg) if err != nil { log.Error(err) close() fmt.Printf("%s client %s crashed (file write error)\n", time.Now().Format(TimeFormat), client.ID.String()) return c.NoContent(http.StatusInternalServerError) } } return c.NoContent(http.StatusOK) }