package server import ( "embed" "fmt" "html/template" "log" "net/http" "github.com/gin-gonic/gin" "github.com/gorilla/websocket" ) //go:embed static var staticFiles embed.FS var upgrader = websocket.Upgrader{ CheckOrigin: func(r *http.Request) bool { return true }, } type InputFunc func(string) type Server struct { addr string outputChan chan string dealInputFunc InputFunc clients []*Client historyOutput string } type Client struct { conn *websocket.Conn } var GlobalServer *Server func NewServer(addr string, dealInputFunc InputFunc) { GlobalServer = &Server{ addr: addr, outputChan: make(chan string), dealInputFunc: dealInputFunc, } } func (s *Server) Run() { router := gin.Default() tpl, err := template.ParseFS(staticFiles, "static/*") if err != nil { log.Fatalf("Error parsing templates: %v", err) } router.SetHTMLTemplate(tpl) router.GET("/ws", s.handleWebSocket) router.GET("/video/current", GetCurrentVideo) router.GET("/video/list", GetVideoList) router.GET( "/", func(c *gin.Context) { c.HTML(200, "index.html", nil) }, ) go func() { if err := router.Run(s.addr); err != nil { log.Fatalf("Error starting server: %v", err) } }() go func() { for { output := <-s.outputChan s.historyOutput += output for _, client := range s.clients { _ = client.conn.WriteMessage(websocket.TextMessage, []byte(output)) } } }() } func (s *Server) handleWebSocket(c *gin.Context) { ws, err := upgrader.Upgrade(c.Writer, c.Request, nil) if err != nil { return } defer ws.Close() client := &Client{conn: ws} s.clients = append(s.clients, client) _ = client.conn.WriteMessage(websocket.TextMessage, []byte(s.historyOutput)) defer func() { for i, c := range s.clients { if c == client { s.clients = append(s.clients[:i], s.clients[i+1:]...) break } } }() for { // recive message _, msg, err := ws.ReadMessage() if err != nil { log.Printf("Websocket reading message error: %v", err) break } s.dealInputFunc(string(msg)) } } func (s *Server) Print(msg ...any) { s.outputChan <- fmt.Sprint(msg...) } func (s *Server) Println(msg ...any) { s.outputChan <- fmt.Sprintln(msg...) } func (s *Server) Printf(format string, args ...interface{}) { s.outputChan <- fmt.Sprintf(format, args...) } func (s *Server) Close() { close(s.outputChan) }