progress on server refactor
This commit is contained in:
parent
81abb88317
commit
78af798d68
@ -6,7 +6,6 @@ require (
|
|||||||
github.com/go-chi/chi v4.0.3+incompatible
|
github.com/go-chi/chi v4.0.3+incompatible
|
||||||
github.com/gorilla/websocket v1.4.1
|
github.com/gorilla/websocket v1.4.1
|
||||||
github.com/kataras/go-events v0.0.2
|
github.com/kataras/go-events v0.0.2
|
||||||
github.com/matoous/go-nanoid v1.1.0
|
|
||||||
github.com/pion/logging v0.2.2
|
github.com/pion/logging v0.2.2
|
||||||
github.com/pion/webrtc/v2 v2.1.18
|
github.com/pion/webrtc/v2 v2.1.18
|
||||||
github.com/pkg/errors v0.8.1
|
github.com/pkg/errors v0.8.1
|
||||||
|
@ -81,8 +81,6 @@ github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzR
|
|||||||
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||||
github.com/marten-seemann/qtls v0.2.3 h1:0yWJ43C62LsZt08vuQJDK1uC1czUc3FJeCLPoNAI4vA=
|
github.com/marten-seemann/qtls v0.2.3 h1:0yWJ43C62LsZt08vuQJDK1uC1czUc3FJeCLPoNAI4vA=
|
||||||
github.com/marten-seemann/qtls v0.2.3/go.mod h1:xzjG7avBwGGbdZ8dTGxlBnLArsVKLvwmjgmPuiQEcYk=
|
github.com/marten-seemann/qtls v0.2.3/go.mod h1:xzjG7avBwGGbdZ8dTGxlBnLArsVKLvwmjgmPuiQEcYk=
|
||||||
github.com/matoous/go-nanoid v1.1.0 h1:B4BSMxTVgYrCHqtovL/adb8GFkE4mPCNntOOrdZLeCk=
|
|
||||||
github.com/matoous/go-nanoid v1.1.0/go.mod h1:L+uFUqrYwDgNWu5R02GrSxxcqX7ghiFuKPlKEOZ90GE=
|
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
|
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||||
|
@ -1,15 +1,25 @@
|
|||||||
package event
|
package event
|
||||||
|
|
||||||
const SDP_REPLY = "sdp/reply"
|
const SIGNAL_ANSWER = "signal/answer"
|
||||||
const SDP_PROVIDE = "sdp/provide"
|
const SIGNAL_PROVIDE = "signal/provide"
|
||||||
|
|
||||||
const CONTROL_RELEASE = "control/release"
|
|
||||||
const CONTROL_RELEASED = "control/released"
|
|
||||||
const CONTROL_REQUEST = "control/request"
|
|
||||||
const CONTROL_GIVE = "control/give"
|
|
||||||
const CONTROL_GIVEN = "control/given"
|
|
||||||
const CONTROL_LOCKED = "control/locked"
|
|
||||||
const CONTROL_REQUESTING = "control/requesting"
|
|
||||||
|
|
||||||
const IDENTITY_PROVIDE = "identity/provide"
|
const IDENTITY_PROVIDE = "identity/provide"
|
||||||
const IDENTITY_NAME = "identity/name"
|
const IDENTITY_DETAILS = "identity/details"
|
||||||
|
|
||||||
|
const MEMBER_LIST = "member/list"
|
||||||
|
const MEMBER_CONNECTED = "member/connected"
|
||||||
|
const MEMBER_DISCONNECTED = "member/disconnected"
|
||||||
|
|
||||||
|
const CONTROL_LOCKED = "control/locked"
|
||||||
|
const CONTROL_RELEASE = "control/release"
|
||||||
|
const CONTROL_REQUEST = "control/request"
|
||||||
|
const CONTROL_REQUESTING = "control/requesting"
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
const ADMIN_BAN = "admin/ban"
|
||||||
|
const ADMIN_KICK = "admin/kick"
|
||||||
|
const ADMIN_LOCK = "admin/lock"
|
||||||
|
const ADMIN_MUTE = "admin/mute"
|
||||||
|
const ADMIN_UNMUTE = "admin/unmute"
|
||||||
|
const ADMIN_FORCE_CONTROL = "admin/force/control"
|
||||||
|
const ADMIN_FORCE_RELEASE = "admin/force/release"
|
||||||
|
@ -1,15 +1,47 @@
|
|||||||
package message
|
package message
|
||||||
|
|
||||||
|
import "n.eko.moe/neko/internal/session"
|
||||||
|
|
||||||
type Message struct {
|
type Message struct {
|
||||||
Event string `json:"event"`
|
Event string `json:"event"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type IdentityProvide struct {
|
type Identity struct {
|
||||||
Message
|
Message
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type SDP struct {
|
type IdentityDetails struct {
|
||||||
|
Message
|
||||||
|
Username string `json:"username"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Signal struct {
|
||||||
Message
|
Message
|
||||||
SDP string `json:"sdp"`
|
SDP string `json:"sdp"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Members struct {
|
||||||
|
Message
|
||||||
|
Memebers []*session.Session `json:"members"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Member struct {
|
||||||
|
Message
|
||||||
|
*session.Session
|
||||||
|
}
|
||||||
|
type MemberDisconnected struct {
|
||||||
|
Message
|
||||||
|
ID string `json:"id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Control struct {
|
||||||
|
Message
|
||||||
|
ID string `json:"id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Chat struct {
|
||||||
|
Message
|
||||||
|
ID string `json:"id"`
|
||||||
|
Content string `json:"content"`
|
||||||
|
}
|
||||||
|
@ -29,6 +29,7 @@ func (m *SessionManager) New(id string, admin bool, socket *websocket.Conn) *Ses
|
|||||||
ID: id,
|
ID: id,
|
||||||
Admin: admin,
|
Admin: admin,
|
||||||
socket: socket,
|
socket: socket,
|
||||||
|
connected: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
m.members[id] = session
|
m.members[id] = session
|
||||||
@ -76,6 +77,17 @@ func (m *SessionManager) Get(id string) (*Session, bool) {
|
|||||||
return session, ok
|
return session, ok
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *SessionManager) GetConnected() []*Session {
|
||||||
|
var sessions []*Session
|
||||||
|
for _, sess := range m.members {
|
||||||
|
if sess.connected {
|
||||||
|
sessions = append(sessions, sess)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sessions
|
||||||
|
}
|
||||||
|
|
||||||
func (m *SessionManager) Set(id string, session *Session) {
|
func (m *SessionManager) Set(id string, session *Session) {
|
||||||
m.members[id] = session
|
m.members[id] = session
|
||||||
}
|
}
|
||||||
@ -115,6 +127,8 @@ func (m *SessionManager) SetName(id string, name string) (bool, error) {
|
|||||||
session, ok := m.members[id]
|
session, ok := m.members[id]
|
||||||
if ok {
|
if ok {
|
||||||
session.Name = name
|
session.Name = name
|
||||||
|
session.connected = true
|
||||||
|
m.emmiter.Emit("connected", id, session)
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,24 +140,21 @@ func (m *SessionManager) Clear() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *SessionManager) Brodcast(v interface{}, exclude interface{}) error {
|
func (m *SessionManager) Brodcast(v interface{}, exclude interface{}) error {
|
||||||
if exclude != nil {
|
|
||||||
for id, sess := range m.members {
|
for id, sess := range m.members {
|
||||||
if in, _ := utils.ArrayIn(id, exclude); in {
|
if !sess.connected {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := sess.Send(v); err != nil {
|
if exclude != nil {
|
||||||
return err
|
if in, _ := utils.ArrayIn(id, exclude); in {
|
||||||
}
|
continue
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for _, sess := range m.members {
|
|
||||||
if err := sess.Send(v); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := sess.Send(v); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -165,6 +176,12 @@ func (m *SessionManager) OnCreated(listener func(id string, session *Session)) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *SessionManager) OnConnected(listener func(id string, session *Session)) {
|
||||||
|
m.emmiter.On("connected", func(payload ...interface{}) {
|
||||||
|
listener(payload[0].(string), payload[1].(*Session))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func (m *SessionManager) OnDestroy(listener func(id string)) {
|
func (m *SessionManager) OnDestroy(listener func(id string)) {
|
||||||
m.emmiter.On("destroyed", func(payload ...interface{}) {
|
m.emmiter.On("destroyed", func(payload ...interface{}) {
|
||||||
listener(payload[0].(string))
|
listener(payload[0].(string))
|
||||||
|
@ -8,9 +8,10 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Session struct {
|
type Session struct {
|
||||||
ID string
|
ID string `json:"id"`
|
||||||
Name string
|
Name string `json:"username"`
|
||||||
Admin bool
|
Admin bool `json:"admin"`
|
||||||
|
connected bool
|
||||||
socket *websocket.Conn
|
socket *websocket.Conn
|
||||||
peer *webrtc.PeerConnection
|
peer *webrtc.PeerConnection
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
|
98
server/internal/utils/uid.go
Normal file
98
server/internal/utils/uid.go
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/rand"
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
defaultAlphabet = "_-0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" // len=64
|
||||||
|
defaultSize = 21
|
||||||
|
defaultMaskSize = 5
|
||||||
|
)
|
||||||
|
|
||||||
|
// Generator function
|
||||||
|
type Generator func([]byte) (int, error)
|
||||||
|
|
||||||
|
// BytesGenerator is the default bytes generator
|
||||||
|
var BytesGenerator Generator = rand.Read
|
||||||
|
|
||||||
|
func initMasks(params ...int) []uint {
|
||||||
|
var size int
|
||||||
|
if len(params) == 0 {
|
||||||
|
size = defaultMaskSize
|
||||||
|
} else {
|
||||||
|
size = params[0]
|
||||||
|
}
|
||||||
|
masks := make([]uint, size)
|
||||||
|
for i := 0; i < size; i++ {
|
||||||
|
shift := 3 + i
|
||||||
|
masks[i] = (2 << uint(shift)) - 1
|
||||||
|
}
|
||||||
|
return masks
|
||||||
|
}
|
||||||
|
|
||||||
|
func getMask(alphabet string, masks []uint) int {
|
||||||
|
for i := 0; i < len(masks); i++ {
|
||||||
|
curr := int(masks[i])
|
||||||
|
if curr >= len(alphabet)-1 {
|
||||||
|
return curr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// GenerateUID is a low-level function to change alphabet and ID size.
|
||||||
|
func GenerateUID(alphabet string, size int) (string, error) {
|
||||||
|
if len(alphabet) == 0 || len(alphabet) > 255 {
|
||||||
|
return "", fmt.Errorf("alphabet must not empty and contain no more than 255 chars. Current len is %d", len(alphabet))
|
||||||
|
}
|
||||||
|
if size <= 0 {
|
||||||
|
return "", fmt.Errorf("size must be positive integer")
|
||||||
|
}
|
||||||
|
|
||||||
|
masks := initMasks(size)
|
||||||
|
mask := getMask(alphabet, masks)
|
||||||
|
ceilArg := 1.6 * float64(mask*size) / float64(len(alphabet))
|
||||||
|
step := int(math.Ceil(ceilArg))
|
||||||
|
|
||||||
|
id := make([]byte, size)
|
||||||
|
bytes := make([]byte, step)
|
||||||
|
for j := 0; ; {
|
||||||
|
_, err := BytesGenerator(bytes)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
for i := 0; i < step; i++ {
|
||||||
|
currByte := bytes[i] & byte(mask)
|
||||||
|
if currByte < byte(len(alphabet)) {
|
||||||
|
id[j] = alphabet[currByte]
|
||||||
|
j++
|
||||||
|
if j == size {
|
||||||
|
return string(id[:size]), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewUID generates secure URL-friendly unique ID.
|
||||||
|
func NewUID(param ...int) (string, error) {
|
||||||
|
var size int
|
||||||
|
if len(param) == 0 {
|
||||||
|
size = defaultSize
|
||||||
|
} else {
|
||||||
|
size = param[0]
|
||||||
|
}
|
||||||
|
bytes := make([]byte, size)
|
||||||
|
_, err := BytesGenerator(bytes)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
id := make([]byte, size)
|
||||||
|
for i := 0; i < size; i++ {
|
||||||
|
id[i] = defaultAlphabet[bytes[i]&63]
|
||||||
|
}
|
||||||
|
return string(id[:size]), nil
|
||||||
|
}
|
@ -25,7 +25,6 @@ type loggerFactory struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (l loggerFactory) NewLogger(subsystem string) logging.LeveledLogger {
|
func (l loggerFactory) NewLogger(subsystem string) logging.LeveledLogger {
|
||||||
l.logger.Debug().Msgf("creating logger for %s", subsystem)
|
|
||||||
return logger{
|
return logger{
|
||||||
logger: l.logger.With().Str("subsystem", subsystem).Logger(),
|
logger: l.logger.With().Str("subsystem", subsystem).Logger(),
|
||||||
}
|
}
|
||||||
|
@ -192,8 +192,8 @@ func (m *WebRTCManager) CreatePeer(id string, sdp string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := session.Send(message.SDP{
|
if err := session.Send(message.Signal{
|
||||||
Message: message.Message{Event: event.SDP_REPLY},
|
Message: message.Message{Event: event.SIGNAL_ANSWER},
|
||||||
SDP: answer.SDP,
|
SDP: answer.SDP,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return err
|
return err
|
||||||
|
78
server/internal/websocket/control.go
Normal file
78
server/internal/websocket/control.go
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
package websocket
|
||||||
|
|
||||||
|
import (
|
||||||
|
"n.eko.moe/neko/internal/event"
|
||||||
|
"n.eko.moe/neko/internal/message"
|
||||||
|
"n.eko.moe/neko/internal/session"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (h *MessageHandler) controlRelease(id string, session *session.Session) error {
|
||||||
|
|
||||||
|
// check if session is host
|
||||||
|
if !h.sessions.IsHost(id) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// release host
|
||||||
|
h.logger.Debug().Str("id", id).Msgf("host called %s", event.CONTROL_RELEASE)
|
||||||
|
h.sessions.ClearHost()
|
||||||
|
|
||||||
|
// tell everyone
|
||||||
|
if err := h.sessions.Brodcast(
|
||||||
|
message.Control{
|
||||||
|
Message: message.Message{Event: event.CONTROL_RELEASE},
|
||||||
|
ID: id,
|
||||||
|
}, nil); err != nil {
|
||||||
|
h.logger.Warn().Err(err).Msgf("brodcasting event %s has failed", event.CONTROL_RELEASE)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *MessageHandler) controlRequest(id string, session *session.Session) error {
|
||||||
|
h.logger.Debug().Str("id", id).Msgf("user called %s", event.CONTROL_REQUEST)
|
||||||
|
|
||||||
|
// check for host
|
||||||
|
if !h.sessions.HasHost() {
|
||||||
|
// set host
|
||||||
|
h.sessions.SetHost(id)
|
||||||
|
|
||||||
|
// let everyone know
|
||||||
|
if err := h.sessions.Brodcast(
|
||||||
|
message.Control{
|
||||||
|
Message: message.Message{Event: event.CONTROL_LOCKED},
|
||||||
|
ID: id,
|
||||||
|
}, nil); err != nil {
|
||||||
|
h.logger.Warn().Err(err).Msgf("brodcasting event %s has failed", event.CONTROL_LOCKED)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// get host
|
||||||
|
host, ok := h.sessions.GetHost()
|
||||||
|
if ok {
|
||||||
|
|
||||||
|
// tell session there is a host
|
||||||
|
if err := session.Send(message.Control{
|
||||||
|
Message: message.Message{Event: event.CONTROL_REQUEST},
|
||||||
|
ID: host.ID,
|
||||||
|
}); err != nil {
|
||||||
|
h.logger.Warn().Err(err).Str("id", id).Msgf("sending event %s has failed", event.CONTROL_REQUEST)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// tell host session wants to be host
|
||||||
|
if err := host.Send(message.Control{
|
||||||
|
Message: message.Message{Event: event.CONTROL_REQUESTING},
|
||||||
|
ID: id,
|
||||||
|
}); err != nil {
|
||||||
|
h.logger.Warn().Err(err).Str("id", host.ID).Msgf("sending event %s has failed", event.CONTROL_REQUESTING)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
@ -6,12 +6,12 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
gonanoid "github.com/matoous/go-nanoid"
|
|
||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
|
|
||||||
"n.eko.moe/neko/internal/config"
|
"n.eko.moe/neko/internal/config"
|
||||||
"n.eko.moe/neko/internal/session"
|
"n.eko.moe/neko/internal/session"
|
||||||
|
"n.eko.moe/neko/internal/utils"
|
||||||
"n.eko.moe/neko/internal/webrtc"
|
"n.eko.moe/neko/internal/webrtc"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -38,8 +38,6 @@ func New(sessions *session.SessionManager, webrtc *webrtc.WebRTCManager, conf *c
|
|||||||
// Send pings to peer with this period. Must be less than pongWait.
|
// Send pings to peer with this period. Must be less than pongWait.
|
||||||
const pingPeriod = 60 * time.Second
|
const pingPeriod = 60 * time.Second
|
||||||
|
|
||||||
const alphabet = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
|
||||||
|
|
||||||
type WebSocketHandler struct {
|
type WebSocketHandler struct {
|
||||||
logger zerolog.Logger
|
logger zerolog.Logger
|
||||||
upgrader websocket.Upgrader
|
upgrader websocket.Upgrader
|
||||||
@ -65,15 +63,23 @@ func (ws *WebSocketHandler) Start() error {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
ws.sessions.OnCreated(func(id string, session *session.Session) {
|
ws.sessions.OnCreated(func(id string, session *session.Session) {
|
||||||
if err := ws.handler.Created(id, session); err != nil {
|
if err := ws.handler.SessionCreated(id, session); err != nil {
|
||||||
ws.logger.Warn().Str("id", id).Err(err).Msg("session created with and error")
|
ws.logger.Warn().Str("id", id).Err(err).Msg("session created with and error")
|
||||||
} else {
|
} else {
|
||||||
ws.logger.Debug().Str("id", id).Msg("session created")
|
ws.logger.Debug().Str("id", id).Msg("session created")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
ws.sessions.OnConnected(func(id string, session *session.Session) {
|
||||||
|
if err := ws.handler.SessionConnected(id, session); err != nil {
|
||||||
|
ws.logger.Warn().Str("id", id).Err(err).Msg("session connected with and error")
|
||||||
|
} else {
|
||||||
|
ws.logger.Debug().Str("id", id).Msg("session connected")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
ws.sessions.OnDestroy(func(id string) {
|
ws.sessions.OnDestroy(func(id string) {
|
||||||
if err := ws.handler.Destroyed(id); err != nil {
|
if err := ws.handler.SessionDestroyed(id); err != nil {
|
||||||
ws.logger.Warn().Str("id", id).Err(err).Msg("session destroyed with and error")
|
ws.logger.Warn().Str("id", id).Err(err).Msg("session destroyed with and error")
|
||||||
} else {
|
} else {
|
||||||
ws.logger.Debug().Str("id", id).Msg("session destroyed")
|
ws.logger.Debug().Str("id", id).Msg("session destroyed")
|
||||||
@ -122,7 +128,7 @@ func (ws *WebSocketHandler) Upgrade(w http.ResponseWriter, r *http.Request) erro
|
|||||||
Msg("session ended")
|
Msg("session ended")
|
||||||
}()
|
}()
|
||||||
|
|
||||||
if err = ws.handler.Connected(id, socket); err != nil {
|
if err = ws.handler.SocketConnected(id, socket); err != nil {
|
||||||
ws.logger.Error().Err(err).Msg("connection failed")
|
ws.logger.Error().Err(err).Msg("connection failed")
|
||||||
if err = socket.Close(); err != nil {
|
if err = socket.Close(); err != nil {
|
||||||
return err
|
return err
|
||||||
@ -135,7 +141,7 @@ func (ws *WebSocketHandler) Upgrade(w http.ResponseWriter, r *http.Request) erro
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (ws *WebSocketHandler) authenticate(r *http.Request) (string, bool, error) {
|
func (ws *WebSocketHandler) authenticate(r *http.Request) (string, bool, error) {
|
||||||
id, err := gonanoid.Generate(alphabet, 32)
|
id, err := utils.NewUID(32)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", false, err
|
return "", false, err
|
||||||
}
|
}
|
||||||
@ -165,7 +171,7 @@ func (ws *WebSocketHandler) handle(socket *websocket.Conn, id string) {
|
|||||||
defer func() {
|
defer func() {
|
||||||
ticker.Stop()
|
ticker.Stop()
|
||||||
ws.logger.Debug().Str("address", socket.RemoteAddr().String()).Msg("handle socket ending")
|
ws.logger.Debug().Str("address", socket.RemoteAddr().String()).Msg("handle socket ending")
|
||||||
ws.handler.Disconnected(id)
|
ws.handler.SocketDisconnected(id)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
|
14
server/internal/websocket/identity.go
Normal file
14
server/internal/websocket/identity.go
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
package websocket
|
||||||
|
|
||||||
|
import (
|
||||||
|
"n.eko.moe/neko/internal/message"
|
||||||
|
"n.eko.moe/neko/internal/session"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (h *MessageHandler) identityDetails(id string, session *session.Session, payload *message.IdentityDetails) error {
|
||||||
|
if _, err := h.sessions.SetName(id, payload.Username); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
@ -20,36 +20,14 @@ type MessageHandler struct {
|
|||||||
webrtc *webrtc.WebRTCManager
|
webrtc *webrtc.WebRTCManager
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *MessageHandler) Connected(id string, socket *websocket.Conn) error {
|
func (h *MessageHandler) SocketConnected(id string, socket *websocket.Conn) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *MessageHandler) Disconnected(id string) error {
|
func (h *MessageHandler) SocketDisconnected(id string) error {
|
||||||
return h.sessions.Destroy(id)
|
return h.sessions.Destroy(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *MessageHandler) Created(id string, session *session.Session) error {
|
|
||||||
if err := session.Send(message.IdentityProvide{
|
|
||||||
Message: message.Message{Event: event.IDENTITY_PROVIDE},
|
|
||||||
ID: id,
|
|
||||||
}); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *MessageHandler) Destroyed(id string) error {
|
|
||||||
if h.sessions.IsHost(id) {
|
|
||||||
h.sessions.ClearHost()
|
|
||||||
if err := h.sessions.Brodcast(message.Message{Event: event.CONTROL_RELEASED}, []string{id}); err != nil {
|
|
||||||
h.logger.Warn().Err(err).Msgf("brodcasting event %s has failed", event.CONTROL_RELEASED)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *MessageHandler) Message(id string, raw []byte) error {
|
func (h *MessageHandler) Message(id string, raw []byte) error {
|
||||||
header := message.Message{}
|
header := message.Message{}
|
||||||
if err := json.Unmarshal(raw, &header); err != nil {
|
if err := json.Unmarshal(raw, &header); err != nil {
|
||||||
@ -62,9 +40,18 @@ func (h *MessageHandler) Message(id string, raw []byte) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch header.Event {
|
switch header.Event {
|
||||||
case event.SDP_PROVIDE:
|
case event.SIGNAL_PROVIDE:
|
||||||
payload := message.SDP{}
|
payload := message.Signal{}
|
||||||
return errors.Wrapf(utils.Unmarshal(&payload, raw, func() error { return h.webrtc.CreatePeer(id, payload.SDP) }), "%s failed", header.Event)
|
return errors.Wrapf(
|
||||||
|
utils.Unmarshal(&payload, raw, func() error {
|
||||||
|
return h.webrtc.CreatePeer(id, payload.SDP)
|
||||||
|
}), "%s failed", header.Event)
|
||||||
|
case event.IDENTITY_DETAILS:
|
||||||
|
payload := &message.IdentityDetails{}
|
||||||
|
return errors.Wrapf(
|
||||||
|
utils.Unmarshal(payload, raw, func() error {
|
||||||
|
return h.identityDetails(id, session, payload)
|
||||||
|
}), "%s failed", header.Event)
|
||||||
case event.CONTROL_RELEASE:
|
case event.CONTROL_RELEASE:
|
||||||
return errors.Wrapf(h.controlRelease(id, session), "%s failed", header.Event)
|
return errors.Wrapf(h.controlRelease(id, session), "%s failed", header.Event)
|
||||||
case event.CONTROL_REQUEST:
|
case event.CONTROL_REQUEST:
|
||||||
@ -73,59 +60,3 @@ func (h *MessageHandler) Message(id string, raw []byte) error {
|
|||||||
return errors.Errorf("unknown message event %s", header.Event)
|
return errors.Errorf("unknown message event %s", header.Event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *MessageHandler) controlRelease(id string, session *session.Session) error {
|
|
||||||
if !h.sessions.IsHost(id) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
h.logger.Debug().Str("id", id).Msgf("host called %s", event.CONTROL_RELEASED)
|
|
||||||
h.sessions.ClearHost()
|
|
||||||
|
|
||||||
if err := session.Send(message.Message{Event: event.CONTROL_RELEASE}); err != nil {
|
|
||||||
h.logger.Warn().Err(err).Str("id", id).Msgf("sending event %s has failed", event.CONTROL_RELEASE)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := h.sessions.Brodcast(message.Message{Event: event.CONTROL_RELEASED}, []string{session.ID}); err != nil {
|
|
||||||
h.logger.Warn().Err(err).Msgf("brodcasting event %s has failed", event.CONTROL_RELEASED)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *MessageHandler) controlRequest(id string, session *session.Session) error {
|
|
||||||
h.logger.Debug().Str("id", id).Msgf("user called %s", event.CONTROL_REQUEST)
|
|
||||||
|
|
||||||
if !h.sessions.HasHost() {
|
|
||||||
h.sessions.SetHost(id)
|
|
||||||
|
|
||||||
if err := session.Send(message.Message{Event: event.CONTROL_GIVE}); err != nil {
|
|
||||||
h.logger.Warn().Err(err).Str("id", id).Msgf("sending event %s has failed", event.CONTROL_GIVE)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := h.sessions.Brodcast(message.Message{Event: event.CONTROL_GIVEN}, []string{session.ID}); err != nil {
|
|
||||||
h.logger.Warn().Err(err).Msgf("brodcasting event %s has failed", event.CONTROL_GIVEN)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := session.Send(message.Message{Event: event.CONTROL_LOCKED}); err != nil {
|
|
||||||
h.logger.Warn().Err(err).Str("id", id).Msgf("sending event %s has failed", event.CONTROL_LOCKED)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
host, ok := h.sessions.GetHost()
|
|
||||||
if ok {
|
|
||||||
if err := host.Send(message.Message{Event: event.CONTROL_REQUESTING}); err != nil {
|
|
||||||
h.logger.Warn().Err(err).Str("id", id).Msgf("sending event %s has failed", event.CONTROL_REQUESTING)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
78
server/internal/websocket/session.go
Normal file
78
server/internal/websocket/session.go
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
package websocket
|
||||||
|
|
||||||
|
import (
|
||||||
|
"n.eko.moe/neko/internal/event"
|
||||||
|
"n.eko.moe/neko/internal/message"
|
||||||
|
"n.eko.moe/neko/internal/session"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (h *MessageHandler) SessionCreated(id string, session *session.Session) error {
|
||||||
|
if err := session.Send(message.Identity{
|
||||||
|
Message: message.Message{Event: event.IDENTITY_PROVIDE},
|
||||||
|
ID: id,
|
||||||
|
}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *MessageHandler) SessionConnected(id string, session *session.Session) error {
|
||||||
|
// send list of members to session
|
||||||
|
if err := session.Send(message.Members{
|
||||||
|
Message: message.Message{Event: event.MEMBER_LIST},
|
||||||
|
Memebers: h.sessions.GetConnected(),
|
||||||
|
}); err != nil {
|
||||||
|
h.logger.Warn().Str("id", id).Err(err).Msgf("sending event %s has failed", event.MEMBER_LIST)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// tell session there is a host
|
||||||
|
host, ok := h.sessions.GetHost()
|
||||||
|
if ok {
|
||||||
|
if err := session.Send(message.Control{
|
||||||
|
Message: message.Message{Event: event.CONTROL_LOCKED},
|
||||||
|
ID: host.ID,
|
||||||
|
}); err != nil {
|
||||||
|
h.logger.Warn().Str("id", id).Err(err).Msgf("sending event %s has failed", event.CONTROL_LOCKED)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// let everyone know there is a new session
|
||||||
|
if err := h.sessions.Brodcast(
|
||||||
|
message.Member{
|
||||||
|
Message: message.Message{Event: event.MEMBER_CONNECTED},
|
||||||
|
Session: session,
|
||||||
|
}, nil); err != nil {
|
||||||
|
h.logger.Warn().Err(err).Msgf("brodcasting event %s has failed", event.CONTROL_RELEASE)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *MessageHandler) SessionDestroyed(id string) error {
|
||||||
|
// clear host if exists
|
||||||
|
if h.sessions.IsHost(id) {
|
||||||
|
h.sessions.ClearHost()
|
||||||
|
if err := h.sessions.Brodcast(message.Control{
|
||||||
|
Message: message.Message{Event: event.CONTROL_RELEASE},
|
||||||
|
ID: id,
|
||||||
|
}, nil); err != nil {
|
||||||
|
h.logger.Warn().Err(err).Msgf("brodcasting event %s has failed", event.CONTROL_RELEASE)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// let everyone know session disconnected
|
||||||
|
if err := h.sessions.Brodcast(
|
||||||
|
message.MemberDisconnected{
|
||||||
|
Message: message.Message{Event: event.MEMBER_DISCONNECTED},
|
||||||
|
ID: id,
|
||||||
|
}, nil); err != nil {
|
||||||
|
h.logger.Warn().Err(err).Msgf("brodcasting event %s has failed", event.MEMBER_DISCONNECTED)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
Reference in New Issue
Block a user