update wshub

This commit is contained in:
aynakeya
2024-04-29 20:22:35 -07:00
parent d514f96c28
commit 88066bd3b9
9 changed files with 489 additions and 19 deletions

16
plugin/wshub/events.go Normal file
View File

@@ -0,0 +1,16 @@
package wshub
import (
"AynaLivePlayer/pkg/event"
"encoding/json"
)
type EventData struct {
EventID event.EventId
Data interface{}
}
type EventDataReceived struct {
EventID event.EventId
Data json.RawMessage
}

165
plugin/wshub/server.go Normal file
View File

@@ -0,0 +1,165 @@
package wshub
import (
"AynaLivePlayer/core/events"
"AynaLivePlayer/global"
"AynaLivePlayer/pkg/logger"
"context"
"encoding/json"
"errors"
"fmt"
"github.com/gorilla/websocket"
"net/http"
"sync"
)
var upgrader = websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
CheckOrigin: func(r *http.Request) bool {
return true
},
}
type wsClient struct {
conn *websocket.Conn
Data chan []byte
Close chan byte
}
func (c *wsClient) start() {
for {
msgType, val, err := c.conn.ReadMessage()
if err != nil {
c.Close <- 1
return
}
if msgType == websocket.TextMessage {
return
}
var data EventDataReceived
err = json.Unmarshal(val, &data)
if err != nil {
global.Logger.Warn("unmarshal event data failed", err)
return
}
actualEventData, err := events.UnmarshalEventData(data.EventID, data.Data)
if err != nil {
global.Logger.Warn("unmarshal event data failed", err)
return
}
global.EventManager.CallA(data.EventID, actualEventData)
}
}
type wsServer struct {
Running bool
Server *http.Server
clients map[*wsClient]bool
mux *http.ServeMux
lock sync.RWMutex
port *int
log logger.ILogger
}
func newWsServer(port *int) *wsServer {
mux := http.NewServeMux()
s := &wsServer{
Running: false,
clients: make(map[*wsClient]bool),
mux: mux,
port: port,
log: global.Logger.WithPrefix("plugin.wshub.server"),
}
mux.HandleFunc("/wsinfo", s.handleWsInfo)
return s
}
func (s *wsServer) broadcast(data []byte) {
s.lock.RLock()
defer s.lock.RUnlock()
for client := range s.clients {
client.Data <- data
}
}
func (s *wsServer) register(client *wsClient) {
s.lock.Lock()
s.clients[client] = true
s.lock.Unlock()
}
func (s *wsServer) unregister(client *wsClient) {
s.lock.Lock()
delete(s.clients, client)
s.lock.Unlock()
}
func (s *wsServer) handleWsInfo(w http.ResponseWriter, r *http.Request) {
s.log.Debug("connection start")
conn, err := upgrader.Upgrade(w, r, nil)
if err != nil {
s.log.Warnf("upgrade error: %s", err)
return
}
client := &wsClient{
conn: conn,
Data: make(chan []byte, 16),
Close: make(chan byte, 1),
}
s.register(client)
defer s.unregister(client)
go client.start()
for {
select {
case data := <-client.Data:
err := client.conn.WriteMessage(websocket.TextMessage, data)
if err != nil {
s.log.Warn("write message failed", err)
return
}
case _ = <-client.Close:
s.log.Infof("client %s close", client.conn.RemoteAddr().String())
if err := client.conn.Close(); err != nil {
s.log.Warnf("close connection encouter an error: %s", err)
}
return
}
}
}
func (s *wsServer) Start() {
s.log.Debug("WebInfoServer starting...")
s.Running = true
go func() {
s.Server = &http.Server{
Addr: fmt.Sprintf("localhost:%d", *s.port),
Handler: s.mux,
}
err := s.Server.ListenAndServe()
s.Running = false
if errors.Is(err, http.ErrServerClosed) {
s.log.Info("WebInfoServer closed")
return
}
if err != nil {
s.log.Errorf("Failed to start webinfo server: %s", err)
return
}
}()
}
func (s *wsServer) Stop() error {
s.log.Debug("WebInfoServer stopping...")
s.lock.Lock()
s.clients = make(map[*wsClient]bool)
s.lock.Unlock()
if s.Server != nil {
return s.Server.Shutdown(context.TODO())
}
return nil
}
func (s *wsServer) getWsUrl() string {
return fmt.Sprintf("ws://localhost:%d/wsinfo", *s.port)
}

175
plugin/wshub/wshub.go Normal file
View File

@@ -0,0 +1,175 @@
package wshub
import (
"AynaLivePlayer/core/events"
"AynaLivePlayer/global"
"AynaLivePlayer/gui"
"AynaLivePlayer/gui/component"
"AynaLivePlayer/pkg/config"
"AynaLivePlayer/pkg/event"
"AynaLivePlayer/pkg/i18n"
"AynaLivePlayer/pkg/logger"
"encoding/json"
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/container"
"fyne.io/fyne/v2/data/binding"
"fyne.io/fyne/v2/theme"
"fyne.io/fyne/v2/widget"
)
type WsHub struct {
config.BaseConfig
Enabled bool
Port int
panel fyne.CanvasObject
server *wsServer
log logger.ILogger
}
func NewWsHub() *WsHub {
return &WsHub{
Enabled: false,
Port: 29629,
log: global.Logger.WithPrefix("plugin.wshub"),
}
}
func (w *WsHub) Enable() error {
config.LoadConfig(w)
w.server = newWsServer(&w.Port)
gui.AddConfigLayout(w)
w.registerEvents()
w.log.Info("webinfo loaded")
if w.Enabled {
w.log.Info("starting web backend server")
w.server.Start()
}
return nil
}
func (w *WsHub) Disable() error {
if w.server.Running {
err := w.server.Stop()
if err != nil {
w.log.Warnf("stop server have error: %s", err)
}
}
return nil
}
func (w *WsHub) Name() string {
return "WsHub"
}
func (w *WsHub) Title() string {
return i18n.T("plugin.wshub.title")
}
func (w *WsHub) Description() string {
return i18n.T("plugin.wshub.description")
}
func (w *WsHub) CreatePanel() fyne.CanvasObject {
if w.panel != nil {
return w.panel
}
statusText := widget.NewLabel("")
freshStatusText := func() {
if w.server.Running {
statusText.SetText(i18n.T("plugin.wshub.server_status.running"))
return
} else {
statusText.SetText(i18n.T("plugin.wshub.server_status.stopped"))
}
}
serverStatus := container.NewHBox(
widget.NewLabel(i18n.T("plugin.wshub.server_status")),
statusText,
)
autoStart := container.NewHBox(
widget.NewLabel(i18n.T("plugin.wshub.autostart")),
component.NewCheckOneWayBinding("", &w.Enabled, w.Enabled))
freshStatusText()
serverPort := container.NewBorder(nil, nil,
widget.NewLabel(i18n.T("plugin.wshub.port")), nil,
widget.NewEntryWithData(binding.IntToString(binding.BindInt(&w.Port))),
)
serverUrl := widget.NewEntry()
serverUrl.SetText(w.server.getWsUrl())
serverUrl.Disable()
serverPreview := container.NewBorder(nil, nil,
widget.NewLabel(i18n.T("plugin.wshub.server_link")), nil,
serverUrl,
)
refreshServerUrl := func() {
serverUrl.SetText(w.server.getWsUrl())
}
stopBtn := component.NewAsyncButtonWithIcon(
i18n.T("plugin.wshub.server_control.stop"),
theme.MediaStopIcon(),
func() {
if !w.server.Running {
return
}
w.log.Info("User try stop webinfo server")
err := w.server.Stop()
if err != nil {
w.log.Warnf("stop server have error: %s", err)
}
freshStatusText()
},
)
startBtn := component.NewAsyncButtonWithIcon(
i18n.T("plugin.wshub.server_control.start"),
theme.MediaPlayIcon(),
func() {
if w.server.Running {
return
}
w.log.Infof("User try start webinfo server with port %d", w.Port)
w.server.Start()
freshStatusText()
refreshServerUrl()
},
)
restartBtn := component.NewAsyncButtonWithIcon(
i18n.T("plugin.wshub.server_control.restart"),
theme.MediaReplayIcon(),
func() {
w.log.Infof("User try restart webinfo server with port %d", w.Port)
if w.server.Running {
if err := w.server.Stop(); err != nil {
w.log.Warnf("stop server have error: %s", err)
return
}
}
w.server.Start()
freshStatusText()
refreshServerUrl()
},
)
ctrlBtns := container.NewHBox(
widget.NewLabel(i18n.T("plugin.wshub.server_control")),
startBtn, stopBtn, restartBtn,
)
w.panel = container.NewVBox(serverStatus, autoStart, serverPreview, serverPort, ctrlBtns)
return nil
}
func (w *WsHub) registerEvents() {
for eid, _ := range events.EventsMapping {
global.EventManager.RegisterA(eid,
"plugin.wshub.event."+string(eid),
func(e *event.Event) {
val, err := json.Marshal(EventData{
EventID: e.Id,
Data: e.Data,
})
if err != nil {
w.log.Errorf("failed to marshal event data %v", err)
return
}
w.server.broadcast(val)
})
}
}