From 822f3197b6f710a1a62da481f4564fa8dd527091 Mon Sep 17 00:00:00 2001 From: jamesread Date: Thu, 6 Nov 2025 09:52:16 +0000 Subject: [PATCH] chore: (#675) Remove dead websocket code --- service/internal/websocket/websocket.go | 185 ------------------------ service/main.go | 3 - 2 files changed, 188 deletions(-) delete mode 100644 service/internal/websocket/websocket.go diff --git a/service/internal/websocket/websocket.go b/service/internal/websocket/websocket.go deleted file mode 100644 index f489988..0000000 --- a/service/internal/websocket/websocket.go +++ /dev/null @@ -1,185 +0,0 @@ -package websocket - -import ( - "net/http" - "sync" - - apiv1 "github.com/OliveTin/OliveTin/gen/olivetin/api/v1" - "github.com/OliveTin/OliveTin/internal/executor" - ws "github.com/gorilla/websocket" - log "github.com/sirupsen/logrus" - "google.golang.org/protobuf/encoding/protojson" - "google.golang.org/protobuf/reflect/protoreflect" -) - -var upgrader = ws.Upgrader{ - CheckOrigin: checkOriginPermissive, -} - -var ( - sendmutex = sync.Mutex{} -) - -type WebsocketClient struct { - conn *ws.Conn -} - -var clients []*WebsocketClient - -var marshalOptions = protojson.MarshalOptions{ - UseProtoNames: false, // eg: canExec for js instead of can_exec from protobuf - EmitUnpopulated: true, -} - -var ExecutionListener WebsocketExecutionListener - -type WebsocketExecutionListener struct{} - -func (WebsocketExecutionListener) OnExecutionStarted(ile *executor.InternalLogEntry) { - broadcast(&apiv1.EventExecutionStarted{ - LogEntry: internalLogEntryToPb(ile), - }) -} - -func OnEntityChanged() { - broadcast(&apiv1.EventEntityChanged{}) -} - -func (WebsocketExecutionListener) OnActionMapRebuilt() { - broadcast(&apiv1.EventConfigChanged{}) -} - -/* -The default checkOrigin function checks that the origin (browser) matches the -request origin. However in OliveTin we expect many users to deliberately proxy -the connection with reverse proxies. - -So, we just permit any origin. After some searching I'm not sure if this exposes -OliveTin to security issues, but it seems probably not. It would be possible to -create a config option like PermitWebsocketConnectionsFrom or something, but -I'd prefer if OliveTin works as much as possible "out of the box". - -If this does expose OliveTin to security issues, it will be changed in the -future obviously. -*/ -func checkOriginPermissive(r *http.Request) bool { - return true -} - -func (WebsocketExecutionListener) OnOutputChunk(chunk []byte, executionTrackingId string) { - log.Tracef("outputchunk: %s", string(chunk)) - - oc := &apiv1.EventOutputChunk{ - Output: string(chunk), - ExecutionTrackingId: executionTrackingId, - } - - broadcast(oc) -} - -func (WebsocketExecutionListener) OnExecutionFinished(logEntry *executor.InternalLogEntry) { - evt := &apiv1.EventExecutionFinished{ - LogEntry: internalLogEntryToPb(logEntry), - } - - log.Infof("WS Execution finished: %v", evt.LogEntry) - - broadcast(evt) -} - -func broadcast(pbmsg protoreflect.ProtoMessage) { - payload, err := marshalOptions.Marshal(pbmsg) - - if err != nil { - log.Errorf("websocket marshal error: %v", err) - return - } - - messageType := pbmsg.ProtoReflect().Descriptor().FullName() - - // - // So, the websocket wants to encode messages using the same protomarshaller - // as the REST API - this gives consistency instead of using encoding/json - // and allows us to set specific marshalOptions. - // - // However, the protomarshaller will marshal the type, but the JavaScript at - // the other end has no idea what type this object is - as we're just sending - // it as JSON over the websocket. - // - // Therefore, we wrap the nicely marsheled bytes in a hacky JSON string - // literal and encode that string just with a byte array cast. - hackyMessageEnvelope := "{\"type\": \"" + messageType + "\", \"payload\": " - - hackyMessage := []byte{} - hackyMessage = append(hackyMessage, []byte(hackyMessageEnvelope)...) - hackyMessage = append(hackyMessage, payload...) - hackyMessage = append(hackyMessage, []byte("}")...) - // - - sendmutex.Lock() - for _, client := range clients { - err := client.conn.WriteMessage(ws.TextMessage, hackyMessage) - - if err != nil { - log.Warnf("websocket send error: %v", err) - } - } - sendmutex.Unlock() -} - -func (c *WebsocketClient) messageLoop() { - for { - mt, message, err := c.conn.ReadMessage() - - if err != nil { - log.Debugf("err: %v", err) - break - } - - log.Tracef("websocket recv: %s %d", message, mt) - } -} - -func HandleWebsocket(w http.ResponseWriter, r *http.Request) bool { - c, err := upgrader.Upgrade(w, r, nil) - - if err != nil { - log.Warnf("Websocket issue: %v", err) - return false - } - - // defer c.Close() - - wsclient := &WebsocketClient{ - conn: c, - } - - sendmutex.Lock() - - clients = append(clients, wsclient) - - sendmutex.Unlock() - - go wsclient.messageLoop() - - return true -} - -func internalLogEntryToPb(logEntry *executor.InternalLogEntry) *apiv1.LogEntry { - return &apiv1.LogEntry{ - ActionTitle: logEntry.ActionTitle, - ActionIcon: logEntry.ActionIcon, - ActionId: logEntry.ActionId, - DatetimeStarted: logEntry.DatetimeStarted.Format("2006-01-02 15:04:05"), - DatetimeFinished: logEntry.DatetimeFinished.Format("2006-01-02 15:04:05"), - Output: logEntry.Output, - TimedOut: logEntry.TimedOut, - Blocked: logEntry.Blocked, - ExitCode: logEntry.ExitCode, - Tags: logEntry.Tags, - ExecutionTrackingId: logEntry.ExecutionTrackingID, - ExecutionStarted: logEntry.ExecutionStarted, - ExecutionFinished: logEntry.ExecutionFinished, - User: logEntry.Username, - } -} diff --git a/service/main.go b/service/main.go index 1068d81..f1dd357 100644 --- a/service/main.go +++ b/service/main.go @@ -18,7 +18,6 @@ import ( "github.com/OliveTin/OliveTin/internal/onstartup" "github.com/OliveTin/OliveTin/internal/servicehost" updatecheck "github.com/OliveTin/OliveTin/internal/updatecheck" - "github.com/OliveTin/OliveTin/internal/websocket" "os" "strconv" @@ -225,7 +224,6 @@ func main() { executor := executor.DefaultExecutor(cfg) executor.RebuildActionMap() - executor.AddListener(websocket.ExecutionListener) config.AddListener(executor.RebuildActionMap) go onstartup.Execute(cfg, executor) @@ -233,7 +231,6 @@ func main() { go onfileindir.WatchFilesInDirectory(cfg, executor) go oncalendarfile.Schedule(cfg, executor) - entities.AddListener(websocket.OnEntityChanged) entities.AddListener(executor.RebuildActionMap) go entities.SetupEntityFileWatchers(cfg)