diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2fb2b80 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/.idea +/out \ No newline at end of file diff --git a/command/commands.go b/command/commands.go deleted file mode 100755 index 554e8ed..0000000 --- a/command/commands.go +++ /dev/null @@ -1,58 +0,0 @@ -package command - -import ( - "bufio" - "fmt" - "github.com/ParadoxPixel/ThemePark-Websocket/server" - "os" - "strings" -) - -var commands = make(map[string]func([]string) bool) - -func ReadConsole() { - loadCommands() - reader := bufio.NewReader(os.Stdin) - - for { - text, _ := reader.ReadString('\n') - text = strings.Replace(text, "\n", "", -1) - - args := strings.Split(text, " ") - command := strings.ToLower(args[0]) - args = args[1:] - - b := handleCommand(command, args) - if b { - break - } - } -} - -func loadCommands() { - commands["exit"] = func(i []string) bool { - server.Stop() - return true - } - - commands["ip"] = func(i []string) bool { - ip, err := GetPublicIp() - if err != nil { - fmt.Println("Unable to get public IP") - } else { - fmt.Println("IP:", ip) - } - - return false - } -} - -func handleCommand(cmd string, args []string) bool { - f := commands[cmd] - if f == nil { - fmt.Println("Unknown command:", cmd) - return false - } - - return f(args) -} diff --git a/command/public_ip.go b/command/public_ip.go deleted file mode 100755 index aff1521..0000000 --- a/command/public_ip.go +++ /dev/null @@ -1,22 +0,0 @@ -package command - -import ( - "io/ioutil" - "net/http" -) - -func GetPublicIp() (str string, err error) { - url := "https://api.ipify.org?format=text" - resp, err := http.Get(url) - if err != nil { - return "", err - } - - defer resp.Body.Close() - ip, err := ioutil.ReadAll(resp.Body) - if err != nil { - return "", err - } - - return string(ip), nil -} \ No newline at end of file diff --git a/data/server_manager.go b/data/server_manager.go index 5e341bc..a22d97b 100755 --- a/data/server_manager.go +++ b/data/server_manager.go @@ -5,15 +5,10 @@ import ( "sync" ) -var serverMux sync.RWMutex -var servers = make(map[string]*objects.Server) +var servers = new(sync.Map) func AddServer(server *objects.Server) { - serverMux.Lock() - if _,ok := servers[server.ID]; !ok { - servers[server.ID] = server - } - serverMux.Unlock() + servers.LoadOrStore(server.ID, server) } func CanServer(server string) bool { @@ -28,27 +23,12 @@ func CanServer(server string) bool { } } -func GetServer(server string) *objects.Server { - serverMux.Lock() - val,ok := servers[server] - serverMux.Unlock() - if ok { - return val - } else { - return nil - } -} - func HasServer(publicKey string) (bool, *objects.Server) { - serverMux.Lock() - val,ok := servers[publicKey] - serverMux.Unlock() - - return ok, val + val, ok := servers.Load(publicKey) + return ok, val.(*objects.Server) } -func RemoveServer(session string) { - serverMux.Lock() - delete(servers, session) - serverMux.Unlock() -} \ No newline at end of file +func RemoveServer(session string) *objects.Server { + val, _ := servers.LoadAndDelete(session) + return val.(*objects.Server) +} diff --git a/data/session_manager.go b/data/session_manager.go deleted file mode 100755 index b714a1d..0000000 --- a/data/session_manager.go +++ /dev/null @@ -1,45 +0,0 @@ -package data - -import ( - "github.com/ParadoxPixel/ThemePark-Websocket/objects" - "sync" -) - -var sessionMux sync.RWMutex -var sessions = make(map[string]*objects.Session) - -func AddSession(session *objects.Session) { - sessionMux.Lock() - sessions[session.Token] = session - sessionMux.Unlock() -} - -func GetSession(session string) *objects.Session { - sessionMux.Lock() - val := sessions[session] - sessionMux.Unlock() - - return val -} - -func HasSession(session string) bool { - sessionMux.Lock() - _,ok := sessions[session] - sessionMux.Unlock() - - return ok -} - -func CanSession(session string) bool { - if session == "" || session == "null" { - return false - } - - return !HasSession(session) -} - -func RemoveSession(session string) { - sessionMux.Lock() - delete(sessions, session) - sessionMux.Unlock() -} \ No newline at end of file diff --git a/handlers/data/handler.go b/handlers/data/handler.go index f45847c..3f1986f 100755 --- a/handlers/data/handler.go +++ b/handlers/data/handler.go @@ -10,10 +10,11 @@ import ( func Load(namespace socketio.Namespace, debug bool) { namespace.OnEvent("data", func(so socketio.Socket, msg string) { - clientType := so.GetQuery().Get("type") == "server" + isServer := so.GetQuery().Get("type") == "server" var ok bool var server *objects.Server - if !clientType { + var err error + if !isServer { ok, server = data.HasServer(so.GetQuery().Get("control_id")) if !ok { if debug { @@ -27,28 +28,39 @@ func Load(namespace socketio.Namespace, debug bool) { return } - _ = server.Socket.Emit("data", msg) + err = server.Socket.Emit("data", msg) + if err != nil && debug { + log.Println("error while sending data to server:", err) + } return } ok, server = data.HasServer(so.GetQuery().Get("id")) - if !strings.HasPrefix(msg, "{") { - args := strings.SplitN(msg, "@", 2) - ok, session := server.HasSession(args[0]) - if !ok { - if debug { - log.Println( - "Unable to send packet from server:", - server.ID, - "to client:", - args[0], - ) - } - return + if msg[0] == '{' { + err = server.Socket.EmitError("messages can only be send to clients") + if err != nil && debug { + log.Println("error while sending data to server:", err) } - - _ = session.Emit("data", args[1]) return } + + args := strings.SplitN(msg, "@", 2) + ok, session := server.HasSession(args[0]) + if !ok { + if debug { + log.Println( + "Unable to send packet from server:", + server.ID, + "to client:", + args[0], + ) + } + return + } + + err = session.Emit("data", args[1]) + if err != nil && debug { + log.Println("error while sending data to server:", err) + } }) } diff --git a/handlers/user/client.go b/handlers/user/client.go new file mode 100644 index 0000000..0e1e515 --- /dev/null +++ b/handlers/user/client.go @@ -0,0 +1,80 @@ +package user + +import ( + "github.com/Mindgamesnl/socketio" + "github.com/ParadoxPixel/ThemePark-Websocket/data" + "log" +) + +func clientLogin(so socketio.Socket) { + ok, server := data.HasServer(so.GetQuery().Get("control_id")) + if !ok { + if debug { + log.Println( + "No server with id:", + so.GetQuery().Get("control_id"), + "for token:", + so.GetQuery().Get("token"), + ) + } + _ = so.Emit("close", "SERVER_ERROR") + _ = so.Close() + return + } + + b := server.AddSession(so.GetQuery().Get("token"), so.GetQuery().Get("attraction"), so) + if !b { + if debug { + log.Println( + "Server with id:", + so.GetQuery().Get("control_id"), + "already has operator for attraction:", + so.GetQuery().Get("attraction"), + ) + } + _ = so.Emit("close", "AUTHENTICATION_ERROR") + _ = so.Close() + return + } + + if debug { + log.Println( + "Client connected to id:", + so.GetQuery().Get("control_id"), + "with token:", + so.GetQuery().Get("token"), + "to attraction:", + so.GetQuery().Get("attraction"), + ) + } + + err := server.Socket.Emit("data", "{\"channel\":\"SERVER_IN_REGISTER_CLIENT\",\"data\":{\"payload\":{\"uuid\":\""+so.GetQuery().Get("uuid")+"\",\"token\":\""+so.GetQuery().Get("token")+"\",\"attraction_id\":\""+so.GetQuery().Get("attraction")+"\"},\"type\":\"ClientConnectPayload\"}}") + if err != nil && debug { + log.Println(err) + } +} + +func clientQuit(so socketio.Socket) { + session := so.GetQuery().Get("token") + ok, server := data.HasServer(so.GetQuery().Get("control_id")) + if !ok { + return + } + + if debug { + log.Println( + "Client disconnected to id:", + so.GetQuery().Get("control_id"), + "with token:", + so.GetQuery().Get("token"), + "to attraction:", + so.GetQuery().Get("attraction"), + ) + } + + server.RemoveSession(session, so.GetQuery().Get("attraction")) + err := server.Socket.Emit("data", "{\"channel\":\"SERVER_IN_UNREGISTER_CLIENT\",\"data\":{\"payload\":{\"uuid\":\""+so.GetQuery().Get("uuid")+"\"},\"type\":\"ClientDisconnectPayload\"}}") + if err != nil && debug { + log.Println(err) + } +} diff --git a/handlers/user/handler.go b/handlers/user/handler.go index 868addd..bd16dad 100755 --- a/handlers/user/handler.go +++ b/handlers/user/handler.go @@ -3,8 +3,6 @@ package user import ( "fmt" "github.com/Mindgamesnl/socketio" - "github.com/ParadoxPixel/ThemePark-Websocket/data" - "github.com/ParadoxPixel/ThemePark-Websocket/objects" "log" ) @@ -22,57 +20,18 @@ func Load(namespace socketio.Namespace, b bool) { return } else { _ = so.Close() + if debug { + log.Println("invalid client type:", clientType) + } } }) namespace.OnDisconnect(func(so socketio.Socket) { clientType := so.GetQuery().Get("type") - var session string if clientType == "server" { - session = so.GetQuery().Get("id") - obj := data.GetServer(session) - if obj == nil { - return - } - - data.RemoveServer(session) - if debug { - log.Println( - "Server with id:", - so.GetQuery().Get("id"), - "disconnected", - ) - } - for _, user := range obj.Sessions { - _ = user.Emit("close", "SERVER_ERROR") - _ = user.Close() - } + serverQuit(so) } else if clientType == "client" { - session = so.GetQuery().Get("token") - obj := data.GetSession(session) - if obj == nil { - return - } - - ok, server := data.HasServer(obj.ID) - if !ok { - return - } - - if debug { - log.Println( - "Client disconnected to id:", - so.GetQuery().Get("control_id"), - "with token:", - so.GetQuery().Get("token"), - "to attraction:", - so.GetQuery().Get("attraction"), - ) - } - - data.RemoveSession(session) - server.RemoveSession(session, so.GetQuery().Get("attraction")) - _ = server.Socket.Emit("data", "{\"channel\":\"SERVER_IN_UNREGISTER_CLIENT\",\"data\":{\"payload\":{\"uuid\":\""+obj.UUID+"\"},\"type\":\"ClientDisconnectPayload\"}}") + clientQuit(so) } }) @@ -80,93 +39,3 @@ func Load(namespace socketio.Namespace, b bool) { fmt.Println(err) }) } - -func serverLogin(so socketio.Socket) { - id := so.GetQuery().Get("id") - if !data.CanServer(id) { - if debug { - log.Println( - "Server with id:", - so.GetQuery().Get("id"), - "already connected", - ) - } - - _ = so.Close() - return - } - - data.AddServer(&objects.Server{ - ID: id, - Sessions: make(map[string]socketio.Socket), - Attraction: make(map[string]string), - Socket: so, - }) - if debug { - log.Println( - "Server with id:", - so.GetQuery().Get("id"), - "connected", - ) - } -} - -func clientLogin(so socketio.Socket) { - if !data.CanSession(so.GetQuery().Get("token")) { - _ = so.Close() - return - } - - ok, server := data.HasServer(so.GetQuery().Get("control_id")) - if !ok { - if debug { - log.Println( - "No server with id:", - so.GetQuery().Get("control_id"), - "for token:", - so.GetQuery().Get("token"), - ) - } - _ = so.Emit("close", "SERVER_ERROR") - _ = so.Close() - return - } - - ok = server.CanAttraction(so.GetQuery().Get("attraction")) - if !ok { - if debug { - log.Println( - "Server with id:", - so.GetQuery().Get("control_id"), - "already has operator for attraction:", - so.GetQuery().Get("attraction"), - ) - } - _ = so.Emit("close", "AUTHENTICATION_ERROR") - _ = so.Close() - return - } - - data.AddSession(&objects.Session{ - Token: so.GetQuery().Get("token"), - UUID: so.GetQuery().Get("uuid"), - ID: so.GetQuery().Get("control_id"), - Attraction: so.GetQuery().Get("attraction"), - }) - server.AddSession(so.GetQuery().Get("token"), so.GetQuery().Get("attraction"), so) - if debug { - log.Println( - "Client connected to id:", - so.GetQuery().Get("control_id"), - "with token:", - so.GetQuery().Get("token"), - "to attraction:", - so.GetQuery().Get("attraction"), - ) - } - - err := server.Socket.Emit("data", "{\"channel\":\"SERVER_IN_REGISTER_CLIENT\",\"data\":{\"payload\":{\"uuid\":\""+so.GetQuery().Get("uuid")+"\",\"token\":\""+so.GetQuery().Get("token")+"\",\"attraction_id\":\""+so.GetQuery().Get("attraction")+"\"},\"type\":\"ClientConnectPayload\"}}") - if err != nil { - log.Println(err) - } -} diff --git a/handlers/user/server.go b/handlers/user/server.go new file mode 100644 index 0000000..2e8efed --- /dev/null +++ b/handlers/user/server.go @@ -0,0 +1,62 @@ +package user + +import ( + "github.com/Mindgamesnl/socketio" + "github.com/ParadoxPixel/ThemePark-Websocket/data" + "github.com/ParadoxPixel/ThemePark-Websocket/objects" + "log" + "sync" +) + +func serverLogin(so socketio.Socket) { + id := so.GetQuery().Get("id") + if !data.CanServer(id) { + if debug { + log.Println( + "Server with id:", + so.GetQuery().Get("id"), + "already connected", + ) + } + + _ = so.Close() + return + } + + data.AddServer(&objects.Server{ + ID: id, + Sessions: make(map[string]socketio.Socket), + Attraction: make(map[string]string), + Socket: so, + Mux: new(sync.RWMutex), + }) + if debug { + log.Println( + "Server with id:", + so.GetQuery().Get("id"), + "connected", + ) + } +} + +func serverQuit(so socketio.Socket) { + session := so.GetQuery().Get("id") + obj := data.RemoveServer(session) + if obj == nil { + return + } + + if debug { + log.Println( + "Server with id:", + so.GetQuery().Get("id"), + "disconnected", + ) + } + + // Disconnect users + for _, user := range obj.Sessions { + _ = user.Emit("close", "SERVER_ERROR") + _ = user.Close() + } +} diff --git a/main.go b/main.go index 7946236..37691fc 100755 --- a/main.go +++ b/main.go @@ -2,7 +2,6 @@ package main import ( "fmt" - "github.com/ParadoxPixel/ThemePark-Websocket/command" "github.com/ParadoxPixel/ThemePark-Websocket/objects" "github.com/ParadoxPixel/ThemePark-Websocket/server" ) @@ -14,7 +13,5 @@ func main() { return } - go server.Start("/", config.Address, config.Debug) - - command.ReadConsole() + server.Start("/", config.Address, config.Debug) } diff --git a/objects/server.go b/objects/server.go index 8ab5338..0865818 100755 --- a/objects/server.go +++ b/objects/server.go @@ -6,32 +6,44 @@ import ( ) type Server struct { - Socket socketio.Socket - ID string - Sessions map[string]socketio.Socket - Attraction map[string]string - mux sync.RWMutex + Socket socketio.Socket + ID string + Sessions map[string]socketio.Socket + Attraction map[string]string + Mux *sync.RWMutex } func (serv *Server) CanAttraction(attraction string) bool { - serv.mux.RLock() - defer serv.mux.RUnlock() + serv.Mux.RLock() + defer serv.Mux.RUnlock() - _,b := serv.Attraction[attraction] + _, b := serv.Attraction[attraction] return !b } -func (serv *Server) AddSession(session, attraction string, io socketio.Socket) { - serv.mux.Lock() +func (serv *Server) AddSession(session, attraction string, io socketio.Socket) bool { + serv.Mux.Lock() + defer serv.Mux.Unlock() + + // Check if session in use + if _, b := serv.Sessions[session]; b { + return false + } + + // Check if attraction is already controlled + if _, b := serv.Attraction[attraction]; b { + return false + } + serv.Sessions[session] = io serv.Attraction[attraction] = session - serv.mux.Unlock() + return true } func (serv *Server) HasSession(session string) (bool, socketio.Socket) { - serv.mux.RLock() - defer serv.mux.RUnlock() + serv.Mux.RLock() + defer serv.Mux.RUnlock() io, b := serv.Sessions[session] @@ -39,8 +51,8 @@ func (serv *Server) HasSession(session string) (bool, socketio.Socket) { } func (serv *Server) RemoveSession(session, attraction string) { - serv.mux.Lock() + serv.Mux.Lock() delete(serv.Sessions, session) delete(serv.Attraction, attraction) - serv.mux.Unlock() -} \ No newline at end of file + serv.Mux.Unlock() +} diff --git a/objects/session.go b/objects/session.go deleted file mode 100755 index f57e459..0000000 --- a/objects/session.go +++ /dev/null @@ -1,8 +0,0 @@ -package objects - -type Session struct { - Token string `json:"token"` - UUID string `json:"uuid"` - ID string `json:"id"` - Attraction string `json:"attraction"` -} \ No newline at end of file