WIP legacy adapter.

This commit is contained in:
Miroslav Šedivý 2024-07-20 15:45:01 +02:00
parent e4c0c68d79
commit 260a1973f5
4 changed files with 823 additions and 205 deletions

View File

@ -38,14 +38,9 @@ func (h *LegacyHandler) Route(r types.Router) {
log.Println("legacy handler route") log.Println("legacy handler route")
r.Get("/ws", func(w http.ResponseWriter, r *http.Request) error { r.Get("/ws", func(w http.ResponseWriter, r *http.Request) error {
connBackend, _, err := DefaultDialer.Dial("ws://127.0.0.1:8080/api/ws?token="+r.URL.Query().Get("token"), nil) s := newSession("http://127.0.0.1:8080")
if err != nil {
return utils.HttpError(http.StatusServiceUnavailable).
WithInternalErr(err).
Msg("couldn't dial to remote backend url")
}
defer connBackend.Close()
// create a new websocket connection
connClient, err := DefaultUpgrader.Upgrade(w, r, nil) connClient, err := DefaultUpgrader.Upgrade(w, r, nil)
if err != nil { if err != nil {
return utils.HttpError(http.StatusInternalServerError). return utils.HttpError(http.StatusInternalServerError).
@ -53,10 +48,36 @@ func (h *LegacyHandler) Route(r types.Router) {
Msg("couldn't upgrade connection to websocket") Msg("couldn't upgrade connection to websocket")
} }
defer connClient.Close() defer connClient.Close()
s.connClient = connClient
// create a new session
password := r.URL.Query().Get("password")
token, err := s.create(password)
if err != nil {
log.Printf("couldn't create a new session: %v", err)
return nil
}
defer s.destroy()
// dial to the remote backend
connBackend, _, err := DefaultDialer.Dial("ws://127.0.0.1:8080/api/ws?token="+token, nil)
if err != nil {
log.Printf("couldn't dial to the remote backend: %v", err)
return nil
}
defer connBackend.Close()
s.connBackend = connBackend
// request signal
if err = connBackend.WriteMessage(websocket.TextMessage, []byte(`{"event":"signal/request", "payload":{}}`)); err != nil {
log.Printf("couldn't request signal: %v", err)
return nil
}
// copy messages between the client and the backend
errClient := make(chan error, 1) errClient := make(chan error, 1)
errBackend := make(chan error, 1) errBackend := make(chan error, 1)
replicateWebsocketConn := func(dst, src *websocket.Conn, errc chan error, rewriteTextMessage func([]byte) ([]byte, error)) { replicateWebsocketConn := func(dst, src *websocket.Conn, errc chan error, rewriteTextMessage func([]byte, func([]byte) error) error) {
for { for {
msgType, msg, err := src.ReadMessage() msgType, msg, err := src.ReadMessage()
if err != nil { if err != nil {
@ -71,25 +92,33 @@ func (h *LegacyHandler) Route(r types.Router) {
break break
} }
if msgType == websocket.TextMessage { if msgType == websocket.TextMessage {
msg, err = rewriteTextMessage(msg) doBreak := false
err = rewriteTextMessage(msg, func(msg []byte) error {
err := dst.WriteMessage(msgType, msg)
if err != nil {
doBreak = true
}
return err
})
if doBreak {
errc <- err
break
}
if err != nil { if err != nil {
log.Printf("websocketproxy: Error when rewriting message: %v", err) log.Printf("websocketproxy: Error when rewriting message: %v", err)
continue continue
} }
} }
err = dst.WriteMessage(msgType, msg)
if err != nil {
errc <- err
break
} }
} }
}
// client -> backend
go replicateWebsocketConn(connClient, connBackend, errClient, h.wsToBackend)
// backend -> client // backend -> client
go replicateWebsocketConn(connBackend, connClient, errBackend, h.wsToClient) go replicateWebsocketConn(connClient, connBackend, errClient, s.wsToClient)
// client -> backend
go replicateWebsocketConn(connBackend, connClient, errBackend, s.wsToBackend)
var message string var message string
select { select {
@ -97,7 +126,6 @@ func (h *LegacyHandler) Route(r types.Router) {
message = "websocketproxy: Error when copying from backend to client: %v" message = "websocketproxy: Error when copying from backend to client: %v"
case err = <-errBackend: case err = <-errBackend:
message = "websocketproxy: Error when copying from client to backend: %v" message = "websocketproxy: Error when copying from client to backend: %v"
} }
if e, ok := err.(*websocket.CloseError); !ok || e.Code == websocket.CloseAbnormalClosure { if e, ok := err.(*websocket.CloseError); !ok || e.Code == websocket.CloseAbnormalClosure {

View File

@ -0,0 +1,96 @@
package legacy
import (
"bytes"
"encoding/json"
"fmt"
"io"
"log"
"net/http"
"github.com/demodesk/neko/internal/api"
"github.com/demodesk/neko/pkg/types"
"github.com/gorilla/websocket"
)
type session struct {
url string
id string
token string
profile types.MemberProfile
client *http.Client
connClient *websocket.Conn
connBackend *websocket.Conn
}
func newSession(url string) *session {
return &session{
url: url,
client: http.DefaultClient,
}
}
func (s *session) apiReq(method, path string, request, response any) error {
body, err := json.Marshal(request)
if err != nil {
return err
}
req, err := http.NewRequest(method, s.url+path, bytes.NewReader(body))
if err != nil {
return err
}
req.Header.Set("Content-Type", "application/json")
if s.token != "" {
req.Header.Set("Authorization", "Bearer "+s.token)
}
res, err := s.client.Do(req)
if err != nil {
return err
}
defer res.Body.Close()
if res.StatusCode != http.StatusOK {
body, _ := io.ReadAll(res.Body)
return fmt.Errorf("unexpected status code: %d, body: %s", res.StatusCode, body)
}
return json.NewDecoder(res.Body).Decode(response)
}
func (s *session) create(password string) (string, error) {
data := api.SessionDataPayload{}
// pefrom login with arbitrary username that will be changed later
err := s.apiReq(http.MethodPost, "/api/login", api.SessionLoginPayload{
Username: "admin",
Password: password,
}, &data)
if err != nil {
return "", err
}
s.id = data.ID
s.token = data.Token
s.profile = data.Profile
if s.token == "" {
return "", fmt.Errorf("token not found")
}
return data.Token, nil
}
func (s *session) destroy() {
defer s.client.CloseIdleConnections()
// logout session
err := s.apiReq(http.MethodPost, "/api/logout", nil, nil)
if err != nil {
log.Println("failed to logout session:", err)
}
}

View File

@ -4,158 +4,293 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"github.com/demodesk/neko/internal/http/legacy/event" oldEvent "github.com/demodesk/neko/internal/http/legacy/event"
"github.com/demodesk/neko/internal/http/legacy/message" oldMessage "github.com/demodesk/neko/internal/http/legacy/message"
"github.com/pion/webrtc/v3"
"github.com/demodesk/neko/pkg/types"
"github.com/demodesk/neko/pkg/types/event"
"github.com/demodesk/neko/pkg/types/message"
chat "github.com/demodesk/neko/internal/plugins/chat"
filetransfer "github.com/demodesk/neko/internal/plugins/filetransfer"
) )
func (h *LegacyHandler) wsToBackend(msg []byte) ([]byte, error) { func (s *session) wsToBackend(msg []byte, sendMsg func([]byte) error) error {
header := message.Message{} header := oldMessage.Message{}
err := json.Unmarshal(msg, &header) err := json.Unmarshal(msg, &header)
if err != nil { if err != nil {
return nil, err return err
}
send := func(event string, payload any) error {
rawPayload, err := json.Marshal(payload)
if err != nil {
return err
}
msg, err := json.Marshal(&types.WebSocketMessage{
Event: event,
Payload: rawPayload,
})
if err != nil {
return err
}
return sendMsg(msg)
} }
var response any
switch header.Event { switch header.Event {
// Signal Events // Signal Events
case event.SIGNAL_OFFER: case oldEvent.SIGNAL_OFFER:
request := &message.SignalOffer{} request := &oldMessage.SignalOffer{}
err := json.Unmarshal(msg, request) err := json.Unmarshal(msg, request)
if err != nil { if err != nil {
return nil, err return err
} }
case event.SIGNAL_ANSWER: return send(event.SIGNAL_OFFER, &message.SignalDescription{
request := &message.SignalAnswer{} SDP: request.SDP,
})
case oldEvent.SIGNAL_ANSWER:
request := &oldMessage.SignalAnswer{}
err := json.Unmarshal(msg, request) err := json.Unmarshal(msg, request)
if err != nil { if err != nil {
return nil, err return err
} }
case event.SIGNAL_CANDIDATE: // TODO: Set Display Name here.
request := &message.SignalCandidate{}
return send(event.SIGNAL_ANSWER, &message.SignalDescription{
SDP: request.SDP,
})
case oldEvent.SIGNAL_CANDIDATE:
request := &oldMessage.SignalCandidate{}
err := json.Unmarshal(msg, request) err := json.Unmarshal(msg, request)
if err != nil { if err != nil {
return nil, err return err
} }
var candidate webrtc.ICECandidateInit
err = json.Unmarshal([]byte(request.Data), &candidate)
if err != nil {
return err
}
return send(event.SIGNAL_CANDIDATE, &message.SignalCandidate{
ICECandidateInit: candidate,
})
// Control Events // Control Events
case event.CONTROL_RELEASE: case oldEvent.CONTROL_RELEASE:
case event.CONTROL_REQUEST: return send(event.CONTROL_RELEASE, nil)
case event.CONTROL_GIVE:
request := &message.Control{} case oldEvent.CONTROL_REQUEST:
return send(event.CONTROL_REQUEST, nil)
case oldEvent.CONTROL_GIVE:
request := &oldMessage.Control{}
err := json.Unmarshal(msg, request) err := json.Unmarshal(msg, request)
if err != nil { if err != nil {
return nil, err return err
} }
case event.CONTROL_CLIPBOARD: // TODO: No WS equivalent, call HTTP API.
request := &message.Clipboard{} return fmt.Errorf("event not implemented: %s", header.Event)
case oldEvent.CONTROL_CLIPBOARD:
request := &oldMessage.Clipboard{}
err := json.Unmarshal(msg, request) err := json.Unmarshal(msg, request)
if err != nil { if err != nil {
return nil, err return err
} }
case event.CONTROL_KEYBOARD: return send(event.CLIPBOARD_SET, &message.ClipboardData{
request := &message.Keyboard{} Text: request.Text,
})
case oldEvent.CONTROL_KEYBOARD:
request := &oldMessage.Keyboard{}
err := json.Unmarshal(msg, request) err := json.Unmarshal(msg, request)
if err != nil { if err != nil {
return nil, err return err
} }
if request.Layout != nil {
err = send(event.KEYBOARD_MAP, &message.KeyboardMap{
KeyboardMap: types.KeyboardMap{
Layout: *request.Layout,
},
})
if err != nil {
return err
}
}
if request.CapsLock != nil || request.NumLock != nil || request.ScrollLock != nil {
err = send(event.KEYBOARD_MODIFIERS, &message.KeyboardModifiers{
KeyboardModifiers: types.KeyboardModifiers{
CapsLock: request.CapsLock,
NumLock: request.NumLock,
// ScrollLock: request.ScrollLock, // ScrollLock is deprecated.
},
})
if err != nil {
return err
}
}
return nil
// Chat Events // Chat Events
case event.CHAT_MESSAGE: case oldEvent.CHAT_MESSAGE:
request := &message.ChatReceive{} request := &oldMessage.ChatReceive{}
err := json.Unmarshal(msg, request) err := json.Unmarshal(msg, request)
if err != nil { if err != nil {
return nil, err return err
} }
case event.CHAT_EMOTE: return send(chat.CHAT_MESSAGE, &chat.Content{
request := &message.EmoteReceive{} Text: request.Content,
})
case oldEvent.CHAT_EMOTE:
request := &oldMessage.EmoteReceive{}
err := json.Unmarshal(msg, request) err := json.Unmarshal(msg, request)
if err != nil { if err != nil {
return nil, err return err
} }
// TODO: Emote plugin not implemented.
return fmt.Errorf("event not implemented: %s", header.Event)
// File Transfer Events // File Transfer Events
case event.FILETRANSFER_REFRESH: case oldEvent.FILETRANSFER_REFRESH:
return send(filetransfer.FILETRANSFER_UPDATE, nil)
// Screen Events // Screen Events
case event.SCREEN_RESOLUTION: case oldEvent.SCREEN_RESOLUTION:
case event.SCREEN_CONFIGURATIONS: // No WS equivalent, call HTTP API and return screen resolution.
case event.SCREEN_SET: return fmt.Errorf("event not implemented: %s", header.Event)
request := &message.ScreenResolution{}
case oldEvent.SCREEN_CONFIGURATIONS:
// No WS equivalent, call HTTP API and return screen configurations.
return fmt.Errorf("event not implemented: %s", header.Event)
case oldEvent.SCREEN_SET:
request := &oldMessage.ScreenResolution{}
err := json.Unmarshal(msg, request) err := json.Unmarshal(msg, request)
if err != nil { if err != nil {
return nil, err return err
} }
return send(event.SCREEN_SET, &message.ScreenSize{
ScreenSize: types.ScreenSize{
Width: request.Width,
Height: request.Height,
Rate: request.Rate,
},
})
// Broadcast Events // Broadcast Events
case event.BROADCAST_CREATE: case oldEvent.BROADCAST_CREATE:
request := &message.BroadcastCreate{} request := &oldMessage.BroadcastCreate{}
err := json.Unmarshal(msg, request) err := json.Unmarshal(msg, request)
if err != nil { if err != nil {
return nil, err return err
} }
case event.BROADCAST_DESTROY: // TODO: No WS equivalent, call HTTP API.
return fmt.Errorf("event not implemented: %s", header.Event)
case oldEvent.BROADCAST_DESTROY:
// TODO: No WS equivalent, call HTTP API.
return fmt.Errorf("event not implemented: %s", header.Event)
// Admin Events // Admin Events
case event.ADMIN_LOCK: case oldEvent.ADMIN_LOCK:
request := &message.AdminLock{} request := &oldMessage.AdminLock{}
err := json.Unmarshal(msg, request) err := json.Unmarshal(msg, request)
if err != nil { if err != nil {
return nil, err return err
} }
case event.ADMIN_UNLOCK: // TODO: No WS equivalent, call HTTP API.
request := &message.AdminLock{} return fmt.Errorf("event not implemented: %s", header.Event)
case oldEvent.ADMIN_UNLOCK:
request := &oldMessage.AdminLock{}
err := json.Unmarshal(msg, request) err := json.Unmarshal(msg, request)
if err != nil { if err != nil {
return nil, err return err
} }
case event.ADMIN_CONTROL: // TODO: No WS equivalent, call HTTP API.
case event.ADMIN_RELEASE: return fmt.Errorf("event not implemented: %s", header.Event)
case event.ADMIN_GIVE:
request := &message.Admin{} case oldEvent.ADMIN_CONTROL:
// TODO: No WS equivalent, call HTTP API.
return fmt.Errorf("event not implemented: %s", header.Event)
case oldEvent.ADMIN_RELEASE:
// TODO: No WS equivalent, call HTTP API.
return fmt.Errorf("event not implemented: %s", header.Event)
case oldEvent.ADMIN_GIVE:
request := &oldMessage.Admin{}
err := json.Unmarshal(msg, request) err := json.Unmarshal(msg, request)
if err != nil { if err != nil {
return nil, err return err
} }
case event.ADMIN_BAN: // TODO: No WS equivalent, call HTTP API.
request := &message.Admin{} return fmt.Errorf("event not implemented: %s", header.Event)
case oldEvent.ADMIN_BAN:
request := &oldMessage.Admin{}
err := json.Unmarshal(msg, request) err := json.Unmarshal(msg, request)
if err != nil { if err != nil {
return nil, err return err
} }
case event.ADMIN_KICK: // TODO: No WS equivalent, call HTTP API.
request := &message.Admin{} return fmt.Errorf("event not implemented: %s", header.Event)
case oldEvent.ADMIN_KICK:
request := &oldMessage.Admin{}
err := json.Unmarshal(msg, request) err := json.Unmarshal(msg, request)
if err != nil { if err != nil {
return nil, err return err
} }
case event.ADMIN_MUTE: // TODO: No WS equivalent, call HTTP API.
request := &message.Admin{} return fmt.Errorf("event not implemented: %s", header.Event)
case oldEvent.ADMIN_MUTE:
request := &oldMessage.Admin{}
err := json.Unmarshal(msg, request) err := json.Unmarshal(msg, request)
if err != nil { if err != nil {
return nil, err return err
} }
case event.ADMIN_UNMUTE: // TODO: No WS equivalent, call HTTP API.
request := &message.Admin{} return fmt.Errorf("event not implemented: %s", header.Event)
case oldEvent.ADMIN_UNMUTE:
request := &oldMessage.Admin{}
err := json.Unmarshal(msg, request) err := json.Unmarshal(msg, request)
if err != nil { if err != nil {
return nil, err return err
} }
// TODO: No WS equivalent, call HTTP API.
return fmt.Errorf("event not implemented: %s", header.Event)
default: default:
return nil, fmt.Errorf("unknown event type: %s", header.Event) return fmt.Errorf("unknown event type: %s", header.Event)
} }
return json.Marshal(request)
} }

View File

@ -2,161 +2,520 @@ package legacy
import ( import (
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"github.com/demodesk/neko/internal/http/legacy/event" oldEvent "github.com/demodesk/neko/internal/http/legacy/event"
"github.com/demodesk/neko/internal/http/legacy/message" oldMessage "github.com/demodesk/neko/internal/http/legacy/message"
oldTypes "github.com/demodesk/neko/internal/http/legacy/types"
"github.com/pion/webrtc/v3"
chat "github.com/demodesk/neko/internal/plugins/chat"
filetransfer "github.com/demodesk/neko/internal/plugins/filetransfer"
"github.com/demodesk/neko/pkg/types"
"github.com/demodesk/neko/pkg/types/event"
"github.com/demodesk/neko/pkg/types/message"
) )
func (h *LegacyHandler) wsToClient(msg []byte) ([]byte, error) { func sessionDataToMember(id string, session message.SessionData) (*oldTypes.Member, error) {
header := message.Message{} settings := chat.Settings{
err := json.Unmarshal(msg, &header) CanSend: true, // defaults to true
if err != nil { CanReceive: true, // defaults to true
return nil, err
} }
var payload any err := session.Profile.Plugins.Unmarshal(chat.PluginName, &settings)
switch header.Event { if err != nil && !errors.Is(err, types.ErrPluginSettingsNotFound) {
return nil, fmt.Errorf("unable to unmarshal %s plugin settings from global settings: %w", chat.PluginName, err)
}
return &oldTypes.Member{
ID: id,
Name: session.Profile.Name,
Admin: session.Profile.IsAdmin,
Muted: !settings.CanSend,
}, nil
}
func sendControlHost(request message.ControlHost, send func(payload any) error) error {
if request.HasHost {
if request.ID == request.HostID {
return send(&oldMessage.Control{
Event: oldEvent.CONTROL_LOCKED,
ID: request.ID,
})
}
return send(&oldMessage.ControlTarget{
Event: oldEvent.CONTROL_GIVE,
ID: request.ID,
Target: request.HostID,
})
}
if request.ID != "" {
return send(&oldMessage.Control{
Event: oldEvent.CONTROL_RELEASE,
ID: request.ID,
})
}
return nil
}
func (s *session) wsToClient(msg []byte, sendMsg func([]byte) error) error {
data := types.WebSocketMessage{}
err := json.Unmarshal(msg, &data)
if err != nil {
return err
}
send := func(payload any) error {
msg, err := json.Marshal(payload)
if err != nil {
return err
}
return sendMsg(msg)
}
switch data.Event {
// System Events // System Events
case: case event.SYSTEM_DISCONNECT:
payload = &message.SystemMessage{ request := &message.SystemDisconnect{}
Event: event.SYSTEM_DISCONNECT, err := json.Unmarshal(data.Payload, request)
if err != nil {
return err
} }
case:
payload = &message.SystemMessage{ return send(&oldMessage.SystemMessage{
Event: event.SYSTEM_ERROR, Event: oldEvent.SYSTEM_DISCONNECT,
Message: request.Message,
})
// case:
// send(&oldMessage.SystemMessage{
// Event: oldEvent.SYSTEM_ERROR,
// })
case event.SYSTEM_INIT:
request := &message.SystemInit{}
err := json.Unmarshal(data.Payload, request)
if err != nil {
return err
} }
case:
payload = &message.SystemInit{ //
Event: event.SYSTEM_INIT, // MembersList
//
membersList := []*oldTypes.Member{}
for id, session := range request.Sessions {
member, err := sessionDataToMember(id, session)
if err != nil {
return err
} }
membersList = append(membersList, member)
}
err = send(&oldMessage.MembersList{
Event: oldEvent.MEMBER_LIST,
Members: membersList,
})
if err != nil {
return err
}
//
// ScreenSize
//
err = send(&oldMessage.ScreenResolution{
Event: oldEvent.SCREEN_RESOLUTION,
Width: request.ScreenSize.Width,
Height: request.ScreenSize.Height,
Rate: request.ScreenSize.Rate,
})
if err != nil {
return err
}
// actually its already set when we create the session
s.id = request.SessionId
//
// ControlHost
//
err = sendControlHost(request.ControlHost, send)
if err != nil {
return err
}
//
// FileTransfer
//
filetransferSettings := filetransfer.Settings{
Enabled: true, // defaults to true
}
err = request.Settings.Plugins.Unmarshal(filetransfer.PluginName, &filetransferSettings)
if err != nil && !errors.Is(err, types.ErrPluginSettingsNotFound) {
return fmt.Errorf("unable to unmarshal %s plugin settings from global settings: %w", filetransfer.PluginName, err)
}
//
// Locks
//
locks := map[string]string{}
if request.Settings.LockedLogins {
locks["login"] = "" // TODO: We don't know who locked the login.
}
if request.Settings.LockedControls {
locks["control"] = "" // TODO: We don't know who locked the control.
}
if !filetransferSettings.Enabled {
locks["filetransfer"] = "" // TODO: We don't know who locked the file transfer.
}
return send(&oldMessage.SystemInit{
Event: oldEvent.SYSTEM_INIT,
ImplicitHosting: request.Settings.ImplicitHosting,
Locks: locks,
FileTransfer: true, // TODO: We don't know if file transfer is enabled, we would need to check the global config somehow.
})
case event.SYSTEM_ADMIN:
request := &message.SystemAdmin{}
err := json.Unmarshal(data.Payload, request)
if err != nil {
return err
}
//
// ScreenSizesList
//
rates := map[string][]int16{}
for _, size := range request.ScreenSizesList {
key := fmt.Sprintf("%dx%d", size.Width, size.Height)
rates[key] = append(rates[key], size.Rate)
}
usedScreenSizes := map[string]struct{}{}
screenSizesList := map[int]oldTypes.ScreenConfiguration{}
for i, size := range request.ScreenSizesList {
key := fmt.Sprintf("%dx%d", size.Width, size.Height)
if _, ok := usedScreenSizes[key]; ok {
continue
}
ratesMap := map[int]int16{}
for i, rate := range rates[key] {
ratesMap[i] = rate
}
screenSizesList[i] = oldTypes.ScreenConfiguration{
Width: size.Width,
Height: size.Height,
Rates: ratesMap,
}
}
err = send(&oldMessage.ScreenConfigurations{
Event: oldEvent.SCREEN_CONFIGURATIONS,
Configurations: screenSizesList,
})
if err != nil {
return err
}
//
// BroadcastStatus
//
return send(&oldMessage.BroadcastStatus{
Event: oldEvent.BROADCAST_STATUS,
URL: request.BroadcastStatus.URL,
IsActive: request.BroadcastStatus.IsActive,
})
// Member Events // Member Events
case:
payload = &message.MembersList{ // TODO: This is on Created but old API wants OnConnected.
Event: event.MEMBER_LIST, case event.SESSION_CREATED:
request := &message.SessionData{}
err := json.Unmarshal(data.Payload, request)
if err != nil {
return err
} }
case:
payload = &message.Member{ member, err := sessionDataToMember(request.ID, *request)
Event: event.MEMBER_CONNECTED, if err != nil {
return err
} }
case:
payload = &message.MemberDisconnected{ return send(&oldMessage.Member{
Event: event.MEMBER_DISCONNECTED, Event: oldEvent.MEMBER_CONNECTED,
Member: member,
})
// TODO: This is on Deleted but old API wants OnDisconnected.
case event.SESSION_DELETED:
request := &message.SessionID{}
err := json.Unmarshal(data.Payload, request)
if err != nil {
return err
} }
return send(&oldMessage.MemberDisconnected{
Event: oldEvent.MEMBER_DISCONNECTED,
ID: request.ID,
})
// TODO: This would need some context to know it message has been sent already/to get session data on connect.
//case event.SESSION_STATE:
// request := &message.SessionState{}
// err := json.Unmarshal(data.Payload, request)
// if err != nil {
// return err
// }
// if request.IsConnected {
// // oldEvent.MEMBER_CONNECTED if not sent already
// } else {
// // oldEvent.MEMBER_DISCONNECTED if nor sent already
// }
// Signal Events // Signal Events
case: case event.SIGNAL_OFFER:
payload = &message.SignalOffer{ request := &message.SignalDescription{}
Event: event.SIGNAL_OFFER, err := json.Unmarshal(data.Payload, request)
} if err != nil {
case: return err
payload = &message.SignalAnswer{
Event: event.SIGNAL_ANSWER,
}
case:
payload = &message.SignalCandidate{
Event: event.SIGNAL_CANDIDATE,
}
case:
payload = &message.SignalProvide{
Event: event.SIGNAL_PROVIDE,
} }
return send(&oldMessage.SignalOffer{
Event: oldEvent.SIGNAL_OFFER,
SDP: request.SDP,
})
case event.SIGNAL_ANSWER:
request := &message.SignalDescription{}
err := json.Unmarshal(data.Payload, request)
if err != nil {
return err
}
return send(&oldMessage.SignalAnswer{
Event: oldEvent.SIGNAL_ANSWER,
DisplayName: s.profile.Name, // DisplayName
SDP: request.SDP,
})
case event.SIGNAL_CANDIDATE:
request := &message.SignalCandidate{}
err := json.Unmarshal(data.Payload, request)
if err != nil {
return err
}
json, err := json.Marshal(request.ICECandidateInit)
if err != nil {
return err
}
return send(&oldMessage.SignalCandidate{
Event: oldEvent.SIGNAL_CANDIDATE,
Data: string(json),
})
case event.SIGNAL_PROVIDE:
request := &message.SignalProvide{}
err := json.Unmarshal(data.Payload, request)
if err != nil {
return err
}
iceServers := []webrtc.ICEServer{}
for _, ice := range request.ICEServers {
iceServers = append(iceServers, webrtc.ICEServer{
URLs: ice.URLs,
Username: ice.Username,
Credential: ice.Credential,
CredentialType: webrtc.ICECredentialTypePassword,
})
}
return send(&oldMessage.SignalProvide{
Event: oldEvent.SIGNAL_PROVIDE,
ID: s.id, // SessionId
SDP: request.SDP,
Lite: len(iceServers) == 0, // if no ICE servers are provided, it's a lite offer
ICE: iceServers,
})
// Control Events // Control Events
case: case event.CLIPBOARD_UPDATED:
payload = &message.Clipboard{ request := &message.ClipboardData{}
Event: event.CONTROL_CLIPBOARD, err := json.Unmarshal(data.Payload, request)
if err != nil {
return err
} }
case:
payload = &message.Control{ return send(&oldMessage.Clipboard{
Event: event.CONTROL_REQUEST, Event: oldEvent.CONTROL_CLIPBOARD,
Text: request.Text,
})
case event.CONTROL_HOST:
request := &message.ControlHost{}
err := json.Unmarshal(data.Payload, request)
if err != nil {
return err
} }
case:
payload = &message.Control{ return sendControlHost(*request, send)
Event: event.CONTROL_REQUESTING,
case event.CONTROL_REQUEST:
request := &message.SessionID{}
err := json.Unmarshal(data.Payload, request)
if err != nil {
return err
} }
case:
payload = &message.ControlTarget{ if s.id == request.ID {
Event: event.CONTROL_GIVE, // if i am the one that is requesting, send CONTROL_REQUEST to me
} // message.AdminTarget return send(&oldMessage.Control{
case: Event: oldEvent.CONTROL_REQUEST,
payload = &message.Control{ ID: request.ID,
Event: event.CONTROL_RELEASE, })
} } else {
case: // if not, let me know someone else is requesting
payload = &message.Control{ return send(&oldMessage.Control{
Event: event.CONTROL_LOCKED, Event: oldEvent.CONTROL_REQUESTING,
ID: request.ID,
})
} }
// Chat Events // Chat Events
case: case chat.CHAT_MESSAGE:
payload = &message.ChatSend{ request := &chat.Message{}
Event: event.CHAT_MESSAGE, err := json.Unmarshal(data.Payload, request)
} if err != nil {
case: return err
payload = &message.EmoteSend{
Event: event.CHAT_EMOTE,
} }
return send(&oldMessage.ChatSend{
Event: oldEvent.CHAT_MESSAGE,
ID: request.ID,
Content: request.Content.Text,
})
// TODO: emotes.
//case:
// send(&oldMessage.EmoteSend{
// Event: oldEvent.CHAT_EMOTE,
// })
// File Transfer Events // File Transfer Events
case: case filetransfer.FILETRANSFER_UPDATE:
payload = &message.FileTransferList{ request := &filetransfer.Message{}
Event: event.FILETRANSFER_LIST, err := json.Unmarshal(data.Payload, request)
if err != nil {
return err
} }
files := []oldTypes.FileListItem{}
for _, file := range request.Files {
var itemType string
switch file.Type {
case filetransfer.ItemTypeFile:
itemType = "file"
case filetransfer.ItemTypeDir:
itemType = "dir"
}
files = append(files, oldTypes.FileListItem{
Filename: file.Name,
Type: itemType,
Size: file.Size,
})
}
return send(&oldMessage.FileTransferList{
Event: oldEvent.FILETRANSFER_LIST,
Cwd: request.RootDir,
Files: files,
})
// Screen Events // Screen Events
case: case event.SCREEN_UPDATED:
payload = &message.ScreenResolution{ request := &message.ScreenSizeUpdate{}
Event: event.SCREEN_RESOLUTION, err := json.Unmarshal(data.Payload, request)
} if err != nil {
case: return err
payload = &message.ScreenConfigurations{
Event: event.SCREEN_CONFIGURATIONS,
} }
return send(&oldMessage.ScreenResolution{
Event: oldEvent.SCREEN_RESOLUTION,
ID: request.ID,
Width: request.ScreenSize.Width,
Height: request.ScreenSize.Height,
Rate: request.ScreenSize.Rate,
})
// Broadcast Events // Broadcast Events
case: case event.BROADCAST_STATUS:
payload = &message.BroadcastStatus{ request := &message.BroadcastStatus{}
Event: event.BROADCAST_STATUS, err := json.Unmarshal(data.Payload, request)
if err != nil {
return err
} }
return send(&oldMessage.BroadcastStatus{
Event: oldEvent.BROADCAST_STATUS,
URL: request.URL,
IsActive: request.IsActive,
})
/*
// Admin Events // Admin Events
case: case:
payload = &message.AdminLock{ send(&oldMessage.AdminLock{
Event: event.ADMIN_UNLOCK, Event: oldEvent.ADMIN_UNLOCK,
} })
case: case:
payload = &message.AdminLock{ send(&oldMessage.AdminLock{
Event: event.ADMIN_LOCK, Event: oldEvent.ADMIN_LOCK,
} })
case: case:
payload = &message.AdminTarget{ send(&oldMessage.AdminTarget{
Event: event.ADMIN_CONTROL, Event: oldEvent.ADMIN_CONTROL,
} // message.Admin } // )oldMessage.Admin
case: case:
payload = &message.AdminTarget{ send(&oldMessage.AdminTarget{
Event: event.ADMIN_RELEASE, Event: oldEvent.ADMIN_RELEASE,
} // message.Admin } // )oldMessage.Admin
case: case:
payload = &message.AdminTarget{ send(&oldMessage.AdminTarget{
Event: event.ADMIN_MUTE, Event: oldEvent.ADMIN_MUTE,
} })
case: case:
payload = &message.AdminTarget{ send(&oldMessage.AdminTarget{
Event: event.ADMIN_UNMUTE, Event: oldEvent.ADMIN_UNMUTE,
} })
case: case:
payload = &message.AdminTarget{ send(&oldMessage.AdminTarget{
Event: event.ADMIN_KICK, Event: oldEvent.ADMIN_KICK,
} })
case: case:
payload = &message.AdminTarget{ send(&oldMessage.AdminTarget{
Event: event.ADMIN_BAN, Event: oldEvent.ADMIN_BAN,
} })
default: */
return nil, fmt.Errorf("unknown event type: %s", header.Event)
}
return json.Marshal(payload) case event.SYSTEM_HEARTBEAT:
return nil
default:
return fmt.Errorf("unknown event type: %s", data.Event)
}
} }