From ba7aa75630bd72892fb72bf56b07387ff6b848b1 Mon Sep 17 00:00:00 2001 From: Dominique Debergue Date: Mon, 24 Dec 2018 18:38:43 -0800 Subject: [PATCH 001/132] Create CONTRIBUTING.md --- CONTRIBUTING.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..dc7e374 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,14 @@ +## Ways to contribute + +1) See if there is an Issue that you can take up to fix or implement +2) Have a good idea? Open and submit a detailed Issue. +3) Email me with comments or recommendations directly: dominiquedebergue@gmail.com + +## Guidlines + +1) First, check to see if a similar issue has already been opened +2) Follow the [Code of Conduct](https://github.com/hewiefreeman/GopherGameServer/blob/master/CODE_OF_CONDUCT.md) +3) BE DETAILED in your Pull Requests +4) Do not introduce any further 3rd-party package dependencies unless provided a valid reason +5) Do not submit content that does not pass golint, or has not been formatted with `gofmt` +6) Do not submit content that has little to no documentation on exported functions, variables, etc From 32bd11742c5e556cd5594106275b5eacb729f925 Mon Sep 17 00:00:00 2001 From: Dominique Debergue Date: Mon, 24 Dec 2018 18:41:18 -0800 Subject: [PATCH 002/132] Update README.md --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index d7817cc..28d2cf6 100644 --- a/README.md +++ b/README.md @@ -61,4 +61,7 @@ Then install the server: # Contributions -**Gopher Game Server will be open for contributions as soon as version 1.0 is finished. At that time, contribution information will be posted here.** +Please read the following articles before submitting any contributions or filing an Issue! + + - [Contribution Guidlines](https://github.com/hewiefreeman/GopherGameServer/blob/master/CONTRIBUTING.md) + - [Code of Conduct](https://github.com/hewiefreeman/GopherGameServer/blob/master/CODE_OF_CONDUCT.md) From dde347c3be142d506bb0f1614d6d67dd0c308b5e Mon Sep 17 00:00:00 2001 From: Dominique Debergue Date: Mon, 24 Dec 2018 18:42:50 -0800 Subject: [PATCH 003/132] Update CONTRIBUTING.md --- CONTRIBUTING.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index dc7e374..587a119 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,8 +1,9 @@ ## Ways to contribute 1) See if there is an Issue that you can take up to fix or implement -2) Have a good idea? Open and submit a detailed Issue. -3) Email me with comments or recommendations directly: dominiquedebergue@gmail.com +2) Help expand and clarify documentation and/or usage section +3) Have a good idea? Open and submit a detailed Issue. +4) Email me with comments or recommendations directly: dominiquedebergue@gmail.com ## Guidlines From 74411594a6a2bc6d8ecc46ffd817ed906affdd65 Mon Sep 17 00:00:00 2001 From: Dominique Debergue Date: Mon, 24 Dec 2018 18:43:24 -0800 Subject: [PATCH 004/132] Update CONTRIBUTING.md --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 587a119..46fc380 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,7 +2,7 @@ 1) See if there is an Issue that you can take up to fix or implement 2) Help expand and clarify documentation and/or usage section -3) Have a good idea? Open and submit a detailed Issue. +3) Have a good idea? Open and submit a detailed Issue 4) Email me with comments or recommendations directly: dominiquedebergue@gmail.com ## Guidlines From 61cb5f42147341f22acd2c8e128b88fc458adf0e Mon Sep 17 00:00:00 2001 From: Dominique Debergue Date: Mon, 24 Dec 2018 18:48:04 -0800 Subject: [PATCH 005/132] Update README.md --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index 28d2cf6..a0929f6 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,6 @@ Gopher Game Server is a full featured, super fast, and fully customizable game server written in Go. Comes with a client API for JavaScript (and eventually Java, C++, and C). --**PROJECT IN DEVELOPMENT**- - Gopher Game Server is designed to provide all necessary tools to ease developments of any type of online game (or any real-time app/chat). Gopher will handle all server-side synchronizing and data type conversions, therefore, client actions receiving, variable setting, message sending, and other functionalities are unproblematic. Gopher uses WebSockets and JSON to pass messages between the clients and the server. The JSON enabled server is designed to pass any types of data between client and server without cares of type conversions on either end. WebSockets increases efficiency of the server as far as possible on the network, since the WebSocket protocol is newer and doesn't send as much header and meta data that standard HTTP and most other protocols require. From f3ca636bcd2eaff39979a1cad10f960ac9edc80e Mon Sep 17 00:00:00 2001 From: hewiefreeman Date: Mon, 24 Dec 2018 18:40:03 -0800 Subject: [PATCH 006/132] gofmt formatting --- actions/actions.go | 4 ++-- helpers/errors.go | 24 ++++++++++++------------ macros.go | 16 ++++++++-------- server.go | 24 ++++++++++++------------ users/users.go | 1 - 5 files changed, 34 insertions(+), 35 deletions(-) diff --git a/actions/actions.go b/actions/actions.go index 9465c68..217db6b 100644 --- a/actions/actions.go +++ b/actions/actions.go @@ -47,8 +47,8 @@ var ( // Default `ClientError`s const ( - ErrorMismatchedTypes = iota + 1001 // Client didn't pass the right data type for the given action - ErrorUnrecognizedAction // The custom action has not been defined + ErrorMismatchedTypes = iota + 1001 // Client didn't pass the right data type for the given action + ErrorUnrecognizedAction // The custom action has not been defined ) // These are the accepted data types that a client can send with a CustomClientMessage. You must use one diff --git a/helpers/errors.go b/helpers/errors.go index b96f7c2..322ad92 100644 --- a/helpers/errors.go +++ b/helpers/errors.go @@ -10,18 +10,18 @@ type GopherError struct { // Client response message error IDs const ( - ErrorGopherInvalidAction = iota + 1001 // Invalid client action - ErrorGopherIncorrectFormat // The client's data is not a map/object - ErrorGopherIncorrectCustomAction // Incorrect custom client action type - ErrorGopherNotLoggedIn // The client must be logged in to take action - ErrorGopherLoggedIn // The client must be logged out to take action - ErrorGopherStatusChange // Error while changing User's status - ErrorGopherFeatureDisabled // The feature required for the action is disabled - ErrorGopherColumnsFormat // The client's custom columns data is not a map/object - ErrorGopherNameFormat // The client's user name data is not a string - ErrorGopherPasswordFormat // The client's password data is not a string - ErrorGopherRememberFormat // The client's remember-me data is not a boolean - ErrorGopherGuestFormat // The client's guest data is not a boolean + ErrorGopherInvalidAction = iota + 1001 // Invalid client action + ErrorGopherIncorrectFormat // The client's data is not a map/object + ErrorGopherIncorrectCustomAction // Incorrect custom client action type + ErrorGopherNotLoggedIn // The client must be logged in to take action + ErrorGopherLoggedIn // The client must be logged out to take action + ErrorGopherStatusChange // Error while changing User's status + ErrorGopherFeatureDisabled // The feature required for the action is disabled + ErrorGopherColumnsFormat // The client's custom columns data is not a map/object + ErrorGopherNameFormat // The client's user name data is not a string + ErrorGopherPasswordFormat // The client's password data is not a string + ErrorGopherRememberFormat // The client's remember-me data is not a boolean + ErrorGopherGuestFormat // The client's guest data is not a boolean ErrorGopherNewPasswordFormat ErrorGopherRoomNameFormat ErrorGopherRoomTypeFormat diff --git a/macros.go b/macros.go index a838ac9..470f209 100644 --- a/macros.go +++ b/macros.go @@ -3,19 +3,19 @@ package gopher import ( "bufio" "fmt" + "github.com/hewiefreeman/GopherGameServer/rooms" + "github.com/hewiefreeman/GopherGameServer/users" "os" - "strings" "strconv" - "github.com/hewiefreeman/GopherGameServer/users" - "github.com/hewiefreeman/GopherGameServer/rooms" + "strings" ) -func macroListener(){ +func macroListener() { for { reader := bufio.NewReader(os.Stdin) fmt.Print("[Gopher] Command: ") text, _ := reader.ReadString('\n') - stop := handleMacro(text[0:len(text)-2]) + stop := handleMacro(text[0 : len(text)-2]) if stop { return } @@ -49,7 +49,7 @@ func macroKick(macro string) { return } user.Kick() - fmt.Println("Kicked user '"+userName+"'") + fmt.Println("Kicked user '" + userName + "'") } func macroNewRoom(macro string) { @@ -72,7 +72,7 @@ func macroNewRoom(macro string) { fmt.Println(roomErr) return } - fmt.Println("Created room '"+s[1]+"'") + fmt.Println("Created room '" + s[1] + "'") } func macroNewRoomType(macro string) { @@ -90,5 +90,5 @@ func macroNewRoomType(macro string) { fmt.Println("The server must be paused to create a room type") return } - fmt.Println("Created room type '"+s[1]+"'") + fmt.Println("Created room type '" + s[1] + "'") } diff --git a/server.go b/server.go index 2d7ff34..c923edd 100644 --- a/server.go +++ b/server.go @@ -6,17 +6,17 @@ package gopher import ( "context" + "encoding/json" "fmt" "github.com/hewiefreeman/GopherGameServer/actions" "github.com/hewiefreeman/GopherGameServer/database" + "github.com/hewiefreeman/GopherGameServer/helpers" "github.com/hewiefreeman/GopherGameServer/rooms" "github.com/hewiefreeman/GopherGameServer/users" - "github.com/hewiefreeman/GopherGameServer/helpers" - "net/http" - "strconv" - "encoding/json" "io/ioutil" + "net/http" "os" + "strconv" ) /////////// TO DOs: @@ -141,7 +141,7 @@ func Start(s *ServerSettings) { fmt.Println("Shutting down...") return } - os.Remove(settings.RecoveryLocation+"/test.txt") + os.Remove(settings.RecoveryLocation + "/test.txt") } else if settings.EnableAdminTools == true && (settings.AdminToolsLogin == "" || settings.AdminToolsPassword == "") { fmt.Println("AdminToolsLogin and AdminToolsPassword in ServerSettings are required for Administrator Tools. Shutting down...") @@ -437,7 +437,7 @@ func recoverState() { for name, val := range roomsMap { var m map[string]interface{} if m, ok = val.(map[string]interface{}); !ok { - fmt.Println("Error recovering room '"+name+"': Incorrect room format") + fmt.Println("Error recovering room '" + name + "': Incorrect room format") continue } var rType string @@ -446,23 +446,23 @@ func recoverState() { var inviteList []interface{} var owner string if rType, ok = m["t"].(string); !ok { - fmt.Println("Error recovering room '"+name+"': Incorrect room type format") + fmt.Println("Error recovering room '" + name + "': Incorrect room type format") continue } if isPrivate, ok = m["p"].(bool); !ok { - fmt.Println("Error recovering room '"+name+"': Incorrect private format") + fmt.Println("Error recovering room '" + name + "': Incorrect private format") continue } if maxUsers, ok = m["m"].(float64); !ok { - fmt.Println("Error recovering room '"+name+"': Incorrect maximum users format") + fmt.Println("Error recovering room '" + name + "': Incorrect maximum users format") continue } if inviteList, ok = m["i"].([]interface{}); !ok { - fmt.Println("Error recovering room '"+name+"': Incorrect invite list format") + fmt.Println("Error recovering room '" + name + "': Incorrect invite list format") continue } if owner, ok = m["o"].(string); !ok { - fmt.Println("Error recovering room '"+name+"': Incorrect owner format") + fmt.Println("Error recovering room '" + name + "': Incorrect owner format") continue } room, roomErr := rooms.New(name, rType, isPrivate, int(maxUsers), owner) @@ -473,7 +473,7 @@ func recoverState() { for i := 0; i < len(inviteList); i++ { var userName string if userName, ok = inviteList[i].(string); !ok { - fmt.Println("Error recovering room '"+name+"': Incorrect user name format in invite list") + fmt.Println("Error recovering room '" + name + "': Incorrect user name format in invite list") continue } invErr := room.AddInvite(userName) diff --git a/users/users.go b/users/users.go index 846eeea..0a940ac 100644 --- a/users/users.go +++ b/users/users.go @@ -60,7 +60,6 @@ var ( rememberMe bool = false multiConnect bool = false - LoginCallback func(string, int, map[string]interface{}, map[string]interface{}) bool // LoginCallback is only for internal Gopher Game Server mechanics. LogoutCallback func(string, int) // LogoutCallback is only for internal Gopher Game Server mechanics. ) From c659dee0e83b60fd7e95bbcd34ceb111a3127906 Mon Sep 17 00:00:00 2001 From: hewiefreeman Date: Mon, 24 Dec 2018 18:46:11 -0800 Subject: [PATCH 007/132] gofmt formatting, and golinting --- callbacks.go | 2 ++ database/authentication.go | 15 ++++++++++----- helpers/saveState.go | 1 + rooms/rooms.go | 2 +- users/users.go | 6 ++++-- 5 files changed, 18 insertions(+), 8 deletions(-) diff --git a/callbacks.go b/callbacks.go index 2b140c0..34f74bb 100644 --- a/callbacks.go +++ b/callbacks.go @@ -8,7 +8,9 @@ import ( ) const ( + // Incorrect function input or return parameters ErrorIncorrectFunction = "Incorrect function parameters or return parameters" + // The server is running ErrorServerRunning = "Cannot call when the server is running." ) diff --git a/database/authentication.go b/database/authentication.go index 8c306d8..9a90f57 100644 --- a/database/authentication.go +++ b/database/authentication.go @@ -16,11 +16,16 @@ var ( customAccountInfoChangeRequirements map[string]struct{} = make(map[string]struct{}) customDeleteAccountRequirements map[string]struct{} = make(map[string]struct{}) - SignUpCallback func(string, map[string]interface{}) bool // SignUpCallback is only for internal Gopher Game Server mechanics. - LoginCallback func(string, int, map[string]interface{}, map[string]interface{}) bool // LoginCallback is only for internal Gopher Game Server mechanics. - DeleteAccountCallback func(string, int, map[string]interface{}, map[string]interface{}) bool // DeleteAccountCallback is only for internal Gopher Game Server mechanics. - AccountInfoChangeCallback func(string, int, map[string]interface{}, map[string]interface{}) bool // AccountInfoChangeCallback is only for internal Gopher Game Server mechanics. - PasswordChangeCallback func(string, int, map[string]interface{}, map[string]interface{}) bool // PasswordChangeCallback is only for internal Gopher Game Server mechanics. + // SignUpCallback is only for internal Gopher Game Server mechanics. + SignUpCallback func(string, map[string]interface{}) bool + // LoginCallback is only for internal Gopher Game Server mechanics. + LoginCallback func(string, int, map[string]interface{}, map[string]interface{}) bool + // DeleteAccountCallback is only for internal Gopher Game Server mechanics. + DeleteAccountCallback func(string, int, map[string]interface{}, map[string]interface{}) bool + // AccountInfoChangeCallback is only for internal Gopher Game Server mechanics. + AccountInfoChangeCallback func(string, int, map[string]interface{}, map[string]interface{}) bool + // PasswordChangeCallback is only for internal Gopher Game Server mechanics. + PasswordChangeCallback func(string, int, map[string]interface{}, map[string]interface{}) bool ) // Authentication error messages diff --git a/helpers/saveState.go b/helpers/saveState.go index 6a036b3..3cf02e3 100644 --- a/helpers/saveState.go +++ b/helpers/saveState.go @@ -6,6 +6,7 @@ import ( "time" ) +// SaveState is only for internal Gopher Server mechanics. func SaveState(stateObj map[string]interface{}, saveFolder string) error { //WRITE THE STATE stateStr, err := json.Marshal(stateObj) diff --git a/rooms/rooms.go b/rooms/rooms.go index f4cabe1..f17817e 100644 --- a/rooms/rooms.go +++ b/rooms/rooms.go @@ -605,7 +605,7 @@ func Resume() { } } -// Resume is only for internal Gopher Game Server mechanics. +// GetState is only for internal Gopher Game Server mechanics. func GetState() map[string]interface{} { state := make(map[string]interface{}) roomsMux.Lock() diff --git a/users/users.go b/users/users.go index 0a940ac..8183245 100644 --- a/users/users.go +++ b/users/users.go @@ -60,8 +60,10 @@ var ( rememberMe bool = false multiConnect bool = false - LoginCallback func(string, int, map[string]interface{}, map[string]interface{}) bool // LoginCallback is only for internal Gopher Game Server mechanics. - LogoutCallback func(string, int) // LogoutCallback is only for internal Gopher Game Server mechanics. + // LoginCallback is only for internal Gopher Game Server mechanics. + LoginCallback func(string, int, map[string]interface{}, map[string]interface{}) bool + // LogoutCallback is only for internal Gopher Game Server mechanics. + LogoutCallback func(string, int) ) // These represent the four statuses a User could be. From f986bc6059bb1676feb60785c4770a364bf82e41 Mon Sep 17 00:00:00 2001 From: hewiefreeman Date: Mon, 24 Dec 2018 18:49:41 -0800 Subject: [PATCH 008/132] gofmt formatting, and golinting --- callbacks.go | 5 +++-- server.go | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/callbacks.go b/callbacks.go index 34f74bb..d239d5c 100644 --- a/callbacks.go +++ b/callbacks.go @@ -8,9 +8,10 @@ import ( ) const ( - // Incorrect function input or return parameters + // ErrorIncorrectFunction is thrown when function input or return parameters don't match with the callback ErrorIncorrectFunction = "Incorrect function parameters or return parameters" - // The server is running + // ErrorServerRunning is thrown when an action cannot be taken because the server is running. Pausing the server + // will enable you to run the command. ErrorServerRunning = "Cannot call when the server is running." ) diff --git a/server.go b/server.go index c923edd..b66dd11 100644 --- a/server.go +++ b/server.go @@ -337,7 +337,7 @@ func Resume() { } } -// Stop will log all Users off, save the state of the server if EnableRecovery in ServerSettings is set to true, then shut the server down. +// ShutDown will log all Users off, save the state of the server if EnableRecovery in ServerSettings is set to true, then shut the server down. func ShutDown() error { if !serverStopping { serverStopping = true @@ -399,7 +399,7 @@ func recoverState() { return } var newestFile string - var newestTime int64 = 0 + var newestTime int64 for _, f := range files { if len(f.Name()) < 19 || f.Name()[0:15] != "Gopher Recovery" { continue From f4c0f30db00c34e0698f41c08360055f95e376a0 Mon Sep 17 00:00:00 2001 From: hewiefreeman Date: Mon, 24 Dec 2018 20:49:09 -0800 Subject: [PATCH 009/132] gofmt formatting --- callbacks.go | 2 +- helpers/clientResponses.go | 2 -- helpers/errors.go | 2 -- macros.go | 2 +- rooms/roomTypes.go | 2 -- 5 files changed, 2 insertions(+), 8 deletions(-) diff --git a/callbacks.go b/callbacks.go index d239d5c..97a7f89 100644 --- a/callbacks.go +++ b/callbacks.go @@ -12,7 +12,7 @@ const ( ErrorIncorrectFunction = "Incorrect function parameters or return parameters" // ErrorServerRunning is thrown when an action cannot be taken because the server is running. Pausing the server // will enable you to run the command. - ErrorServerRunning = "Cannot call when the server is running." + ErrorServerRunning = "Cannot call when the server is running." ) // SetStartCallback sets the callback that triggers when the server first starts up. The diff --git a/helpers/clientResponses.go b/helpers/clientResponses.go index b14ed93..2c7f049 100644 --- a/helpers/clientResponses.go +++ b/helpers/clientResponses.go @@ -1,7 +1,5 @@ package helpers -import () - //BUILT-IN CLIENT ACTION/RESPONSE MESSAGE TYPES const ( ClientActionSignup = "s" diff --git a/helpers/errors.go b/helpers/errors.go index 322ad92..8f0d6f4 100644 --- a/helpers/errors.go +++ b/helpers/errors.go @@ -1,7 +1,5 @@ package helpers -import () - // GopherError is used when sending an error message to the client API. type GopherError struct { Message string diff --git a/macros.go b/macros.go index 470f209..48aaaa3 100644 --- a/macros.go +++ b/macros.go @@ -42,7 +42,7 @@ func handleMacro(macro string) bool { // KICK A USER func macroKick(macro string) { - userName := macro[5:len(macro)] + userName := macro[5:] user, userErr := users.Get(userName) if userErr != nil { fmt.Println(userErr) diff --git a/rooms/roomTypes.go b/rooms/roomTypes.go index f78e4f7..bc392e4 100644 --- a/rooms/roomTypes.go +++ b/rooms/roomTypes.go @@ -1,7 +1,5 @@ package rooms -import () - var ( roomTypes = make(map[string]*RoomType) ) From da53f75edc54aa0fa86f0718efee892b3765f37f Mon Sep 17 00:00:00 2001 From: Dominique Debergue Date: Tue, 25 Dec 2018 01:02:08 -0800 Subject: [PATCH 010/132] Update README.md --- README.md | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index a0929f6..3b1b541 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,38 @@ Then install the server: # Usage -(Coming soon...) +**-UNDER CONSTRUCTION-** + +### Table of Contents + +1) [**Getting Started**](https://github.com/hewiefreeman/GopherGameServer/wiki/Getting-Started) + - [Set-Up](https://github.com/hewiefreeman/GopherGameServer/wiki/Getting-Started#set-up) + - [Core Server Settings](https://github.com/hewiefreeman/GopherGameServer/wiki/Getting-Started#core-server-settings) + - Server Callbacks + - Micro Commands +2) **Rooms** + - Room Types + - Creating Rooms + - Room Variables + - Room Callbacks + - Chat & Voice Messaging +3) **Users** + - Login & Logout + - Joining & Leaving Rooms + - User Variables + - Initiating and Revoking Room Invites + - Messaging +4) **Custom Client Actions** + - Creating a Custom Client Action + - Responding to a Custom Client Action +6) **Saving & Restoring** + - Set-Up +5) **MySQL Features** + - Set-Up + - Securely Authenticating Clients + - Customize Authentication Features + - Custom Account Info + - Friending # Contributions From 72b3981cc85631324a9eb675eb9b68ac38249d65 Mon Sep 17 00:00:00 2001 From: Dominique Debergue Date: Tue, 25 Dec 2018 01:02:45 -0800 Subject: [PATCH 011/132] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3b1b541..0458b8f 100644 --- a/README.md +++ b/README.md @@ -90,7 +90,7 @@ Then install the server: # Contributions -Please read the following articles before submitting any contributions or filing an Issue! +Please read the following articles before submitting any contributions or filing an Issue: - [Contribution Guidlines](https://github.com/hewiefreeman/GopherGameServer/blob/master/CONTRIBUTING.md) - [Code of Conduct](https://github.com/hewiefreeman/GopherGameServer/blob/master/CODE_OF_CONDUCT.md) From a683cc642b62785b5ebae88de302d2f70f264bc8 Mon Sep 17 00:00:00 2001 From: Dominique Debergue Date: Tue, 25 Dec 2018 01:06:04 -0800 Subject: [PATCH 012/132] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0458b8f..ecf4262 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) [![GoDoc](https://godoc.org/github.com/hewiefreeman/GopherGameServer?status.svg)](https://godoc.org/github.com/hewiefreeman/GopherGameServer) [![Go Report Card](https://goreportcard.com/badge/github.com/hewiefreeman/GopherGameServer)](https://goreportcard.com/report/github.com/hewiefreeman/GopherGameServer) -Gopher Game Server is a full featured, super fast, and fully customizable game server written in Go. Comes with a client API for JavaScript (and eventually Java, C++, and C). +Gopher Game Server is a full featured, fast, and fully customizable game server written in Go. Comes with a client API for JavaScript (and eventually Java, C++, and C). Gopher Game Server is designed to provide all necessary tools to ease developments of any type of online game (or any real-time app/chat). Gopher will handle all server-side synchronizing and data type conversions, therefore, client actions receiving, variable setting, message sending, and other functionalities are unproblematic. From eabb40d4538910b02d079787a605a6941c617e4a Mon Sep 17 00:00:00 2001 From: hewiefreeman Date: Tue, 25 Dec 2018 13:25:56 -0800 Subject: [PATCH 013/132] Changed server stop callback setter to SetShutDownCallback, and general clean-up --- callbacks.go | 2 +- sockets.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/callbacks.go b/callbacks.go index 97a7f89..b4c50a8 100644 --- a/callbacks.go +++ b/callbacks.go @@ -72,7 +72,7 @@ func SetResumeCallback(cb interface{}) error { // func serverStopped(){ // //code... // } -func SetStopCallback(cb interface{}) error { +func SetShutDownCallback(cb interface{}) error { if serverStarted { return errors.New(ErrorServerRunning) } else if callback, ok := cb.(func()); ok { diff --git a/sockets.go b/sockets.go index b33f465..32030ea 100644 --- a/sockets.go +++ b/sockets.go @@ -30,7 +30,7 @@ func socketInitializer(w http.ResponseWriter, r *http.Request) { origin := r.Header.Get("Origin") + ":" + strconv.Itoa(settings.Port) host := settings.HostName + ":" + strconv.Itoa(settings.Port) hostAlias := settings.HostAlias + ":" + strconv.Itoa(settings.Port) - if origin != host && (hostAlias != "" && origin != hostAlias) { + if origin != host && (settings.HostAlias != "" && origin != hostAlias) { http.Error(w, "Origin not allowed.", http.StatusForbidden) return } From 7f5c9597d4120d4b7fdfb93d42622a3223d2e89d Mon Sep 17 00:00:00 2001 From: Dominique Debergue Date: Tue, 25 Dec 2018 14:42:49 -0800 Subject: [PATCH 014/132] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ecf4262..9bbd330 100644 --- a/README.md +++ b/README.md @@ -62,8 +62,8 @@ Then install the server: 1) [**Getting Started**](https://github.com/hewiefreeman/GopherGameServer/wiki/Getting-Started) - [Set-Up](https://github.com/hewiefreeman/GopherGameServer/wiki/Getting-Started#set-up) - [Core Server Settings](https://github.com/hewiefreeman/GopherGameServer/wiki/Getting-Started#core-server-settings) - - Server Callbacks - - Micro Commands + - [Server Callbacks](https://github.com/hewiefreeman/GopherGameServer/wiki/Getting-Started#server-callbacks) + - [Macro Commands](https://github.com/hewiefreeman/GopherGameServer/wiki/Getting-Started#macro-commands) 2) **Rooms** - Room Types - Creating Rooms From b62c5ff8af321e2a4bcc78b01bceaa19e7df0f96 Mon Sep 17 00:00:00 2001 From: Dominique Debergue Date: Tue, 25 Dec 2018 14:46:36 -0800 Subject: [PATCH 015/132] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 9bbd330..6b44fd5 100644 --- a/README.md +++ b/README.md @@ -89,6 +89,7 @@ Then install the server: - Friending # Contributions +Contributions are open and welcomed! Help is needed for everything from documentation, cleaning up code, performance enhancements, client APIs and more. Show your support by starring or following the project! Please read the following articles before submitting any contributions or filing an Issue: From ac2ec3c61f882475bc4cccaa69810df76e0cf266 Mon Sep 17 00:00:00 2001 From: Dominique Debergue Date: Tue, 25 Dec 2018 14:50:26 -0800 Subject: [PATCH 016/132] Update README.md --- README.md | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/README.md b/README.md index 6b44fd5..b669555 100644 --- a/README.md +++ b/README.md @@ -2,11 +2,7 @@ [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) [![GoDoc](https://godoc.org/github.com/hewiefreeman/GopherGameServer?status.svg)](https://godoc.org/github.com/hewiefreeman/GopherGameServer) [![Go Report Card](https://goreportcard.com/badge/github.com/hewiefreeman/GopherGameServer)](https://goreportcard.com/report/github.com/hewiefreeman/GopherGameServer) -Gopher Game Server is a full featured, fast, and fully customizable game server written in Go. Comes with a client API for JavaScript (and eventually Java, C++, and C). - -Gopher Game Server is designed to provide all necessary tools to ease developments of any type of online game (or any real-time app/chat). Gopher will handle all server-side synchronizing and data type conversions, therefore, client actions receiving, variable setting, message sending, and other functionalities are unproblematic. - -Gopher uses WebSockets and JSON to pass messages between the clients and the server. The JSON enabled server is designed to pass any types of data between client and server without cares of type conversions on either end. WebSockets increases efficiency of the server as far as possible on the network, since the WebSocket protocol is newer and doesn't send as much header and meta data that standard HTTP and most other protocols require. +Gopher Game Server is designed to provide all necessary tools to greatly ease developments of any type of online game (or any real-time app/chat). Gopher will handle all server-side synchronizing and data type conversions, therefore, client actions receiving, variable setting, message sending, and other functionalities are unproblematic. Moreover, Gopher has a built-in, fully customizable MySQL client authentication mechanism that manages users' accounts for you. It even ties in a friending tool, so users can befriend and invite one another to groups, check each other's status, and more. All components are easily configurable and customizable for specific project's needs. From b9d9cbd7a2fd94b2eb24ae8c19279890f3452435 Mon Sep 17 00:00:00 2001 From: Dominique Debergue Date: Tue, 25 Dec 2018 14:51:09 -0800 Subject: [PATCH 017/132] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b669555..5888765 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Gopher Game Server is designed to provide all necessary tools to greatly ease developments of any type of online game (or any real-time app/chat). Gopher will handle all server-side synchronizing and data type conversions, therefore, client actions receiving, variable setting, message sending, and other functionalities are unproblematic. -Moreover, Gopher has a built-in, fully customizable MySQL client authentication mechanism that manages users' accounts for you. It even ties in a friending tool, so users can befriend and invite one another to groups, check each other's status, and more. All components are easily configurable and customizable for specific project's needs. +Moreover, Gopher has a built-in, fully customizable SQL client authentication mechanism that manages users' accounts for you. It even ties in a friending tool, so users can befriend and invite one another to groups, check each other's status, and more. All components are easily configurable and customizable for specific project's needs. ### Main features: From f4e6c05d0a6f27bd64393491b821b10748cb8459 Mon Sep 17 00:00:00 2001 From: Dominique Debergue Date: Tue, 25 Dec 2018 18:14:52 -0800 Subject: [PATCH 018/132] Update README.md --- README.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 5888765..fcf48e0 100644 --- a/README.md +++ b/README.md @@ -60,11 +60,12 @@ Then install the server: - [Core Server Settings](https://github.com/hewiefreeman/GopherGameServer/wiki/Getting-Started#core-server-settings) - [Server Callbacks](https://github.com/hewiefreeman/GopherGameServer/wiki/Getting-Started#server-callbacks) - [Macro Commands](https://github.com/hewiefreeman/GopherGameServer/wiki/Getting-Started#macro-commands) -2) **Rooms** - - Room Types - - Creating Rooms - - Room Variables - - Room Callbacks +2) [**Rooms**](https://github.com/hewiefreeman/GopherGameServer/wiki/Rooms) + - [Room Types](https://github.com/hewiefreeman/GopherGameServer/wiki/Rooms#room-types) + - [Room Broadcasts](https://github.com/hewiefreeman/GopherGameServer/wiki/Rooms#room-broadcasts) + - [Room Callbacks](https://github.com/hewiefreeman/GopherGameServer/wiki/Rooms#room-callbacks) + - [Creating & Deleting Rooms](https://github.com/hewiefreeman/GopherGameServer/wiki/Rooms#creating--deleting-rooms) + - [Room Variables](https://github.com/hewiefreeman/GopherGameServer/wiki/Rooms#room-variables) - Chat & Voice Messaging 3) **Users** - Login & Logout From a2a9b8b8cc5d736f174c023fad12b3583240e470 Mon Sep 17 00:00:00 2001 From: Dominique Debergue Date: Tue, 25 Dec 2018 22:16:22 -0800 Subject: [PATCH 019/132] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fcf48e0..b2cfe68 100644 --- a/README.md +++ b/README.md @@ -66,7 +66,7 @@ Then install the server: - [Room Callbacks](https://github.com/hewiefreeman/GopherGameServer/wiki/Rooms#room-callbacks) - [Creating & Deleting Rooms](https://github.com/hewiefreeman/GopherGameServer/wiki/Rooms#creating--deleting-rooms) - [Room Variables](https://github.com/hewiefreeman/GopherGameServer/wiki/Rooms#room-variables) - - Chat & Voice Messaging + - [Chat & Voice Messaging](https://github.com/hewiefreeman/GopherGameServer/wiki/Rooms#chat--voice-messaging) 3) **Users** - Login & Logout - Joining & Leaving Rooms From 6f8d02fc0a52aa68fcdd26486ee03265dac5e785 Mon Sep 17 00:00:00 2001 From: Dominique Debergue Date: Wed, 26 Dec 2018 15:35:38 -0800 Subject: [PATCH 020/132] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b2cfe68..61abac6 100644 --- a/README.md +++ b/README.md @@ -66,7 +66,7 @@ Then install the server: - [Room Callbacks](https://github.com/hewiefreeman/GopherGameServer/wiki/Rooms#room-callbacks) - [Creating & Deleting Rooms](https://github.com/hewiefreeman/GopherGameServer/wiki/Rooms#creating--deleting-rooms) - [Room Variables](https://github.com/hewiefreeman/GopherGameServer/wiki/Rooms#room-variables) - - [Chat & Voice Messaging](https://github.com/hewiefreeman/GopherGameServer/wiki/Rooms#chat--voice-messaging) + - [Messaging](https://github.com/hewiefreeman/GopherGameServer/wiki/Rooms#messaging) 3) **Users** - Login & Logout - Joining & Leaving Rooms From b2627662e4f8dae010f6b700df887f162dcb45ff Mon Sep 17 00:00:00 2001 From: Dominique Debergue Date: Thu, 27 Dec 2018 15:43:32 -0800 Subject: [PATCH 021/132] Update README.md --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 61abac6..bc2bb85 100644 --- a/README.md +++ b/README.md @@ -67,12 +67,12 @@ Then install the server: - [Creating & Deleting Rooms](https://github.com/hewiefreeman/GopherGameServer/wiki/Rooms#creating--deleting-rooms) - [Room Variables](https://github.com/hewiefreeman/GopherGameServer/wiki/Rooms#room-variables) - [Messaging](https://github.com/hewiefreeman/GopherGameServer/wiki/Rooms#messaging) -3) **Users** - - Login & Logout - - Joining & Leaving Rooms - - User Variables - - Initiating and Revoking Room Invites - - Messaging +3) [**Users**](https://github.com/hewiefreeman/GopherGameServer/wiki/Users) + - [Login & Logout](https://github.com/hewiefreeman/GopherGameServer/wiki/Users#login-and-logout) + - [Joining & Leaving Rooms](https://github.com/hewiefreeman/GopherGameServer/wiki/Users#joining--leaving-rooms) + - [User Variables](https://github.com/hewiefreeman/GopherGameServer/wiki/Users#user-variables) + - [Initiating and Revoking Room Invites](https://github.com/hewiefreeman/GopherGameServer/wiki/Users#initiating-and-revoking-room-invites) + - [Messaging](https://github.com/hewiefreeman/GopherGameServer/wiki/Users#messaging) 4) **Custom Client Actions** - Creating a Custom Client Action - Responding to a Custom Client Action From bc9ff7d4b0d1da7cefd59334a7af026d52518337 Mon Sep 17 00:00:00 2001 From: hewiefreeman Date: Thu, 27 Dec 2018 16:51:04 -0800 Subject: [PATCH 022/132] Added roomdelete macro command, clean-up, and small changes to match usage wiki examples. --- actions/actions.go | 8 ++++---- callbacks.go | 2 +- macros.go | 25 +++++++++++++------------ rooms/rooms.go | 6 +++--- 4 files changed, 21 insertions(+), 20 deletions(-) diff --git a/actions/actions.go b/actions/actions.go index 217db6b..535b6b7 100644 --- a/actions/actions.go +++ b/actions/actions.go @@ -16,7 +16,7 @@ import ( type CustomClientAction struct { dataType int - callback func(interface{}, Client) + callback func(interface{}, *Client) } // Client objects are created and sent along with your CustomClientAction callback function when a @@ -75,7 +75,7 @@ const ( // // (*)Callback function format: // -// func yourFunction(actionData interface{}, client Client) { +// func yourFunction(actionData interface{}, client *Client) { // //... // // // optional client response @@ -88,7 +88,7 @@ const ( // // // Note: This function can only be called BEFORE starting the server. -func New(actionType string, dataType int, callback func(interface{}, Client)) error { +func New(actionType string, dataType int, callback func(interface{}, *Client)) error { if serverStarted { return errors.New("Cannot make a new CustomClientAction once the server has started") } @@ -126,7 +126,7 @@ func HandleCustomClientAction(action string, data interface{}, user *users.User, return } //EXECUTE CALLBACK - customAction.callback(data, client) + customAction.callback(data, &client) } else { client.Respond(nil, NewError("Unrecognized action", ErrorUnrecognizedAction)) } diff --git a/callbacks.go b/callbacks.go index b4c50a8..1fe1752 100644 --- a/callbacks.go +++ b/callbacks.go @@ -66,7 +66,7 @@ func SetResumeCallback(cb interface{}) error { return nil } -// SetStopCallback sets the callback that triggers when the server is stopped. The +// SetShutDownCallback sets the callback that triggers when the server is shut down. The // function passed must have the same parameter types as the following example: // // func serverStopped(){ diff --git a/macros.go b/macros.go index 48aaaa3..bf6a558 100644 --- a/macros.go +++ b/macros.go @@ -30,8 +30,8 @@ func handleMacro(macro string) bool { } else if macro == "shutdown" { ShutDown() return true - } else if len(macro) >= 13 && macro[0:11] == "newroomtype" { - macroNewRoomType(macro) + } else if len(macro) >= 12 && macro[0:10] == "deleteroom" { + macroDeleteRoom(macro) } else if len(macro) >= 9 && macro[0:7] == "newroom" { macroNewRoom(macro) } else if len(macro) >= 6 && macro[0:4] == "kick" { @@ -75,20 +75,21 @@ func macroNewRoom(macro string) { fmt.Println("Created room '" + s[1] + "'") } -func macroNewRoomType(macro string) { +func macroDeleteRoom(macro string) { s := strings.Split(macro, " ") - if len(s) != 3 { - fmt.Println("newroomtype expects 2 parameters (name string, serverOnly bool)") + if len(s) != 2 { + fmt.Println("deleteroom expects 1 parameter (name string)") return } - serverOnly := false - if s[2] == "true" || s[2] == "t" { - serverOnly = true + room, roomErr := rooms.Get(s[1]) + if roomErr != nil { + fmt.Println(roomErr) + return } - rooms.NewRoomType(s[1], serverOnly) - if _, ok := rooms.GetRoomTypes()[s[1]]; !ok { - fmt.Println("The server must be paused to create a room type") + deleteErr := room.Delete() + if deleteErr != nil { + fmt.Println(deleteErr) return } - fmt.Println("Created room type '" + s[1] + "'") + fmt.Println("Deleted room '" + s[1] + "'") } diff --git a/rooms/rooms.go b/rooms/rooms.go index f17817e..db995e0 100644 --- a/rooms/rooms.go +++ b/rooms/rooms.go @@ -24,9 +24,9 @@ import ( // Room represents a room on the server that Users can join and leave. Use rooms.New() to make a new Room. // -// WARNING: When you use a *User object in your code, DO NOT dereference it. Instead, there are -// many methods for *User for retrieving any information about them you could possibly need. -// Dereferencing them could cause data races in the User fields that get locked by mutexes. +// WARNING: When you use a *Room object in your code, DO NOT dereference it. Instead, there are +// many methods for *Room for maniupulating and retrieving any information about them you could possibly need. +// Dereferencing them could cause data races in the Room fields that get locked by mutexes. type Room struct { name string rType string From 1814bbb8db4c3bfc5bc3841f4d8a3b7e44f4ea18 Mon Sep 17 00:00:00 2001 From: Dominique Debergue Date: Thu, 27 Dec 2018 17:44:13 -0800 Subject: [PATCH 023/132] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index bc2bb85..b0193e1 100644 --- a/README.md +++ b/README.md @@ -73,9 +73,9 @@ Then install the server: - [User Variables](https://github.com/hewiefreeman/GopherGameServer/wiki/Users#user-variables) - [Initiating and Revoking Room Invites](https://github.com/hewiefreeman/GopherGameServer/wiki/Users#initiating-and-revoking-room-invites) - [Messaging](https://github.com/hewiefreeman/GopherGameServer/wiki/Users#messaging) -4) **Custom Client Actions** - - Creating a Custom Client Action - - Responding to a Custom Client Action +4) [**Custom Client Actions**](https://github.com/hewiefreeman/GopherGameServer/wiki/Custom-Client-Actions) + - [Creating a Custom Client Action](https://github.com/hewiefreeman/GopherGameServer/wiki/Custom-Client-Actions#creating-a-custom-client-action) + - [Responding to a Custom Client Action](https://github.com/hewiefreeman/GopherGameServer/wiki/Custom-Client-Actions#responding-to-a-custom-client-action) 6) **Saving & Restoring** - Set-Up 5) **MySQL Features** From b659dfd46089776d6eff6bf54572158e6d66b272 Mon Sep 17 00:00:00 2001 From: Dominique Debergue Date: Thu, 27 Dec 2018 17:45:04 -0800 Subject: [PATCH 024/132] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b0193e1..7079f0b 100644 --- a/README.md +++ b/README.md @@ -86,7 +86,7 @@ Then install the server: - Friending # Contributions -Contributions are open and welcomed! Help is needed for everything from documentation, cleaning up code, performance enhancements, client APIs and more. Show your support by starring or following the project! +Contributions are open and welcomed! Help is needed for everything from documentation, cleaning up code, performance enhancements, client APIs and more. Don't forget to show your support by starring or following the project! Please read the following articles before submitting any contributions or filing an Issue: From 84eba98668204307946b7200f77ded85c80cd751 Mon Sep 17 00:00:00 2001 From: Dominique Debergue Date: Thu, 27 Dec 2018 18:15:33 -0800 Subject: [PATCH 025/132] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 7079f0b..9fb4d76 100644 --- a/README.md +++ b/README.md @@ -76,8 +76,8 @@ Then install the server: 4) [**Custom Client Actions**](https://github.com/hewiefreeman/GopherGameServer/wiki/Custom-Client-Actions) - [Creating a Custom Client Action](https://github.com/hewiefreeman/GopherGameServer/wiki/Custom-Client-Actions#creating-a-custom-client-action) - [Responding to a Custom Client Action](https://github.com/hewiefreeman/GopherGameServer/wiki/Custom-Client-Actions#responding-to-a-custom-client-action) -6) **Saving & Restoring** - - Set-Up +6) [**Saving & Restoring**](https://github.com/hewiefreeman/GopherGameServer/wiki/Saving-&-Restoring) + - [Set-Up](https://github.com/hewiefreeman/GopherGameServer/wiki/Saving-&-Restoring#set-up) 5) **MySQL Features** - Set-Up - Securely Authenticating Clients From d62a3ce23e6114bd71c17ea3dbbe2b534df97c8f Mon Sep 17 00:00:00 2001 From: Dominique Debergue Date: Thu, 27 Dec 2018 19:31:49 -0800 Subject: [PATCH 026/132] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 9fb4d76..315097d 100644 --- a/README.md +++ b/README.md @@ -78,8 +78,8 @@ Then install the server: - [Responding to a Custom Client Action](https://github.com/hewiefreeman/GopherGameServer/wiki/Custom-Client-Actions#responding-to-a-custom-client-action) 6) [**Saving & Restoring**](https://github.com/hewiefreeman/GopherGameServer/wiki/Saving-&-Restoring) - [Set-Up](https://github.com/hewiefreeman/GopherGameServer/wiki/Saving-&-Restoring#set-up) -5) **MySQL Features** - - Set-Up +5) [**SQL Features**](https://github.com/hewiefreeman/GopherGameServer/wiki/SQL-Features) + - [Set-Up](https://github.com/hewiefreeman/GopherGameServer/wiki/SQL-Features#set-up) - Securely Authenticating Clients - Customize Authentication Features - Custom Account Info From e24ef94bbc93841021a49989b13eb7f0993376e5 Mon Sep 17 00:00:00 2001 From: Dominique Debergue Date: Thu, 27 Dec 2018 19:34:48 -0800 Subject: [PATCH 027/132] Update README.md --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index 315097d..30f5720 100644 --- a/README.md +++ b/README.md @@ -51,8 +51,6 @@ Then install the server: # Usage -**-UNDER CONSTRUCTION-** - ### Table of Contents 1) [**Getting Started**](https://github.com/hewiefreeman/GopherGameServer/wiki/Getting-Started) From d2f0d1431561bc45cfb3d4fa335fc907398edd87 Mon Sep 17 00:00:00 2001 From: Dominique Debergue Date: Thu, 27 Dec 2018 19:37:53 -0800 Subject: [PATCH 028/132] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 30f5720..0b32fc8 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,9 @@ [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) [![GoDoc](https://godoc.org/github.com/hewiefreeman/GopherGameServer?status.svg)](https://godoc.org/github.com/hewiefreeman/GopherGameServer) [![Go Report Card](https://goreportcard.com/badge/github.com/hewiefreeman/GopherGameServer)](https://goreportcard.com/report/github.com/hewiefreeman/GopherGameServer) -Gopher Game Server is designed to provide all necessary tools to greatly ease developments of any type of online game (or any real-time app/chat). Gopher will handle all server-side synchronizing and data type conversions, therefore, client actions receiving, variable setting, message sending, and other functionalities are unproblematic. +Gopher Game Server is designed to provide all necessary tools to greatly ease developments of any type of online game (or any real-time app/chat). Gopher will handle all server-side synchronizing and data type conversions, therefore, client actions receiving, variable setting, messaging, and other functionalities are unproblematic. -Moreover, Gopher has a built-in, fully customizable SQL client authentication mechanism that manages users' accounts for you. It even ties in a friending tool, so users can befriend and invite one another to groups, check each other's status, and more. All components are easily configurable and customizable for specific project's needs. +Moreover, Gopher has a built-in, fully customizable SQL client authentication mechanism that creates and manages users' accounts for you. It even ties in a friending tool, so users can befriend and invite one another to groups, check each other's status, and more. All components are easily configurable and customizable for specific project's needs. ### Main features: From 18f7ac0f900ab9299ced6e013f7b4fbea9911442 Mon Sep 17 00:00:00 2001 From: Dominique Debergue Date: Sun, 30 Dec 2018 18:12:16 -0800 Subject: [PATCH 029/132] Update README.md --- README.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 0b32fc8..07f3bcd 100644 --- a/README.md +++ b/README.md @@ -70,6 +70,7 @@ Then install the server: - [Joining & Leaving Rooms](https://github.com/hewiefreeman/GopherGameServer/wiki/Users#joining--leaving-rooms) - [User Variables](https://github.com/hewiefreeman/GopherGameServer/wiki/Users#user-variables) - [Initiating and Revoking Room Invites](https://github.com/hewiefreeman/GopherGameServer/wiki/Users#initiating-and-revoking-room-invites) + - [User Status](https://github.com/hewiefreeman/GopherGameServer/wiki/Users#user-status) - [Messaging](https://github.com/hewiefreeman/GopherGameServer/wiki/Users#messaging) 4) [**Custom Client Actions**](https://github.com/hewiefreeman/GopherGameServer/wiki/Custom-Client-Actions) - [Creating a Custom Client Action](https://github.com/hewiefreeman/GopherGameServer/wiki/Custom-Client-Actions#creating-a-custom-client-action) @@ -78,10 +79,11 @@ Then install the server: - [Set-Up](https://github.com/hewiefreeman/GopherGameServer/wiki/Saving-&-Restoring#set-up) 5) [**SQL Features**](https://github.com/hewiefreeman/GopherGameServer/wiki/SQL-Features) - [Set-Up](https://github.com/hewiefreeman/GopherGameServer/wiki/SQL-Features#set-up) - - Securely Authenticating Clients - - Customize Authentication Features - - Custom Account Info - - Friending + - [Authenticating Clients](https://github.com/hewiefreeman/GopherGameServer/wiki/SQL-Features#authenticating-clients) + - [Custom Account Info](https://github.com/hewiefreeman/GopherGameServer/wiki/SQL-Features#custom-account-info) + - [Customizing Authentication Features](https://github.com/hewiefreeman/GopherGameServer/wiki/SQL-Features#customizing-authentication-features) + - [Auto-Login (Remember Me)](https://github.com/hewiefreeman/GopherGameServer/wiki/SQL-Features#auto-login-remember-me) + - [Friending](https://github.com/hewiefreeman/GopherGameServer/wiki/SQL-Features#friending) # Contributions Contributions are open and welcomed! Help is needed for everything from documentation, cleaning up code, performance enhancements, client APIs and more. Don't forget to show your support by starring or following the project! From 36ab961bf3b5169ef85116361a70c23786dda8a6 Mon Sep 17 00:00:00 2001 From: Dominique Debergue Date: Sun, 30 Dec 2018 18:17:14 -0800 Subject: [PATCH 030/132] Delete saveState_test.go --- helpers/saveState_test.go | 16 ---------------- 1 file changed, 16 deletions(-) delete mode 100644 helpers/saveState_test.go diff --git a/helpers/saveState_test.go b/helpers/saveState_test.go deleted file mode 100644 index 6d3826d..0000000 --- a/helpers/saveState_test.go +++ /dev/null @@ -1,16 +0,0 @@ -package helpers - -import ( - "fmt" - "testing" -) - -func TestSaveState(*testing.T) { - e := make(map[string]interface{}) - e["wtf"] = make(map[string]interface{}) - e["wtf"].(map[string]interface{})["innerWtf"] = "howdy do!" - err := saveState(e) - if err != nil { - fmt.Println(err) - } -} From 7c38da2d61f87209f7be6f8d587fccba9d3aacf7 Mon Sep 17 00:00:00 2001 From: hewiefreeman Date: Sun, 30 Dec 2018 18:29:41 -0800 Subject: [PATCH 031/132] Added a connID optional parameter to *User.DataMessage() and clean-up --- clientActions.go | 2 +- rooms/rooms.go | 1 + users/messages.go | 12 +++++++++--- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/clientActions.go b/clientActions.go index 3cf575d..f613d5f 100644 --- a/clientActions.go +++ b/clientActions.go @@ -381,7 +381,7 @@ func clientActionLogin(params interface{}, user **users.User, deviceTag *string, var dPass string var cID string var err helpers.GopherError - if (*settings).EnableSqlFeatures { + if (*settings).EnableSqlFeatures && !guest { uName, dbIndex, dPass, err = database.LoginClient(name, pass, *deviceTag, remMe, customCols) if err.ID != 0 { return nil, true, err diff --git a/rooms/rooms.go b/rooms/rooms.go index db995e0..12eace6 100644 --- a/rooms/rooms.go +++ b/rooms/rooms.go @@ -451,6 +451,7 @@ func (r *Room) RemoveInvite(userName string) error { } r.mux.Lock() + if r.usersMap == nil { r.mux.Unlock() return errors.New("The room '" + r.name + "' does not exist") diff --git a/users/messages.go b/users/messages.go index f8421c5..8891118 100644 --- a/users/messages.go +++ b/users/messages.go @@ -42,15 +42,21 @@ func (u *User) PrivateMessage(userName string, message interface{}) { ////////////////////////////////////////////////////////////////////////////////////////////////////// // DataMessage sends a data message directly to the User. -func (u *User) DataMessage(data interface{}) { +func (u *User) DataMessage(data interface{}, connID string) { //CONSTRUCT MESSAGE message := make(map[string]interface{}) message[helpers.ServerActionDataMessage] = data //SEND MESSAGE TO USER u.mux.Lock() - for _, conn := range u.conns { - (*conn).socket.WriteJSON(message) + if connID == "" { + for _, conn := range u.conns { + (*conn).socket.WriteJSON(message) + } + } else { + if conn, ok := u.conns[connID]; ok { + (*conn).socket.WriteJSON(message) + } } u.mux.Unlock() } From 1383a4024a1775bc29c73837b0790301f6efc972 Mon Sep 17 00:00:00 2001 From: hewiefreeman Date: Tue, 8 Jan 2019 20:57:38 -0800 Subject: [PATCH 032/132] Fixed multiple resposes bug for affected client actions, and more documentation. --- clientActions.go | 74 ++++++++++++++++----------------- helpers/errors.go | 104 ++++++++++++++++++++++++---------------------- server.go | 2 +- 3 files changed, 92 insertions(+), 88 deletions(-) diff --git a/clientActions.go b/clientActions.go index f613d5f..d201765 100644 --- a/clientActions.go +++ b/clientActions.go @@ -133,7 +133,7 @@ func clientCustomAction(params interface{}, user **users.User, conn *websocket.C userRef := *user (*clientMux).Unlock() actions.HandleCustomClientAction(action, pMap["d"], userRef, conn, connID) - return nil, false, helpers.NewError("", 0) + return nil, false, helpers.NoError() } ////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -158,7 +158,7 @@ func clientActionChangeStatus(params interface{}, user **users.User, clientMux * // userRef.SetStatus(status) // - return status, true, helpers.NewError("", 0) + return status, true, helpers.NoError() } ////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -202,7 +202,7 @@ func clientActionSignup(params interface{}, user **users.User, clientMux *sync.M } // - return nil, true, helpers.NewError("", 0) + return nil, true, helpers.NoError() } func clientActionDeleteAccount(params interface{}, user **users.User, clientMux *sync.Mutex) (interface{}, bool, helpers.GopherError) { @@ -248,7 +248,7 @@ func clientActionDeleteAccount(params interface{}, user **users.User, clientMux return nil, true, deleteErr } // - return nil, true, helpers.NewError("", 0) + return nil, true, helpers.NoError() } func clientActionChangePassword(params interface{}, user **users.User, clientMux *sync.Mutex) (interface{}, bool, helpers.GopherError) { @@ -289,7 +289,7 @@ func clientActionChangePassword(params interface{}, user **users.User, clientMux } // - return nil, true, helpers.NewError("", 0) + return nil, true, helpers.NoError() } func clientActionChangeAccountInfo(params interface{}, user **users.User, clientMux *sync.Mutex) (interface{}, bool, helpers.GopherError) { @@ -326,7 +326,7 @@ func clientActionChangeAccountInfo(params interface{}, user **users.User, client } // - return nil, true, helpers.NewError("", 0) + return nil, true, helpers.NoError() } ////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -399,7 +399,7 @@ func clientActionLogin(params interface{}, user **users.User, deviceTag *string, *connID = cID // - return nil, false, helpers.NewError("", 0) + return nil, false, helpers.NoError() } func clientActionLogout(user **users.User, deviceTag *string, devicePass *string, deviceUserID *int, connID *string, clientMux *sync.Mutex) (interface{}, bool, helpers.GopherError) { @@ -422,7 +422,7 @@ func clientActionLogout(user **users.User, deviceTag *string, devicePass *string *connID = "" // - return nil, false, helpers.NewError("", 0) + return nil, false, helpers.NoError() } ////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -455,7 +455,7 @@ func clientActionJoinRoom(params interface{}, user **users.User, connID string, } // - return nil, true, helpers.NewError("", 0) + return nil, false, helpers.NoError() } func clientActionLeaveRoom(user **users.User, connID string, clientMux *sync.Mutex) (interface{}, bool, helpers.GopherError) { @@ -473,7 +473,7 @@ func clientActionLeaveRoom(user **users.User, connID string, clientMux *sync.Mut } // - return nil, true, helpers.NewError("", 0) + return nil, false, helpers.NoError() } func clientActionCreateRoom(params interface{}, user **users.User, connID string, clientMux *sync.Mutex) (interface{}, bool, helpers.GopherError) { @@ -533,7 +533,7 @@ func clientActionCreateRoom(params interface{}, user **users.User, connID string } // - return roomName, true, helpers.NewError("", 0) + return roomName, true, helpers.NoError() } func clientActionDeleteRoom(params interface{}, user **users.User, clientMux *sync.Mutex) (interface{}, bool, helpers.GopherError) { @@ -571,7 +571,7 @@ func clientActionDeleteRoom(params interface{}, user **users.User, clientMux *sy return nil, true, helpers.NewError(deleteErr.Error(), helpers.ErrorGopherDeleteRoom) } - return nil, true, helpers.NewError("", 0) + return nil, true, helpers.NoError() } func clientActionRoomInvite(params interface{}, user **users.User, connID string, clientMux *sync.Mutex) (interface{}, bool, helpers.GopherError) { @@ -602,7 +602,7 @@ func clientActionRoomInvite(params interface{}, user **users.User, connID string return nil, true, helpers.NewError(invUserErr.Error(), helpers.ErrorGopherInvite) } // - return nil, true, helpers.NewError("", 0) + return nil, true, helpers.NoError() } func clientActionRevokeInvite(params interface{}, user **users.User, connID string, clientMux *sync.Mutex) (interface{}, bool, helpers.GopherError) { @@ -628,7 +628,7 @@ func clientActionRevokeInvite(params interface{}, user **users.User, connID stri return nil, true, helpers.NewError(revokeErr.Error(), helpers.ErrorGopherRevokeInvite) } // - return nil, true, helpers.NewError("", 0) + return nil, true, helpers.NoError() } ////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -639,50 +639,50 @@ func clientActionVoiceStream(params interface{}, user **users.User, conn *websoc (*clientMux).Lock() if *user == nil { (*clientMux).Unlock() - return nil, false, helpers.NewError("", 0) + return nil, false, helpers.NoError() } userRef := *user (*clientMux).Unlock() //GET CURRENT ROOM currRoom := userRef.RoomIn(connID) if currRoom == nil || currRoom.Name() == "" { - return nil, false, helpers.NewError("", 0) + return nil, false, helpers.NoError() } //CHECK IF VOICE CHAT ROOM rType := rooms.GetRoomTypes()[currRoom.Type()] if !rType.VoiceChatEnabled() { - return nil, false, helpers.NewError("", 0) + return nil, false, helpers.NoError() } //SEND VOICE STREAM currRoom.VoiceStream(userRef.Name(), conn, params) // - return nil, false, helpers.NewError("", 0) + return nil, false, helpers.NoError() } func clientActionChatMessage(params interface{}, user **users.User, connID string, clientMux *sync.Mutex) (interface{}, bool, helpers.GopherError) { (*clientMux).Lock() if *user == nil { (*clientMux).Unlock() - return nil, false, helpers.NewError("", 0) + return nil, false, helpers.NoError() } userRef := *user (*clientMux).Unlock() //GET CURRENT ROOM currRoom := userRef.RoomIn(connID) if currRoom == nil || currRoom.Name() == "" { - return nil, false, helpers.NewError("", 0) + return nil, false, helpers.NoError() } //SEND CHAT MESSAGE currRoom.ChatMessage(userRef.Name(), params) // - return nil, false, helpers.NewError("", 0) + return nil, false, helpers.NoError() } func clientActionPrivateMessage(params interface{}, user **users.User, connID string, clientMux *sync.Mutex) (interface{}, bool, helpers.GopherError) { (*clientMux).Lock() if *user == nil { (*clientMux).Unlock() - return nil, false, helpers.NewError("", 0) + return nil, false, helpers.NoError() } userRef := *user (*clientMux).Unlock() @@ -691,20 +691,20 @@ func clientActionPrivateMessage(params interface{}, user **users.User, connID st var pMap map[string]interface{} var userName string if pMap, ok = params.(map[string]interface{}); !ok { - return nil, false, helpers.NewError("", 0) + return nil, false, helpers.NoError() } if userName, ok = pMap["u"].(string); !ok { - return nil, false, helpers.NewError("", 0) + return nil, false, helpers.NoError() } //GET CURRENT ROOM currRoom := userRef.RoomIn(connID) if currRoom == nil || currRoom.Name() == "" { - return nil, false, helpers.NewError("", 0) + return nil, false, helpers.NoError() } //SEND CHAT MESSAGE userRef.PrivateMessage(userName, pMap["m"]) // - return nil, false, helpers.NewError("", 0) + return nil, false, helpers.NoError() } ////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -715,7 +715,7 @@ func clientActionSetVariable(params interface{}, user **users.User, connID strin (*clientMux).Lock() if *user == nil { (*clientMux).Unlock() - return nil, false, helpers.NewError("", 0) + return nil, false, helpers.NoError() } userRef := *user (*clientMux).Unlock() @@ -725,23 +725,23 @@ func clientActionSetVariable(params interface{}, user **users.User, connID strin var varKey string var varVal interface{} if pMap, ok = params.(map[string]interface{}); !ok { - return nil, false, helpers.NewError("", 0) + return nil, false, helpers.NoError() } if varKey, ok = pMap["k"].(string); !ok { - return nil, false, helpers.NewError("", 0) + return nil, false, helpers.NoError() } varVal = pMap["v"] //SET THE VARIABLE userRef.SetVariable(varKey, varVal, connID) // - return nil, false, helpers.NewError("", 0) + return nil, false, helpers.NoError() } func clientActionSetVariables(params interface{}, user **users.User, connID string, clientMux *sync.Mutex) (interface{}, bool, helpers.GopherError) { (*clientMux).Lock() if *user == nil { (*clientMux).Unlock() - return nil, false, helpers.NewError("", 0) + return nil, false, helpers.NoError() } userRef := *user (*clientMux).Unlock() @@ -749,12 +749,12 @@ func clientActionSetVariables(params interface{}, user **users.User, connID stri var ok bool var pMap map[string]interface{} if pMap, ok = params.(map[string]interface{}); !ok { - return nil, false, helpers.NewError("", 0) + return nil, false, helpers.NoError() } //SET THE VARIABLES userRef.SetVariables(pMap, connID) // - return nil, false, helpers.NewError("", 0) + return nil, false, helpers.NoError() } ////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -786,7 +786,7 @@ func clientActionFriendRequest(params interface{}, user **users.User, clientMux } // - return nil, false, helpers.NewError("", 0) + return nil, false, helpers.NoError() } func clientActionAcceptFriend(params interface{}, user **users.User, clientMux *sync.Mutex) (interface{}, bool, helpers.GopherError) { @@ -814,7 +814,7 @@ func clientActionAcceptFriend(params interface{}, user **users.User, clientMux * } // - return nil, false, helpers.NewError("", 0) + return nil, false, helpers.NoError() } func clientActionDeclineFriend(params interface{}, user **users.User, clientMux *sync.Mutex) (interface{}, bool, helpers.GopherError) { @@ -842,7 +842,7 @@ func clientActionDeclineFriend(params interface{}, user **users.User, clientMux } // - return nil, false, helpers.NewError("", 0) + return nil, false, helpers.NoError() } func clientActionRemoveFriend(params interface{}, user **users.User, clientMux *sync.Mutex) (interface{}, bool, helpers.GopherError) { @@ -870,5 +870,5 @@ func clientActionRemoveFriend(params interface{}, user **users.User, clientMux * } // - return nil, false, helpers.NewError("", 0) + return nil, false, helpers.NoError() } diff --git a/helpers/errors.go b/helpers/errors.go index 8f0d6f4..394e2c2 100644 --- a/helpers/errors.go +++ b/helpers/errors.go @@ -8,63 +8,67 @@ type GopherError struct { // Client response message error IDs const ( - ErrorGopherInvalidAction = iota + 1001 // Invalid client action - ErrorGopherIncorrectFormat // The client's data is not a map/object - ErrorGopherIncorrectCustomAction // Incorrect custom client action type - ErrorGopherNotLoggedIn // The client must be logged in to take action - ErrorGopherLoggedIn // The client must be logged out to take action - ErrorGopherStatusChange // Error while changing User's status - ErrorGopherFeatureDisabled // The feature required for the action is disabled - ErrorGopherColumnsFormat // The client's custom columns data is not a map/object - ErrorGopherNameFormat // The client's user name data is not a string - ErrorGopherPasswordFormat // The client's password data is not a string - ErrorGopherRememberFormat // The client's remember-me data is not a boolean - ErrorGopherGuestFormat // The client's guest data is not a boolean - ErrorGopherNewPasswordFormat - ErrorGopherRoomNameFormat - ErrorGopherRoomTypeFormat - ErrorGopherPrivateFormat - ErrorGopherMaxRoomFormat - ErrorGopherRoomControl - ErrorGopherServerRoom - ErrorGopherNotOwner - ErrorGopherLogin - ErrorGopherSignUp - ErrorGopherJoin - ErrorGopherLeave - ErrorGopherCreateRoom - ErrorGopherDeleteRoom - ErrorGopherInvite - ErrorGopherRevokeInvite - ErrorGopherFriendRequest - ErrorGopherFriendAccept - ErrorGopherFriendDecline - ErrorGopherFriendRemove + ErrorGopherInvalidAction = iota + 1001 // 1001. Invalid client action + ErrorGopherIncorrectFormat // 1002. The client's data is not a map/object + ErrorGopherIncorrectCustomAction // 1003. Incorrect custom client action type + ErrorGopherNotLoggedIn // 1004. The client must be logged in to take action + ErrorGopherLoggedIn // 1005. The client must be logged out to take action + ErrorGopherStatusChange // 1006. Error while changing User's status + ErrorGopherFeatureDisabled // 1007. The feature required for the action is disabled + ErrorGopherColumnsFormat // 1008. The client's custom columns data is not a map/object + ErrorGopherNameFormat // 1009. The client's user name data is not a string + ErrorGopherPasswordFormat // 1010. The client's password data is not a string + ErrorGopherRememberFormat // 1011. The client's remember-me data is not a boolean + ErrorGopherGuestFormat // 1012. The client's guest data is not a boolean + ErrorGopherNewPasswordFormat // 1013. The client's new password data is not a string + ErrorGopherRoomNameFormat // 1014. The client's room name data is not a string + ErrorGopherRoomTypeFormat // 1015. The client's room type data is not a string + ErrorGopherPrivateFormat // 1016. The client's private room data is not a boolean + ErrorGopherMaxRoomFormat // 1017. The client's maximum room capacity data is not an integer + ErrorGopherRoomControl // 1018. Clients do not have the ability to control rooms + ErrorGopherServerRoom // 1019. The room type specified can only be made by the server + ErrorGopherNotOwner // 1020. The client must be the owner of the room to take action + ErrorGopherLogin // 1021. There was an error logging in + ErrorGopherSignUp // 1022. There was an error signing up + ErrorGopherJoin // 1023. There was an error joining a room + ErrorGopherLeave // 1024. There was an error leaving a room + ErrorGopherCreateRoom // 1025. There was an error creating a room + ErrorGopherDeleteRoom // 1026. There was an error deleting a room + ErrorGopherInvite // 1027. There was an error inviting User to a room + ErrorGopherRevokeInvite // 1028. There was an error revoking a User's invitation to a room + ErrorGopherFriendRequest // 1029. There was an error sending a friend request + ErrorGopherFriendAccept // 1030. There was an error accepting a friend request + ErrorGopherFriendDecline // 1031. There was an error declining a friend request + ErrorGopherFriendRemove // 1032. There was an error removing a friend // Authentication - ErrorAuthUnexpected - ErrorAuthAlreadyLogged - ErrorAuthRequiredName - ErrorAuthRequiredPass - ErrorAuthRequiredNewPass - ErrorAuthRequiredID - ErrorAuthRequiredSocket - ErrorAuthNameUnavail - ErrorAuthMaliciousChars - ErrorAuthIncorrectCols - ErrorAuthInsufficientCols - ErrorAuthEncryption - ErrorAuthQuery - ErrorAuthIncorrectLogin - ErrorDatabaseInvalidAutolog - ErrorAuthConversion + ErrorAuthUnexpected // 1033. There was an unexpected authorization error + ErrorAuthAlreadyLogged // 1034. The client is already logged in + ErrorAuthRequiredName // 1035. A user name is required + ErrorAuthRequiredPass // 1036. A password is required + ErrorAuthRequiredNewPass // 1037. A new password is required + ErrorAuthRequiredID // 1038. An account id is required + ErrorAuthRequiredSocket // 1039. A client socket pointer is required + ErrorAuthNameUnavail // 1040. The user name is unavailable + ErrorAuthMaliciousChars // 1041. There are malicious characters in the client's request variables + ErrorAuthIncorrectCols // 1042. The client supplied incorrect custom account info column data + ErrorAuthInsufficientCols // 1043. The client supplied an insufficient ammount of custom account info columns + ErrorAuthEncryption // 1044. There was an error while encrypting data + ErrorAuthQuery // 1045. There was an error while querying the database + ErrorAuthIncorrectLogin // 1046. The client supplied an incorrect login or password + ErrorDatabaseInvalidAutolog // 1047. The client supplied incorrect auto-login (remember me) data + ErrorAuthConversion // 1048. There was an error while converting data to be stored on the database // Misc errors - ErrorActionDenied - ErrorServerPaused + ErrorActionDenied // 1049. The callback for this action denied it's completion + ErrorServerPaused // 1050. The server is paused ) // NewError creates a new GopherError. func NewError(message string, id int) GopherError { return GopherError{Message: message, ID: id} } + +func NoError() GopherError { + return GopherError{Message: "", ID: 0} +} diff --git a/server.go b/server.go index b66dd11..4ab64c9 100644 --- a/server.go +++ b/server.go @@ -21,7 +21,7 @@ import ( /////////// TO DOs: /////////// - Admin tools -/////////// - More useful command-line macros +/////////// - More useful command-line macros // ServerSettings are the core settings for the Gopher Game Server. You must fill one of these out to customize // the server's functionality to your liking. From 1e33a2b129ceb9a6312d35666f24d3fd9fc2f2da Mon Sep 17 00:00:00 2001 From: Dominique Debergue Date: Tue, 8 Jan 2019 21:18:14 -0800 Subject: [PATCH 033/132] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 07f3bcd..d456a7f 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ Moreover, Gopher has a built-in, fully customizable SQL client authentication me The Java, C++, and C (possibly more with some help) client APIs will be made after completing version 1.0 and the JavaScript client API. # Installing -Gopher Game Server requires at least **Go v1.8+**, and **MySQL v5.7+** for the authentication and friending features. +Gopher Game Server requires at least **Go v1.8+** (and **MySQL v5.7+** for the authentication and friending features). First, install the dependencies: From 5f29aa1e8a47a1aba37e1d4da5d43edeb1edd27d Mon Sep 17 00:00:00 2001 From: hewiefreeman Date: Sat, 12 Jan 2019 15:57:45 -0800 Subject: [PATCH 034/132] Documentation and editing functionalities to match wiki and intended usage. --- clientActions.go | 2 +- helpers/errors.go | 3 ++- rooms/rooms.go | 2 +- server.go | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/clientActions.go b/clientActions.go index d201765..89571c6 100644 --- a/clientActions.go +++ b/clientActions.go @@ -571,7 +571,7 @@ func clientActionDeleteRoom(params interface{}, user **users.User, clientMux *sy return nil, true, helpers.NewError(deleteErr.Error(), helpers.ErrorGopherDeleteRoom) } - return nil, true, helpers.NoError() + return roomName, true, helpers.NoError() } func clientActionRoomInvite(params interface{}, user **users.User, connID string, clientMux *sync.Mutex) (interface{}, bool, helpers.GopherError) { diff --git a/helpers/errors.go b/helpers/errors.go index 394e2c2..95dd78e 100644 --- a/helpers/errors.go +++ b/helpers/errors.go @@ -52,7 +52,7 @@ const ( ErrorAuthNameUnavail // 1040. The user name is unavailable ErrorAuthMaliciousChars // 1041. There are malicious characters in the client's request variables ErrorAuthIncorrectCols // 1042. The client supplied incorrect custom account info column data - ErrorAuthInsufficientCols // 1043. The client supplied an insufficient ammount of custom account info columns + ErrorAuthInsufficientCols // 1043. The client supplied an insufficient amount of custom account info columns ErrorAuthEncryption // 1044. There was an error while encrypting data ErrorAuthQuery // 1045. There was an error while querying the database ErrorAuthIncorrectLogin // 1046. The client supplied an incorrect login or password @@ -69,6 +69,7 @@ func NewError(message string, id int) GopherError { return GopherError{Message: message, ID: id} } +// NoError creates a new GopherError that represents a state in which no error occured. func NoError() GopherError { return GopherError{Message: "", ID: 0} } diff --git a/rooms/rooms.go b/rooms/rooms.go index 12eace6..eec2553 100644 --- a/rooms/rooms.go +++ b/rooms/rooms.go @@ -388,7 +388,7 @@ func (r *Room) RemoveUser(userName string, connID string) error { } //SEND RESPONSE TO CLIENT - clientResp := helpers.MakeClientResponse(helpers.ClientActionLeaveRoom, nil, helpers.NewError("", 0)) + clientResp := helpers.MakeClientResponse(helpers.ClientActionLeaveRoom, r.Name(), helpers.NewError("", 0)) uConn.socket.WriteJSON(clientResp) // diff --git a/server.go b/server.go index 4ab64c9..d775cb0 100644 --- a/server.go +++ b/server.go @@ -291,7 +291,7 @@ func makeServer(handleDir string, tls bool) *http.Server { ////////////////////////////////////////////////////////////////////////////////////////////////////// // Pause will log all Users off and prevent anyone from logging in. All rooms and their variables created by the server will remain in memory. -// Same goes for rooms created by Users unless `RoomDeleteOnLeave` in `ServerSettings` is set to true. +// Same goes for rooms created by Users unless RoomDeleteOnLeave in ServerSettings is set to true. func Pause() { if !serverPaused { serverPaused = true From 57583efbacef86b047cb92c19042c8e7b51dff43 Mon Sep 17 00:00:00 2001 From: Dominique Debergue Date: Sat, 12 Jan 2019 20:02:13 -0800 Subject: [PATCH 035/132] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index d456a7f..7243382 100644 --- a/README.md +++ b/README.md @@ -88,6 +88,8 @@ Then install the server: # Contributions Contributions are open and welcomed! Help is needed for everything from documentation, cleaning up code, performance enhancements, client APIs and more. Don't forget to show your support by starring or following the project! +If you want to make a client API in an unsupported language and want to know where to start and/or have any questions, feel free to [email me](mailto:dominiquedebergue@gmail.com?subject=[GitHub]%20Gopher%20Game%20Server)! + Please read the following articles before submitting any contributions or filing an Issue: - [Contribution Guidlines](https://github.com/hewiefreeman/GopherGameServer/blob/master/CONTRIBUTING.md) From ceccf958dd7192854817a254a9339d4b302ba4de Mon Sep 17 00:00:00 2001 From: Dominique Debergue Date: Sun, 13 Jan 2019 02:36:47 -0800 Subject: [PATCH 036/132] Update README.md --- README.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 7243382..2e4f57a 100644 --- a/README.md +++ b/README.md @@ -37,18 +37,6 @@ Then install the server: go get github.com/hewiefreeman/GopherGameServer -# Documentation - -[Package gopher](https://godoc.org/github.com/hewiefreeman/GopherGameServer) - Main server package for startup and settings - -[Package rooms](https://godoc.org/github.com/hewiefreeman/GopherGameServer/rooms) - Package for using the Room, RoomType, and RoomUser types - -[Package users](https://godoc.org/github.com/hewiefreeman/GopherGameServer/users) - Package for using the User type - -[Package actions](https://godoc.org/github.com/hewiefreeman/GopherGameServer/actions) - Package for making custom client actions - -[Package database](https://godoc.org/github.com/hewiefreeman/GopherGameServer/database) - Package for customizing your database - # Usage ### Table of Contents @@ -85,6 +73,18 @@ Then install the server: - [Auto-Login (Remember Me)](https://github.com/hewiefreeman/GopherGameServer/wiki/SQL-Features#auto-login-remember-me) - [Friending](https://github.com/hewiefreeman/GopherGameServer/wiki/SQL-Features#friending) +# Documentation + +[Package gopher](https://godoc.org/github.com/hewiefreeman/GopherGameServer) - Main server package for startup and settings + +[Package rooms](https://godoc.org/github.com/hewiefreeman/GopherGameServer/rooms) - Package for using the Room, RoomType, and RoomUser types + +[Package users](https://godoc.org/github.com/hewiefreeman/GopherGameServer/users) - Package for using the User type + +[Package actions](https://godoc.org/github.com/hewiefreeman/GopherGameServer/actions) - Package for making custom client actions + +[Package database](https://godoc.org/github.com/hewiefreeman/GopherGameServer/database) - Package for customizing your database + # Contributions Contributions are open and welcomed! Help is needed for everything from documentation, cleaning up code, performance enhancements, client APIs and more. Don't forget to show your support by starring or following the project! From 0f6d4b6eb0a35fe7a264289feaaee5927c31c18a Mon Sep 17 00:00:00 2001 From: hewiefreeman Date: Sun, 13 Jan 2019 18:17:58 -0800 Subject: [PATCH 037/132] Revised some mechanics to match intended usage documented in the Wiki, and added a to-do in server.go --- database/authentication.go | 1 + database/setup.go | 4 +--- server.go | 1 + 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/database/authentication.go b/database/authentication.go index 9a90f57..6f6619f 100644 --- a/database/authentication.go +++ b/database/authentication.go @@ -363,6 +363,7 @@ func AutoLoginClient(tag string, pass string, newPass string, dbID int) (string, if pass != dPass { //SOMEONE TRIED TO COMPROMISE THIS KEY PAIR. DELETE IT NOW. RemoveAutoLog(dbID, tag) + return "", helpers.NewError(errorInvalidAutoLog, helpers.ErrorDatabaseInvalidAutolog) } //UPDATE TO NEW PASS diff --git a/database/setup.go b/database/setup.go index 242e544..4ebd0b3 100644 --- a/database/setup.go +++ b/database/setup.go @@ -56,9 +56,7 @@ func setUp() error { _, friendsErr := database.Exec("CREATE TABLE " + tableFriends + " (" + friendsColumnUser + " INTEGER NOT NULL, " + friendsColumnFriend + " INTEGER NOT NULL, " + - friendsColumnStatus + " INTEGER NOT NULL, " + - "FOREIGN KEY(" + friendsColumnUser + ") REFERENCES " + tableUsers + "(" + usersColumnID + "), " + - "FOREIGN KEY(" + friendsColumnFriend + ") REFERENCES " + tableUsers + "(" + usersColumnID + ")" + + friendsColumnStatus + " INTEGER NOT NULL" + ");") if friendsErr != nil { return friendsErr diff --git a/server.go b/server.go index d775cb0..e9c4d95 100644 --- a/server.go +++ b/server.go @@ -20,6 +20,7 @@ import ( ) /////////// TO DOs: +/////////// - Database sharding by every 20,000 IDs for friends tables /////////// - Admin tools /////////// - More useful command-line macros From 140dbb1efebbbac877c6a3c5eaf7da6fdaf06f60 Mon Sep 17 00:00:00 2001 From: Dominique Debergue Date: Sun, 13 Jan 2019 18:37:43 -0800 Subject: [PATCH 038/132] Update README.md --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index 2e4f57a..cef2466 100644 --- a/README.md +++ b/README.md @@ -22,8 +22,6 @@ Moreover, Gopher has a built-in, fully customizable SQL client authentication me - JavaScript: [Gopher Client JS](https://github.com/hewiefreeman/GopherClientJS) -The Java, C++, and C (possibly more with some help) client APIs will be made after completing version 1.0 and the JavaScript client API. - # Installing Gopher Game Server requires at least **Go v1.8+** (and **MySQL v5.7+** for the authentication and friending features). From c500ad23ebfc0027bb7fe8249f685a01ab748d4f Mon Sep 17 00:00:00 2001 From: Dominique Debergue Date: Sun, 13 Jan 2019 23:03:41 -0800 Subject: [PATCH 039/132] Update LICENSE --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index c05e850..191e120 100644 --- a/LICENSE +++ b/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright [2018] [Dominique Claude Debergue] + Copyright [2019] [Dominique Claude Debergue] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. From 8d7b54e78de7427d18de71670c6fd1d6d871da93 Mon Sep 17 00:00:00 2001 From: Dominique Debergue Date: Sun, 13 Jan 2019 23:07:54 -0800 Subject: [PATCH 040/132] Update README.md --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index cef2466..f0f9e35 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,10 @@ Moreover, Gopher has a built-in, fully customizable SQL client authentication me # Client APIs - - JavaScript: [Gopher Client JS](https://github.com/hewiefreeman/GopherClientJS) + - JavaScript: [GopherClientJS](https://github.com/hewiefreeman/GopherClientJS) + - Java: [GopherClientJava](https://github.com/hewiefreeman/GopherClientJava) + + > If you want to make a client API in an unsupported language and want to know where to start and/or have any questions, feel free to [email me](mailto:dominiquedebergue@gmail.com?subject=[GitHub]%20Gopher%20Game%20Server)! # Installing Gopher Game Server requires at least **Go v1.8+** (and **MySQL v5.7+** for the authentication and friending features). From 57ca24b617f89e21139a31bc619681b83e4f1ddf Mon Sep 17 00:00:00 2001 From: hewiefreeman Date: Fri, 25 Jan 2019 19:06:31 -0800 Subject: [PATCH 041/132] Implementing database sharding and shard management mechanisms. --- database/sharding.go | 172 +++++++++++++++++++++++++++++++++++++++++++ server.go | 4 +- 2 files changed, 175 insertions(+), 1 deletion(-) create mode 100644 database/sharding.go diff --git a/database/sharding.go b/database/sharding.go new file mode 100644 index 0000000..90a7341 --- /dev/null +++ b/database/sharding.go @@ -0,0 +1,172 @@ +package database + +import ( + "errors" + "sync" + "database/sql" +) + +var ( + shardingRules []shardingOptions = []shardingOptions{shardingOptions{}, shardingOptions{}, shardingOptions{}} +) + +const ( + ShardingTableUsers = iota // The Users table is being sharded + ShardingTableFriends // The Friends table is being sharded + ShardingTableAutologs // The Autologs table is being sharded +) + +const ( + ShardByLetter = iota + ShardByNumber +) + +type shardingOptions struct { + column string // The name of the column to use for sharding + + letterShards map[string]dbShard + + interval int + numberMux sync.Mutex + numberShards map[int]dbShard + highestInterval int + newShardNumber int + newShardCallback func(int) error +} + +type dbShard struct { + conn *sql.DB + + ip string + port int + protocol string + user string + password string + database string +} + +func SetShardingColumn (table int, column string, shardType int) error { + if serverPaused || serverStarted { + return errors.New("Cannot make new sharding rule type once the server has started") + } else if table < 0 || table > len(shardingRules)-1 { + return errors.New("Incorrect table number") + } else if shardType != ShardByLetter && shardType != ShardByNumber { + return errors.New("Incorrect sharding type") + } else if shardingRules[table].numberShards != nil && shardType == ShardByLetter { + return errors.New("Table is already using numeric sharding rules") + } else if shardingRules[table].letterShards != nil && shardType == ShardByNumber { + return errors.New("Table is already using letter sharding rules") + } else if shardingRules[table].column != "" { + return errors.New("Table already has a sharding rule type for the column '"+shardingRules[table].column+"'") + } else if column == "" { + return errors.New("Must supply a column name") + } + + // Set the rule type + shardingRules[table].column = column + + if shardType == ShardByLetter { + shardingRules[table].letterShards = make(map[string]dbShard) + } else if shardType == ShardByNumber { + shardingRules[table].numberShards = make(map[int]dbShard) + // Set defaults + shardingRules[table].interval = 20000; + shardingRules[table].newShardNumber = 19000; + shardingRules[table].highestInterval = 1; + shardingRules[table].newShardCallback = defaultNewNumberShard; + } + + return nil +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// SHARDING BY LETTER ////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +func SetShardingLetterDatabase(table int, letter string, ip string, port int, protocol string, user string, password string, db string) error { + if serverPaused || serverStarted { + return errors.New("Cannot make new sharding rule by letter once the server has started") + } else if table < 0 || table > len(shardingRules)-1 { + return errors.New("Incorrect table number") + } else if shardingRules[table].numberShards != nil { + return errors.New("Table is using numeric sharding rules") + } else if shardingRules[table].column == "" { + return errors.New("Table has no sharding column set") + } + + rule := dbShard{ ip: ip, port: port, protocol: protocol, user: user, password: password, database: db } + + shardingRules[table].letterShards[letter] = rule; + + return nil +} + +func GetLetterDatabase(s string) { + // Get a database by the starting letter(s) of a string +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// SHARDING BY NUMBER ////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +// SetShardingInterval sets the interval at which a numerically sharded database will shard by. +func SetShardingInterval(table int, interval int, newShardNumber int, newShardCallback func(int) error) error { + if serverPaused || serverStarted { + return errors.New("Cannot set sharding interval once the server has started") + } else if table < 0 || table > len(shardingRules)-1 { + return errors.New("Incorrect table number") + } else if shardingRules[table].letterShards != nil { + return errors.New("Table is using letter sharding rules") + } else if shardingRules[table].column == "" { + return errors.New("Table has no sharding column set") + } else if interval <= 100 { + return errors.New("Sharding interval requires a minimum of 100") + } else if newShardNumber >= interval || newShardNumber < 50 { + return errors.New("New shard number requires a minimum of 50 and must be less than sharding interval") + } + + shardingRules[table].interval = interval; + shardingRules[table].highestInterval = 1; + shardingRules[table].newShardNumber = newShardNumber; + if newShardCallback != nil { + shardingRules[table].newShardCallback = newShardCallback; + } + + return nil +} + +// NewNumberDatabase will open a connection to a database shard +func NewNumberShard(table int, start int, ip string, port int, protocol string, user string, password string, db string) error { + if table < 0 || table > len(shardingRules)-1 { + return errors.New("Incorrect table number") + } else if shardingRules[table].letterShards != nil { + return errors.New("Table is using letter sharding rules") + } else if shardingRules[table].column == "" { + return errors.New("Table has no sharding column set") + } else if start != 1 && start % shardingRules[table].interval != 0 { + return errors.New("Shard start number must be 1 or divisible by the sharding interval") + } + + rule := dbShard{ ip: ip, port: port, protocol: protocol, user: user, password: password, database: db } + + shardingRules[table].numberMux.Lock() + if start != shardingRules[table].highestInterval { + shardingRules[table].numberMux.Unlock() + return errors.New("New shard's start must be equal to the table's highest interval") + } + + if start == 1 { + shardingRules[table].highestInterval = shardingRules[table].interval + }else{ + shardingRules[table].highestInterval = start+shardingRules[table].interval + } + shardingRules[table].numberShards[start] = rule + shardingRules[table].numberMux.Unlock() + + return nil +} + +func defaultNewNumberShard(table int) error { + // make a new table on same database instance + return nil +} diff --git a/server.go b/server.go index e9c4d95..be0b462 100644 --- a/server.go +++ b/server.go @@ -21,6 +21,7 @@ import ( /////////// TO DOs: /////////// - Database sharding by every 20,000 IDs for friends tables +/////////// - Database sharding for Users tables /////////// - Admin tools /////////// - More useful command-line macros @@ -56,7 +57,8 @@ type ServerSettings struct { SqlDatabase string // SQL database name (Required for SQL features) EncryptionCost int // The amount of encryption iterations the server will run when storing and checking passwords. The higher the number, the longer encryptions take, but are more secure. Default is 4, range is 4-31. CustomLoginColumn string // The custom AccountInfoColumn you wish to use for logging in instead of the default name column. - RememberMe bool // Enables the "Remember Me" login feature. You can read more about this in project's "Usage" section. + RememberMe bool // Enables the "Remember Me" login feature. You can read more about this in project's wiki. + //ShardingRules database.ShardingRules EnableRecovery bool // Enables the recovery of all Rooms, their settings, and their variables on start-up after terminating the server. RecoveryLocation string // The folder location (starting from system's root folder) where you would like to store the recovery data. (Required for recovery) From 1d2d897c321d2756bdf5a6b24610ffe1b5d267ac Mon Sep 17 00:00:00 2001 From: hewiefreeman Date: Fri, 25 Jan 2019 20:56:04 -0800 Subject: [PATCH 042/132] Implementing database sharding and shard management mechanisms. --- database/sharding.go | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/database/sharding.go b/database/sharding.go index 90a7341..98eafca 100644 --- a/database/sharding.go +++ b/database/sharding.go @@ -135,7 +135,7 @@ func SetShardingInterval(table int, interval int, newShardNumber int, newShardCa return nil } -// NewNumberDatabase will open a connection to a database shard +// NewNumberDatabase will open a connection to the database shard for the starting interval func NewNumberShard(table int, start int, ip string, port int, protocol string, user string, password string, db string) error { if table < 0 || table > len(shardingRules)-1 { return errors.New("Incorrect table number") @@ -144,7 +144,7 @@ func NewNumberShard(table int, start int, ip string, port int, protocol string, } else if shardingRules[table].column == "" { return errors.New("Table has no sharding column set") } else if start != 1 && start % shardingRules[table].interval != 0 { - return errors.New("Shard start number must be 1 or divisible by the sharding interval") + return errors.New("New shard's start must be 1 or divisible by the table's sharding interval") } rule := dbShard{ ip: ip, port: port, protocol: protocol, user: user, password: password, database: db } @@ -167,6 +167,27 @@ func NewNumberShard(table int, start int, ip string, port int, protocol string, } func defaultNewNumberShard(table int) error { - // make a new table on same database instance - return nil + var prevInterval int + if shardingRules[table].highestInterval == shardingRules[table].interval { + prevInterval = 1 + } else { + prevInterval = shardingRules[table].highestInterval-shardingRules[table].interval + } + + // Get previous interval's info + shardingRules[table].numberMux.Lock() + ip := shardingRules[table].numberShards[prevInterval].ip + port := shardingRules[table].numberShards[prevInterval].port + protocol := shardingRules[table].numberShards[prevInterval].protocol + user := shardingRules[table].numberShards[prevInterval].user + password := shardingRules[table].numberShards[prevInterval].password + db := shardingRules[table].numberShards[prevInterval].database + shardingRules[table].numberMux.Unlock() + + // make a new table on same database instance as the previous interval + + // + err := NewNumberShard(table, shardingRules[table].highestInterval, ip, port, protocol, user, password, db); + + return err } From 04956bdbfdf37802805e032aeac782d89d6709c1 Mon Sep 17 00:00:00 2001 From: Dominique Debergue Date: Fri, 25 Jan 2019 21:34:59 -0800 Subject: [PATCH 043/132] Update README.md --- README.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f0f9e35..3ee5470 100644 --- a/README.md +++ b/README.md @@ -6,18 +6,26 @@ Gopher Game Server is designed to provide all necessary tools to greatly ease de Moreover, Gopher has a built-in, fully customizable SQL client authentication mechanism that creates and manages users' accounts for you. It even ties in a friending tool, so users can befriend and invite one another to groups, check each other's status, and more. All components are easily configurable and customizable for specific project's needs. -### Main features: +### Main features - Super easy and flexible APIs for server, database, and client coding - Chat, private messaging, and voice chat - Customizable client authentication (**\***) - - Built-in Friending (**\***) + - Built-in friending mechanism (**\***) - Supports multiple connections on the same User - Server saves state on shut-down and restores on reboot - Tools provided for administrating server while running (**\***) A MySQL (or similar SQL) database is required for the authentication/friending feature, but is an optional (like most) feature that can be enabled or disabled to use your own implementations. +### Upcoming features + + - Customizable sharding mechanism for accounts, freinds, and auto-login databases (**\***) + - Distributed server deployment tools + - Secure server cluster broadcasts with caching optimizations + +(**\***) Replication limitations: Sharding will be supported for MySQL master-slave replication (or no replication) **only**. Master-master replication support will be considered if the demand is high enough, or a contributor submits a viable solution. + # Client APIs - JavaScript: [GopherClientJS](https://github.com/hewiefreeman/GopherClientJS) From 1e1c6ef3ae6cb49571b4647a870c619954fe6f48 Mon Sep 17 00:00:00 2001 From: Dominique Debergue Date: Fri, 25 Jan 2019 21:35:47 -0800 Subject: [PATCH 044/132] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3ee5470..55c1d6b 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ Moreover, Gopher has a built-in, fully customizable SQL client authentication me - Server saves state on shut-down and restores on reboot - Tools provided for administrating server while running -(**\***) A MySQL (or similar SQL) database is required for the authentication/friending feature, but is an optional (like most) feature that can be enabled or disabled to use your own implementations. +> (**\***) A MySQL (or similar SQL) database is required for the authentication/friending feature, but is an optional (like most) feature that can be enabled or disabled to use your own implementations. ### Upcoming features @@ -24,7 +24,7 @@ Moreover, Gopher has a built-in, fully customizable SQL client authentication me - Distributed server deployment tools - Secure server cluster broadcasts with caching optimizations -(**\***) Replication limitations: Sharding will be supported for MySQL master-slave replication (or no replication) **only**. Master-master replication support will be considered if the demand is high enough, or a contributor submits a viable solution. +> (**\***) Replication limitations: Sharding will be supported for MySQL master-slave replication (or no replication) **only**. Master-master replication support will be considered if the demand is high enough, or a contributor submits a viable solution. # Client APIs From 8d209e46fabd8ba9b8ede86f963e557235ae21d5 Mon Sep 17 00:00:00 2001 From: hewiefreeman Date: Fri, 25 Jan 2019 22:28:23 -0800 Subject: [PATCH 045/132] Adding more useful macros --- macros.go | 55 +++++++++++++++++++++++++++++++++++++++++++++++++- users/users.go | 10 +++++++++ 2 files changed, 64 insertions(+), 1 deletion(-) diff --git a/macros.go b/macros.go index bf6a558..5d9604c 100644 --- a/macros.go +++ b/macros.go @@ -34,13 +34,16 @@ func handleMacro(macro string) bool { macroDeleteRoom(macro) } else if len(macro) >= 9 && macro[0:7] == "newroom" { macroNewRoom(macro) + } else if len(macro) >= 9 && macro[0:7] == "getuser" { + macroGetUser(macro) + } else if len(macro) >= 9 && macro[0:7] == "getroom" { + macroGetRoom(macro) } else if len(macro) >= 6 && macro[0:4] == "kick" { macroKick(macro) } return false } -// KICK A USER func macroKick(macro string) { userName := macro[5:] user, userErr := users.Get(userName) @@ -93,3 +96,53 @@ func macroDeleteRoom(macro string) { } fmt.Println("Deleted room '" + s[1] + "'") } + +func macroGetUser(macro string) { + s := strings.Split(macro, " ") + if len(s) != 2 { + fmt.Println("getuser expects 1 parameter (name string)") + return + } + + user, userErr := users.Get(s[1]) + if userErr != nil { + fmt.Println(userErr) + return + } + + fmt.Println("-- User '"+s[1]+"' --") + fmt.Println("Status:", user.Status()) + fmt.Println("Guest:", user.IsGuest()) + fmt.Println("Connections:") + conns := user.ConnectionIDs() + for i := 0; i < len(conns); i++ { + fmt.Println(" [ ID: '"+conns[i]+"', Room: '"+user.RoomIn(conns[i]).Name()+"', Vars:", user.GetVariables(nil, conns[i]), "]") + } + fmt.Println("Friends:", user.Friends()) + fmt.Println("Database ID:", user.DatabaseID()) +} + +func macroGetRoom(macro string) { + s := strings.Split(macro, " ") + if len(s) != 2 { + fmt.Println("getroom expects 1 parameter (name string)") + return + } + + room, roomErr := rooms.Get(s[1]) + if roomErr != nil { + fmt.Println(roomErr) + return + } + + invList, _ := room.InviteList() + usrMap, _ := room.GetUserMap() + + fmt.Println("-- Room '"+s[1]+"' --") + fmt.Println("Type:", room.Type()) + fmt.Println("Private:", room.IsPrivate()) + fmt.Println("Owner:", room.Owner()) + fmt.Println("Max Users:", room.MaxUsers()) + fmt.Println("Users:", "("+strconv.Itoa(room.NumUsers())+")", usrMap) + fmt.Println("Invite List:", invList) +} diff --git a/users/users.go b/users/users.go index 8183245..7681dda 100644 --- a/users/users.go +++ b/users/users.go @@ -739,6 +739,16 @@ func (u *User) IsGuest() bool { return u.isGuest } +func (u *User) ConnectionIDs() []string { + var ids []string + u.mux.Lock() + for id, _ := range u.conns { + ids = append(ids, id) + } + u.mux.Unlock() + return ids +} + ////////////////////////////////////////////////////////////////////////////////////////////////////// // SERVER STARTUP FUNCTIONS ////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////// From ce903197e0bf769502c5917e7d055aef2d577eee Mon Sep 17 00:00:00 2001 From: hewiefreeman Date: Fri, 25 Jan 2019 23:09:49 -0800 Subject: [PATCH 046/132] Implementing database sharding and shard management mechanisms. --- database/sharding.go | 25 +++++++++++++++++++++---- macros.go | 6 +++++- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/database/sharding.go b/database/sharding.go index 98eafca..3fcfbd8 100644 --- a/database/sharding.go +++ b/database/sharding.go @@ -4,10 +4,11 @@ import ( "errors" "sync" "database/sql" + "strconv" ) var ( - shardingRules []shardingOptions = []shardingOptions{shardingOptions{}, shardingOptions{}, shardingOptions{}} + shardingRules []ShardingRules = []ShardingRules{ShardingRules{}, ShardingRules{}, ShardingRules{}} ) const ( @@ -21,7 +22,7 @@ const ( ShardByNumber ) -type shardingOptions struct { +type ShardingRules struct { column string // The name of the column to use for sharding letterShards map[string]dbShard @@ -79,6 +80,13 @@ func SetShardingColumn (table int, column string, shardType int) error { return nil } +func GetShardingRules(table int) ShardingRules { + if table < 0 || table > len(shardingRules)-1 { + return ShardingRules{} + } + return shardingRules[table] +} + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // SHARDING BY LETTER ////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -181,13 +189,22 @@ func defaultNewNumberShard(table int) error { protocol := shardingRules[table].numberShards[prevInterval].protocol user := shardingRules[table].numberShards[prevInterval].user password := shardingRules[table].numberShards[prevInterval].password - db := shardingRules[table].numberShards[prevInterval].database shardingRules[table].numberMux.Unlock() // make a new table on same database instance as the previous interval + var db string + if table == ShardingTableFriends { + db = tableFriends + } else if table == ShardingTableUsers { + db = tableUsers + } else if table == ShardingTableAutologs { + db = tableAutologs + } + + db = db + strconv.Itoa(shardingRules[table].highestInterval) // - err := NewNumberShard(table, shardingRules[table].highestInterval, ip, port, protocol, user, password, db); + err := NewNumberShard(table, shardingRules[table].highestInterval, ip, port, protocol, user, password, db) return err } diff --git a/macros.go b/macros.go index 5d9604c..14010e0 100644 --- a/macros.go +++ b/macros.go @@ -143,6 +143,10 @@ func macroGetRoom(macro string) { fmt.Println("Private:", room.IsPrivate()) fmt.Println("Owner:", room.Owner()) fmt.Println("Max Users:", room.MaxUsers()) - fmt.Println("Users:", "("+strconv.Itoa(room.NumUsers())+")", usrMap) + var users []string + for name, _ := range usrMap { + users = append(users, name) + } + fmt.Println("Users:", "("+strconv.Itoa(room.NumUsers())+")", users) fmt.Println("Invite List:", invList) } From 80f615dfb99bd31bdc25616373a70884382dc2e0 Mon Sep 17 00:00:00 2001 From: Dominique Debergue Date: Sat, 26 Jan 2019 02:33:08 -0800 Subject: [PATCH 047/132] Set theme jekyll-theme-hacker --- _config.yml | 1 + 1 file changed, 1 insertion(+) create mode 100644 _config.yml diff --git a/_config.yml b/_config.yml new file mode 100644 index 0000000..fc24e7a --- /dev/null +++ b/_config.yml @@ -0,0 +1 @@ +theme: jekyll-theme-hacker \ No newline at end of file From 6b5d956204eb8cb63439750f4748adc0d801ea2c Mon Sep 17 00:00:00 2001 From: hewiefreeman Date: Sat, 26 Jan 2019 02:58:57 -0800 Subject: [PATCH 048/132] Clean-up, gofmt, golint --- database/sharding.go | 62 +++++++++++++++++++++++++------------------- helpers/errors.go | 2 +- macros.go | 6 ++--- users/users.go | 3 ++- 4 files changed, 42 insertions(+), 31 deletions(-) diff --git a/database/sharding.go b/database/sharding.go index 3fcfbd8..18540df 100644 --- a/database/sharding.go +++ b/database/sharding.go @@ -1,29 +1,34 @@ package database import ( - "errors" - "sync" "database/sql" + "errors" "strconv" + "sync" ) var ( shardingRules []ShardingRules = []ShardingRules{ShardingRules{}, ShardingRules{}, ShardingRules{}} ) +// Definitions for the three built-in Gopher Game Server tables. Chose one of these to make your sharding +// rules. const ( - ShardingTableUsers = iota // The Users table is being sharded - ShardingTableFriends // The Friends table is being sharded - ShardingTableAutologs // The Autologs table is being sharded + ShardingTableUsers = iota // The Users table is being sharded + ShardingTableFriends // The Friends table is being sharded + ShardingTableAutologs // The Autologs table is being sharded ) +// Sharding rule types. ShardByLetter shards the table by starting letter(s), and ShardByNumber shards +// the table in increments (best used with auto-incrementing primary keys). const ( ShardByLetter = iota ShardByNumber ) +// ShardingRules holds the necessary sharding rules and data for a table. type ShardingRules struct { - column string // The name of the column to use for sharding + column string letterShards map[string]dbShard @@ -46,7 +51,8 @@ type dbShard struct { database string } -func SetShardingColumn (table int, column string, shardType int) error { +// SetShardingColumn sets the column name and sharding type for a table. +func SetShardingColumn(table int, column string, shardType int) error { if serverPaused || serverStarted { return errors.New("Cannot make new sharding rule type once the server has started") } else if table < 0 || table > len(shardingRules)-1 { @@ -58,7 +64,7 @@ func SetShardingColumn (table int, column string, shardType int) error { } else if shardingRules[table].letterShards != nil && shardType == ShardByNumber { return errors.New("Table is already using letter sharding rules") } else if shardingRules[table].column != "" { - return errors.New("Table already has a sharding rule type for the column '"+shardingRules[table].column+"'") + return errors.New("Table already has a sharding rule type for the column '" + shardingRules[table].column + "'") } else if column == "" { return errors.New("Must supply a column name") } @@ -71,26 +77,29 @@ func SetShardingColumn (table int, column string, shardType int) error { } else if shardType == ShardByNumber { shardingRules[table].numberShards = make(map[int]dbShard) // Set defaults - shardingRules[table].interval = 20000; - shardingRules[table].newShardNumber = 19000; - shardingRules[table].highestInterval = 1; - shardingRules[table].newShardCallback = defaultNewNumberShard; + shardingRules[table].interval = 20000 + shardingRules[table].newShardNumber = 19000 + shardingRules[table].highestInterval = 1 + shardingRules[table].newShardCallback = defaultNewNumberShard } return nil } -func GetShardingRules(table int) ShardingRules { +// GetShardingRules gets the *ShardingRules for a table. +func GetShardingRules(table int) *ShardingRules { if table < 0 || table > len(shardingRules)-1 { return ShardingRules{} } - return shardingRules[table] + return &shardingRules[table] } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // SHARDING BY LETTER ////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// SetShardingLetterDatabase opens a connection to a database that holds all entries where the specified sharding column starts with the +// starting letter(s). func SetShardingLetterDatabase(table int, letter string, ip string, port int, protocol string, user string, password string, db string) error { if serverPaused || serverStarted { return errors.New("Cannot make new sharding rule by letter once the server has started") @@ -102,13 +111,14 @@ func SetShardingLetterDatabase(table int, letter string, ip string, port int, pr return errors.New("Table has no sharding column set") } - rule := dbShard{ ip: ip, port: port, protocol: protocol, user: user, password: password, database: db } + rule := dbShard{ip: ip, port: port, protocol: protocol, user: user, password: password, database: db} - shardingRules[table].letterShards[letter] = rule; + shardingRules[table].letterShards[letter] = rule return nil } +// GetLetterDatabase gets the database that could be holding the entry. func GetLetterDatabase(s string) { // Get a database by the starting letter(s) of a string } @@ -133,17 +143,17 @@ func SetShardingInterval(table int, interval int, newShardNumber int, newShardCa return errors.New("New shard number requires a minimum of 50 and must be less than sharding interval") } - shardingRules[table].interval = interval; - shardingRules[table].highestInterval = 1; - shardingRules[table].newShardNumber = newShardNumber; + shardingRules[table].interval = interval + shardingRules[table].highestInterval = 1 + shardingRules[table].newShardNumber = newShardNumber if newShardCallback != nil { - shardingRules[table].newShardCallback = newShardCallback; + shardingRules[table].newShardCallback = newShardCallback } return nil } -// NewNumberDatabase will open a connection to the database shard for the starting interval +// NewNumberShard opens a connection to the database shard for the starting interval. func NewNumberShard(table int, start int, ip string, port int, protocol string, user string, password string, db string) error { if table < 0 || table > len(shardingRules)-1 { return errors.New("Incorrect table number") @@ -151,11 +161,11 @@ func NewNumberShard(table int, start int, ip string, port int, protocol string, return errors.New("Table is using letter sharding rules") } else if shardingRules[table].column == "" { return errors.New("Table has no sharding column set") - } else if start != 1 && start % shardingRules[table].interval != 0 { + } else if start != 1 && start%shardingRules[table].interval != 0 { return errors.New("New shard's start must be 1 or divisible by the table's sharding interval") } - rule := dbShard{ ip: ip, port: port, protocol: protocol, user: user, password: password, database: db } + rule := dbShard{ip: ip, port: port, protocol: protocol, user: user, password: password, database: db} shardingRules[table].numberMux.Lock() if start != shardingRules[table].highestInterval { @@ -165,8 +175,8 @@ func NewNumberShard(table int, start int, ip string, port int, protocol string, if start == 1 { shardingRules[table].highestInterval = shardingRules[table].interval - }else{ - shardingRules[table].highestInterval = start+shardingRules[table].interval + } else { + shardingRules[table].highestInterval = start + shardingRules[table].interval } shardingRules[table].numberShards[start] = rule shardingRules[table].numberMux.Unlock() @@ -179,7 +189,7 @@ func defaultNewNumberShard(table int) error { if shardingRules[table].highestInterval == shardingRules[table].interval { prevInterval = 1 } else { - prevInterval = shardingRules[table].highestInterval-shardingRules[table].interval + prevInterval = shardingRules[table].highestInterval - shardingRules[table].interval } // Get previous interval's info diff --git a/helpers/errors.go b/helpers/errors.go index 95dd78e..66cf9eb 100644 --- a/helpers/errors.go +++ b/helpers/errors.go @@ -69,7 +69,7 @@ func NewError(message string, id int) GopherError { return GopherError{Message: message, ID: id} } -// NoError creates a new GopherError that represents a state in which no error occured. +// NoError creates a new GopherError that represents a state in which no error occurred. func NoError() GopherError { return GopherError{Message: "", ID: 0} } diff --git a/macros.go b/macros.go index 14010e0..9c478b3 100644 --- a/macros.go +++ b/macros.go @@ -110,7 +110,7 @@ func macroGetUser(macro string) { return } - fmt.Println("-- User '"+s[1]+"' --") + fmt.Println("-- User '" + s[1] + "' --") fmt.Println("Status:", user.Status()) fmt.Println("Guest:", user.IsGuest()) fmt.Println("Connections:") @@ -138,13 +138,13 @@ func macroGetRoom(macro string) { invList, _ := room.InviteList() usrMap, _ := room.GetUserMap() - fmt.Println("-- Room '"+s[1]+"' --") + fmt.Println("-- Room '" + s[1] + "' --") fmt.Println("Type:", room.Type()) fmt.Println("Private:", room.IsPrivate()) fmt.Println("Owner:", room.Owner()) fmt.Println("Max Users:", room.MaxUsers()) var users []string - for name, _ := range usrMap { + for name := range usrMap { users = append(users, name) } fmt.Println("Users:", "("+strconv.Itoa(room.NumUsers())+")", users) diff --git a/users/users.go b/users/users.go index 7681dda..6732cf5 100644 --- a/users/users.go +++ b/users/users.go @@ -739,10 +739,11 @@ func (u *User) IsGuest() bool { return u.isGuest } +// ConnectionIDs returns a []string of all the User's connection IDs func (u *User) ConnectionIDs() []string { var ids []string u.mux.Lock() - for id, _ := range u.conns { + for id := range u.conns { ids = append(ids, id) } u.mux.Unlock() From f7a568a7cf7960046a8079843b15c92db0c43919 Mon Sep 17 00:00:00 2001 From: hewiefreeman Date: Sat, 26 Jan 2019 03:02:39 -0800 Subject: [PATCH 049/132] Continuing implementation for database sharding mechanism --- database/sharding.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/database/sharding.go b/database/sharding.go index 18540df..8153201 100644 --- a/database/sharding.go +++ b/database/sharding.go @@ -89,7 +89,7 @@ func SetShardingColumn(table int, column string, shardType int) error { // GetShardingRules gets the *ShardingRules for a table. func GetShardingRules(table int) *ShardingRules { if table < 0 || table > len(shardingRules)-1 { - return ShardingRules{} + return &ShardingRules{} } return &shardingRules[table] } From 64bdcd7943225cd4ce7c2af5de3471b5bdf3d5c3 Mon Sep 17 00:00:00 2001 From: hewiefreeman Date: Sat, 26 Jan 2019 17:03:45 -0800 Subject: [PATCH 050/132] Making project site --- .github/SITE/site.css | 39 +++++++++++++++++++++++++++++++++++++++ _config.yml | 1 - index.html | 35 +++++++++++++++++++++++++++++++++++ 3 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 .github/SITE/site.css delete mode 100644 _config.yml create mode 100644 index.html diff --git a/.github/SITE/site.css b/.github/SITE/site.css new file mode 100644 index 0000000..d93ce32 --- /dev/null +++ b/.github/SITE/site.css @@ -0,0 +1,39 @@ +body { + font-family: 'Open Sans', sans-serif; + font-weight: 600; + font-size: 16px; + color: #ffffff; + + background: #1c1c1c; +} + +.flexWrap { + display: flex; + flex-direction: column; + justify-content: flex-start; + align-items: stretch; + align-content: flex-start; + + top: 0; + left: 0; + + width: 100%; + height: 100%; +} + +.topBar { + display: flex; + flex-direction: column; + + height: 0px; + min-height: 0px; + + background: orange; + z-index: 2; +} + +.content { + display: block; + + background: #1c1c1c; +} diff --git a/_config.yml b/_config.yml deleted file mode 100644 index fc24e7a..0000000 --- a/_config.yml +++ /dev/null @@ -1 +0,0 @@ -theme: jekyll-theme-hacker \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 0000000..38410e9 --- /dev/null +++ b/index.html @@ -0,0 +1,35 @@ + + + Gopher Game Server + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+ + From 80e4ab1ef838e8f609f623c949c68bfe7c8aae7a Mon Sep 17 00:00:00 2001 From: hewiefreeman Date: Sat, 26 Jan 2019 17:10:56 -0800 Subject: [PATCH 051/132] Making project site --- index.html => docs/index.html | 0 {.github/SITE => docs}/site.css | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename index.html => docs/index.html (100%) rename {.github/SITE => docs}/site.css (100%) diff --git a/index.html b/docs/index.html similarity index 100% rename from index.html rename to docs/index.html diff --git a/.github/SITE/site.css b/docs/site.css similarity index 100% rename from .github/SITE/site.css rename to docs/site.css From 9c6e18326288665d50c3a99c27fc1d1e660e47db Mon Sep 17 00:00:00 2001 From: hewiefreeman Date: Mon, 28 Jan 2019 17:59:06 -0800 Subject: [PATCH 052/132] Continuing sharding implementation and fixing macro commands for Ubuntu. --- database/sharding.go | 4 ++-- macros.go | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/database/sharding.go b/database/sharding.go index 8153201..1878d37 100644 --- a/database/sharding.go +++ b/database/sharding.go @@ -98,9 +98,9 @@ func GetShardingRules(table int) *ShardingRules { // SHARDING BY LETTER ////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// SetShardingLetterDatabase opens a connection to a database that holds all entries where the specified sharding column starts with the +// NewLetterShard opens a connection to a database that holds all entries where the specified sharding column starts with the // starting letter(s). -func SetShardingLetterDatabase(table int, letter string, ip string, port int, protocol string, user string, password string, db string) error { +func NewLetterShard(table int, letter string, ip string, port int, protocol string, user string, password string, db string) error { if serverPaused || serverStarted { return errors.New("Cannot make new sharding rule by letter once the server has started") } else if table < 0 || table > len(shardingRules)-1 { diff --git a/macros.go b/macros.go index 9c478b3..b1562a6 100644 --- a/macros.go +++ b/macros.go @@ -23,6 +23,7 @@ func macroListener() { } func handleMacro(macro string) bool { + fmt.Println(macro); if macro == "pause" { Pause() } else if macro == "resume" { From 54025e1863be9358956e144a53c1581306f7271d Mon Sep 17 00:00:00 2001 From: hewiefreeman Date: Mon, 28 Jan 2019 18:04:30 -0800 Subject: [PATCH 053/132] Continuing sharding implementation and fixing macro commands for Ubuntu. --- macros.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/macros.go b/macros.go index b1562a6..cf99415 100644 --- a/macros.go +++ b/macros.go @@ -15,7 +15,10 @@ func macroListener() { reader := bufio.NewReader(os.Stdin) fmt.Print("[Gopher] Command: ") text, _ := reader.ReadString('\n') - stop := handleMacro(text[0 : len(text)-2]) + var stop bool + if(len(text) >= 2){ + stop = handleMacro(text[0 : len(text)-2]) + } if stop { return } From 13c733d7b38309f978782d13788055527f2b4e4d Mon Sep 17 00:00:00 2001 From: hewiefreeman Date: Mon, 28 Jan 2019 19:48:57 -0800 Subject: [PATCH 054/132] Fixing macro compatability with linux/ubuntu --- macros.go | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/macros.go b/macros.go index cf99415..d8c4d6d 100644 --- a/macros.go +++ b/macros.go @@ -15,10 +15,8 @@ func macroListener() { reader := bufio.NewReader(os.Stdin) fmt.Print("[Gopher] Command: ") text, _ := reader.ReadString('\n') - var stop bool - if(len(text) >= 2){ - stop = handleMacro(text[0 : len(text)-2]) - } + final := strings.TrimSpace(text) + stop := handleMacro(final) if stop { return } @@ -26,7 +24,7 @@ func macroListener() { } func handleMacro(macro string) bool { - fmt.Println(macro); + fmt.Println("'"+macro+"'"); if macro == "pause" { Pause() } else if macro == "resume" { From aefbf739f3eeb0707524b6511c3ecc4ea56dad96 Mon Sep 17 00:00:00 2001 From: hewiefreeman Date: Tue, 29 Jan 2019 00:10:19 -0800 Subject: [PATCH 055/132] Fixed macro compatibility with different operating systems and added a couple more useful commands. --- macros.go | 5 ++++- rooms/rooms.go | 8 ++++++++ users/users.go | 8 ++++++++ 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/macros.go b/macros.go index d8c4d6d..5a981ca 100644 --- a/macros.go +++ b/macros.go @@ -24,7 +24,6 @@ func macroListener() { } func handleMacro(macro string) bool { - fmt.Println("'"+macro+"'"); if macro == "pause" { Pause() } else if macro == "resume" { @@ -32,6 +31,10 @@ func handleMacro(macro string) bool { } else if macro == "shutdown" { ShutDown() return true + } else if macro == "roomcount" { + fmt.Println("Room count: ", rooms.RoomCount()) + } else if macro == "usercount" { + fmt.Println("User count: ", users.UserCount()) } else if len(macro) >= 12 && macro[0:10] == "deleteroom" { macroDeleteRoom(macro) } else if len(macro) >= 9 && macro[0:7] == "newroom" { diff --git a/rooms/rooms.go b/rooms/rooms.go index eec2553..e7e63c9 100644 --- a/rooms/rooms.go +++ b/rooms/rooms.go @@ -513,6 +513,14 @@ func (r *Room) GetUserMap() (map[string]*RoomUser, error) { // Room ATTRIBUTE READERS ///////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// RoomCount returns the number of Rooms created on the server. +func RoomCount() int { + roomsMux.Lock() + length := len(rooms) + roomsMux.Unlock() + return length +} + // Name gets the name of the Room. func (r *Room) Name() string { return r.name diff --git a/users/users.go b/users/users.go index 6732cf5..179602f 100644 --- a/users/users.go +++ b/users/users.go @@ -672,6 +672,14 @@ func (u *User) RevokeInvite(revokeUser string, connID string) error { // User ATTRIBUTE READERS //////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////// +// UserCount returns the number of Users logged into the server. +func UserCount() int { + usersMux.Lock() + length := len(users) + usersMux.Unlock() + return length +} + // Name gets the name of the User. func (u *User) Name() string { return u.name From 819c9f17fa4eb8cabf253725b8b8c7955d0cd513 Mon Sep 17 00:00:00 2001 From: Dominique Debergue Date: Thu, 31 Jan 2019 21:32:51 -0800 Subject: [PATCH 056/132] Update README.md --- README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index 55c1d6b..7dfc4bf 100644 --- a/README.md +++ b/README.md @@ -20,12 +20,10 @@ Moreover, Gopher has a built-in, fully customizable SQL client authentication me ### Upcoming features - - Customizable sharding mechanism for accounts, freinds, and auto-login databases (**\***) + - Customizable sharding mechanism for accounts, freinds, and auto-login databases - Distributed server deployment tools - Secure server cluster broadcasts with caching optimizations -> (**\***) Replication limitations: Sharding will be supported for MySQL master-slave replication (or no replication) **only**. Master-master replication support will be considered if the demand is high enough, or a contributor submits a viable solution. - # Client APIs - JavaScript: [GopherClientJS](https://github.com/hewiefreeman/GopherClientJS) From c2b87018bb322e770eaa20c64fdf531b7d9f7a2e Mon Sep 17 00:00:00 2001 From: hewiefreeman Date: Fri, 1 Feb 2019 01:23:02 -0800 Subject: [PATCH 057/132] Changing implementation for sharding mechanism, slice append() optimizations, bug fixes, and general clean-up --- database/authentication.go | 39 +++- database/database.go | 40 ++-- database/sharding.go | 367 +++++++++++++++++++++---------------- macros.go | 2 +- server.go | 5 +- users/users.go | 6 +- 6 files changed, 267 insertions(+), 192 deletions(-) diff --git a/database/authentication.go b/database/authentication.go index 6f6619f..775cd6b 100644 --- a/database/authentication.go +++ b/database/authentication.go @@ -181,11 +181,12 @@ func SignUpClient(userName string, password string, customCols map[string]interf return helpers.NewError(hashErr.Error(), helpers.ErrorAuthEncryption) } - var vals []interface{} = []interface{}{} + var vals []interface{} //CREATE PART 1 OF QUERY queryPart1 := "INSERT INTO " + tableUsers + " (" + usersColumnName + ", " + usersColumnPassword + ", " if customCols != nil { + vals = make([]interface{}, 0, len(customCols)) if customLoginColumn != "" { if _, ok := customCols[customLoginColumn]; !ok { return helpers.NewError(errorInsufficientCols, helpers.ErrorAuthInsufficientCols) @@ -257,17 +258,22 @@ func LoginClient(userName string, password string, deviceTag string, remMe bool, } //FIRST THREE ARE id, password, name IN THAT ORDER - var vals []interface{} = []interface{}{new(int), new([]byte), new(string)} - + var vals []interface{} //CONSTRUCT SELECT QUERY selectQuery := "Select " + usersColumnID + ", " + usersColumnPassword + ", " + usersColumnName + ", " if customCols != nil { + vals = make([]interface{}, 0, len(customCols)+3) + vals = append(vals, new(int), new([]byte), new(string)) for key := range customCols { selectQuery = selectQuery + key + ", " //MAINTAIN THE ORDER IN WHICH THE COLUMNS WERE DECLARED VIA A SLICE vals = append(vals, new(interface{})) } + } else { + vals = make([]interface{}, 0, 3) + vals = append(vals, new(int), new([]byte), new(string)) } + if len(customLoginColumn) > 0 { selectQuery = selectQuery[0:len(selectQuery)-2] + " FROM " + tableUsers + " WHERE " + customLoginColumn + "=\"" + userName + "\" LIMIT 1;" } else { @@ -433,18 +439,24 @@ func ChangePassword(userName string, password string, newPassword string, custom } //FIRST TWO ARE id, password IN THAT ORDER - var vals []interface{} = []interface{}{new(int), new([]byte)} - var valsList []interface{} = []interface{}{} + var vals []interface{} + var valsList []interface{} //CONSTRUCT SELECT QUERY selectQuery := "Select " + usersColumnID + ", " + usersColumnPassword + ", " if customCols != nil { + vals = make([]interface{}, 0, len(customCols)+2) + vals = append(vals, new(int), new([]byte)) + valsList = make([]interface{}, 0, len(customCols)) for key, val := range customCols { selectQuery = selectQuery + key + ", " //MAINTAIN THE ORDER IN WHICH THE COLUMNS WERE DECLARED VIA A SLICE vals = append(vals, new(interface{})) valsList = append(valsList, []interface{}{val, customAccountInfo[key].dataType, key}) } + }else{ + vals = make([]interface{}, 0, 2) + vals = append(vals, new(int), new([]byte)) } selectQuery = selectQuery[0:len(selectQuery)-2] + " FROM " + tableUsers + " WHERE " + usersColumnName + "=\"" + userName + "\" LIMIT 1;" @@ -526,18 +538,24 @@ func ChangeAccountInfo(userName string, password string, customCols map[string]i } //FIRST TWO ARE id, password IN THAT ORDER - var vals []interface{} = []interface{}{new(int), new([]byte)} - var valsList []interface{} = []interface{}{} + var vals []interface{} + var valsList []interface{} //CONSTRUCT SELECT QUERY selectQuery := "Select " + usersColumnID + ", " + usersColumnPassword + ", " if customCols != nil { + vals = make([]interface{}, 0, len(customCols)+2) + vals = append(vals, new(int), new([]byte)) + valsList = make([]interface{}, 0, len(customCols)) for key, val := range customCols { selectQuery = selectQuery + key + ", " //MAINTAIN THE ORDER IN WHICH THE COLUMNS WERE DECLARED VIA A SLICE vals = append(vals, new(interface{})) valsList = append(valsList, []interface{}{val, customAccountInfo[key].dataType, key}) } + }else{ + vals = make([]interface{}, 0, 2) + vals = append(vals, new(int), new([]byte)) } selectQuery = selectQuery[0:len(selectQuery)-2] + " FROM " + tableUsers + " WHERE " + usersColumnName + "=\"" + userName + "\" LIMIT 1;" @@ -625,16 +643,21 @@ func DeleteAccount(userName string, password string, customCols map[string]inter } //FIRST TWO ARE id, password IN THAT ORDER - var vals []interface{} = []interface{}{new(int), new([]byte)} + var vals []interface{} //CONSTRUCT SELECT QUERY selectQuery := "Select " + usersColumnID + ", " + usersColumnPassword + ", " if customCols != nil { + vals = make([]interface{}, 0, len(customCols)+2) + vals = append(vals, new(int), new([]byte)) for key := range customCols { selectQuery = selectQuery + key + ", " //MAINTAIN THE ORDER IN WHICH THE COLUMNS WERE DECLARED VIA A SLICE vals = append(vals, new(interface{})) } + }else{ + vals = make([]interface{}, 0, 2) + vals = append(vals, new(int), new([]byte)) } selectQuery = selectQuery[0:len(selectQuery)-2] + " FROM " + tableUsers + " WHERE " + usersColumnName + "=\"" + userName + "\" LIMIT 1;" diff --git a/database/database.go b/database/database.go index 2b4fc18..7142ecc 100644 --- a/database/database.go +++ b/database/database.go @@ -20,7 +20,7 @@ var ( serverStarted bool = false serverPaused bool = false rememberMe bool = false - databaseName string + databaseName string = "gopherDB" inited bool = false ) @@ -77,24 +77,29 @@ func Init(userName string, password string, dbName string, protocol string, ip s var err error //OPEN THE DATABASE - var openErr error - database, openErr = sql.Open("mysql", userName+":"+password+"@"+protocol+"("+ip+":"+strconv.Itoa(port)+")/"+dbName) - if err != nil { - return openErr - } - //NOTE: Open doesn't open a connection. - //MUST PING TO CHECK IF FOUND DATABASE - pingErr := database.Ping() - if pingErr != nil { - return errors.New("Could not connect to database!") - } + if !shardingInit { + database, err = sql.Open("mysql", userName+":"+password+"@"+protocol+"("+ip+":"+strconv.Itoa(port)+")/"+dbName) + if err != nil { + return err + } + //NOTE: Open doesn't open a connection. + //MUST PING TO CHECK IF FOUND DATABASE + err = database.Ping() + if err != nil { + return errors.New("Could not connect to database!") + } - databaseName = dbName + if len(dbName) != 0 { + databaseName = dbName + } + } else { + setShardingDefaults(ip, port, protocol, userName, password) + } //CONFIGURE DATABASE - setupErr := setUp() - if setupErr != nil { - return setupErr + err = setUp() + if err != nil { + return err } // @@ -135,9 +140,10 @@ func GetUserDatabaseIndex(userName string) (int, error) { /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // SetServerStarted is for Gopher Game Server internal mechanics only. -func SetServerStarted(val bool) { +func SetServerStarted(val bool, sharding bool) { if !serverStarted { serverStarted = val + shardingInit = sharding } } diff --git a/database/sharding.go b/database/sharding.go index 1878d37..1316e3c 100644 --- a/database/sharding.go +++ b/database/sharding.go @@ -2,45 +2,33 @@ package database import ( "database/sql" - "errors" + //"errors" "strconv" "sync" ) var ( - shardingRules []ShardingRules = []ShardingRules{ShardingRules{}, ShardingRules{}, ShardingRules{}} -) + shardingInit bool -// Definitions for the three built-in Gopher Game Server tables. Chose one of these to make your sharding -// rules. -const ( - ShardingTableUsers = iota // The Users table is being sharded - ShardingTableFriends // The Friends table is being sharded - ShardingTableAutologs // The Autologs table is being sharded -) + usersPrefix string = "users_" + usersShards map[string]*DBShard -// Sharding rule types. ShardByLetter shards the table by starting letter(s), and ShardByNumber shards -// the table in increments (best used with auto-incrementing primary keys). -const ( - ShardByLetter = iota - ShardByNumber -) + friendsPrefix string = "friends_" + friendsShards map[string]*DBShard -// ShardingRules holds the necessary sharding rules and data for a table. -type ShardingRules struct { - column string + autologPrefix string = "autologs_" + autologShards map[string]*DBShard +) - letterShards map[string]dbShard +type DBShard struct { + master *DBReplica - interval int - numberMux sync.Mutex - numberShards map[int]dbShard - highestInterval int - newShardNumber int - newShardCallback func(int) error + mux sync.Mutex + replicaOn int + replicas []*DBReplica } -type dbShard struct { +type DBReplica struct { conn *sql.DB ip string @@ -48,173 +36,228 @@ type dbShard struct { protocol string user string password string - database string -} - -// SetShardingColumn sets the column name and sharding type for a table. -func SetShardingColumn(table int, column string, shardType int) error { - if serverPaused || serverStarted { - return errors.New("Cannot make new sharding rule type once the server has started") - } else if table < 0 || table > len(shardingRules)-1 { - return errors.New("Incorrect table number") - } else if shardType != ShardByLetter && shardType != ShardByNumber { - return errors.New("Incorrect sharding type") - } else if shardingRules[table].numberShards != nil && shardType == ShardByLetter { - return errors.New("Table is already using numeric sharding rules") - } else if shardingRules[table].letterShards != nil && shardType == ShardByNumber { - return errors.New("Table is already using letter sharding rules") - } else if shardingRules[table].column != "" { - return errors.New("Table already has a sharding rule type for the column '" + shardingRules[table].column + "'") - } else if column == "" { - return errors.New("Must supply a column name") + + mux sync.Mutex + healthy bool +} + +///////////////////////////////////////////////////////////////////////////////////////// +////// INIT ///////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////// + +func setShardingDefaults(ip string, port int, protocol string, userName string, password string) error { + if usersShards == nil { + shard, shardErr := NewDBShard(ip, port, protocol, userName, password, false) + if shardErr != nil { + return shardErr + } + usersShards = make(map[string]*DBShard) + // + usersShards["a-h"] = shard + usersShards["i-q"] = shard + usersShards["r-z"] = shard + } else { + fillShardGaps(&usersShards) } - // Set the rule type - shardingRules[table].column = column - - if shardType == ShardByLetter { - shardingRules[table].letterShards = make(map[string]dbShard) - } else if shardType == ShardByNumber { - shardingRules[table].numberShards = make(map[int]dbShard) - // Set defaults - shardingRules[table].interval = 20000 - shardingRules[table].newShardNumber = 19000 - shardingRules[table].highestInterval = 1 - shardingRules[table].newShardCallback = defaultNewNumberShard + if friendsShards == nil { + friendsShards = usersShards + } else { + fillShardGaps(&friendsShards) } + if autologShards == nil { + autologShards = usersShards + } else { + fillShardGaps(&autologShards) + } + + // return nil } -// GetShardingRules gets the *ShardingRules for a table. -func GetShardingRules(table int) *ShardingRules { - if table < 0 || table > len(shardingRules)-1 { - return &ShardingRules{} - } - return &shardingRules[table] -} - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// SHARDING BY LETTER ////////////////////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -// NewLetterShard opens a connection to a database that holds all entries where the specified sharding column starts with the -// starting letter(s). -func NewLetterShard(table int, letter string, ip string, port int, protocol string, user string, password string, db string) error { - if serverPaused || serverStarted { - return errors.New("Cannot make new sharding rule by letter once the server has started") - } else if table < 0 || table > len(shardingRules)-1 { - return errors.New("Incorrect table number") - } else if shardingRules[table].numberShards != nil { - return errors.New("Table is using numeric sharding rules") - } else if shardingRules[table].column == "" { - return errors.New("Table has no sharding column set") - } +func fillShardGaps(shardMap *map[string]*DBShard) { - rule := dbShard{ip: ip, port: port, protocol: protocol, user: user, password: password, database: db} +} + +///////////////////////////////////////////////////////////////////////////////////////// +////// ADDING SHARDS //////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////// - shardingRules[table].letterShards[letter] = rule +func SetUserShard(letters string, shard *DBShard) error { + if !letterFormatCheck(letters) { + } else if letterConflict(letters, usersShards) { + + } + + // return nil } -// GetLetterDatabase gets the database that could be holding the entry. -func GetLetterDatabase(s string) { - // Get a database by the starting letter(s) of a string -} - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// SHARDING BY NUMBER ////////////////////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -// SetShardingInterval sets the interval at which a numerically sharded database will shard by. -func SetShardingInterval(table int, interval int, newShardNumber int, newShardCallback func(int) error) error { - if serverPaused || serverStarted { - return errors.New("Cannot set sharding interval once the server has started") - } else if table < 0 || table > len(shardingRules)-1 { - return errors.New("Incorrect table number") - } else if shardingRules[table].letterShards != nil { - return errors.New("Table is using letter sharding rules") - } else if shardingRules[table].column == "" { - return errors.New("Table has no sharding column set") - } else if interval <= 100 { - return errors.New("Sharding interval requires a minimum of 100") - } else if newShardNumber >= interval || newShardNumber < 50 { - return errors.New("New shard number requires a minimum of 50 and must be less than sharding interval") - } +func SetFriendShard(letters string, shard *DBShard) error { + if !letterFormatCheck(letters) { + + } else if letterConflict(letters, friendsShards) { - shardingRules[table].interval = interval - shardingRules[table].highestInterval = 1 - shardingRules[table].newShardNumber = newShardNumber - if newShardCallback != nil { - shardingRules[table].newShardCallback = newShardCallback } + // return nil } -// NewNumberShard opens a connection to the database shard for the starting interval. -func NewNumberShard(table int, start int, ip string, port int, protocol string, user string, password string, db string) error { - if table < 0 || table > len(shardingRules)-1 { - return errors.New("Incorrect table number") - } else if shardingRules[table].letterShards != nil { - return errors.New("Table is using letter sharding rules") - } else if shardingRules[table].column == "" { - return errors.New("Table has no sharding column set") - } else if start != 1 && start%shardingRules[table].interval != 0 { - return errors.New("New shard's start must be 1 or divisible by the table's sharding interval") +func SetAutologShard(letters string, shard *DBShard) error { + if !letterFormatCheck(letters) { + + } else if letterConflict(letters, autologShards) { + } - rule := dbShard{ip: ip, port: port, protocol: protocol, user: user, password: password, database: db} + // + return nil +} + +func letterFormatCheck(letters string) bool { + + // Pass + return true +} + +func letterConflict(letters string, m map[string]*DBShard) bool { - shardingRules[table].numberMux.Lock() - if start != shardingRules[table].highestInterval { - shardingRules[table].numberMux.Unlock() - return errors.New("New shard's start must be equal to the table's highest interval") + // Pass + return true +} + +///////////////////////////////////////////////////////////////////////////////////////// +////// DBShard ////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////// + +func NewDBShard(ip string, port int, protocol string, userName string, password string, master bool) (*DBShard, error) { + replica, replicaErr := NewDBReplica(ip, port, protocol, userName, password) + if replicaErr != nil { + return nil, replicaErr + } + if master { + shard := DBShard{master: replica} + return &shard, nil } + replicaList := []*DBReplica{replica} + shard := DBShard{replicas: replicaList} + return &shard, nil +} - if start == 1 { - shardingRules[table].highestInterval = shardingRules[table].interval - } else { - shardingRules[table].highestInterval = start + shardingRules[table].interval +func (s *DBShard) SetMasterDB(r *DBReplica) { + if inited { + return } - shardingRules[table].numberShards[start] = rule - shardingRules[table].numberMux.Unlock() + s.master = r +} - return nil +func (s *DBShard) AddReplica(r *DBReplica) { + s.mux.Lock() + s.replicas = append(s.replicas, r) + s.mux.Unlock() } -func defaultNewNumberShard(table int) error { - var prevInterval int - if shardingRules[table].highestInterval == shardingRules[table].interval { - prevInterval = 1 - } else { - prevInterval = shardingRules[table].highestInterval - shardingRules[table].interval +func (s *DBShard) Master() *DBReplica { + return s.master +} + +func (s *DBShard) GetReplica() *DBReplica { + s.mux.Lock() + for i := 0; i < len(s.replicas); i++ { + s.replicaOn++ + if s.replicaOn > len(s.replicas)-1 { + s.replicaOn = 0 + } + if s.replicas[s.replicaOn].Healthy() { + r := s.replicas[s.replicaOn] + s.mux.Unlock() + return r + } } + s.mux.Unlock() + return nil +} + +///////////////////////////////////////////////////////////////////////////////////////// +////// DBReplica //////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////// - // Get previous interval's info - shardingRules[table].numberMux.Lock() - ip := shardingRules[table].numberShards[prevInterval].ip - port := shardingRules[table].numberShards[prevInterval].port - protocol := shardingRules[table].numberShards[prevInterval].protocol - user := shardingRules[table].numberShards[prevInterval].user - password := shardingRules[table].numberShards[prevInterval].password - shardingRules[table].numberMux.Unlock() - - // make a new table on same database instance as the previous interval - var db string - if table == ShardingTableFriends { - db = tableFriends - } else if table == ShardingTableUsers { - db = tableUsers - } else if table == ShardingTableAutologs { - db = tableAutologs +func NewDBReplica(ip string, port int, protocol string, userName string, password string) (*DBReplica, error) { + db, err := sql.Open("mysql", userName+":"+password+"@"+protocol+"("+ip+":"+strconv.Itoa(port)+")/"+databaseName) + if err != nil { + return nil, err + } + err = db.Ping() + if err != nil { + return nil, err } - db = db + strconv.Itoa(shardingRules[table].highestInterval) + r := DBReplica{conn: db, ip: ip, port: port, protocol: protocol, user:userName, password: password, healthy: true} - // - err := NewNumberShard(table, shardingRules[table].highestInterval, ip, port, protocol, user, password, db) + return &r, nil +} + +func (r *DBReplica) Conn() *sql.DB { + return r.conn +} + +func (r *DBReplica) IP() string { + return r.ip +} + +func (r *DBReplica) Port() int { + return r.port +} - return err +func (r *DBReplica) Protocol() string { + return r.protocol +} + +func (r *DBReplica) UserName() string { + return r.user +} + +func (r *DBReplica) Password() string { + return r.password +} + +func (r *DBReplica) Healthy() bool { + r.mux.Lock() + h := r.healthy + r.mux.Unlock() + return h +} + +func (r *DBReplica) SetHealthy(h bool) { + r.mux.Lock() + r.healthy = h + r.mux.Unlock() +} + +///////////////////////////////////////////////////////////////////////////////////////// +////// TABE PREFIX SETTERS ////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////// + +func SetUsersTablePrefix(prefix string) { + if inited { + return + } + usersPrefix = prefix +} + +func SetFriendsTablePrefix(prefix string) { + if inited { + return + } + friendsPrefix = prefix +} + +func SetAutologTablePrefix(prefix string) { + if inited { + return + } + autologPrefix = prefix } diff --git a/macros.go b/macros.go index 5a981ca..533a61b 100644 --- a/macros.go +++ b/macros.go @@ -148,7 +148,7 @@ func macroGetRoom(macro string) { fmt.Println("Private:", room.IsPrivate()) fmt.Println("Owner:", room.Owner()) fmt.Println("Max Users:", room.MaxUsers()) - var users []string + users := make([]string, 0, len(usrMap)) for name := range usrMap { users = append(users, name) } diff --git a/server.go b/server.go index be0b462..9ec2914 100644 --- a/server.go +++ b/server.go @@ -58,7 +58,7 @@ type ServerSettings struct { EncryptionCost int // The amount of encryption iterations the server will run when storing and checking passwords. The higher the number, the longer encryptions take, but are more secure. Default is 4, range is 4-31. CustomLoginColumn string // The custom AccountInfoColumn you wish to use for logging in instead of the default name column. RememberMe bool // Enables the "Remember Me" login feature. You can read more about this in project's wiki. - //ShardingRules database.ShardingRules + Sharding bool // Enables the built-in database sharding mechanism. EnableRecovery bool // Enables the recovery of all Rooms, their settings, and their variables on start-up after terminating the server. RecoveryLocation string // The folder location (starting from system's root folder) where you would like to store the recovery data. (Required for recovery) @@ -185,6 +185,7 @@ func Start(s *ServerSettings) { EncryptionCost: 4, CustomLoginColumn: "", RememberMe: false, + Sharding: false, EnableRecovery: false, RecoveryLocation: "C:/", @@ -203,7 +204,7 @@ func Start(s *ServerSettings) { users.SetServerStarted(true) rooms.SetServerStarted(true) actions.SetServerStarted(true) - database.SetServerStarted(true) + database.SetServerStarted(true, (*settings).Sharding) //START UP DATABASE if (*settings).EnableSqlFeatures { diff --git a/users/users.go b/users/users.go index 179602f..549333c 100644 --- a/users/users.go +++ b/users/users.go @@ -185,7 +185,7 @@ func Login(userName string, dbID int, autologPass string, isGuest bool, remMe bo vars := make(map[string]interface{}) conn := userConn{socket: socket, room: nil, vars: vars, user: connUser, clientMux: clientMux} //FRIENDS OBJECTS - var friends []map[string]interface{} = []map[string]interface{}{} + var friends []map[string]interface{} var friendsMap map[string]*database.Friend //ADD THE userConn TO THE User OR MAKE THE User if userExists { @@ -193,6 +193,7 @@ func Login(userName string, dbID int, autologPass string, isGuest bool, remMe bo (*users[userName]).conns[connID] = &conn friendsMap = (*users[userName]).friends (*users[userName]).mux.Unlock() + friends = make([]map[string]interface{}, 0, len(friendsMap)) //MAKE FRINDS LIST FOR SERVER RESPONSE for _, val := range friendsMap { friendEntry := make(map[string]interface{}) @@ -215,6 +216,7 @@ func Login(userName string, dbID int, autologPass string, isGuest bool, remMe bo friendsMap, friendsErr = database.GetFriends(dbID) // map[string]Friend if friendsErr == nil { //MAKE FRINDS LIST FOR SERVER RESPONSE + friends = make([]map[string]interface{}, 0, len(friendsMap)) for _, val := range friendsMap { friendEntry := make(map[string]interface{}) friendEntry["n"] = val.Name() @@ -749,8 +751,8 @@ func (u *User) IsGuest() bool { // ConnectionIDs returns a []string of all the User's connection IDs func (u *User) ConnectionIDs() []string { - var ids []string u.mux.Lock() + ids := make([]string, 0, len(u.conns)) for id := range u.conns { ids = append(ids, id) } From 40ebf8d621ca098ee8c5a17f8531272f130257c2 Mon Sep 17 00:00:00 2001 From: hewiefreeman Date: Mon, 4 Feb 2019 19:50:20 -0800 Subject: [PATCH 058/132] Reworking sharding system to use consistent hashing for database shard lookups --- database/sharding.go | 173 +++++++++++++++++++++++++++-------------- helpers/crypto.go | 7 ++ helpers/crypto_test.go | 27 +++++++ 3 files changed, 148 insertions(+), 59 deletions(-) create mode 100644 helpers/crypto_test.go diff --git a/database/sharding.go b/database/sharding.go index 1316e3c..1034ec3 100644 --- a/database/sharding.go +++ b/database/sharding.go @@ -1,23 +1,32 @@ package database import ( + "github.com/hewiefreeman/GopherGameServer/helpers" "database/sql" - //"errors" + "errors" "strconv" "sync" ) var ( shardingInit bool + partitionSplit int = 500 // Each database shard will split into tables of this size for easy further sharding later on + shardTargetLoad int = 30000 // The maximum load a database shard should take in your system. This does not control the connection, merely triggers a warning for admins + // Table name prefixes usersPrefix string = "users_" - usersShards map[string]*DBShard - friendsPrefix string = "friends_" - friendsShards map[string]*DBShard - autologPrefix string = "autologs_" - autologShards map[string]*DBShard + + // Database shards + userShardsMux sync.Mutex + userShards map[int]*DBShard = make(map[int]*DBShard) // default trusted database shards + + friendsShardsMux sync.Mutex + friendsShards map[int]*DBShard = make(map[int]*DBShard) // dedicated friends database shards + + autologShardsMux sync.Mutex + autologShards map[int]*DBShard = make(map[int]*DBShard) // dedicated autolog database shards ) type DBShard struct { @@ -46,87 +55,128 @@ type DBReplica struct { ///////////////////////////////////////////////////////////////////////////////////////// func setShardingDefaults(ip string, port int, protocol string, userName string, password string) error { - if usersShards == nil { - shard, shardErr := NewDBShard(ip, port, protocol, userName, password, false) - if shardErr != nil { + // Set default shard if no shards are set + if len(userShards) == 0 { + // Make connection to default shard + defShard, shardErr := NewDBShard(ip, port, protocol, userName, password, false) + if shardErr { return shardErr } - usersShards = make(map[string]*DBShard) - // - usersShards["a-h"] = shard - usersShards["i-q"] = shard - usersShards["r-z"] = shard - } else { - fillShardGaps(&usersShards) - } - - if friendsShards == nil { - friendsShards = usersShards - } else { - fillShardGaps(&friendsShards) - } - - if autologShards == nil { - autologShards = usersShards - } else { - fillShardGaps(&autologShards) + // Append default shard to user shards + userShardsMux.Lock() + appendShards(&userShards, defShard) + userShardsMux.Unlock() } // return nil } -func fillShardGaps(shardMap *map[string]*DBShard) { - -} - ///////////////////////////////////////////////////////////////////////////////////////// -////// ADDING SHARDS //////////////////////////////////////////////////////////////// +////// SET-UP /////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////// -func SetUserShard(letters string, shard *DBShard) error { - if !letterFormatCheck(letters) { +func AddUserShards(shards *DBShard...) { + // REQUIRES GLOBAL PAUSE (Which only master server can do) - } else if letterConflict(letters, usersShards) { + userShardsMux.Lock() + //prevLength := len(userShards) + appendShards(&userShards, shards) + userShardsMux.Unlock() - } - - // - return nil + // IF THIS IS MASTER, RESORT THE DATABASES + // THEN SEND COMMAND TO REST OF GAME SERVERS } -func SetFriendShard(letters string, shard *DBShard) error { - if !letterFormatCheck(letters) { - - } else if letterConflict(letters, friendsShards) { +func AddFriendsShards(shards *DBShard...) { + // REQUIRES GLOBAL PAUSE (Which only master server can do) - } + friendsShardsMux.Lock() + //prevLength := len(userShards) + appendShards(&friendsShards, shards) + friendsShardsMux.Unlock() - // - return nil + // IF THIS IS MASTER, RESORT THE DATABASES + // THEN SEND COMMAND TO REST OF GAME SERVERS } -func SetAutologShard(letters string, shard *DBShard) error { - if !letterFormatCheck(letters) { +func AddAutologShards(shards *DBShard...) { + // REQUIRES GLOBAL PAUSE (Which only master server can do) - } else if letterConflict(letters, autologShards) { + autologShardsMux.Lock() + //prevLength := len(userShards) + appendShards(&autologShards, shards) + autologShardsMux.Unlock() - } + // IF THIS IS MASTER, RESORT THE DATABASES + // THEN SEND COMMAND TO REST OF GAME SERVERS +} - // - return nil +func appendShards(dest *map[int]*DBShard, shards *DBShard...) { + for s := range shards { + (*dest)[len(*dest)] = s + } } -func letterFormatCheck(letters string) bool { +///////////////////////////////////////////////////////////////////////////////////////// +////// Sharding Utilities /////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////// - // Pass - return true +func GetUserShard(userName string) (*DBShard, error) { + userShardsMux.Lock() + userDBNumb := helpers.HashNumber(userName, len(userShards)) + var ok bool + var s *DBShard + if s, ok = userShards[userDBNumb]; !ok { + userShardsMux.Unlock() + return nil, errors.New("Cannot find shard") + } + userShardsMux.Unlock() + return s, nil } -func letterConflict(letters string, m map[string]*DBShard) bool { +func GetUserShardByNumber(hashNumber int) (*DBShard, error) { + userShardsMux.Lock() + var ok bool + var s *DBShard + if s, ok = userShards[hashNumber]; !ok { + userShardsMux.Unlock() + return nil, errors.New("Cannot find shard") + } + userShardsMux.Unlock() + return s, nil +} - // Pass - return true +func GetFriendsShard(hashNumber int) (*DBShard, error) { + friendsShardsMux.Lock() + if len(friendsShards) == 0 { + friendsShardsMux.Unlock() + return getUserShardByNumber(hashNumber) + } + var ok bool + var s *DBShard + if s, ok = friendsShards[hashNumber]; !ok { + friendsShardsMux.Unlock() + return nil, errors.New("Cannot find shard") + } + friendsShardsMux.Unlock() + return s, nil +} + +func GetAutoLogShard(hashNumber int) (*DBShard, error) { + autologShardsMux.Lock() + if len(autologShards) == 0 { + autologShardsMux.Unlock() + return getUserShardByNumber(hashNumber) + } + var ok bool + var s *DBShard + if s, ok = autologShards[hashNumber]; !ok { + autologShardsMux.Unlock() + return nil, errors.New("Cannot find shard") + } + autologShardsMux.Unlock() + return s, nil } ///////////////////////////////////////////////////////////////////////////////////////// @@ -155,9 +205,13 @@ func (s *DBShard) SetMasterDB(r *DBReplica) { } func (s *DBShard) AddReplica(r *DBReplica) { + // REQUIRES GLOBAL PAUSE (Which only master server can do) + s.mux.Lock() s.replicas = append(s.replicas, r) s.mux.Unlock() + + // IF THIS IS MASTER, SEND COMMAND TO REST OF GAME SERVERS } func (s *DBShard) Master() *DBReplica { @@ -166,6 +220,7 @@ func (s *DBShard) Master() *DBReplica { func (s *DBShard) GetReplica() *DBReplica { s.mux.Lock() + // GET NEXT HEALTHY REPLICA for i := 0; i < len(s.replicas); i++ { s.replicaOn++ if s.replicaOn > len(s.replicas)-1 { diff --git a/helpers/crypto.go b/helpers/crypto.go index 74dc137..72409e8 100644 --- a/helpers/crypto.go +++ b/helpers/crypto.go @@ -4,6 +4,7 @@ import ( "crypto/rand" "encoding/base64" "golang.org/x/crypto/bcrypt" + "hash/fnv" ) // GenerateRandomBytes uses the `crypto/rand` library to create a secure random `[]byte` at a given size `n`. @@ -37,3 +38,9 @@ func CompareEncryptedData(str string, hash []byte) bool { err := bcrypt.CompareHashAndPassword(hash, []byte(str)) return err == nil } + +func HashNumber(s string, amount int) int { + h := fnv.New32a() + h.Write([]byte(s)) + return int(h.Sum32())%amount +} diff --git a/helpers/crypto_test.go b/helpers/crypto_test.go new file mode 100644 index 0000000..f6ca23f --- /dev/null +++ b/helpers/crypto_test.go @@ -0,0 +1,27 @@ +package helpers + +import ( + "testing" + "fmt" +) + +func TestHashNumber(t *testing.T) { + + amount := 40 + lst := make([]int, amount, amount) + + for i := 0; i < 1000000; i++ { + str, err := GenerateSecureString(3) + if err != nil { + fmt.Println(err) + return + } + + numb := HashNumber(str, amount) + lst[numb]++ + } + + for i := 0; i < len(lst); i++ { + fmt.Println("Database", i, "would have", lst[i], "entries") + } +} From fa226a9f4140fe3a360329a76f270f01a3588a6c Mon Sep 17 00:00:00 2001 From: Dominique Debergue Date: Mon, 4 Feb 2019 20:21:06 -0800 Subject: [PATCH 059/132] Update README.md --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 7dfc4bf..189f6cd 100644 --- a/README.md +++ b/README.md @@ -14,15 +14,16 @@ Moreover, Gopher has a built-in, fully customizable SQL client authentication me - Built-in friending mechanism (**\***) - Supports multiple connections on the same User - Server saves state on shut-down and restores on reboot - - Tools provided for administrating server while running > (**\***) A MySQL (or similar SQL) database is required for the authentication/friending feature, but is an optional (like most) feature that can be enabled or disabled to use your own implementations. ### Upcoming features - Customizable sharding mechanism for accounts, freinds, and auto-login databases - - Distributed server deployment tools + - Support for master-slave and master-master replication (or MySQL Group Replication) + - Distributed load balancer/monitor - Secure server cluster broadcasts with caching optimizations + - Tools for administrating and monitoring servers # Client APIs From db897f046cc6507e9c722d8c1841281dde704492 Mon Sep 17 00:00:00 2001 From: hewiefreeman Date: Tue, 5 Feb 2019 18:23:54 -0800 Subject: [PATCH 060/132] Continuing implementations for database sharding and replication, and changing friending/auto-logging storage methods --- database/authentication.go | 143 +++++++++++++++++++++++++++++++++---- database/sharding.go | 106 ++++++++++++++++++--------- helpers/crypto.go | 4 +- helpers/crypto_test.go | 6 +- sockets.go | 4 +- 5 files changed, 208 insertions(+), 55 deletions(-) diff --git a/database/authentication.go b/database/authentication.go index 775cd6b..d841d54 100644 --- a/database/authentication.go +++ b/database/authentication.go @@ -39,6 +39,7 @@ const ( errorInsufficientCols = "Insufficient custom column data" errorIncorrectLogin = "Incorrect login or password" errorInvalidAutoLog = "Invalid auto-login data" + errorNoShardFound = "Could not find a master or healthy replica database" ) ////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -184,7 +185,19 @@ func SignUpClient(userName string, password string, customCols map[string]interf var vals []interface{} //CREATE PART 1 OF QUERY - queryPart1 := "INSERT INTO " + tableUsers + " (" + usersColumnName + ", " + usersColumnPassword + ", " + var queryPart1 string + var shard *DBShard + var err error + if shardingInit { + shard, err = GetUserShard(helpers.UserHashNumber(userName)) + if err != nil { + return helpers.NewError(err.Error(), helpers.ErrorAuthUnexpected) + } + queryPart1 = "INSERT INTO " + usersShardPrefix + strconv.Itoa(shard.ID()) + " (" + usersColumnName + ", " + usersColumnPassword + ", " + }else{ + queryPart1 = "INSERT INTO " + tableUsers + " (" + usersColumnName + ", " + usersColumnPassword + ", " + } + if customCols != nil { vals = make([]interface{}, 0, len(customCols)) if customLoginColumn != "" { @@ -226,8 +239,19 @@ func SignUpClient(userName string, password string, customCols map[string]interf queryPart2 = queryPart2[0:len(queryPart2)-2] + ");" - //EXECUTE QUERY - _, insertErr := database.Exec(queryPart1 + queryPart2) + var insertErr error + if shardingInit { + // GET MASTER OR NEXT HEALTHY REPLICA + var r *DBReplica = shard.Master() + if r == nil { + return helpers.NewError(errorNoShardFound, helpers.ErrorAuthUnexpected) + } + //EXECUTE QUERY + _, insertErr = r.Conn().Exec(queryPart1 + queryPart2) + } else { + //EXECUTE QUERY + _, insertErr = database.Exec(queryPart1 + queryPart2) + } if insertErr != nil { return helpers.NewError(insertErr.Error(), helpers.ErrorAuthQuery) } @@ -257,10 +281,23 @@ func LoginClient(userName string, password string, deviceTag string, remMe bool, return "", 0, "", helpers.NewError(errorIncorrectCols, helpers.ErrorAuthIncorrectCols) } + // GET SHARD + var shard *DBShard + var err error + hashNum := helpers.UserHashNumber(userName) + if shardingInit { + shard, err = GetUserShard(hashNum) + if err != nil { + return "", 0, "", helpers.NewError(err.Error(), helpers.ErrorAuthUnexpected) + } + } + //FIRST THREE ARE id, password, name IN THAT ORDER var vals []interface{} + //CONSTRUCT SELECT QUERY selectQuery := "Select " + usersColumnID + ", " + usersColumnPassword + ", " + usersColumnName + ", " + if customCols != nil { vals = make([]interface{}, 0, len(customCols)+3) vals = append(vals, new(int), new([]byte), new(string)) @@ -274,14 +311,30 @@ func LoginClient(userName string, password string, deviceTag string, remMe bool, vals = append(vals, new(int), new([]byte), new(string)) } + // GET LOGIN COLUMN AND TABLE NAME + var loginCol string = usersColumnName + var tableName string = tableUsers if len(customLoginColumn) > 0 { - selectQuery = selectQuery[0:len(selectQuery)-2] + " FROM " + tableUsers + " WHERE " + customLoginColumn + "=\"" + userName + "\" LIMIT 1;" - } else { - selectQuery = selectQuery[0:len(selectQuery)-2] + " FROM " + tableUsers + " WHERE " + usersColumnName + "=\"" + userName + "\" LIMIT 1;" + loginCol = customLoginColumn } + if shardingInit { + tableName = usersShardPrefix + strconv.Itoa(shard.ID()) + } + + selectQuery = selectQuery[0:len(selectQuery)-2] + " FROM " + tableName + " WHERE " + loginCol + "=\"" + userName + "\" LIMIT 1;" //EXECUTE SELECT QUERY - checkRows, err := database.Query(selectQuery) + var checkRows *sql.Rows + if shardingInit { + // GET REPLICA + var r *DBReplica = shard.GetReplica() + if r == nil { + return "", 0, "", helpers.NewError(errorNoShardFound, helpers.ErrorAuthUnexpected) + } + checkRows, err = r.Conn().Query(selectQuery) + } else { + checkRows, err = database.Query(selectQuery) + } if err != nil { return "", 0, "", helpers.NewError(errorIncorrectLogin, helpers.ErrorAuthIncorrectLogin) } @@ -329,8 +382,30 @@ func LoginClient(userName string, password string, deviceTag string, remMe bool, //MAKE AUTO-LOG ENTRY devicePass, devicePassErr = helpers.GenerateSecureString(32) if devicePassErr == nil { - database.Exec("INSERT INTO " + tableAutologs + " (" + autologsColumnID + ", " + autologsColumnDeviceTag + ", " + autologsColumnDevicePass + - ") VALUES (" + strconv.Itoa(*dbIndex) + ", \"" + deviceTag + "\", \"" + devicePass + "\");") + var exErr error + if shardingInit { + // GET AUTOLOG SHARD/MASTER + shard, err = GetAutologShard(hashNum) + if err == nil { + var r *DBReplica = shard.Master() + if r != nil { + _, exErr = r.Conn().Exec("INSERT INTO " + autologShardPrefix + strconv.Itoa(shard.ID()) + " (" + autologsColumnID + ", " + autologsColumnDeviceTag + ", " + autologsColumnDevicePass + + ") VALUES (" + strconv.Itoa(hashNum) + ", \"" + deviceTag + "\", \"" + devicePass + "\");") + } else { + ///// LOG ERROR!!!! + } + } else { + ////// LOG ERROR!!!!!!! + } + } else { + _, exErr = database.Exec("INSERT INTO " + tableAutologs + " (" + autologsColumnID + ", " + autologsColumnDeviceTag + ", " + autologsColumnDevicePass + + ") VALUES (" + strconv.Itoa(*dbIndex) + ", \"" + deviceTag + "\", \"" + devicePass + "\");") + } + if exErr != nil { + ////// LOG ERROR!!!!!! + } + } else { + ////// LOG ERROR!!!!!! } } @@ -350,11 +425,29 @@ func AutoLoginClient(tag string, pass string, newPass string, dbID int) (string, if checkStringSQLInjection(tag) { return "", helpers.NewError(errorMaliciousChars, helpers.ErrorAuthMaliciousChars) } + //EXECUTE SELECT QUERY var dPass string - checkRows, err := database.Query("Select " + autologsColumnDevicePass + " FROM " + tableAutologs + " WHERE " + autologsColumnID + "=" + strconv.Itoa(dbID) + " AND " + + var shard *DBShard + var err error + db := database + tableName := tableAutologs + if shardingInit { + // SET DB TO SHARD REPLICA + shard, err = GetAutologShard(dbID) + if err != nil { + return "", helpers.NewError(err, helpers.ErrorAuthUnexpected) + } + r := shard.GetReplica() + if r == nil { + return "", helpers.NewError(errorNoShardFound, helpers.ErrorAuthUnexpected) + } + tableName = autologShardPrefix + strconv.Itoa(shard.ID()) + db = r.Conn() + } + checkRows, checkErr := db.Query("Select " + autologsColumnDevicePass + " FROM " + tableName + " WHERE " + autologsColumnID + "=" + strconv.Itoa(dbID) + " AND " + autologsColumnDeviceTag + "=\"" + tag + "\" LIMIT 1;") - if err != nil { + if checkErr != nil { return "", helpers.NewError(errorInvalidAutoLog, helpers.ErrorDatabaseInvalidAutolog) } // @@ -373,16 +466,38 @@ func AutoLoginClient(tag string, pass string, newPass string, dbID int) (string, } //UPDATE TO NEW PASS - _, updateErr := database.Exec("UPDATE " + tableAutologs + " SET " + autologsColumnDevicePass + "=\"" + newPass + "\" WHERE " + autologsColumnID + "=" + strconv.Itoa(dbID) + " AND " + + if shardingInit { + // SWITCH TO MASTER + r := shard.Master() + if r == nil { + return "", helpers.NewError(errorNoShardFound, helpers.ErrorAuthUnexpected) + } + db = r.Conn() + } + _, updateErr := db.Exec("UPDATE " + tableName + " SET " + autologsColumnDevicePass + "=\"" + newPass + "\" WHERE " + autologsColumnID + "=" + strconv.Itoa(dbID) + " AND " + autologsColumnDeviceTag + "=\"" + tag + "\" LIMIT 1;") if updateErr != nil { return "", helpers.NewError(errorInvalidAutoLog, helpers.ErrorDatabaseInvalidAutolog) } //EVERYTHING WENT WELL, GET THE User's NAME + tableName = tableUsers + if shardingInit { + // SET DB TO SHARD REPLICA + shard, err = GetUserShard(dbID) + if err != nil { + return "", helpers.NewError(err, helpers.ErrorAuthUnexpected) + } + r := shard.GetReplica() + if r == nil { + return "", helpers.NewError(errorNoShardFound, helpers.ErrorAuthUnexpected) + } + tableName = usersShardPrefix + strconv.Itoa(shard.ID()) + db = r.Conn() + } var userName string - userRows, err := database.Query("Select " + usersColumnName + " FROM " + tableUsers + " WHERE " + usersColumnID + "=" + strconv.Itoa(dbID) + " LIMIT 1;") - if err != nil { + userRows, usrErr := db.Query("Select " + usersColumnName + " FROM " + tableName + " WHERE " + usersColumnID + "=" + strconv.Itoa(dbID) + " LIMIT 1;") + if usrErr != nil { return "", helpers.NewError(errorInvalidAutoLog, helpers.ErrorDatabaseInvalidAutolog) } // diff --git a/database/sharding.go b/database/sharding.go index 1034ec3..780d0fc 100644 --- a/database/sharding.go +++ b/database/sharding.go @@ -10,13 +10,13 @@ import ( var ( shardingInit bool - partitionSplit int = 500 // Each database shard will split into tables of this size for easy further sharding later on - shardTargetLoad int = 30000 // The maximum load a database shard should take in your system. This does not control the connection, merely triggers a warning for admins + shardTargetEntries int = 30000 // The maximum entries a database table shard should hold in your system. This does not control the max entry count + shardPercentWarning int = 80 // // Table name prefixes - usersPrefix string = "users_" - friendsPrefix string = "friends_" - autologPrefix string = "autologs_" + usersShardPrefix string = "users_" + friendsShardPrefix string = "friends_" + autologShardPrefix string = "autologs_" // Database shards userShardsMux sync.Mutex @@ -32,6 +32,8 @@ var ( type DBShard struct { master *DBReplica + id int + mux sync.Mutex replicaOn int replicas []*DBReplica @@ -40,6 +42,8 @@ type DBShard struct { type DBReplica struct { conn *sql.DB + id int + ip string port int protocol string @@ -54,17 +58,26 @@ type DBReplica struct { ////// INIT ///////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////// +func ShardingInited() bool { + return shardingInit +} + func setShardingDefaults(ip string, port int, protocol string, userName string, password string) error { // Set default shard if no shards are set if len(userShards) == 0 { - // Make connection to default shard - defShard, shardErr := NewDBShard(ip, port, protocol, userName, password, false) - if shardErr { - return shardErr + // Make connection to default partitions + var defaultDBs []*DBShard = make([]*DBShard, 3, 3) + for i := 0; i < 3; i++ { + defShard, shardErr := NewDBShard(ip, port, protocol, userName, password, false) + if shardErr { + return shardErr + } + defaultDBs[i] = defShard } + // Append default shard to user shards userShardsMux.Lock() - appendShards(&userShards, defShard) + appendShards(&userShards, defaultDBs) userShardsMux.Unlock() } @@ -76,6 +89,20 @@ func setShardingDefaults(ip string, port int, protocol string, userName string, ////// SET-UP /////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////// +func SetShardingTargetEntries(maxEntries int) { + if inited { + return + } + shardTargetEntries = maxEntries +} + +func SetEntriesWarningPercent(percent int) { + if inited { + return + } + shardPercentWarning = percent +} + func AddUserShards(shards *DBShard...) { // REQUIRES GLOBAL PAUSE (Which only master server can do) @@ -114,32 +141,24 @@ func AddAutologShards(shards *DBShard...) { func appendShards(dest *map[int]*DBShard, shards *DBShard...) { for s := range shards { + (*s).id = len(*dest) (*dest)[len(*dest)] = s } } ///////////////////////////////////////////////////////////////////////////////////////// -////// Sharding Utilities /////////////////////////////////////////////////////////// +////// Shard Getters //////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////// -func GetUserShard(userName string) (*DBShard, error) { +func GetUserShard(hashNumber int) (*DBShard, error) { userShardsMux.Lock() - userDBNumb := helpers.HashNumber(userName, len(userShards)) - var ok bool - var s *DBShard - if s, ok = userShards[userDBNumb]; !ok { + if len(userShards) == 0 { userShardsMux.Unlock() - return nil, errors.New("Cannot find shard") + return nil, errors.New("No shards exist") } - userShardsMux.Unlock() - return s, nil -} - -func GetUserShardByNumber(hashNumber int) (*DBShard, error) { - userShardsMux.Lock() var ok bool var s *DBShard - if s, ok = userShards[hashNumber]; !ok { + if s, ok = userShards[hashNumber%len(userShards)]; !ok { userShardsMux.Unlock() return nil, errors.New("Cannot find shard") } @@ -151,11 +170,11 @@ func GetFriendsShard(hashNumber int) (*DBShard, error) { friendsShardsMux.Lock() if len(friendsShards) == 0 { friendsShardsMux.Unlock() - return getUserShardByNumber(hashNumber) + return GetUserShard(hashNumber) } var ok bool var s *DBShard - if s, ok = friendsShards[hashNumber]; !ok { + if s, ok = friendsShards[hashNumber%len(friendsShards)]; !ok { friendsShardsMux.Unlock() return nil, errors.New("Cannot find shard") } @@ -167,11 +186,11 @@ func GetAutoLogShard(hashNumber int) (*DBShard, error) { autologShardsMux.Lock() if len(autologShards) == 0 { autologShardsMux.Unlock() - return getUserShardByNumber(hashNumber) + return GetUserShard(hashNumber) } var ok bool var s *DBShard - if s, ok = autologShards[hashNumber]; !ok { + if s, ok = autologShards[hashNumber%len(autologShards)]; !ok { autologShardsMux.Unlock() return nil, errors.New("Cannot find shard") } @@ -183,7 +202,7 @@ func GetAutoLogShard(hashNumber int) (*DBShard, error) { ////// DBShard ////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////// -func NewDBShard(ip string, port int, protocol string, userName string, password string, master bool) (*DBShard, error) { +func NewDBShard(ip string, port int, protocol string, userName string, password string, master bool, shardID int) (*DBShard, error) { replica, replicaErr := NewDBReplica(ip, port, protocol, userName, password) if replicaErr != nil { return nil, replicaErr @@ -208,6 +227,7 @@ func (s *DBShard) AddReplica(r *DBReplica) { // REQUIRES GLOBAL PAUSE (Which only master server can do) s.mux.Lock() + (*r).id = len(s.replicas) s.replicas = append(s.replicas, r) s.mux.Unlock() @@ -215,11 +235,21 @@ func (s *DBShard) AddReplica(r *DBReplica) { } func (s *DBShard) Master() *DBReplica { + if s.master == nil { + return s.GetReplica() + } return s.master } func (s *DBShard) GetReplica() *DBReplica { s.mux.Lock() + if len(s.replicas) == 0 { + if s.master == nil { + s.mux.Unlock() + return nil + } + return s.master + } // GET NEXT HEALTHY REPLICA for i := 0; i < len(s.replicas); i++ { s.replicaOn++ @@ -236,11 +266,15 @@ func (s *DBShard) GetReplica() *DBReplica { return nil } +func (s *DBShard) ID() int { + return s.id +} + ///////////////////////////////////////////////////////////////////////////////////////// ////// DBReplica //////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////// -func NewDBReplica(ip string, port int, protocol string, userName string, password string) (*DBReplica, error) { +func NewDBReplica(ip string, port int, protocol string, userName string, password string, replicaID int) (*DBReplica, error) { db, err := sql.Open("mysql", userName+":"+password+"@"+protocol+"("+ip+":"+strconv.Itoa(port)+")/"+databaseName) if err != nil { return nil, err @@ -259,6 +293,10 @@ func (r *DBReplica) Conn() *sql.DB { return r.conn } +func (r *DBReplica) ID() int { + return r.id +} + func (r *DBReplica) IP() string { return r.ip } @@ -293,26 +331,26 @@ func (r *DBReplica) SetHealthy(h bool) { } ///////////////////////////////////////////////////////////////////////////////////////// -////// TABE PREFIX SETTERS ////////////////////////////////////////////////////////// +////// TABLE PREFIX SETTERS ///////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////// func SetUsersTablePrefix(prefix string) { if inited { return } - usersPrefix = prefix + usersShardPrefix = prefix } func SetFriendsTablePrefix(prefix string) { if inited { return } - friendsPrefix = prefix + friendsShardPrefix = prefix } func SetAutologTablePrefix(prefix string) { if inited { return } - autologPrefix = prefix + autologShardPrefix = prefix } diff --git a/helpers/crypto.go b/helpers/crypto.go index 72409e8..7fbd56e 100644 --- a/helpers/crypto.go +++ b/helpers/crypto.go @@ -39,8 +39,8 @@ func CompareEncryptedData(str string, hash []byte) bool { return err == nil } -func HashNumber(s string, amount int) int { +func UserHashNumber(s string) int { h := fnv.New32a() h.Write([]byte(s)) - return int(h.Sum32())%amount + return int(h.Sum32()) } diff --git a/helpers/crypto_test.go b/helpers/crypto_test.go index f6ca23f..8bc0c5b 100644 --- a/helpers/crypto_test.go +++ b/helpers/crypto_test.go @@ -7,17 +7,17 @@ import ( func TestHashNumber(t *testing.T) { - amount := 40 + amount := 5 lst := make([]int, amount, amount) - for i := 0; i < 1000000; i++ { + for i := 0; i < 50000; i++ { str, err := GenerateSecureString(3) if err != nil { fmt.Println(err) return } - numb := HashNumber(str, amount) + numb := UserHashNumber(str)%amount lst[numb]++ } diff --git a/sockets.go b/sockets.go index 32030ea..585d85f 100644 --- a/sockets.go +++ b/sockets.go @@ -298,8 +298,8 @@ func (c *connections) subtract() { c.connsMux.Unlock() } -// ClientsConnected gets the number of clients connected to the server. Includes connections -// not logged in as a User. +// ClientsConnected returns the number of clients connected to the server. Includes connections +// not logged in as a User. To get the number of Users logged in, use the users.UserCount() function. func ClientsConnected() int { conns.connsMux.Lock() defer conns.connsMux.Unlock() From b14c0c6193c5587c794dbe4acf6b1c77d5e49eaa Mon Sep 17 00:00:00 2001 From: hewiefreeman Date: Tue, 5 Feb 2019 18:40:51 -0800 Subject: [PATCH 061/132] Error fixes to releive any go gets --- database/authentication.go | 5 +++-- database/sharding.go | 24 ++++++++++++------------ 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/database/authentication.go b/database/authentication.go index d841d54..d292139 100644 --- a/database/authentication.go +++ b/database/authentication.go @@ -4,6 +4,7 @@ import ( "errors" "github.com/hewiefreeman/GopherGameServer/helpers" "strconv" + "database/sql" ) var ( @@ -436,7 +437,7 @@ func AutoLoginClient(tag string, pass string, newPass string, dbID int) (string, // SET DB TO SHARD REPLICA shard, err = GetAutologShard(dbID) if err != nil { - return "", helpers.NewError(err, helpers.ErrorAuthUnexpected) + return "", helpers.NewError(err.Error(), helpers.ErrorAuthUnexpected) } r := shard.GetReplica() if r == nil { @@ -486,7 +487,7 @@ func AutoLoginClient(tag string, pass string, newPass string, dbID int) (string, // SET DB TO SHARD REPLICA shard, err = GetUserShard(dbID) if err != nil { - return "", helpers.NewError(err, helpers.ErrorAuthUnexpected) + return "", helpers.NewError(err.Error(), helpers.ErrorAuthUnexpected) } r := shard.GetReplica() if r == nil { diff --git a/database/sharding.go b/database/sharding.go index 780d0fc..3474052 100644 --- a/database/sharding.go +++ b/database/sharding.go @@ -1,7 +1,7 @@ package database import ( - "github.com/hewiefreeman/GopherGameServer/helpers" + //"github.com/hewiefreeman/GopherGameServer/helpers" "database/sql" "errors" "strconv" @@ -68,8 +68,8 @@ func setShardingDefaults(ip string, port int, protocol string, userName string, // Make connection to default partitions var defaultDBs []*DBShard = make([]*DBShard, 3, 3) for i := 0; i < 3; i++ { - defShard, shardErr := NewDBShard(ip, port, protocol, userName, password, false) - if shardErr { + defShard, shardErr := NewDBShard(ip, port, protocol, userName, password, false, i) + if shardErr != nil { return shardErr } defaultDBs[i] = defShard @@ -103,7 +103,7 @@ func SetEntriesWarningPercent(percent int) { shardPercentWarning = percent } -func AddUserShards(shards *DBShard...) { +func AddUserShards(shards []*DBShard) { // REQUIRES GLOBAL PAUSE (Which only master server can do) userShardsMux.Lock() @@ -115,7 +115,7 @@ func AddUserShards(shards *DBShard...) { // THEN SEND COMMAND TO REST OF GAME SERVERS } -func AddFriendsShards(shards *DBShard...) { +func AddFriendsShards(shards []*DBShard) { // REQUIRES GLOBAL PAUSE (Which only master server can do) friendsShardsMux.Lock() @@ -127,7 +127,7 @@ func AddFriendsShards(shards *DBShard...) { // THEN SEND COMMAND TO REST OF GAME SERVERS } -func AddAutologShards(shards *DBShard...) { +func AddAutologShards(shards []*DBShard) { // REQUIRES GLOBAL PAUSE (Which only master server can do) autologShardsMux.Lock() @@ -139,10 +139,10 @@ func AddAutologShards(shards *DBShard...) { // THEN SEND COMMAND TO REST OF GAME SERVERS } -func appendShards(dest *map[int]*DBShard, shards *DBShard...) { - for s := range shards { - (*s).id = len(*dest) - (*dest)[len(*dest)] = s +func appendShards(dest *map[int]*DBShard, shards []*DBShard) { + for i := 0; i < len(shards); i++ { + (*shards[i]).id = len(*dest) + (*dest)[len(*dest)] = shards[i] } } @@ -182,7 +182,7 @@ func GetFriendsShard(hashNumber int) (*DBShard, error) { return s, nil } -func GetAutoLogShard(hashNumber int) (*DBShard, error) { +func GetAutologShard(hashNumber int) (*DBShard, error) { autologShardsMux.Lock() if len(autologShards) == 0 { autologShardsMux.Unlock() @@ -203,7 +203,7 @@ func GetAutoLogShard(hashNumber int) (*DBShard, error) { ///////////////////////////////////////////////////////////////////////////////////////// func NewDBShard(ip string, port int, protocol string, userName string, password string, master bool, shardID int) (*DBShard, error) { - replica, replicaErr := NewDBReplica(ip, port, protocol, userName, password) + replica, replicaErr := NewDBReplica(ip, port, protocol, userName, password, 0) if replicaErr != nil { return nil, replicaErr } From a5edd57bcc61fc6f5d10b194f4a433e7a5ed51da Mon Sep 17 00:00:00 2001 From: hewiefreeman Date: Tue, 23 Jul 2019 19:23:18 -0700 Subject: [PATCH 062/132] Refactored 'rooms' and 'users' packages into 'core' package for consistency, less RAM consumption, and less code redundancy. Updated tests and examples. --- actions/actions.go | 24 +- callbacks.go | 6 +- clientActions.go | 71 +++-- core/core.go | 112 ++++++++ {users => core}/friending.go | 36 +-- rooms/messages.go => core/messaging.go | 141 +++++++--- {rooms => core}/roomTypes.go | 14 +- {rooms => core}/rooms.go | 294 ++++++++------------ {users => core}/users.go | 192 +++++-------- {users => core}/vars.go | 86 +++++- database/authentication.go | 128 ++------- database/database.go | 31 +-- database/sharding.go | 356 ------------------------- helpers/clientResponses.go | 17 +- helpers/crypto_test.go | 57 +++- macros.go | 21 +- rooms/vars.go | 182 ------------- rooms/voice.go | 45 ---- server.go | 54 ++-- sockets.go | 20 +- users/messages.go | 62 ----- 21 files changed, 688 insertions(+), 1261 deletions(-) create mode 100644 core/core.go rename {users => core}/friending.go (89%) rename rooms/messages.go => core/messaging.go (53%) rename {rooms => core}/roomTypes.go (94%) rename {rooms => core}/rooms.go (66%) rename {users => core}/users.go (82%) rename {users => core}/vars.go (65%) delete mode 100644 database/sharding.go delete mode 100644 rooms/vars.go delete mode 100644 rooms/voice.go delete mode 100644 users/messages.go diff --git a/actions/actions.go b/actions/actions.go index 535b6b7..507760d 100644 --- a/actions/actions.go +++ b/actions/actions.go @@ -5,7 +5,7 @@ import ( "errors" "github.com/gorilla/websocket" "github.com/hewiefreeman/GopherGameServer/helpers" - "github.com/hewiefreeman/GopherGameServer/users" + "github.com/hewiefreeman/GopherGameServer/core" ) // CustomClientAction is an action that you can handle on the server from @@ -24,7 +24,7 @@ type CustomClientAction struct { type Client struct { action string - user *users.User + user *core.User connID string socket *websocket.Conn @@ -116,7 +116,7 @@ func NoError() ClientError { // // WARNING: This is only meant for internal Gopher Game Server mechanics. Your CustomClientAction callbacks are called // from this function. This could spawn errors and/or memory leaks. -func HandleCustomClientAction(action string, data interface{}, user *users.User, conn *websocket.Conn, connID string) { +func HandleCustomClientAction(action string, data interface{}, user *core.User, conn *websocket.Conn, connID string) { client := Client{user: user, action: action, socket: conn, connID: connID, responded: false} // CHECK IF ACTION EXISTS if customAction, ok := customClientActions[action]; ok { @@ -198,7 +198,7 @@ func typesMatch(data interface{}, theType int) bool { // is needed. // // NOTE: A response can only be sent once to a Client. Any more calls to Respond() on the same Client will not send a response, -// nor do anything at all. If you want to send a stream of messages to the Client, first get their User object with users.Get() using +// nor do anything at all. If you want to send a stream of messages to the Client, first get their User object with core.GetUser() using // the Client's Name(). Then you can send Data messages directly to the User with the *User.DataMessage() function. func (c *Client) Respond(response interface{}, err ClientError) { //YOU CAN ONLY RESPOND ONCE @@ -207,15 +207,15 @@ func (c *Client) Respond(response interface{}, err ClientError) { } (*c).responded = true //CONSTRUCT MESSAGE - r := make(map[string]interface{}) + r := make(map[string]map[string]interface{}) r[helpers.ServerActionCustomClientActionResponse] = make(map[string]interface{}) - r[helpers.ServerActionCustomClientActionResponse].(map[string]interface{})["a"] = (*c).action + r[helpers.ServerActionCustomClientActionResponse]["a"] = (*c).action if err.id != -1 { - r[helpers.ServerActionCustomClientActionResponse].(map[string]interface{})["e"] = make(map[string]interface{}) - r[helpers.ServerActionCustomClientActionResponse].(map[string]interface{})["e"].(map[string]interface{})["m"] = err.message - r[helpers.ServerActionCustomClientActionResponse].(map[string]interface{})["e"].(map[string]interface{})["id"] = err.id + r[helpers.ServerActionCustomClientActionResponse]["e"] = make(map[string]interface{}) + r[helpers.ServerActionCustomClientActionResponse]["e"].(map[string]interface{})["m"] = err.message + r[helpers.ServerActionCustomClientActionResponse]["e"].(map[string]interface{})["id"] = err.id } else { - r[helpers.ServerActionCustomClientActionResponse].(map[string]interface{})["r"] = response + r[helpers.ServerActionCustomClientActionResponse]["r"] = response } //SEND MESSAGE TO CLIENT @@ -227,7 +227,7 @@ func (c *Client) Respond(response interface{}, err ClientError) { /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // User gets the *User of the Client. -func (c *Client) User() *users.User { +func (c *Client) User() *core.User { return c.user } @@ -262,14 +262,12 @@ func SetServerStarted(val bool) { func Pause() { if !serverPaused { serverPaused = true - serverStarted = false } } // Resume is only for internal Gopher Game Server mechanics. func Resume() { if serverPaused { - serverStarted = true serverPaused = false } } diff --git a/callbacks.go b/callbacks.go index 1fe1752..6a72c2f 100644 --- a/callbacks.go +++ b/callbacks.go @@ -2,8 +2,8 @@ package gopher import ( "errors" + "github.com/hewiefreeman/GopherGameServer/core" "github.com/hewiefreeman/GopherGameServer/database" - "github.com/hewiefreeman/GopherGameServer/users" "net/http" ) @@ -126,7 +126,7 @@ func SetLoginCallback(cb interface{}) error { if (*settings).EnableSqlFeatures { database.LoginCallback = callback } else { - users.LoginCallback = callback + core.LoginCallback = callback } } else { return errors.New(ErrorIncorrectFunction) @@ -146,7 +146,7 @@ func SetLogoutCallback(cb interface{}) error { if serverStarted { return errors.New(ErrorServerRunning) } else if callback, ok := cb.(func(string, int)); ok { - users.LogoutCallback = callback + core.LogoutCallback = callback } else { return errors.New(ErrorIncorrectFunction) } diff --git a/clientActions.go b/clientActions.go index 89571c6..5d82cd8 100644 --- a/clientActions.go +++ b/clientActions.go @@ -3,10 +3,9 @@ package gopher import ( "github.com/gorilla/websocket" "github.com/hewiefreeman/GopherGameServer/actions" + "github.com/hewiefreeman/GopherGameServer/core" "github.com/hewiefreeman/GopherGameServer/database" "github.com/hewiefreeman/GopherGameServer/helpers" - "github.com/hewiefreeman/GopherGameServer/rooms" - "github.com/hewiefreeman/GopherGameServer/users" "sync" ) @@ -34,7 +33,7 @@ const ( errorIncorrectFormatVarKey = "Incorrect data format for variable key" ) -func clientActionHandler(action clientAction, user **users.User, conn *websocket.Conn, +func clientActionHandler(action clientAction, user **core.User, conn *websocket.Conn, deviceTag *string, devicePass *string, deviceUserID *int, connID *string, clientMux *sync.Mutex) (interface{}, bool, helpers.GopherError) { switch _action := action.A; _action { @@ -119,7 +118,7 @@ func clientActionHandler(action clientAction, user **users.User, conn *websocket // CUSTOM CLIENT ACTIONS ///////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////// -func clientCustomAction(params interface{}, user **users.User, conn *websocket.Conn, connID string, clientMux *sync.Mutex) (interface{}, bool, helpers.GopherError) { +func clientCustomAction(params interface{}, user **core.User, conn *websocket.Conn, connID string, clientMux *sync.Mutex) (interface{}, bool, helpers.GopherError) { var ok bool var pMap map[string]interface{} var action string @@ -140,7 +139,7 @@ func clientCustomAction(params interface{}, user **users.User, conn *websocket.C // CHANGE USER STATUS //////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////// -func clientActionChangeStatus(params interface{}, user **users.User, clientMux *sync.Mutex) (interface{}, bool, helpers.GopherError) { +func clientActionChangeStatus(params interface{}, user **core.User, clientMux *sync.Mutex) (interface{}, bool, helpers.GopherError) { (*clientMux).Lock() if *user == nil { (*clientMux).Unlock() @@ -165,7 +164,7 @@ func clientActionChangeStatus(params interface{}, user **users.User, clientMux * // ACCOUNT/DATABASE ACTIONS ////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////// -func clientActionSignup(params interface{}, user **users.User, clientMux *sync.Mutex) (interface{}, bool, helpers.GopherError) { +func clientActionSignup(params interface{}, user **core.User, clientMux *sync.Mutex) (interface{}, bool, helpers.GopherError) { (*clientMux).Lock() if *user != nil { (*clientMux).Unlock() @@ -205,7 +204,7 @@ func clientActionSignup(params interface{}, user **users.User, clientMux *sync.M return nil, true, helpers.NoError() } -func clientActionDeleteAccount(params interface{}, user **users.User, clientMux *sync.Mutex) (interface{}, bool, helpers.GopherError) { +func clientActionDeleteAccount(params interface{}, user **core.User, clientMux *sync.Mutex) (interface{}, bool, helpers.GopherError) { (*clientMux).Lock() if *user != nil { (*clientMux).Unlock() @@ -237,7 +236,7 @@ func clientActionDeleteAccount(params interface{}, user **users.User, clientMux } //CHECK IF USER IS ONLINE - _, err := users.Get(userName) + _, err := core.GetUser(userName) if err == nil { return nil, true, helpers.NewError(err.Error(), helpers.ErrorGopherLoggedIn) } @@ -251,7 +250,7 @@ func clientActionDeleteAccount(params interface{}, user **users.User, clientMux return nil, true, helpers.NoError() } -func clientActionChangePassword(params interface{}, user **users.User, clientMux *sync.Mutex) (interface{}, bool, helpers.GopherError) { +func clientActionChangePassword(params interface{}, user **core.User, clientMux *sync.Mutex) (interface{}, bool, helpers.GopherError) { (*clientMux).Lock() if *user == nil { (*clientMux).Unlock() @@ -292,7 +291,7 @@ func clientActionChangePassword(params interface{}, user **users.User, clientMux return nil, true, helpers.NoError() } -func clientActionChangeAccountInfo(params interface{}, user **users.User, clientMux *sync.Mutex) (interface{}, bool, helpers.GopherError) { +func clientActionChangeAccountInfo(params interface{}, user **core.User, clientMux *sync.Mutex) (interface{}, bool, helpers.GopherError) { (*clientMux).Lock() if *user == nil { (*clientMux).Unlock() @@ -333,7 +332,7 @@ func clientActionChangeAccountInfo(params interface{}, user **users.User, client // LOGIN+LOGOUT ACTIONS ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////// -func clientActionLogin(params interface{}, user **users.User, deviceTag *string, devicePass *string, deviceUserID *int, conn *websocket.Conn, +func clientActionLogin(params interface{}, user **core.User, deviceTag *string, devicePass *string, deviceUserID *int, conn *websocket.Conn, connID *string, clientMux *sync.Mutex) (interface{}, bool, helpers.GopherError) { (*clientMux).Lock() if *user != nil { @@ -386,9 +385,9 @@ func clientActionLogin(params interface{}, user **users.User, deviceTag *string, if err.ID != 0 { return nil, true, err } - cID, err = users.Login(uName, dbIndex, dPass, guest, remMe, conn, user, clientMux) + cID, err = core.Login(uName, dbIndex, dPass, guest, remMe, conn, user, clientMux) } else { - cID, err = users.Login(name, -1, "", guest, false, conn, user, clientMux) + cID, err = core.Login(name, -1, "", guest, false, conn, user, clientMux) } if err.ID != 0 { return nil, true, err @@ -402,7 +401,7 @@ func clientActionLogin(params interface{}, user **users.User, deviceTag *string, return nil, false, helpers.NoError() } -func clientActionLogout(user **users.User, deviceTag *string, devicePass *string, deviceUserID *int, connID *string, clientMux *sync.Mutex) (interface{}, bool, helpers.GopherError) { +func clientActionLogout(user **core.User, deviceTag *string, devicePass *string, deviceUserID *int, connID *string, clientMux *sync.Mutex) (interface{}, bool, helpers.GopherError) { (*clientMux).Lock() if *user == nil { (*clientMux).Unlock() @@ -429,7 +428,7 @@ func clientActionLogout(user **users.User, deviceTag *string, devicePass *string // ROOM ACTIONS ////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////// -func clientActionJoinRoom(params interface{}, user **users.User, connID string, clientMux *sync.Mutex) (interface{}, bool, helpers.GopherError) { +func clientActionJoinRoom(params interface{}, user **core.User, connID string, clientMux *sync.Mutex) (interface{}, bool, helpers.GopherError) { (*clientMux).Lock() if *user == nil { (*clientMux).Unlock() @@ -444,7 +443,7 @@ func clientActionJoinRoom(params interface{}, user **users.User, connID string, return nil, true, helpers.NewError(errorIncorrectFormat, helpers.ErrorGopherIncorrectFormat) } //GET ROOM - room, roomErr := rooms.Get(roomName) + room, roomErr := core.GetRoom(roomName) if roomErr != nil { return nil, true, helpers.NewError(roomErr.Error(), helpers.ErrorGopherJoin) } @@ -458,7 +457,7 @@ func clientActionJoinRoom(params interface{}, user **users.User, connID string, return nil, false, helpers.NoError() } -func clientActionLeaveRoom(user **users.User, connID string, clientMux *sync.Mutex) (interface{}, bool, helpers.GopherError) { +func clientActionLeaveRoom(user **core.User, connID string, clientMux *sync.Mutex) (interface{}, bool, helpers.GopherError) { (*clientMux).Lock() if *user == nil { (*clientMux).Unlock() @@ -476,7 +475,7 @@ func clientActionLeaveRoom(user **users.User, connID string, clientMux *sync.Mut return nil, false, helpers.NoError() } -func clientActionCreateRoom(params interface{}, user **users.User, connID string, clientMux *sync.Mutex) (interface{}, bool, helpers.GopherError) { +func clientActionCreateRoom(params interface{}, user **core.User, connID string, clientMux *sync.Mutex) (interface{}, bool, helpers.GopherError) { (*clientMux).Lock() if *user == nil { (*clientMux).Unlock() @@ -511,7 +510,7 @@ func clientActionCreateRoom(params interface{}, user **users.User, connID string } maxUsers := int(maxUsersF) // - if rType, ok := rooms.GetRoomTypes()[roomType]; !ok { + if rType, ok := core.GetRoomTypes()[roomType]; !ok { return nil, true, helpers.NewError(errorRoomType, helpers.ErrorGopherMaxRoomFormat) } else if rType.ServerOnly() { return nil, true, helpers.NewError(errorServerRoom, helpers.ErrorGopherServerRoom) @@ -522,7 +521,7 @@ func clientActionCreateRoom(params interface{}, user **users.User, connID string return nil, true, errors.New("You must leave your current room to create a room") }*/ //MAKE THE Room - room, roomErr := rooms.New(roomName, roomType, private, maxUsers, userRef.Name()) + room, roomErr := core.NewRoom(roomName, roomType, private, maxUsers, userRef.Name()) if roomErr != nil { return nil, true, helpers.NewError(roomErr.Error(), helpers.ErrorGopherCreateRoom) } @@ -536,7 +535,7 @@ func clientActionCreateRoom(params interface{}, user **users.User, connID string return roomName, true, helpers.NoError() } -func clientActionDeleteRoom(params interface{}, user **users.User, clientMux *sync.Mutex) (interface{}, bool, helpers.GopherError) { +func clientActionDeleteRoom(params interface{}, user **core.User, clientMux *sync.Mutex) (interface{}, bool, helpers.GopherError) { (*clientMux).Lock() if *user == nil { (*clientMux).Unlock() @@ -554,14 +553,14 @@ func clientActionDeleteRoom(params interface{}, user **users.User, clientMux *sy return nil, true, helpers.NewError(errorIncorrectFormat, helpers.ErrorGopherIncorrectFormat) } //GET ROOM - room, roomErr := rooms.Get(roomName) + room, roomErr := core.GetRoom(roomName) if roomErr != nil { return nil, true, helpers.NewError(roomErr.Error(), helpers.ErrorGopherDeleteRoom) } else if room.Owner() != userRef.Name() { return nil, true, helpers.NewError(errorNotOwner, helpers.ErrorGopherNotOwner) } // - rType := rooms.GetRoomTypes()[room.Type()] + rType := core.GetRoomTypes()[room.Type()] if rType.ServerOnly() { return nil, true, helpers.NewError(errorServerRoom, helpers.ErrorGopherServerRoom) } @@ -574,7 +573,7 @@ func clientActionDeleteRoom(params interface{}, user **users.User, clientMux *sy return roomName, true, helpers.NoError() } -func clientActionRoomInvite(params interface{}, user **users.User, connID string, clientMux *sync.Mutex) (interface{}, bool, helpers.GopherError) { +func clientActionRoomInvite(params interface{}, user **core.User, connID string, clientMux *sync.Mutex) (interface{}, bool, helpers.GopherError) { (*clientMux).Lock() if *user == nil { (*clientMux).Unlock() @@ -592,7 +591,7 @@ func clientActionRoomInvite(params interface{}, user **users.User, connID string return nil, true, helpers.NewError(errorIncorrectFormat, helpers.ErrorGopherIncorrectFormat) } //GET INVITED USER - invUser, invUserErr := users.Get(name) + invUser, invUserErr := core.GetUser(name) if invUserErr != nil { return nil, true, helpers.NewError(invUserErr.Error(), helpers.ErrorGopherInvite) } @@ -605,7 +604,7 @@ func clientActionRoomInvite(params interface{}, user **users.User, connID string return nil, true, helpers.NoError() } -func clientActionRevokeInvite(params interface{}, user **users.User, connID string, clientMux *sync.Mutex) (interface{}, bool, helpers.GopherError) { +func clientActionRevokeInvite(params interface{}, user **core.User, connID string, clientMux *sync.Mutex) (interface{}, bool, helpers.GopherError) { (*clientMux).Lock() if *user == nil { (*clientMux).Unlock() @@ -635,7 +634,7 @@ func clientActionRevokeInvite(params interface{}, user **users.User, connID stri // CHAT+VOICE ACTIONS //////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////// -func clientActionVoiceStream(params interface{}, user **users.User, conn *websocket.Conn, connID string, clientMux *sync.Mutex) (interface{}, bool, helpers.GopherError) { +func clientActionVoiceStream(params interface{}, user **core.User, conn *websocket.Conn, connID string, clientMux *sync.Mutex) (interface{}, bool, helpers.GopherError) { (*clientMux).Lock() if *user == nil { (*clientMux).Unlock() @@ -649,7 +648,7 @@ func clientActionVoiceStream(params interface{}, user **users.User, conn *websoc return nil, false, helpers.NoError() } //CHECK IF VOICE CHAT ROOM - rType := rooms.GetRoomTypes()[currRoom.Type()] + rType := core.GetRoomTypes()[currRoom.Type()] if !rType.VoiceChatEnabled() { return nil, false, helpers.NoError() } @@ -659,7 +658,7 @@ func clientActionVoiceStream(params interface{}, user **users.User, conn *websoc return nil, false, helpers.NoError() } -func clientActionChatMessage(params interface{}, user **users.User, connID string, clientMux *sync.Mutex) (interface{}, bool, helpers.GopherError) { +func clientActionChatMessage(params interface{}, user **core.User, connID string, clientMux *sync.Mutex) (interface{}, bool, helpers.GopherError) { (*clientMux).Lock() if *user == nil { (*clientMux).Unlock() @@ -678,7 +677,7 @@ func clientActionChatMessage(params interface{}, user **users.User, connID strin return nil, false, helpers.NoError() } -func clientActionPrivateMessage(params interface{}, user **users.User, connID string, clientMux *sync.Mutex) (interface{}, bool, helpers.GopherError) { +func clientActionPrivateMessage(params interface{}, user **core.User, connID string, clientMux *sync.Mutex) (interface{}, bool, helpers.GopherError) { (*clientMux).Lock() if *user == nil { (*clientMux).Unlock() @@ -711,7 +710,7 @@ func clientActionPrivateMessage(params interface{}, user **users.User, connID st // USER VARIABLES //////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////// -func clientActionSetVariable(params interface{}, user **users.User, connID string, clientMux *sync.Mutex) (interface{}, bool, helpers.GopherError) { +func clientActionSetVariable(params interface{}, user **core.User, connID string, clientMux *sync.Mutex) (interface{}, bool, helpers.GopherError) { (*clientMux).Lock() if *user == nil { (*clientMux).Unlock() @@ -737,7 +736,7 @@ func clientActionSetVariable(params interface{}, user **users.User, connID strin return nil, false, helpers.NoError() } -func clientActionSetVariables(params interface{}, user **users.User, connID string, clientMux *sync.Mutex) (interface{}, bool, helpers.GopherError) { +func clientActionSetVariables(params interface{}, user **core.User, connID string, clientMux *sync.Mutex) (interface{}, bool, helpers.GopherError) { (*clientMux).Lock() if *user == nil { (*clientMux).Unlock() @@ -761,7 +760,7 @@ func clientActionSetVariables(params interface{}, user **users.User, connID stri // FRIENDING ACTIONS ///////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////// -func clientActionFriendRequest(params interface{}, user **users.User, clientMux *sync.Mutex) (interface{}, bool, helpers.GopherError) { +func clientActionFriendRequest(params interface{}, user **core.User, clientMux *sync.Mutex) (interface{}, bool, helpers.GopherError) { (*clientMux).Lock() if *user == nil { (*clientMux).Unlock() @@ -789,7 +788,7 @@ func clientActionFriendRequest(params interface{}, user **users.User, clientMux return nil, false, helpers.NoError() } -func clientActionAcceptFriend(params interface{}, user **users.User, clientMux *sync.Mutex) (interface{}, bool, helpers.GopherError) { +func clientActionAcceptFriend(params interface{}, user **core.User, clientMux *sync.Mutex) (interface{}, bool, helpers.GopherError) { (*clientMux).Lock() if *user == nil { (*clientMux).Unlock() @@ -817,7 +816,7 @@ func clientActionAcceptFriend(params interface{}, user **users.User, clientMux * return nil, false, helpers.NoError() } -func clientActionDeclineFriend(params interface{}, user **users.User, clientMux *sync.Mutex) (interface{}, bool, helpers.GopherError) { +func clientActionDeclineFriend(params interface{}, user **core.User, clientMux *sync.Mutex) (interface{}, bool, helpers.GopherError) { (*clientMux).Lock() if *user == nil { (*clientMux).Unlock() @@ -845,7 +844,7 @@ func clientActionDeclineFriend(params interface{}, user **users.User, clientMux return nil, false, helpers.NoError() } -func clientActionRemoveFriend(params interface{}, user **users.User, clientMux *sync.Mutex) (interface{}, bool, helpers.GopherError) { +func clientActionRemoveFriend(params interface{}, user **core.User, clientMux *sync.Mutex) (interface{}, bool, helpers.GopherError) { (*clientMux).Lock() if *user == nil { (*clientMux).Unlock() diff --git a/core/core.go b/core/core.go new file mode 100644 index 0000000..b668a5c --- /dev/null +++ b/core/core.go @@ -0,0 +1,112 @@ +package core + +import ( + "github.com/hewiefreeman/GopherGameServer/helpers" +) + +var ( + serverStarted bool = false + serverPaused bool = false + + serverName string + kickOnLogin bool = false + sqlFeatures bool = false + rememberMe bool = false + multiConnect bool = false + deleteRoomOnLeave bool = true +) + +////////////////////////////////////////////////////////////////////////////////////////////////////// +// SERVER STARTUP FUNCTIONS ////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////////// + +// SetServerStarted is for Gopher Game Server internal mechanics only. +func SetServerStarted(val bool) { + if !serverStarted { + serverStarted = val + } +} + +// SettingsSet is for Gopher Game Server internal mechanics only. +func SettingsSet(kickDups bool, name string, deleteOnLeave bool, sqlFeat bool, remMe bool, multiConn bool) { + if !serverStarted { + kickOnLogin = kickDups + serverName = name + sqlFeatures = sqlFeat + rememberMe = remMe + multiConnect = multiConn + deleteRoomOnLeave = deleteOnLeave + } +} + +////////////////////////////////////////////////////////////////////////////////////////////////////// +// SERVER PAUSE AND RESUME /////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////////// + +// Pause is only for internal Gopher Game Server mechanics. +func Pause() { + if !serverPaused { + serverPaused = true + + // + clientResp := helpers.MakeClientResponse(helpers.ClientActionLogout, nil, helpers.NoError()) + usersMux.Lock() + for _, user := range users { + user.mux.Lock() + for connID, conn := range user.conns { + //REMOVE CONNECTION FROM THEIR ROOM + currRoom := conn.room + if currRoom != nil && currRoom.Name() != "" { + user.mux.Unlock() + currRoom.RemoveUser(user, connID) + user.mux.Lock() + } + + //LOG CONNECTION OUT + conn.clientMux.Lock() + if *(conn.user) != nil { + *(conn.user) = nil + } + conn.clientMux.Unlock() + + //SEND LOG OUT MESSAGE + conn.socket.WriteJSON(clientResp) + } + user.mux.Unlock() + } + users = make(map[string]*User) + usersMux.Unlock() + } +} + +// Resume is only for internal Gopher Game Server mechanics. +func Resume() { + if serverPaused { + serverPaused = false + } +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// GET STATE FOR RECOVERY ///////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +// GetState is only for internal Gopher Game Server mechanics. +func GetState() map[string]map[string]interface{} { + state := make(map[string]map[string]interface{}) + roomsMux.Lock() + for _, room := range rooms { + room.mux.Lock() + state[room.name] = make(map[string]interface{}) + state[room.name]["t"] = room.rType + state[room.name]["p"] = room.private + state[room.name]["o"] = room.owner + state[room.name]["m"] = room.maxUsers + state[room.name]["i"] = room.inviteList + state[room.name]["v"] = room.vars + room.mux.Unlock() + } + roomsMux.Unlock() + // + return state +} diff --git a/users/friending.go b/core/friending.go similarity index 89% rename from users/friending.go rename to core/friending.go index 32f6c7b..21e5f55 100644 --- a/users/friending.go +++ b/core/friending.go @@ -1,4 +1,4 @@ -package users +package core import ( "errors" @@ -16,7 +16,7 @@ func (u *User) FriendRequest(friendName string) error { return errors.New("The user '" + friendName + "' cannot be requested as a friend") } //CHECK IF FRIEND IS ONLINE & GET DATABASE ID - friend, friendErr := Get(friendName) + friend, friendErr := GetUser(friendName) var friendOnline bool = false var friendID int if friendErr != nil { @@ -50,9 +50,9 @@ func (u *User) FriendRequest(friendName string) error { //SEND A FRIEND REQUEST TO THE USER IF THEY ARE ONLINE if friendOnline { - message := make(map[string]interface{}) + message := make(map[string]map[string]interface{}) message[helpers.ServerActionFriendRequest] = make(map[string]interface{}) - message[helpers.ServerActionFriendRequest].(map[string]interface{})["n"] = u.name + message[helpers.ServerActionFriendRequest]["n"] = u.name friend.mux.Lock() for _, conn := range friend.conns { (*conn).socket.WriteJSON(message) @@ -61,7 +61,7 @@ func (u *User) FriendRequest(friendName string) error { } //SEND RESPONSE TO CLIENT - clientResp := helpers.MakeClientResponse(helpers.ClientActionFriendRequest, friendName, helpers.NewError("", 0)) + clientResp := helpers.MakeClientResponse(helpers.ClientActionFriendRequest, friendName, helpers.NoError()) u.mux.Lock() for _, conn := range u.conns { (*conn).socket.WriteJSON(clientResp) @@ -84,7 +84,7 @@ func (u *User) AcceptFriendRequest(friendName string) error { return errors.New("The user '" + friendName + "' cannot be accepted as a friend") } //CHECK IF FRIEND IS ONLINE & GET DATABASE ID - friend, friendErr := Get(friendName) + friend, friendErr := GetUser(friendName) var friendOnline bool = false var friendID int if friendErr != nil { @@ -117,10 +117,10 @@ func (u *User) AcceptFriendRequest(friendName string) error { //SEND A FRIEND REQUEST TO THE USER IF THEY ARE ONLINE var status int = StatusOffline if friendOnline { - message := make(map[string]interface{}) + message := make(map[string]map[string]interface{}) message[helpers.ServerActionFriendAccept] = make(map[string]interface{}) - message[helpers.ServerActionFriendAccept].(map[string]interface{})["n"] = u.name - message[helpers.ServerActionFriendAccept].(map[string]interface{})["s"] = u.status + message[helpers.ServerActionFriendAccept]["n"] = u.name + message[helpers.ServerActionFriendAccept]["s"] = u.status friend.mux.Lock() for _, conn := range friend.conns { (*conn).socket.WriteJSON(message) @@ -135,7 +135,7 @@ func (u *User) AcceptFriendRequest(friendName string) error { responseMap["s"] = status //SEND RESPONSE TO CLIENT - clientResp := helpers.MakeClientResponse(helpers.ClientActionAcceptFriend, responseMap, helpers.NewError("", 0)) + clientResp := helpers.MakeClientResponse(helpers.ClientActionAcceptFriend, responseMap, helpers.NoError()) u.mux.Lock() for _, conn := range u.conns { (*conn).socket.WriteJSON(clientResp) @@ -158,7 +158,7 @@ func (u *User) DeclineFriendRequest(friendName string) error { return errors.New("The user '" + friendName + "' cannot be declined as a friend") } //CHECK IF FRIEND IS ONLINE & GET DATABASE ID - friend, friendErr := Get(friendName) + friend, friendErr := GetUser(friendName) var friendOnline bool = false var friendID int if friendErr != nil { @@ -191,9 +191,9 @@ func (u *User) DeclineFriendRequest(friendName string) error { //SEND A FRIEND REQUEST TO THE USER IF THEY ARE ONLINE if friendOnline { - message := make(map[string]interface{}) + message := make(map[string]map[string]interface{}) message[helpers.ServerActionFriendRemove] = make(map[string]interface{}) - message[helpers.ServerActionFriendRemove].(map[string]interface{})["n"] = u.name + message[helpers.ServerActionFriendRemove]["n"] = u.name friend.mux.Lock() for _, conn := range friend.conns { (*conn).socket.WriteJSON(message) @@ -202,7 +202,7 @@ func (u *User) DeclineFriendRequest(friendName string) error { } //SEND RESPONSE TO CLIENT - clientResp := helpers.MakeClientResponse(helpers.ClientActionDeclineFriend, friendName, helpers.NewError("", 0)) + clientResp := helpers.MakeClientResponse(helpers.ClientActionDeclineFriend, friendName, helpers.NoError()) u.mux.Lock() for _, conn := range u.conns { (*conn).socket.WriteJSON(clientResp) @@ -225,7 +225,7 @@ func (u *User) RemoveFriend(friendName string) error { return errors.New("The user '" + friendName + "' cannot be removed as a friend") } //CHECK IF FRIEND IS ONLINE & GET DATABASE ID - friend, friendErr := Get(friendName) + friend, friendErr := GetUser(friendName) var friendOnline bool = false var friendID int if friendErr != nil { @@ -258,9 +258,9 @@ func (u *User) RemoveFriend(friendName string) error { //SEND A FRIEND REQUEST TO THE USER IF THEY ARE ONLINE if friendOnline { - message := make(map[string]interface{}) + message := make(map[string]map[string]interface{}) message[helpers.ServerActionFriendRemove] = make(map[string]interface{}) - message[helpers.ServerActionFriendRemove].(map[string]interface{})["n"] = u.name + message[helpers.ServerActionFriendRemove]["n"] = u.name friend.mux.Lock() for _, conn := range friend.conns { (*conn).socket.WriteJSON(message) @@ -269,7 +269,7 @@ func (u *User) RemoveFriend(friendName string) error { } //SEND RESPONSE TO CLIENT - clientResp := helpers.MakeClientResponse(helpers.ClientActionRemoveFriend, friendName, helpers.NewError("", 0)) + clientResp := helpers.MakeClientResponse(helpers.ClientActionRemoveFriend, friendName, helpers.NoError()) u.mux.Lock() for _, conn := range u.conns { (*conn).socket.WriteJSON(clientResp) diff --git a/rooms/messages.go b/core/messaging.go similarity index 53% rename from rooms/messages.go rename to core/messaging.go index 0bfeb90..38b7715 100644 --- a/rooms/messages.go +++ b/core/messaging.go @@ -1,7 +1,8 @@ -package rooms +package core import ( "errors" + "github.com/gorilla/websocket" "github.com/hewiefreeman/GopherGameServer/helpers" ) @@ -18,25 +19,62 @@ const ( ServerMessageImportant ) -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// CHAT MESSAGES ////////////////////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////////// +// Messaging Users /////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////////// -// ChatMessage sends a chat message to all Users in the Room. -func (r *Room) ChatMessage(author string, message interface{}) error { - //REJECT INCORRECT INPUT - if len(author) == 0 { - return errors.New("*Room.ChatMessage() requires an author") - } else if message == nil { - return errors.New("*Room.ChatMessage() requires a message") +// PrivateMessage sends a private message to another User by name. +func (u *User) PrivateMessage(userName string, message interface{}) { + user, userErr := GetUser(userName) + if userErr != nil { + return } - return r.sendMessage(MessageTypeChat, 0, nil, author, message) + //CONSTRUCT MESSAGE + theMessage := make(map[string]map[string]interface{}) + theMessage[helpers.ServerActionPrivateMessage] = make(map[string]interface{}) + theMessage[helpers.ServerActionPrivateMessage]["f"] = u.name // from + theMessage[helpers.ServerActionPrivateMessage]["t"] = user.name // to + theMessage[helpers.ServerActionPrivateMessage]["m"] = message // message + + //SEND MESSAGES + user.mux.Lock() + for _, conn := range user.conns { + (*conn).socket.WriteJSON(theMessage) + } + user.mux.Unlock() + u.mux.Lock() + for _, conn := range u.conns { + (*conn).socket.WriteJSON(theMessage) + } + u.mux.Unlock() + + return } -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// SERVER MESSAGES //////////////////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// DataMessage sends a data message directly to the User. +func (u *User) DataMessage(data interface{}, connID string) { + //CONSTRUCT MESSAGE + message := make(map[string]interface{}) + message[helpers.ServerActionDataMessage] = data + + //SEND MESSAGE TO USER + u.mux.Lock() + if connID == "" { + for _, conn := range u.conns { + (*conn).socket.WriteJSON(message) + } + } else { + if conn, ok := u.conns[connID]; ok { + (*conn).socket.WriteJSON(message) + } + } + u.mux.Unlock() +} + +////////////////////////////////////////////////////////////////////////////////////////////////////// +// Messaging Rooms /////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////////// // ServerMessage sends a server message to the specified recipients in the Room. The parameter recipients can be nil or an empty slice // of string. In which case, the server message will be sent to all Users in the Room. @@ -48,9 +86,17 @@ func (r *Room) ServerMessage(message interface{}, messageType int, recipients [] return r.sendMessage(MessageTypeServer, messageType, recipients, "", message) } -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// DATA MESSAGES ////////////////////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// ChatMessage sends a chat message to all Users in the Room. +func (r *Room) ChatMessage(author string, message interface{}) error { + //REJECT INCORRECT INPUT + if len(author) == 0 { + return errors.New("*Room.ChatMessage() requires an author") + } else if message == nil { + return errors.New("*Room.ChatMessage() requires a message") + } + + return r.sendMessage(MessageTypeChat, 0, nil, author, message) +} // DataMessage sends a data message to the specified recipients in the Room. The parameter recipients can be nil or an empty slice // of string. In which case, the data message will be sent to all Users in the Room. @@ -70,7 +116,7 @@ func (r *Room) DataMessage(message interface{}, recipients []string) error { for _, u := range userMap { u.mux.Lock() for _, conn := range u.conns { - (*conn).socket.WriteJSON(theMessage) + conn.socket.WriteJSON(theMessage) } u.mux.Unlock() } @@ -79,7 +125,7 @@ func (r *Room) DataMessage(message interface{}, recipients []string) error { if u, ok := userMap[recipients[i]]; ok { u.mux.Lock() for _, conn := range u.conns { - (*conn).socket.WriteJSON(theMessage) + conn.socket.WriteJSON(theMessage) } u.mux.Unlock() } @@ -90,10 +136,6 @@ func (r *Room) DataMessage(message interface{}, recipients []string) error { return nil } -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// SENDING MESSAGES /////////////////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - func (r *Room) sendMessage(mt int, st int, rec []string, a string, m interface{}) error { //GET USER MAP userMap, err := r.GetUserMap() @@ -102,22 +144,22 @@ func (r *Room) sendMessage(mt int, st int, rec []string, a string, m interface{} } //CONSTRUCT MESSAGE - message := make(map[string]interface{}) + message := make(map[string]map[string]interface{}) message[helpers.ServerActionRoomMessage] = make(map[string]interface{}) if mt == MessageTypeServer { - message[helpers.ServerActionRoomMessage].(map[string]interface{})["s"] = st + message[helpers.ServerActionRoomMessage]["s"] = st } // Server messages come with a sub-type if len(a) > 0 && mt != MessageTypeServer { - message[helpers.ServerActionRoomMessage].(map[string]interface{})["a"] = a + message[helpers.ServerActionRoomMessage]["a"] = a } // Non-server messages have authors - message[helpers.ServerActionRoomMessage].(map[string]interface{})["m"] = m // The message + message[helpers.ServerActionRoomMessage]["m"] = m // The message //SEND MESSAGE TO USERS if rec == nil || len(rec) == 0 { for _, u := range userMap { u.mux.Lock() for _, conn := range u.conns { - (*conn).socket.WriteJSON(message) + conn.socket.WriteJSON(message) } u.mux.Unlock() } @@ -126,7 +168,7 @@ func (r *Room) sendMessage(mt int, st int, rec []string, a string, m interface{} if u, ok := userMap[rec[i]]; ok { u.mux.Lock() for _, conn := range u.conns { - (*conn).socket.WriteJSON(message) + conn.socket.WriteJSON(message) } u.mux.Unlock() } @@ -135,3 +177,42 @@ func (r *Room) sendMessage(mt int, st int, rec []string, a string, m interface{} return nil } + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// VOICE STREAMS ////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +// VoiceStream sends a voice stream from the client API to all the users in the room besides the user who is speaking. +func (r *Room) VoiceStream(userName string, userSocket *websocket.Conn, stream interface{}) { + //GET USER MAP + userMap, err := r.GetUserMap() + if err != nil { + return + } + + //CONSTRUCT VOICE MESSAGE + theMessage := make(map[string]map[string]interface{}) + theMessage[helpers.ServerActionVoiceStream] = make(map[string]interface{}) + theMessage[helpers.ServerActionVoiceStream]["u"] = userName + theMessage[helpers.ServerActionVoiceStream]["d"] = stream + + //REMOVE SENDING USER FROM userMap + delete(userMap, userName) // COMMENT OUT FOR ECHO TESTS + + //SEND MESSAGE TO USERS + for _, u := range userMap { + for _, conn := range u.conns { + (*conn).socket.WriteJSON(theMessage) + } + } + + //CONSTRUCT PING MESSAGE + pingMessage := make(map[string]interface{}) + pingMessage[helpers.ServerActionVoicePing] = nil + + //SEND PING MESSAGE TO SENDING USER + userSocket.WriteJSON(pingMessage) + + // + return +} diff --git a/rooms/roomTypes.go b/core/roomTypes.go similarity index 94% rename from rooms/roomTypes.go rename to core/roomTypes.go index bc392e4..61dc763 100644 --- a/rooms/roomTypes.go +++ b/core/roomTypes.go @@ -1,4 +1,4 @@ -package rooms +package core var ( roomTypes = make(map[string]*RoomType) @@ -17,8 +17,8 @@ type RoomType struct { createCallback func(*Room) // roomCreated deleteCallback func(*Room) // roomDeleted - userEnterCallback func(*Room, string) // roomFrom, userName - userLeaveCallback func(*Room, string) // roomFrom, userName + userEnterCallback func(*Room, *RoomUser) // roomFrom, user + userLeaveCallback func(*Room, *RoomUser) // roomFrom, user } // NewRoomType Adds a RoomType to the server. A RoomType is used in conjunction with it's corresponding callbacks @@ -129,7 +129,7 @@ func (r *RoomType) SetDeleteCallback(callback func(*Room)) *RoomType { // and the string is the name of the User that entered. // // Note: You must call this BEFORE starting the server in order for it to take effect. -func (r *RoomType) SetUserEnterCallback(callback func(*Room, string)) *RoomType { +func (r *RoomType) SetUserEnterCallback(callback func(*Room, *RoomUser)) *RoomType { if serverStarted { return r } @@ -142,7 +142,7 @@ func (r *RoomType) SetUserEnterCallback(callback func(*Room, string)) *RoomType // and the string is the name of the User that left. // // Note: You must call this BEFORE starting the server in order for it to take effect. -func (r *RoomType) SetUserLeaveCallback(callback func(*Room, string)) *RoomType { +func (r *RoomType) SetUserLeaveCallback(callback func(*Room, *RoomUser)) *RoomType { if serverStarted { return r } @@ -195,7 +195,7 @@ func (r *RoomType) HasDeleteCallback() bool { } // UserEnterCallback returns the function that this RoomType calls when a User enters a Room of this RoomType. -func (r *RoomType) UserEnterCallback() func(*Room, string) { +func (r *RoomType) UserEnterCallback() func(*Room, *RoomUser) { return r.userEnterCallback } @@ -205,7 +205,7 @@ func (r *RoomType) HasUserEnterCallback() bool { } // UserLeaveCallback returns the function that this RoomType calls when a User leaves a Room of this RoomType. -func (r *RoomType) UserLeaveCallback() func(*Room, string) { +func (r *RoomType) UserLeaveCallback() func(*Room, *RoomUser) { return r.userLeaveCallback } diff --git a/rooms/rooms.go b/core/rooms.go similarity index 66% rename from rooms/rooms.go rename to core/rooms.go index e7e63c9..c33a455 100644 --- a/rooms/rooms.go +++ b/core/rooms.go @@ -1,7 +1,13 @@ -// Package rooms contains all the necessary tools to make and work with Rooms. A Room represents -// a place on the server where a User can join other Users. +// Package core contains all the tools to make and work with Users and Rooms. // -// A Room can either be public or private. Private Rooms must be assigned an "owner", which is the name of a User, or the ServerName +// A User is a client who has successfully logged into the server. You can think of clients who are not attached to a User +// as, for instance, someone in the login screen, but are still connected to the server. A client doesn't +// have to be a User to be able to call your CustomClientActions, so keep that in mind when making them (Refer to the Usage for CustomClientActions). +// +// Users have their own variables which can be accessed and changed anytime. A User variable can +// be anything compatible with interface{}, so pretty much anything. +// +// A Room represents a place on the server where a User can join other Users. Rooms can either be public or private. Private Rooms must be assigned an "owner", which is the name of a User, or the ServerName // from ServerSettings. The server's name that will be used for ownership of private Rooms can be set with the ServerSettings // option ServerName when starting the server. Though keep in mind, setting the ServerName in ServerSettings will prevent a User who wants to go by that name // from logging in. Public Rooms will accept a join request from any User, and private Rooms will only @@ -9,15 +15,12 @@ // Users to a private Room. But remember, just because a User owns a private room doesn't mean the server cannot also invite // to the room via *Room.AddInvite() function. // -// Rooms have their own variables which can be accessed and changed anytime. A Room variable can -// be anything compatible with interface{}, so pretty much anything. Room variables should mainly be used -// for things about the room itself that don't change very often (or, for instance, are absolutely needed for a joining -// User). -package rooms +// Rooms have their own variables which can be accessed and changed anytime. Like User variables, a Room variable can +// be anything compatible with interface{}. +package core import ( "errors" - "github.com/gorilla/websocket" "github.com/hewiefreeman/GopherGameServer/helpers" "sync" ) @@ -41,45 +44,23 @@ type Room struct { vars map[string]interface{} } -// RoomUser is the representation of a User in a Room. Note: These -// are not the Users themselves. There are RoomUser methods that provide the same -// functionality as the matching User methods, but if you really need to get a User type from one of these, use -// users.Get() with the RoomUser's Name() function. type RoomUser struct { - name string - isGuest bool - dbID int - - //mux LOCKS ALL FIELDS BELOW - mux *sync.Mutex // Pointer to the User's mux - conns map[string]*roomUserConn // User's conns info - -} + user *User -type roomUserConn struct { - socket *websocket.Conn - roomIn **Room // Pointer to the User's Room pointer - vars *map[string]interface{} // Pointer to the User's variables + mux sync.Mutex + conns map[string]*userConn } var ( - //THE Rooms AND Rooms MUTEX rooms map[string]*Room = make(map[string]*Room) - roomsMux sync.Mutex //LOCKS rooms - - //SERVER SETTINGS - serverStarted bool = false - serverPaused bool = false - serverName string - deleteRoomOnLeave bool = true - multiConnect bool = false + roomsMux sync.Mutex ) /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // MAKE A NEW ROOM //////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// New adds a new room to the server. This can be called before or after starting the server. +// NewRoom adds a new room to the server. This can be called before or after starting the server. // Parameters: // // - name (string): Name of the Room @@ -91,7 +72,7 @@ var ( // - maxUsers (int): Maximum User capacity (Note: 0 means no limit) // // - owner (string): The owner of the room. If provided a blank string, will set the owner to the ServerName from ServerSettings -func New(name string, rType string, isPrivate bool, maxUsers int, owner string) (*Room, error) { +func NewRoom(name string, rType string, isPrivate bool, maxUsers int, owner string) (*Room, error) { //REJECT INCORRECT INPUT if len(name) == 0 { return &Room{}, errors.New("rooms.New() requires a name") @@ -144,17 +125,19 @@ func (r *Room) Delete() error { } // MAKE LEAVE MESSAGE - leaveMessage := helpers.MakeClientResponse(helpers.ClientActionLeaveRoom, nil, helpers.NewError("", 0)) + leaveMessage := helpers.MakeClientResponse(helpers.ClientActionLeaveRoom, nil, helpers.NoError()) // GO THROUGH ALL Users IN ROOM - for _, v := range r.usersMap { + for _, u := range r.usersMap { //CHANGE User's room POINTER TO nil & SEND MESSAGES - v.mux.Lock() - for key := range v.conns { - (*v.conns[key]).socket.WriteJSON(leaveMessage) - *((*v.conns[key]).roomIn) = nil + u.mux.Lock() + for key := range u.conns { + (*u.conns[key]).socket.WriteJSON(leaveMessage) + u.user.mux.Lock() + (*u.conns[key]).room = nil + u.user.mux.Unlock() } - v.mux.Unlock() + u.mux.Unlock() } r.usersMap = nil @@ -179,8 +162,8 @@ func (r *Room) Delete() error { // GET A ROOM ///////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Get finds a Room on the server. If the room does not exit, an error will be returned. -func Get(roomName string) (*Room, error) { +// GetRoom finds a Room on the server. If the room does not exit, an error will be returned. +func GetRoom(roomName string) (*Room, error) { //REJECT INCORRECT INPUT if len(roomName) == 0 { return &Room{}, errors.New("rooms.Get() requires a room name") @@ -204,23 +187,19 @@ func Get(roomName string) (*Room, error) { // ADD A USER ///////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// AddUser adds a User to the Room. -// -// WARNING: This is only meant for internal Gopher Game Server mechanics. If you want to make a User join a Room, use -// *User.Join() instead. Using this improperly will break server mechanics and cause errors and/or memory leaks. -func (r *Room) AddUser(userName string, dbID int, isGuest bool, socket *websocket.Conn, roomIn **Room, userVars *map[string]interface{}, - userStatus *int, userMux *sync.Mutex, connID string) error { +// AddUser adds a User to the Room. If you are using MultiConnect in ServerSettings, the connID +// parameter is the connection ID associated with one of the connections attached to that User. This must +// be provided when adding a User to a Room with MultiConnect enabled. Otherwise, an empty string can be used. +func (r *Room) AddUser(user *User, connID string) error { + userName := user.Name() // REJECT INCORRECT INPUT - if len(userName) == 0 { - return errors.New("*Room.AddUser() requires a user name") - } else if socket == nil { - return errors.New("*Room.AddUser() requires a user socket") + if user == nil { + return errors.New("*Room.AddUser() requires a valid User") } else if multiConnect && len(connID) == 0 { return errors.New("Must provide a connID when MultiConnect is enabled") } else if !multiConnect { connID = "1" } - r.mux.Lock() if r.usersMap == nil { r.mux.Unlock() @@ -229,10 +208,9 @@ func (r *Room) AddUser(userName string, dbID int, isGuest bool, socket *websocke r.mux.Unlock() return errors.New("The room '" + r.name + "' is full") } - // CHECK IF THE ROOM IS PRIVATE, OWNER JOINS FREELY if r.private && userName != r.owner { - // IF SO, CHECK IF THIS USER IS ON THE INVITE LIST + // IF PRIVATE AND NOT OWNER, CHECK IF THIS USER IS ON THE INVITE LIST if len(r.inviteList) > 0 { for i := 0; i < len(r.inviteList); i++ { if (r.inviteList)[i] == userName { @@ -251,64 +229,69 @@ func (r *Room) AddUser(userName string, dbID int, isGuest bool, socket *websocke } // CHECK IF USER IS ALREADY IN THE ROOM - var roomUserExists bool = false - if rUser, ok := r.usersMap[userName]; ok { - roomUserExists = true + var ru *RoomUser + if u, ok := r.usersMap[userName]; ok { + ru = u if !multiConnect { r.mux.Unlock() return errors.New("User '" + userName + "' is already in room '" + r.name + "'") } - (*rUser.mux).Lock() - if _, ok := rUser.conns[connID]; ok { + u.mux.Lock() + if _, ok := u.conns[connID]; ok { r.mux.Unlock() - (*rUser.mux).Unlock() + u.mux.Unlock() return errors.New("User '" + userName + "' is already in room '" + r.name + "'") } - (*rUser.mux).Unlock() + u.mux.Unlock() } - userList := r.usersMap - newConn := roomUserConn{socket: socket, roomIn: roomIn, vars: userVars} // ADD User TO ROOM - if roomUserExists { - (*r.usersMap[userName]).conns[connID] = &newConn + c := user.getConn(connID) + if c == nil { + r.mux.Unlock() + return errors.New("Invalid connection ID") + } + if ru != nil { + (*r.usersMap[userName]).mux.Lock() + (*r.usersMap[userName]).conns[connID] = c + (*r.usersMap[userName]).mux.Unlock() } else { - conns := make(map[string]*roomUserConn) - conns[connID] = &newConn - newUser := RoomUser{name: userName, isGuest: isGuest, dbID: dbID, mux: userMux, conns: conns} + conns := make(map[string]*userConn) + conns[connID] = c + newUser := RoomUser{user: user, conns: conns} r.usersMap[userName] = &newUser + ru = r.usersMap[userName] } r.mux.Unlock() - // CHANGE USER'S ROOM - (*userMux).Lock() - *roomIn = r - (*userMux).Unlock() - + user.mux.Lock() + c.room = r + user.mux.Unlock() // roomType := roomTypes[r.rType] if roomType.BroadcastUserEnter() { //BROADCAST ENTER TO USERS IN ROOM - message := make(map[string]interface{}) + message := make(map[string]map[string]interface{}) message[helpers.ServerActionUserEnter] = make(map[string]interface{}) - message[helpers.ServerActionUserEnter].(map[string]interface{})["u"] = userName - message[helpers.ServerActionUserEnter].(map[string]interface{})["g"] = isGuest - for _, u := range userList { + message[helpers.ServerActionUserEnter]["u"] = userName + message[helpers.ServerActionUserEnter]["g"] = user.isGuest + for _, u := range r.usersMap { u.mux.Lock() - for _, conn := range u.conns { - (*conn).socket.WriteJSON(message) + if u.user.Name() != userName { + for _, conn := range u.conns { + (*conn).socket.WriteJSON(message) + } } u.mux.Unlock() } } - // CALLBACK if roomType.HasUserEnterCallback() { - roomType.UserEnterCallback()(r, userName) + roomType.UserEnterCallback()(r, ru) } // SEND RESPONSE TO CLIENT - clientResp := helpers.MakeClientResponse(helpers.ClientActionJoinRoom, r.Name(), helpers.NewError("", 0)) - socket.WriteJSON(clientResp) + clientResp := helpers.MakeClientResponse(helpers.ClientActionJoinRoom, r.Name(), helpers.NoError()) + c.socket.WriteJSON(clientResp) // return nil @@ -321,10 +304,11 @@ func (r *Room) AddUser(userName string, dbID int, isGuest bool, socket *websocke // RemoveUser removes a User from the room. If you are using MultiConnect in ServerSettings, the connID // parameter is the connection ID associated with one of the connections attached to that User. This must // be provided when removing a User from a Room with MultiConnect enabled. Otherwise, an empty string can be used. -func (r *Room) RemoveUser(userName string, connID string) error { +func (r *Room) RemoveUser(user *User, connID string) error { + userName := user.Name() //REJECT INCORRECT INPUT - if len(userName) == 0 { - return errors.New("*Room.RemoveUser() requires a user name") + if user == nil || len(userName) == 0 { + return errors.New("*Room.RemoveUser() requires a valid user") } else if multiConnect && len(connID) == 0 { return errors.New("Must provide a connID when MultiConnect is enabled") } else if !multiConnect { @@ -340,16 +324,19 @@ func (r *Room) RemoveUser(userName string, connID string) error { r.mux.Unlock() return errors.New("User '" + userName + "' is not in room '" + r.name + "'") } - if _, ok := (*r.usersMap[userName]).conns[connID]; !ok { + ru := r.usersMap[userName] + ru.mux.Lock() + if _, ok := ru.conns[connID]; !ok { r.mux.Unlock() + ru.mux.Unlock() return errors.New("Invalid connID") } - uConn := *((*r.usersMap[userName]).conns[connID]) - uMux := (*r.usersMap[userName]).mux - delete((*r.usersMap[userName]).conns, connID) - if len((*r.usersMap[userName]).conns) == 0 { + uConn := ru.conns[connID] + delete(ru.conns, connID) + if len(ru.conns) == 0 { delete(r.usersMap, userName) } + ru.mux.Unlock() userList := r.usersMap r.mux.Unlock() // @@ -363,9 +350,9 @@ func (r *Room) RemoveUser(userName string, connID string) error { } } else if roomType.BroadcastUserLeave() { //CONSTRUCT LEAVE MESSAGE - message := make(map[string]interface{}) + message := make(map[string]map[string]interface{}) message[helpers.ServerActionUserLeave] = make(map[string]interface{}) - message[helpers.ServerActionUserLeave].(map[string]interface{})["u"] = userName + message[helpers.ServerActionUserLeave]["u"] = userName //SEND MESSAGE TO USERS for _, u := range userList { @@ -378,17 +365,17 @@ func (r *Room) RemoveUser(userName string, connID string) error { } // CHANGE USER'S ROOM - uMux.Lock() - *(uConn.roomIn) = nil - uMux.Unlock() + user.mux.Lock() + uConn.room = nil + user.mux.Unlock() //CALLBACK if roomType.HasUserLeaveCallback() { - roomType.UserLeaveCallback()(r, userName) + roomType.UserLeaveCallback()(r, ru) } //SEND RESPONSE TO CLIENT - clientResp := helpers.MakeClientResponse(helpers.ClientActionLeaveRoom, r.Name(), helpers.NewError("", 0)) + clientResp := helpers.MakeClientResponse(helpers.ClientActionLeaveRoom, r.Name(), helpers.NoError()) uConn.socket.WriteJSON(clientResp) // @@ -402,10 +389,10 @@ func (r *Room) RemoveUser(userName string, connID string) error { // AddInvite adds a User to a private Room's invite list. This is only meant for internal Gopher Game Server mechanics. // If you want a User to invite someone to a private room, use the *User.Invite() function instead. // -// NOTE: You can use this function safely, but remember that private rooms are designed to have an "owner", +// NOTE: Remember that private rooms are designed to have an "owner", // and only the owner should be able to send an invite and revoke an invitation for their Rooms. Also, *User.Invite() -// will send an invite message to the invited User that the client API can easily receive. Though if you wish to make -// your own implementations for this, don't hesitate! +// will send an invite notification message to the invited User that the client API can easily receive. Though if you wish to make +// your own implementations for sending and recieving these notifications, this function is safe to use. func (r *Room) AddInvite(userName string) error { if !r.private { return errors.New("Room is not private") @@ -435,14 +422,12 @@ func (r *Room) AddInvite(userName string) error { // REMOVE FROM inviteList ///////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// RemoveInvite removes a User from a private Room's invite list. +// RemoveInvite removes a User from a private Room's invite list. To make a User remove someone from their room themselves, +// use the *User.RevokeInvite() function. // // NOTE: You can use this function safely, but remember that private rooms are designed to have an "owner", // and only the owner should be able to send an invite and revoke an invitation for their Rooms. But if you find the // need to break the rules here, by all means do so! -// -// WARNING: This is only meant for internal Gopher Game Server mechanics. If you want a User to remove someone from the room's -// private invite list, use the *User.RevokeInvite() function instead. func (r *Room) RemoveInvite(userName string) error { if !r.private { return errors.New("Room is not private") @@ -458,7 +443,8 @@ func (r *Room) RemoveInvite(userName string) error { } for i := 0; i < len(r.inviteList); i++ { if r.inviteList[i] == userName { - r.inviteList = append(r.inviteList[:i], r.inviteList[i+1:]...) + r.inviteList[i] = r.inviteList[len(r.inviteList)-1] + r.inviteList = r.inviteList[:len(r.inviteList)-1] break } if i == len(r.inviteList)-1 { @@ -559,77 +545,21 @@ func (r *Room) NumUsers() int { // RoomUser ATTRIBUTE READERS ///////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Name gets the name of the RoomUser. -func (u *RoomUser) Name() string { - return u.name -} - -// IsGuest returns true if the RoomUser is a guest. -func (u *RoomUser) IsGuest() bool { - return u.isGuest -} - -// DatabaseID gets the database index of the RoomUser. -func (u *RoomUser) DatabaseID() int { - return u.dbID -} - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// SERVER STARTUP FUNCTIONS /////////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -// SetServerStarted is for Gopher Game Server internal mechanics. -func SetServerStarted(val bool) { - if !serverStarted { - serverStarted = val - } -} - -// SettingsSet is for Gopher Game Server internal mechanics. -func SettingsSet(name string, deleteOnLeave bool, multiConn bool) { - if !serverStarted { - serverName = name - deleteRoomOnLeave = deleteOnLeave - multiConnect = multiConn - } +// User gets the *User object of a *RoomUser. +func (u *RoomUser) User() *User { + return u.user } -////////////////////////////////////////////////////////////////////////////////////////////////////// -// SERVER PAUSE AND RESUME /////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////////////////////////// - -// Pause is only for internal Gopher Game Server mechanics. -func Pause() { - if !serverPaused { - serverPaused = true - serverStarted = false - } -} - -// Resume is only for internal Gopher Game Server mechanics. -func Resume() { - if serverPaused { - serverStarted = true - serverPaused = false - } -} - -// GetState is only for internal Gopher Game Server mechanics. -func GetState() map[string]interface{} { - state := make(map[string]interface{}) - roomsMux.Lock() - for _, room := range rooms { - room.mux.Lock() - state[room.name] = make(map[string]interface{}) - state[room.name].(map[string]interface{})["t"] = room.rType - state[room.name].(map[string]interface{})["p"] = room.private - state[room.name].(map[string]interface{})["o"] = room.owner - state[room.name].(map[string]interface{})["m"] = room.maxUsers - state[room.name].(map[string]interface{})["i"] = room.inviteList - state[room.name].(map[string]interface{})["v"] = room.vars - room.mux.Unlock() - } - roomsMux.Unlock() - // - return state +// ConnectionIDs returns a []string of all the RoomUser's connection IDs. With MultiConnect in ServerSettings enabled, +// this will give you all the connections for this User that are currently in the Room. Otherwise, if you want +// all the User's connection IDs (not just the connections in the specified Room), use *User.ConnectionIDs() after getting +// the *User object with the *RoomUser.User() function. +func (u *RoomUser) ConnectionIDs() []string { + u.mux.Lock() + ids := make([]string, 0, len(u.conns)) + for id := range u.conns { + ids = append(ids, id) + } + u.mux.Unlock() + return ids } diff --git a/users/users.go b/core/users.go similarity index 82% rename from users/users.go rename to core/users.go index 549333c..d3bec8b 100644 --- a/users/users.go +++ b/core/users.go @@ -1,15 +1,29 @@ -// Package users contains all the necessary tools to make and working with Users. A User is a client -// who has successfully logged into the server. You can think of clients who are not attached to a User +// Package core contains all the tools to make and work with Users and Rooms. +// +// A User is a client who has successfully logged into the server. You can think of clients who are not attached to a User // as, for instance, someone in the login screen, but are still connected to the server. A client doesn't -// have to be a User to be able to call your CustomClientActions, so keep that in mind when making them! -package users +// have to be a User to be able to call your CustomClientActions, so keep that in mind when making them (Refer to the Usage for CustomClientActions). +// +// Users have their own variables which can be accessed and changed anytime. A User variable can +// be anything compatible with interface{}, so pretty much anything. +// +// A Room represents a place on the server where a User can join other Users. Rooms can either be public or private. Private Rooms must be assigned an "owner", which is the name of a User, or the ServerName +// from ServerSettings. The server's name that will be used for ownership of private Rooms can be set with the ServerSettings +// option ServerName when starting the server. Though keep in mind, setting the ServerName in ServerSettings will prevent a User who wants to go by that name +// from logging in. Public Rooms will accept a join request from any User, and private Rooms will only +// accept a join request from someone who is on it's invite list. Only the owner of the Room or the server itself can invite +// Users to a private Room. But remember, just because a User owns a private room doesn't mean the server cannot also invite +// to the room via *Room.AddInvite() function. +// +// Rooms have their own variables which can be accessed and changed anytime. Like User variables, a Room variable can +// be anything compatible with interface{}. +package core import ( "errors" "github.com/gorilla/websocket" "github.com/hewiefreeman/GopherGameServer/database" "github.com/hewiefreeman/GopherGameServer/helpers" - "github.com/hewiefreeman/GopherGameServer/rooms" "sync" ) @@ -38,12 +52,14 @@ type User struct { } type userConn struct { - //MUST LOCK clientMux WHEN GETTING/SETTING *user + //MUST LOCK *clientMux WHEN GETTING/SETTING *user clientMux *sync.Mutex user **User socket *websocket.Conn - room *rooms.Room + + //MUST LOCK User's mux FIRST + room *Room vars map[string]interface{} } @@ -51,15 +67,6 @@ var ( users map[string]*User = make(map[string]*User) usersMux sync.Mutex - serverStarted bool = false - serverPaused bool = false - - serverName string - kickOnLogin bool = false - sqlFeatures bool = false - rememberMe bool = false - multiConnect bool = false - // LoginCallback is only for internal Gopher Game Server mechanics. LoginCallback func(string, int, map[string]interface{}, map[string]interface{}) bool // LogoutCallback is only for internal Gopher Game Server mechanics. @@ -133,14 +140,14 @@ func Login(userName string, dbID int, autologPass string, isGuest bool, remMe bo userRoom := (*conn).room if userRoom != nil && userRoom.Name() != "" { userOnline.mux.Unlock() - userRoom.RemoveUser(userOnline.name, connKey) + userRoom.RemoveUser(userOnline, connKey) userOnline.mux.Lock() } (*(*conn).clientMux).Lock() *((*conn).user) = nil (*(*conn).clientMux).Unlock() //SEND LOGOUT MESSAGE TO CLIENT - clientResp := helpers.MakeClientResponse(helpers.ClientActionLogout, nil, helpers.NewError("", 0)) + clientResp := helpers.MakeClientResponse(helpers.ClientActionLogout, nil, helpers.NoError()) (*conn).socket.WriteJSON(clientResp) } userOnline.mux.Unlock() @@ -246,13 +253,13 @@ func Login(userName string, dbID int, autologPass string, isGuest bool, remMe bo usersMux.Unlock() //SEND ONLINE MESSAGE TO FRIENDS - statusMessage := make(map[string]interface{}) + statusMessage := make(map[string]map[string]interface{}) statusMessage[helpers.ServerActionFriendStatusChange] = make(map[string]interface{}) - statusMessage[helpers.ServerActionFriendStatusChange].(map[string]interface{})["n"] = userName - statusMessage[helpers.ServerActionFriendStatusChange].(map[string]interface{})["s"] = 0 + statusMessage[helpers.ServerActionFriendStatusChange]["n"] = userName + statusMessage[helpers.ServerActionFriendStatusChange]["s"] = 0 for key, val := range friendsMap { if val.RequestStatus() == database.FriendStatusAccepted { - friend, friendErr := Get(key) + friend, friendErr := GetUser(key) if friendErr == nil { friend.mux.Lock() for _, friendConn := range friend.conns { @@ -271,11 +278,11 @@ func Login(userName string, dbID int, autologPass string, isGuest bool, remMe bo responseVal["ai"] = dbID responseVal["ap"] = autologPass } - clientResp := helpers.MakeClientResponse(helpers.ClientActionLogin, responseVal, helpers.NewError("", 0)) + clientResp := helpers.MakeClientResponse(helpers.ClientActionLogin, responseVal, helpers.NoError()) socket.WriteJSON(clientResp) // - return connID, helpers.NewError("", 0) + return connID, helpers.NoError() } ////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -303,7 +310,7 @@ func AutoLogIn(tag string, pass string, newPass string, dbID int, conn *websocke return "", userErr } // - return connID, helpers.NewError("", 0) + return connID, helpers.NoError() } ////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -329,19 +336,19 @@ func (u *User) Logout(connID string) { currRoom := (*u.conns[connID]).room if currRoom != nil && currRoom.Name() != "" { u.mux.Unlock() - currRoom.RemoveUser(u.name, connID) + currRoom.RemoveUser(u, connID) u.mux.Lock() } if len(u.conns) == 1 { //SEND STATUS CHANGE TO FRIENDS - statusMessage := make(map[string]interface{}) + statusMessage := make(map[string]map[string]interface{}) statusMessage[helpers.ServerActionFriendStatusChange] = make(map[string]interface{}) - statusMessage[helpers.ServerActionFriendStatusChange].(map[string]interface{})["n"] = u.name - statusMessage[helpers.ServerActionFriendStatusChange].(map[string]interface{})["s"] = StatusOffline + statusMessage[helpers.ServerActionFriendStatusChange]["n"] = u.name + statusMessage[helpers.ServerActionFriendStatusChange]["s"] = StatusOffline for key, val := range u.friends { if val.RequestStatus() == database.FriendStatusAccepted { - friend, friendErr := Get(key) + friend, friendErr := GetUser(key) if friendErr == nil { friend.mux.Lock() for _, friendConn := range friend.conns { @@ -371,7 +378,7 @@ func (u *User) Logout(connID string) { } //SEND RESPONSE TO CLIENT - clientResp := helpers.MakeClientResponse(helpers.ClientActionLogout, nil, helpers.NewError("", 0)) + clientResp := helpers.MakeClientResponse(helpers.ClientActionLogout, nil, helpers.NoError()) socket.WriteJSON(clientResp) //RUN CALLBACK @@ -385,13 +392,13 @@ func (u *User) Kick() { u.mux.Lock() //SEND STATUS CHANGE TO FRIENDS - statusMessage := make(map[string]interface{}) + statusMessage := make(map[string]map[string]interface{}) statusMessage[helpers.ServerActionFriendStatusChange] = make(map[string]interface{}) - statusMessage[helpers.ServerActionFriendStatusChange].(map[string]interface{})["n"] = u.name - statusMessage[helpers.ServerActionFriendStatusChange].(map[string]interface{})["s"] = StatusOffline + statusMessage[helpers.ServerActionFriendStatusChange]["n"] = u.name + statusMessage[helpers.ServerActionFriendStatusChange]["s"] = StatusOffline for key, val := range u.friends { if val.RequestStatus() == database.FriendStatusAccepted { - friend, friendErr := Get(key) + friend, friendErr := GetUser(key) if friendErr == nil { friend.mux.Lock() for _, friendConn := range friend.conns { @@ -403,7 +410,7 @@ func (u *User) Kick() { } //MAKE CLIENT RESPONSE - clientResp := helpers.MakeClientResponse(helpers.ClientActionLogout, nil, helpers.NewError("", 0)) + clientResp := helpers.MakeClientResponse(helpers.ClientActionLogout, nil, helpers.NoError()) //LOOP THROUGH CONNECTIONS for connID, conn := range u.conns { @@ -411,7 +418,7 @@ func (u *User) Kick() { currRoom := (*conn).room if currRoom != nil && currRoom.Name() != "" { u.mux.Unlock() - currRoom.RemoveUser(u.name, connID) + currRoom.RemoveUser(u, connID) u.mux.Lock() } @@ -443,8 +450,8 @@ func (u *User) Kick() { // GET A USER //////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////// -// Get finds a logged in User by their name. Returns an error if the User is not online. -func Get(userName string) (*User, error) { +// GetUser finds a logged in User by their name. Returns an error if the User is not online. +func GetUser(userName string) (*User, error) { //REJECT INCORRECT INPUT if len(userName) == 0 { return &User{}, errors.New("users.Get() requires a user name") @@ -473,7 +480,7 @@ func Get(userName string) (*User, error) { // Join makes a User join a Room. If you are using MultiConnect in ServerSettings, the connID // parameter is the connection ID associated with one of the connections attached to that User. This must // be provided when making a User join a Room with MultiConnect enabled. Otherwise, an empty string can be used. -func (u *User) Join(r *rooms.Room, connID string) error { +func (u *User) Join(r *Room, connID string) error { if multiConnect && len(connID) == 0 { return errors.New("Must provide a connID when MultiConnect is enabled") } else if !multiConnect { @@ -494,14 +501,10 @@ func (u *User) Join(r *rooms.Room, connID string) error { u.Leave(connID) u.mux.Lock() } - roomPointer := &((*u.conns[connID]).room) - varsPointer := &((*u.conns[connID]).vars) - socketPointer := ((*u.conns[connID]).socket) - statusPointer := &u.status u.mux.Unlock() //ADD USER TO DESIGNATED ROOM - addErr := r.AddUser(u.name, u.databaseID, u.isGuest, socketPointer, roomPointer, varsPointer, statusPointer, &u.mux, connID) + addErr := r.AddUser(u, connID) if addErr != nil { return addErr } @@ -528,7 +531,7 @@ func (u *User) Leave(connID string) error { currRoom := (*u.conns[connID]).room u.mux.Unlock() if currRoom != nil && currRoom.Name() != "" { - removeErr := currRoom.RemoveUser(u.name, connID) + removeErr := currRoom.RemoveUser(u, connID) if removeErr != nil { return removeErr } @@ -553,13 +556,13 @@ func (u *User) SetStatus(status int) { u.mux.Unlock() //SEND STATUS CHANGE MESSAGE TO User's FRIENDS WHOM ARE "ACCEPTED" - message := make(map[string]interface{}) + message := make(map[string]map[string]interface{}) message[helpers.ServerActionFriendStatusChange] = make(map[string]interface{}) - message[helpers.ServerActionFriendStatusChange].(map[string]interface{})["n"] = u.name - message[helpers.ServerActionFriendStatusChange].(map[string]interface{})["s"] = status + message[helpers.ServerActionFriendStatusChange]["n"] = u.name + message[helpers.ServerActionFriendStatusChange]["s"] = status for key, val := range friends { if val.RequestStatus() == database.FriendStatusAccepted { - friend, friendErr := Get(key) + friend, friendErr := GetUser(key) if friendErr == nil { friend.mux.Lock() for _, conn := range friend.conns { @@ -593,7 +596,7 @@ func (u *User) Invite(invUser *User, connID string) error { } currRoom := (*u.conns[connID]).room u.mux.Unlock() - rType := rooms.GetRoomTypes()[currRoom.Type()] + rType := GetRoomTypes()[currRoom.Type()] if currRoom == nil || currRoom.Name() == "" { return errors.New("The user '" + u.name + "' is not in a room") } else if !currRoom.IsPrivate() { @@ -611,10 +614,10 @@ func (u *User) Invite(invUser *User, connID string) error { } //MAKE INVITE MESSAGE - invMessage := make(map[string]interface{}) + invMessage := make(map[string]map[string]interface{}) invMessage[helpers.ServerActionRoomInvite] = make(map[string]interface{}) - invMessage[helpers.ServerActionRoomInvite].(map[string]interface{})["u"] = u.name - invMessage[helpers.ServerActionRoomInvite].(map[string]interface{})["r"] = currRoom.Name() + invMessage[helpers.ServerActionRoomInvite]["u"] = u.name + invMessage[helpers.ServerActionRoomInvite]["r"] = currRoom.Name() //SEND MESSAGE invUser.mux.Lock() @@ -649,7 +652,7 @@ func (u *User) RevokeInvite(revokeUser string, connID string) error { } currRoom := (*u.conns[connID]).room u.mux.Unlock() - rType := rooms.GetRoomTypes()[currRoom.Type()] + rType := GetRoomTypes()[currRoom.Type()] if currRoom == nil || currRoom.Name() == "" { return errors.New("The user '" + u.name + "' is not in a room") } else if !currRoom.IsPrivate() { @@ -707,7 +710,7 @@ func (u *User) Friends() map[string]database.Friend { // RoomIn gets the Room that the User is currently in. A nil Room pointer means the User is not in a Room. If you are using MultiConnect in ServerSettings, the connID // parameter is the connection ID associated with one of the connections attached to that User. This must // be provided when getting a User's Room with MultiConnect enabled. Otherwise, an empty string can be used. -func (u *User) RoomIn(connID string) *rooms.Room { +func (u *User) RoomIn(connID string) *Room { if multiConnect && len(connID) == 0 { return nil } else if !multiConnect { @@ -760,76 +763,9 @@ func (u *User) ConnectionIDs() []string { return ids } -////////////////////////////////////////////////////////////////////////////////////////////////////// -// SERVER STARTUP FUNCTIONS ////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////////////////////////// - -// SetServerStarted is for Gopher Game Server internal mechanics only. -func SetServerStarted(val bool) { - if !serverStarted { - serverStarted = val - } -} - -// SettingsSet is for Gopher Game Server internal mechanics only. -func SettingsSet(kickDups bool, name string, deleteOnLeave bool, sqlFeat bool, remMe bool, multiConn bool) { - if !serverStarted { - kickOnLogin = kickDups - serverName = name - sqlFeatures = sqlFeat - rememberMe = remMe - multiConnect = multiConn - rooms.SettingsSet(name, deleteOnLeave, multiConn) - } -} - -////////////////////////////////////////////////////////////////////////////////////////////////////// -// SERVER PAUSE AND RESUME /////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////////////////////////// - -// Pause is only for internal Gopher Game Server mechanics. -func Pause() { - if !serverPaused { - serverPaused = true - - // - clientResp := helpers.MakeClientResponse(helpers.ClientActionLogout, nil, helpers.NewError("", 0)) - usersMux.Lock() - for _, user := range users { - (*user).mux.Lock() - for connID, conn := range (*user).conns { - //REMOVE CONNECTION FROM THEIR ROOM - currRoom := (*conn).room - if currRoom != nil && currRoom.Name() != "" { - (*user).mux.Unlock() - currRoom.RemoveUser((*user).name, connID) - (*user).mux.Lock() - } - - //LOG CONNECTION OUT - (*conn).clientMux.Lock() - if *((*conn).user) != nil { - *((*conn).user) = nil - } - (*conn).clientMux.Unlock() - - //SEND LOG OUT MESSAGE - (*conn).socket.WriteJSON(clientResp) - } - (*user).mux.Unlock() - } - users = make(map[string]*User) - usersMux.Unlock() - - // - serverStarted = false - } -} - -// Resume is only for internal Gopher Game Server mechanics. -func Resume() { - if serverPaused { - serverStarted = true - serverPaused = false - } +func (u *User) getConn(connID string) *userConn { + u.mux.Lock() + conn := u.conns[connID] + u.mux.Unlock() + return conn } diff --git a/users/vars.go b/core/vars.go similarity index 65% rename from users/vars.go rename to core/vars.go index 8ee6022..4b8e1b9 100644 --- a/users/vars.go +++ b/core/vars.go @@ -1,7 +1,8 @@ -package users +package core import ( "github.com/hewiefreeman/GopherGameServer/helpers" + "errors" ) /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -32,7 +33,7 @@ func (u *User) SetVariable(key string, value interface{}, connID string) { } (*u.conns[connID]).vars[key] = value //SEND RESPONSE TO CLIENT - clientResp := helpers.MakeClientResponse(helpers.ClientActionSetVariable, resp, helpers.NewError("", 0)) + clientResp := helpers.MakeClientResponse(helpers.ClientActionSetVariable, resp, helpers.NoError()) (*u.conns[connID]).socket.WriteJSON(clientResp) u.mux.Unlock() } @@ -58,7 +59,7 @@ func (u *User) SetVariables(values map[string]interface{}, connID string) { (*u.conns[connID]).vars[key] = val } //SEND RESPONSE TO CLIENT - clientResp := helpers.MakeClientResponse(helpers.ClientActionSetVariables, values, helpers.NewError("", 0)) + clientResp := helpers.MakeClientResponse(helpers.ClientActionSetVariables, values, helpers.NoError()) (*u.conns[connID]).socket.WriteJSON(clientResp) u.mux.Unlock() } @@ -99,3 +100,82 @@ func (u *User) GetVariables(keys []string, connID string) map[string]interface{} // return value } + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// ROOM VARIABLES ///////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +// SetVariable sets a Room variable. +func (r *Room) SetVariable(key string, value interface{}) { + //REJECT INCORRECT INPUT + if len(key) == 0 { + return + } + + r.mux.Lock() + if r.usersMap == nil { + r.mux.Unlock() + return + } + r.vars[key] = value + r.mux.Unlock() + + // + return +} + +// SetVariables sets all the specified Room variables at once. +func (r *Room) SetVariables(values map[string]interface{}) { + r.mux.Lock() + if r.usersMap == nil { + r.mux.Unlock() + return + } + for key, val := range values { + r.vars[key] = val + } + r.mux.Unlock() + + // + return +} + +// GetVariable gets one of the Room's variables. +func (r *Room) GetVariable(key string) (interface{}, error) { + //REJECT INCORRECT INPUT + if len(key) == 0 { + return nil, errors.New("*Room.GetVariable() requires a key") + } + + r.mux.Lock() + if r.usersMap == nil { + r.mux.Unlock() + return nil, errors.New("Room '" + r.name + "' does not exist") + } + value := r.vars[key] + r.mux.Unlock() + + // + return value, nil +} + +// GetVariables gets all the specified (or all if not) Room variables as a map[string]interface{}. +func (r *Room) GetVariables(keys []string) (map[string]interface{}, error) { + var value map[string]interface{} = make(map[string]interface{}) + r.mux.Lock() + if r.usersMap == nil { + r.mux.Unlock() + return nil, errors.New("Room '" + r.name + "' does not exist") + } + if keys == nil || len(keys) == 0 { + value = r.vars + } else { + for i := 0; i < len(keys); i++ { + value[keys[i]] = r.vars[keys[i]] + } + } + r.mux.Unlock() + + // + return value, nil +} diff --git a/database/authentication.go b/database/authentication.go index d292139..632e04c 100644 --- a/database/authentication.go +++ b/database/authentication.go @@ -4,7 +4,6 @@ import ( "errors" "github.com/hewiefreeman/GopherGameServer/helpers" "strconv" - "database/sql" ) var ( @@ -153,6 +152,12 @@ func checkCustomRequirements(customCols map[string]interface{}, requirements map return true } +////////////////////////////////////////////////////////////////////////////////////////////////////// +// QUERY HELPERS ///////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////////// + + + ////////////////////////////////////////////////////////////////////////////////////////////////////// // SIGN A USER UP //////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -186,18 +191,7 @@ func SignUpClient(userName string, password string, customCols map[string]interf var vals []interface{} //CREATE PART 1 OF QUERY - var queryPart1 string - var shard *DBShard - var err error - if shardingInit { - shard, err = GetUserShard(helpers.UserHashNumber(userName)) - if err != nil { - return helpers.NewError(err.Error(), helpers.ErrorAuthUnexpected) - } - queryPart1 = "INSERT INTO " + usersShardPrefix + strconv.Itoa(shard.ID()) + " (" + usersColumnName + ", " + usersColumnPassword + ", " - }else{ - queryPart1 = "INSERT INTO " + tableUsers + " (" + usersColumnName + ", " + usersColumnPassword + ", " - } + queryPart1 := "INSERT INTO " + tableUsers + " (" + usersColumnName + ", " + usersColumnPassword + ", " if customCols != nil { vals = make([]interface{}, 0, len(customCols)) @@ -240,25 +234,14 @@ func SignUpClient(userName string, password string, customCols map[string]interf queryPart2 = queryPart2[0:len(queryPart2)-2] + ");" - var insertErr error - if shardingInit { - // GET MASTER OR NEXT HEALTHY REPLICA - var r *DBReplica = shard.Master() - if r == nil { - return helpers.NewError(errorNoShardFound, helpers.ErrorAuthUnexpected) - } - //EXECUTE QUERY - _, insertErr = r.Conn().Exec(queryPart1 + queryPart2) - } else { - //EXECUTE QUERY - _, insertErr = database.Exec(queryPart1 + queryPart2) - } + //EXECUTE QUERY + _, insertErr := database.Exec(queryPart1 + queryPart2) if insertErr != nil { return helpers.NewError(insertErr.Error(), helpers.ErrorAuthQuery) } // - return helpers.NewError("", 0) + return helpers.NoError() } ////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -282,17 +265,6 @@ func LoginClient(userName string, password string, deviceTag string, remMe bool, return "", 0, "", helpers.NewError(errorIncorrectCols, helpers.ErrorAuthIncorrectCols) } - // GET SHARD - var shard *DBShard - var err error - hashNum := helpers.UserHashNumber(userName) - if shardingInit { - shard, err = GetUserShard(hashNum) - if err != nil { - return "", 0, "", helpers.NewError(err.Error(), helpers.ErrorAuthUnexpected) - } - } - //FIRST THREE ARE id, password, name IN THAT ORDER var vals []interface{} @@ -318,24 +290,11 @@ func LoginClient(userName string, password string, deviceTag string, remMe bool, if len(customLoginColumn) > 0 { loginCol = customLoginColumn } - if shardingInit { - tableName = usersShardPrefix + strconv.Itoa(shard.ID()) - } selectQuery = selectQuery[0:len(selectQuery)-2] + " FROM " + tableName + " WHERE " + loginCol + "=\"" + userName + "\" LIMIT 1;" //EXECUTE SELECT QUERY - var checkRows *sql.Rows - if shardingInit { - // GET REPLICA - var r *DBReplica = shard.GetReplica() - if r == nil { - return "", 0, "", helpers.NewError(errorNoShardFound, helpers.ErrorAuthUnexpected) - } - checkRows, err = r.Conn().Query(selectQuery) - } else { - checkRows, err = database.Query(selectQuery) - } + checkRows, err := database.Query(selectQuery) if err != nil { return "", 0, "", helpers.NewError(errorIncorrectLogin, helpers.ErrorAuthIncorrectLogin) } @@ -383,25 +342,8 @@ func LoginClient(userName string, password string, deviceTag string, remMe bool, //MAKE AUTO-LOG ENTRY devicePass, devicePassErr = helpers.GenerateSecureString(32) if devicePassErr == nil { - var exErr error - if shardingInit { - // GET AUTOLOG SHARD/MASTER - shard, err = GetAutologShard(hashNum) - if err == nil { - var r *DBReplica = shard.Master() - if r != nil { - _, exErr = r.Conn().Exec("INSERT INTO " + autologShardPrefix + strconv.Itoa(shard.ID()) + " (" + autologsColumnID + ", " + autologsColumnDeviceTag + ", " + autologsColumnDevicePass + - ") VALUES (" + strconv.Itoa(hashNum) + ", \"" + deviceTag + "\", \"" + devicePass + "\");") - } else { - ///// LOG ERROR!!!! - } - } else { - ////// LOG ERROR!!!!!!! - } - } else { - _, exErr = database.Exec("INSERT INTO " + tableAutologs + " (" + autologsColumnID + ", " + autologsColumnDeviceTag + ", " + autologsColumnDevicePass + + _, exErr := database.Exec("INSERT INTO " + tableAutologs + " (" + autologsColumnID + ", " + autologsColumnDeviceTag + ", " + autologsColumnDevicePass + ") VALUES (" + strconv.Itoa(*dbIndex) + ", \"" + deviceTag + "\", \"" + devicePass + "\");") - } if exErr != nil { ////// LOG ERROR!!!!!! } @@ -411,7 +353,7 @@ func LoginClient(userName string, password string, deviceTag string, remMe bool, } // - return *uName, *dbIndex, devicePass, helpers.NewError("", 0) + return *uName, *dbIndex, devicePass, helpers.NoError() } ////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -429,23 +371,8 @@ func AutoLoginClient(tag string, pass string, newPass string, dbID int) (string, //EXECUTE SELECT QUERY var dPass string - var shard *DBShard - var err error db := database tableName := tableAutologs - if shardingInit { - // SET DB TO SHARD REPLICA - shard, err = GetAutologShard(dbID) - if err != nil { - return "", helpers.NewError(err.Error(), helpers.ErrorAuthUnexpected) - } - r := shard.GetReplica() - if r == nil { - return "", helpers.NewError(errorNoShardFound, helpers.ErrorAuthUnexpected) - } - tableName = autologShardPrefix + strconv.Itoa(shard.ID()) - db = r.Conn() - } checkRows, checkErr := db.Query("Select " + autologsColumnDevicePass + " FROM " + tableName + " WHERE " + autologsColumnID + "=" + strconv.Itoa(dbID) + " AND " + autologsColumnDeviceTag + "=\"" + tag + "\" LIMIT 1;") if checkErr != nil { @@ -467,14 +394,6 @@ func AutoLoginClient(tag string, pass string, newPass string, dbID int) (string, } //UPDATE TO NEW PASS - if shardingInit { - // SWITCH TO MASTER - r := shard.Master() - if r == nil { - return "", helpers.NewError(errorNoShardFound, helpers.ErrorAuthUnexpected) - } - db = r.Conn() - } _, updateErr := db.Exec("UPDATE " + tableName + " SET " + autologsColumnDevicePass + "=\"" + newPass + "\" WHERE " + autologsColumnID + "=" + strconv.Itoa(dbID) + " AND " + autologsColumnDeviceTag + "=\"" + tag + "\" LIMIT 1;") if updateErr != nil { @@ -483,19 +402,6 @@ func AutoLoginClient(tag string, pass string, newPass string, dbID int) (string, //EVERYTHING WENT WELL, GET THE User's NAME tableName = tableUsers - if shardingInit { - // SET DB TO SHARD REPLICA - shard, err = GetUserShard(dbID) - if err != nil { - return "", helpers.NewError(err.Error(), helpers.ErrorAuthUnexpected) - } - r := shard.GetReplica() - if r == nil { - return "", helpers.NewError(errorNoShardFound, helpers.ErrorAuthUnexpected) - } - tableName = usersShardPrefix + strconv.Itoa(shard.ID()) - db = r.Conn() - } var userName string userRows, usrErr := db.Query("Select " + usersColumnName + " FROM " + tableName + " WHERE " + usersColumnID + "=" + strconv.Itoa(dbID) + " LIMIT 1;") if usrErr != nil { @@ -515,7 +421,7 @@ func AutoLoginClient(tag string, pass string, newPass string, dbID int) (string, } // - return userName, helpers.NewError("", 0) + return userName, helpers.NoError() } ////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -629,7 +535,7 @@ func ChangePassword(userName string, password string, newPassword string, custom } // - return helpers.NewError("", 0) + return helpers.NoError() } ////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -736,7 +642,7 @@ func ChangeAccountInfo(userName string, password string, customCols map[string]i } // - return helpers.NewError("", 0) + return helpers.NoError() } ////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -827,5 +733,5 @@ func DeleteAccount(userName string, password string, customCols map[string]inter } // - return helpers.NewError("", 0) + return helpers.NoError() } diff --git a/database/database.go b/database/database.go index 7142ecc..44ed785 100644 --- a/database/database.go +++ b/database/database.go @@ -77,23 +77,19 @@ func Init(userName string, password string, dbName string, protocol string, ip s var err error //OPEN THE DATABASE - if !shardingInit { - database, err = sql.Open("mysql", userName+":"+password+"@"+protocol+"("+ip+":"+strconv.Itoa(port)+")/"+dbName) - if err != nil { - return err - } - //NOTE: Open doesn't open a connection. - //MUST PING TO CHECK IF FOUND DATABASE - err = database.Ping() - if err != nil { - return errors.New("Could not connect to database!") - } + database, err = sql.Open("mysql", userName+":"+password+"@"+protocol+"("+ip+":"+strconv.Itoa(port)+")/"+dbName) + if err != nil { + return err + } + //NOTE: Open doesn't open a connection. + //MUST PING TO CHECK IF FOUND DATABASE + err = database.Ping() + if err != nil { + return errors.New("Could not connect to database!") + } - if len(dbName) != 0 { - databaseName = dbName - } - } else { - setShardingDefaults(ip, port, protocol, userName, password) + if len(dbName) != 0 { + databaseName = dbName } //CONFIGURE DATABASE @@ -140,10 +136,9 @@ func GetUserDatabaseIndex(userName string) (int, error) { /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // SetServerStarted is for Gopher Game Server internal mechanics only. -func SetServerStarted(val bool, sharding bool) { +func SetServerStarted(val bool) { if !serverStarted { serverStarted = val - shardingInit = sharding } } diff --git a/database/sharding.go b/database/sharding.go deleted file mode 100644 index 3474052..0000000 --- a/database/sharding.go +++ /dev/null @@ -1,356 +0,0 @@ -package database - -import ( - //"github.com/hewiefreeman/GopherGameServer/helpers" - "database/sql" - "errors" - "strconv" - "sync" -) - -var ( - shardingInit bool - shardTargetEntries int = 30000 // The maximum entries a database table shard should hold in your system. This does not control the max entry count - shardPercentWarning int = 80 // - - // Table name prefixes - usersShardPrefix string = "users_" - friendsShardPrefix string = "friends_" - autologShardPrefix string = "autologs_" - - // Database shards - userShardsMux sync.Mutex - userShards map[int]*DBShard = make(map[int]*DBShard) // default trusted database shards - - friendsShardsMux sync.Mutex - friendsShards map[int]*DBShard = make(map[int]*DBShard) // dedicated friends database shards - - autologShardsMux sync.Mutex - autologShards map[int]*DBShard = make(map[int]*DBShard) // dedicated autolog database shards -) - -type DBShard struct { - master *DBReplica - - id int - - mux sync.Mutex - replicaOn int - replicas []*DBReplica -} - -type DBReplica struct { - conn *sql.DB - - id int - - ip string - port int - protocol string - user string - password string - - mux sync.Mutex - healthy bool -} - -///////////////////////////////////////////////////////////////////////////////////////// -////// INIT ///////////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////////////////// - -func ShardingInited() bool { - return shardingInit -} - -func setShardingDefaults(ip string, port int, protocol string, userName string, password string) error { - // Set default shard if no shards are set - if len(userShards) == 0 { - // Make connection to default partitions - var defaultDBs []*DBShard = make([]*DBShard, 3, 3) - for i := 0; i < 3; i++ { - defShard, shardErr := NewDBShard(ip, port, protocol, userName, password, false, i) - if shardErr != nil { - return shardErr - } - defaultDBs[i] = defShard - } - - // Append default shard to user shards - userShardsMux.Lock() - appendShards(&userShards, defaultDBs) - userShardsMux.Unlock() - } - - // - return nil -} - -///////////////////////////////////////////////////////////////////////////////////////// -////// SET-UP /////////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////////////////// - -func SetShardingTargetEntries(maxEntries int) { - if inited { - return - } - shardTargetEntries = maxEntries -} - -func SetEntriesWarningPercent(percent int) { - if inited { - return - } - shardPercentWarning = percent -} - -func AddUserShards(shards []*DBShard) { - // REQUIRES GLOBAL PAUSE (Which only master server can do) - - userShardsMux.Lock() - //prevLength := len(userShards) - appendShards(&userShards, shards) - userShardsMux.Unlock() - - // IF THIS IS MASTER, RESORT THE DATABASES - // THEN SEND COMMAND TO REST OF GAME SERVERS -} - -func AddFriendsShards(shards []*DBShard) { - // REQUIRES GLOBAL PAUSE (Which only master server can do) - - friendsShardsMux.Lock() - //prevLength := len(userShards) - appendShards(&friendsShards, shards) - friendsShardsMux.Unlock() - - // IF THIS IS MASTER, RESORT THE DATABASES - // THEN SEND COMMAND TO REST OF GAME SERVERS -} - -func AddAutologShards(shards []*DBShard) { - // REQUIRES GLOBAL PAUSE (Which only master server can do) - - autologShardsMux.Lock() - //prevLength := len(userShards) - appendShards(&autologShards, shards) - autologShardsMux.Unlock() - - // IF THIS IS MASTER, RESORT THE DATABASES - // THEN SEND COMMAND TO REST OF GAME SERVERS -} - -func appendShards(dest *map[int]*DBShard, shards []*DBShard) { - for i := 0; i < len(shards); i++ { - (*shards[i]).id = len(*dest) - (*dest)[len(*dest)] = shards[i] - } -} - -///////////////////////////////////////////////////////////////////////////////////////// -////// Shard Getters //////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////////////////// - -func GetUserShard(hashNumber int) (*DBShard, error) { - userShardsMux.Lock() - if len(userShards) == 0 { - userShardsMux.Unlock() - return nil, errors.New("No shards exist") - } - var ok bool - var s *DBShard - if s, ok = userShards[hashNumber%len(userShards)]; !ok { - userShardsMux.Unlock() - return nil, errors.New("Cannot find shard") - } - userShardsMux.Unlock() - return s, nil -} - -func GetFriendsShard(hashNumber int) (*DBShard, error) { - friendsShardsMux.Lock() - if len(friendsShards) == 0 { - friendsShardsMux.Unlock() - return GetUserShard(hashNumber) - } - var ok bool - var s *DBShard - if s, ok = friendsShards[hashNumber%len(friendsShards)]; !ok { - friendsShardsMux.Unlock() - return nil, errors.New("Cannot find shard") - } - friendsShardsMux.Unlock() - return s, nil -} - -func GetAutologShard(hashNumber int) (*DBShard, error) { - autologShardsMux.Lock() - if len(autologShards) == 0 { - autologShardsMux.Unlock() - return GetUserShard(hashNumber) - } - var ok bool - var s *DBShard - if s, ok = autologShards[hashNumber%len(autologShards)]; !ok { - autologShardsMux.Unlock() - return nil, errors.New("Cannot find shard") - } - autologShardsMux.Unlock() - return s, nil -} - -///////////////////////////////////////////////////////////////////////////////////////// -////// DBShard ////////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////////////////// - -func NewDBShard(ip string, port int, protocol string, userName string, password string, master bool, shardID int) (*DBShard, error) { - replica, replicaErr := NewDBReplica(ip, port, protocol, userName, password, 0) - if replicaErr != nil { - return nil, replicaErr - } - if master { - shard := DBShard{master: replica} - return &shard, nil - } - replicaList := []*DBReplica{replica} - shard := DBShard{replicas: replicaList} - return &shard, nil -} - -func (s *DBShard) SetMasterDB(r *DBReplica) { - if inited { - return - } - s.master = r -} - -func (s *DBShard) AddReplica(r *DBReplica) { - // REQUIRES GLOBAL PAUSE (Which only master server can do) - - s.mux.Lock() - (*r).id = len(s.replicas) - s.replicas = append(s.replicas, r) - s.mux.Unlock() - - // IF THIS IS MASTER, SEND COMMAND TO REST OF GAME SERVERS -} - -func (s *DBShard) Master() *DBReplica { - if s.master == nil { - return s.GetReplica() - } - return s.master -} - -func (s *DBShard) GetReplica() *DBReplica { - s.mux.Lock() - if len(s.replicas) == 0 { - if s.master == nil { - s.mux.Unlock() - return nil - } - return s.master - } - // GET NEXT HEALTHY REPLICA - for i := 0; i < len(s.replicas); i++ { - s.replicaOn++ - if s.replicaOn > len(s.replicas)-1 { - s.replicaOn = 0 - } - if s.replicas[s.replicaOn].Healthy() { - r := s.replicas[s.replicaOn] - s.mux.Unlock() - return r - } - } - s.mux.Unlock() - return nil -} - -func (s *DBShard) ID() int { - return s.id -} - -///////////////////////////////////////////////////////////////////////////////////////// -////// DBReplica //////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////////////////// - -func NewDBReplica(ip string, port int, protocol string, userName string, password string, replicaID int) (*DBReplica, error) { - db, err := sql.Open("mysql", userName+":"+password+"@"+protocol+"("+ip+":"+strconv.Itoa(port)+")/"+databaseName) - if err != nil { - return nil, err - } - err = db.Ping() - if err != nil { - return nil, err - } - - r := DBReplica{conn: db, ip: ip, port: port, protocol: protocol, user:userName, password: password, healthy: true} - - return &r, nil -} - -func (r *DBReplica) Conn() *sql.DB { - return r.conn -} - -func (r *DBReplica) ID() int { - return r.id -} - -func (r *DBReplica) IP() string { - return r.ip -} - -func (r *DBReplica) Port() int { - return r.port -} - -func (r *DBReplica) Protocol() string { - return r.protocol -} - -func (r *DBReplica) UserName() string { - return r.user -} - -func (r *DBReplica) Password() string { - return r.password -} - -func (r *DBReplica) Healthy() bool { - r.mux.Lock() - h := r.healthy - r.mux.Unlock() - return h -} - -func (r *DBReplica) SetHealthy(h bool) { - r.mux.Lock() - r.healthy = h - r.mux.Unlock() -} - -///////////////////////////////////////////////////////////////////////////////////////// -////// TABLE PREFIX SETTERS ///////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////////////////// - -func SetUsersTablePrefix(prefix string) { - if inited { - return - } - usersShardPrefix = prefix -} - -func SetFriendsTablePrefix(prefix string) { - if inited { - return - } - friendsShardPrefix = prefix -} - -func SetAutologTablePrefix(prefix string) { - if inited { - return - } - autologShardPrefix = prefix -} diff --git a/helpers/clientResponses.go b/helpers/clientResponses.go index 2c7f049..c2bc994 100644 --- a/helpers/clientResponses.go +++ b/helpers/clientResponses.go @@ -48,21 +48,22 @@ const ( ServerActionSetAutoLoginPass = "ap" ServerActionAutoLoginFailed = "af" ServerActionAutoLoginNotFiled = "ai" + ServerActionWebRTCOffer = "wo" ) // MakeClientResponse is used for Gopher Game Server inner mechanics only. -func MakeClientResponse(action string, responseVal interface{}, err GopherError) map[string]interface{} { - var response map[string]interface{} = make(map[string]interface{}) +func MakeClientResponse(action string, responseVal interface{}, err GopherError) map[string]map[string]interface{} { + var response map[string]map[string]interface{} = make(map[string]map[string]interface{}) if err.ID != 0 { response[ServerActionClientActionResponse] = make(map[string]interface{}) - response[ServerActionClientActionResponse].(map[string]interface{})["a"] = action - response[ServerActionClientActionResponse].(map[string]interface{})["e"] = make(map[string]interface{}) - response[ServerActionClientActionResponse].(map[string]interface{})["e"].(map[string]interface{})["m"] = err.Message - response[ServerActionClientActionResponse].(map[string]interface{})["e"].(map[string]interface{})["id"] = err.ID + response[ServerActionClientActionResponse]["a"] = action + response[ServerActionClientActionResponse]["e"] = make(map[string]interface{}) + response[ServerActionClientActionResponse]["e"].(map[string]interface{})["m"] = err.Message + response[ServerActionClientActionResponse]["e"].(map[string]interface{})["id"] = err.ID } else { response[ServerActionClientActionResponse] = make(map[string]interface{}) - response[ServerActionClientActionResponse].(map[string]interface{})["a"] = action - response[ServerActionClientActionResponse].(map[string]interface{})["r"] = responseVal + response[ServerActionClientActionResponse]["a"] = action + response[ServerActionClientActionResponse]["r"] = responseVal } // diff --git a/helpers/crypto_test.go b/helpers/crypto_test.go index 8bc0c5b..9fe9cb8 100644 --- a/helpers/crypto_test.go +++ b/helpers/crypto_test.go @@ -5,23 +5,70 @@ import ( "fmt" ) -func TestHashNumber(t *testing.T) { +/*func TestHashNumber(t *testing.T) { + // The amount of databases amount := 5 lst := make([]int, amount, amount) - for i := 0; i < 50000; i++ { - str, err := GenerateSecureString(3) + // Maximum ID + max := 4294967295 + + // Max/Min generated IDs + fullMin := 0 + fullMax := 0 + + for i := 0; i < 4000000; i++ { + str, err := GenerateSecureString(32) if err != nil { fmt.Println(err) return } - numb := UserHashNumber(str)%amount - lst[numb]++ + numb := UserHashNumber(str) + if fullMin == 0 || numb < fullMin { + fullMin = numb + } + if numb > fullMax { + fullMax = numb + } + for i := 0; i < amount; i++ { + if numb <= (max/amount)*(i+1) { + lst[i]++ + break + } + } } for i := 0; i < len(lst); i++ { fmt.Println("Database", i, "would have", lst[i], "entries") } + + fmt.Println("Min:", fullMin) + fmt.Println("Max:", fullMax) +}*/ + +func TestSameID(t *testing.T) { + names := make(map[int]string) + + fmt.Println(UserHashNumber("wBQl")) + fmt.Println(UserHashNumber("S3Sk")) + + for i := 0; i < 50000; i++ { + str, err := GenerateSecureString(3) + if err != nil { + fmt.Println(err) + return + } + + numb := UserHashNumber(str) + + if name, ok := names[numb]; ok { + if str != name { + fmt.Println("fault: '"+str+"' and '"+name+"'") + } + continue + } + names[numb] = str + } } diff --git a/macros.go b/macros.go index 533a61b..81fd45e 100644 --- a/macros.go +++ b/macros.go @@ -3,8 +3,7 @@ package gopher import ( "bufio" "fmt" - "github.com/hewiefreeman/GopherGameServer/rooms" - "github.com/hewiefreeman/GopherGameServer/users" + "github.com/hewiefreeman/GopherGameServer/core" "os" "strconv" "strings" @@ -15,8 +14,8 @@ func macroListener() { reader := bufio.NewReader(os.Stdin) fmt.Print("[Gopher] Command: ") text, _ := reader.ReadString('\n') - final := strings.TrimSpace(text) - stop := handleMacro(final) + text = strings.TrimSpace(text) + stop := handleMacro(text) if stop { return } @@ -32,9 +31,9 @@ func handleMacro(macro string) bool { ShutDown() return true } else if macro == "roomcount" { - fmt.Println("Room count: ", rooms.RoomCount()) + fmt.Println("Room count: ", core.RoomCount()) } else if macro == "usercount" { - fmt.Println("User count: ", users.UserCount()) + fmt.Println("User count: ", core.UserCount()) } else if len(macro) >= 12 && macro[0:10] == "deleteroom" { macroDeleteRoom(macro) } else if len(macro) >= 9 && macro[0:7] == "newroom" { @@ -51,7 +50,7 @@ func handleMacro(macro string) bool { func macroKick(macro string) { userName := macro[5:] - user, userErr := users.Get(userName) + user, userErr := core.GetUser(userName) if userErr != nil { fmt.Println(userErr) return @@ -75,7 +74,7 @@ func macroNewRoom(macro string) { fmt.Println("maxUsers must be an integer") return } - _, roomErr := rooms.New(s[1], s[2], isPrivate, maxUsers, "") + _, roomErr := core.NewRoom(s[1], s[2], isPrivate, maxUsers, "") if roomErr != nil { fmt.Println(roomErr) return @@ -89,7 +88,7 @@ func macroDeleteRoom(macro string) { fmt.Println("deleteroom expects 1 parameter (name string)") return } - room, roomErr := rooms.Get(s[1]) + room, roomErr := core.GetRoom(s[1]) if roomErr != nil { fmt.Println(roomErr) return @@ -109,7 +108,7 @@ func macroGetUser(macro string) { return } - user, userErr := users.Get(s[1]) + user, userErr := core.GetUser(s[1]) if userErr != nil { fmt.Println(userErr) return @@ -134,7 +133,7 @@ func macroGetRoom(macro string) { return } - room, roomErr := rooms.Get(s[1]) + room, roomErr := core.GetRoom(s[1]) if roomErr != nil { fmt.Println(roomErr) return diff --git a/rooms/vars.go b/rooms/vars.go deleted file mode 100644 index aa72ef3..0000000 --- a/rooms/vars.go +++ /dev/null @@ -1,182 +0,0 @@ -package rooms - -import ( - "errors" -) - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// ROOM VARIABLES ///////////////////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -// SetVariable sets a Room variable. -func (r *Room) SetVariable(key string, value interface{}) { - //REJECT INCORRECT INPUT - if len(key) == 0 { - return - } - - r.mux.Lock() - if r.usersMap == nil { - r.mux.Unlock() - return - } - r.vars[key] = value - r.mux.Unlock() - - // - return -} - -// SetVariables sets all the specified Room variables at once. -func (r *Room) SetVariables(values map[string]interface{}) { - r.mux.Lock() - if r.usersMap == nil { - r.mux.Unlock() - return - } - for key, val := range values { - r.vars[key] = val - } - r.mux.Unlock() - - // - return -} - -// GetVariable gets one of the Room's variables. -func (r *Room) GetVariable(key string) (interface{}, error) { - //REJECT INCORRECT INPUT - if len(key) == 0 { - return nil, errors.New("*Room.GetVariable() requires a key") - } - - r.mux.Lock() - if r.usersMap == nil { - r.mux.Unlock() - return nil, errors.New("Room '" + r.name + "' does not exist") - } - value := r.vars[key] - r.mux.Unlock() - - // - return value, nil -} - -// GetVariables gets all the specified (or all if not) Room variables as a map[string]interface{}. -func (r *Room) GetVariables(keys []string) (map[string]interface{}, error) { - var value map[string]interface{} = make(map[string]interface{}) - r.mux.Lock() - if r.usersMap == nil { - r.mux.Unlock() - return nil, errors.New("Room '" + r.name + "' does not exist") - } - if keys == nil || len(keys) == 0 { - value = r.vars - } else { - for i := 0; i < len(keys); i++ { - value[keys[i]] = r.vars[keys[i]] - } - } - r.mux.Unlock() - - // - return value, nil -} - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// USER VARIABLES ///////////////////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -// SetVariable sets a RoomUser's variable. If you are using MultiConnect in ServerSettings, the connID -// parameter is the connection ID associated with one of the connections attached to that User. This must -// be provided when manipulating a RoomUser's variables with MultiConnect enabled. Otherwise, an empty string can be used. -func (r *RoomUser) SetVariable(key string, value interface{}, connID string) { - //REJECT INCORRECT INPUT - if len(key) == 0 { - return - } else if multiConnect && len(connID) == 0 { - return - } else if !multiConnect { - connID = "1" - } - (*r.mux).Lock() - if conn, ok := r.conns[connID]; ok { - (*(*conn).vars)[key] = value - } - (*r.mux).Unlock() -} - -// SetVariables sets all the specified RoomUser's variables at once. If you are using MultiConnect in ServerSettings, the connID -// parameter is the connection ID associated with one of the connections attached to that User. This must -// be provided when manipulating a RoomUser's variables with MultiConnect enabled. Otherwise, an empty string can be used. -func (r *RoomUser) SetVariables(values map[string]interface{}, connID string) { - if multiConnect && len(connID) == 0 { - return - } else if !multiConnect { - connID = "1" - } - (*r.mux).Lock() - if conn, ok := r.conns[connID]; ok { - for key, val := range values { - (*(*conn).vars)[key] = val - } - } - (*r.mux).Unlock() -} - -// GetVariable gets a RoomUser's variable. If you are using MultiConnect in ServerSettings, the connID -// parameter is the connection ID associated with one of the connections attached to that User. This must -// be provided when manipulating a RoomUser's variables with MultiConnect enabled. Otherwise, an empty string can be used. -func (r *RoomUser) GetVariable(key string, connID string) interface{} { - //REJECT INCORRECT INPUT - if len(key) == 0 { - return nil - } else if multiConnect && len(connID) == 0 { - return nil - } else if !multiConnect { - connID = "1" - } - - var value interface{} - - (*r.mux).Lock() - if conn, ok := r.conns[connID]; ok { - value = (*(*conn).vars)[key] - } - (*r.mux).Unlock() - - // - return value -} - -// GetVariables gets all the specified (or all if not) RoomUser's variables as a map[string]interface{}. If you are using MultiConnect in ServerSettings, the connID -// parameter is the connection ID associated with one of the connections attached to that User. This must -// be provided when manipulating a RoomUser's variables with MultiConnect enabled. Otherwise, an empty string can be used. -func (r *RoomUser) GetVariables(keys []string, connID string) map[string]interface{} { - if multiConnect && len(connID) == 0 { - return nil - } else if !multiConnect { - connID = "1" - } - - var value map[string]interface{} = make(map[string]interface{}) - - if keys == nil || len(keys) == 0 { - (*r.mux).Lock() - value = *((*r.conns[connID]).vars) - (*r.mux).Unlock() - } else { - (*r.mux).Lock() - for i := 0; i < len(keys); i++ { - if conn, ok := r.conns[connID]; ok { - value[keys[i]] = (*(*conn).vars)[keys[i]] - } else { - value[keys[i]] = nil - } - } - (*r.mux).Unlock() - } - - // - return value -} diff --git a/rooms/voice.go b/rooms/voice.go deleted file mode 100644 index c8a79d6..0000000 --- a/rooms/voice.go +++ /dev/null @@ -1,45 +0,0 @@ -package rooms - -import ( - "github.com/gorilla/websocket" - "github.com/hewiefreeman/GopherGameServer/helpers" -) - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// VOICE STREAMS ////////////////////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -// VoiceStream sends a voice stream from the client API to all the users in the room besides the user who is speaking. -func (r *Room) VoiceStream(userName string, userSocket *websocket.Conn, stream interface{}) { - //GET USER MAP - userMap, err := r.GetUserMap() - if err != nil { - return - } - - //CONSTRUCT VOICE MESSAGE - theMessage := make(map[string]interface{}) - theMessage[helpers.ServerActionVoiceStream] = make(map[string]interface{}) - theMessage[helpers.ServerActionVoiceStream].(map[string]interface{})["u"] = userName - theMessage[helpers.ServerActionVoiceStream].(map[string]interface{})["d"] = stream - - //REMOVE SENDING USER FROM userMap - delete(userMap, userName) // COMMENT OUT FOR ECHO TESTS - - //SEND MESSAGE TO USERS - for _, u := range userMap { - for _, conn := range u.conns { - (*conn).socket.WriteJSON(theMessage) - } - } - - //CONSTRUCT PING MESSAGE - pingMessage := make(map[string]interface{}) - pingMessage[helpers.ServerActionVoicePing] = nil - - //SEND PING MESSAGE TO SENDING USER - userSocket.WriteJSON(pingMessage) - - // - return -} diff --git a/server.go b/server.go index 9ec2914..62f4412 100644 --- a/server.go +++ b/server.go @@ -9,10 +9,9 @@ import ( "encoding/json" "fmt" "github.com/hewiefreeman/GopherGameServer/actions" + "github.com/hewiefreeman/GopherGameServer/core" "github.com/hewiefreeman/GopherGameServer/database" "github.com/hewiefreeman/GopherGameServer/helpers" - "github.com/hewiefreeman/GopherGameServer/rooms" - "github.com/hewiefreeman/GopherGameServer/users" "io/ioutil" "net/http" "os" @@ -20,8 +19,9 @@ import ( ) /////////// TO DOs: -/////////// - Database sharding by every 20,000 IDs for friends tables -/////////// - Database sharding for Users tables +/////////// - Implement WebRTC option for voice chat +/////////// - Make relay for failed P2P connections +/////////// - Switch-out MySQL authentication with GopherGameDB /////////// - Admin tools /////////// - More useful command-line macros @@ -58,15 +58,12 @@ type ServerSettings struct { EncryptionCost int // The amount of encryption iterations the server will run when storing and checking passwords. The higher the number, the longer encryptions take, but are more secure. Default is 4, range is 4-31. CustomLoginColumn string // The custom AccountInfoColumn you wish to use for logging in instead of the default name column. RememberMe bool // Enables the "Remember Me" login feature. You can read more about this in project's wiki. - Sharding bool // Enables the built-in database sharding mechanism. EnableRecovery bool // Enables the recovery of all Rooms, their settings, and their variables on start-up after terminating the server. RecoveryLocation string // The folder location (starting from system's root folder) where you would like to store the recovery data. (Required for recovery) - EnableAdminTools bool // Enables the use of the Admin Tools - EnableRemoteAdmin bool // Enabled administration (only) from outside the origin server. When enabled, will override OriginOnly's functionality, but only for administrator connections. - AdminToolsLogin string // The login name for the Admin Tools (Required for Admin Tools) - AdminToolsPassword string // The password for the Admin Tools (Required for Admin Tools) + AdminLogin string // The login name for the Admin Tools (Required for Admin Tools) + AdminPassword string // The password for the Admin Tools (Required for Admin Tools) } var ( @@ -86,7 +83,7 @@ var ( clientConnectCallback func(*http.ResponseWriter, *http.Request) bool //SERVER VERSION NUMBER - version string = "1.0-ALPHA.3" + version string = "1.0-ALPHA.4" ) ////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -146,10 +143,9 @@ func Start(s *ServerSettings) { } os.Remove(settings.RecoveryLocation + "/test.txt") - } else if settings.EnableAdminTools == true && (settings.AdminToolsLogin == "" || settings.AdminToolsPassword == "") { - fmt.Println("AdminToolsLogin and AdminToolsPassword in ServerSettings are required for Administrator Tools. Shutting down...") + } else if settings.AdminLogin == "" || settings.AdminPassword == "" { + fmt.Println("AdminLogin and AdminPassword in ServerSettings are required. Shutting down...") return - } } else { //DEFAULT localhost SETTINGS @@ -185,26 +181,22 @@ func Start(s *ServerSettings) { EncryptionCost: 4, CustomLoginColumn: "", RememberMe: false, - Sharding: false, EnableRecovery: false, RecoveryLocation: "C:/", - EnableAdminTools: true, - EnableRemoteAdmin: false, - AdminToolsLogin: "admin", - AdminToolsPassword: "password"} + AdminLogin: "admin", + AdminPassword: "password"} } //UPDATE SETTINGS IN users PACKAGE, THEN users WILL UPDATE SETTINGS FOR rooms PACKAGE - users.SettingsSet((*settings).KickDupOnLogin, (*settings).ServerName, (*settings).RoomDeleteOnLeave, (*settings).EnableSqlFeatures, + core.SettingsSet((*settings).KickDupOnLogin, (*settings).ServerName, (*settings).RoomDeleteOnLeave, (*settings).EnableSqlFeatures, (*settings).RememberMe, (*settings).MultiConnect) //NOTIFY PACKAGES OF SERVER START - users.SetServerStarted(true) - rooms.SetServerStarted(true) + core.SetServerStarted(true) actions.SetServerStarted(true) - database.SetServerStarted(true, (*settings).Sharding) + database.SetServerStarted(true) //START UP DATABASE if (*settings).EnableSqlFeatures { @@ -252,8 +244,7 @@ func Start(s *ServerSettings) { fmt.Println("Disconnecting users...") //PAUSE SERVER - users.Pause() - rooms.Pause() + core.Pause() actions.Pause() database.Pause() @@ -302,8 +293,7 @@ func Pause() { fmt.Println("Pausing server...") - users.Pause() - rooms.Pause() + core.Pause() actions.Pause() database.Pause() @@ -325,8 +315,7 @@ func Resume() { serverStarted = true fmt.Println("Resuming server...") - users.Resume() - rooms.Resume() + core.Resume() actions.Resume() database.Resume() @@ -348,8 +337,7 @@ func ShutDown() error { fmt.Println("Disconnecting users...") //PAUSE SERVER - users.Pause() - rooms.Pause() + core.Pause() actions.Pause() database.Pause() @@ -386,8 +374,8 @@ func saveState() { func getState() map[string]interface{} { state := make(map[string]interface{}) - //GET ROOM STATES - state["rooms"] = rooms.GetState() + //GET CORE STATE + state["rooms"] = core.GetState() // return state @@ -469,7 +457,7 @@ func recoverState() { fmt.Println("Error recovering room '" + name + "': Incorrect owner format") continue } - room, roomErr := rooms.New(name, rType, isPrivate, int(maxUsers), owner) + room, roomErr := core.NewRoom(name, rType, isPrivate, int(maxUsers), owner) if roomErr != nil { fmt.Println("Error recovering room '"+name+"':", roomErr) continue diff --git a/sockets.go b/sockets.go index 585d85f..8e7b7ac 100644 --- a/sockets.go +++ b/sockets.go @@ -2,8 +2,8 @@ package gopher import ( "github.com/gorilla/websocket" + "github.com/hewiefreeman/GopherGameServer/core" "github.com/hewiefreeman/GopherGameServer/helpers" - "github.com/hewiefreeman/GopherGameServer/users" "net/http" "strconv" "sync" @@ -64,7 +64,7 @@ func clientActionListener(conn *websocket.Conn) { var action clientAction var clientMux sync.Mutex // LOCKS user AND connID - var user *users.User // THE CLIENT'S User OBJECT + var user *core.User // THE CLIENT'S User OBJECT var connID string // CLIENT SESSION ID // THE CLIENT'S AUTOLOG INFO @@ -201,7 +201,7 @@ func clientActionListener(conn *websocket.Conn) { return } //AUTO-LOG THE CLIENT - connID, gErr = users.AutoLogIn(deviceTag, oldPass, devicePass, deviceUserID, conn, &user, &clientMux) + connID, gErr = core.AutoLogIn(deviceTag, oldPass, devicePass, deviceUserID, conn, &user, &clientMux) if gErr.ID != 0 { //ERROR AUTO-LOGGING - RUN AUTOLOGCOMPLETE AND DELETE KEYS FOR CLIENT, AND SILENTLY CHANGE DEVICE KEY newTag, newTagErr := helpers.GenerateSecureString(32) @@ -210,12 +210,12 @@ func clientActionListener(conn *websocket.Conn) { conn.Close() return } - autologMessage := make(map[string]interface{}) + autologMessage := make(map[string]map[string]interface{}) autologMessage[helpers.ServerActionAutoLoginFailed] = make(map[string]interface{}) - autologMessage[helpers.ServerActionAutoLoginFailed].(map[string]interface{})["dt"] = newTag - autologMessage[helpers.ServerActionAutoLoginFailed].(map[string]interface{})["e"] = make(map[string]interface{}) - autologMessage[helpers.ServerActionAutoLoginFailed].(map[string]interface{})["e"].(map[string]interface{})["m"] = gErr.Message - autologMessage[helpers.ServerActionAutoLoginFailed].(map[string]interface{})["e"].(map[string]interface{})["id"] = gErr.ID + autologMessage[helpers.ServerActionAutoLoginFailed]["dt"] = newTag + autologMessage[helpers.ServerActionAutoLoginFailed]["e"] = make(map[string]interface{}) + autologMessage[helpers.ServerActionAutoLoginFailed]["e"].(map[string]interface{})["m"] = gErr.Message + autologMessage[helpers.ServerActionAutoLoginFailed]["e"].(map[string]interface{})["id"] = gErr.ID writeErr := conn.WriteJSON(autologMessage) if writeErr != nil { conn.WriteControl(websocket.CloseMessage, []byte{}, time.Now().Add(time.Second*1)) @@ -268,7 +268,7 @@ func clientActionListener(conn *websocket.Conn) { } } -func sockedDropped(user *users.User, connID string, clientMux *sync.Mutex) { +func sockedDropped(user *core.User, connID string, clientMux *sync.Mutex) { if user != nil { //CLIENT WAS LOGGED IN. LOG THEM OUT (*clientMux).Unlock() @@ -299,7 +299,7 @@ func (c *connections) subtract() { } // ClientsConnected returns the number of clients connected to the server. Includes connections -// not logged in as a User. To get the number of Users logged in, use the users.UserCount() function. +// not logged in as a User. To get the number of Users logged in, use the core.UserCount() function. func ClientsConnected() int { conns.connsMux.Lock() defer conns.connsMux.Unlock() diff --git a/users/messages.go b/users/messages.go deleted file mode 100644 index 8891118..0000000 --- a/users/messages.go +++ /dev/null @@ -1,62 +0,0 @@ -package users - -import ( - "github.com/hewiefreeman/GopherGameServer/helpers" -) - -////////////////////////////////////////////////////////////////////////////////////////////////////// -// SEND A PRIVATE MESSAGE //////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////////////////////////// - -// PrivateMessage sends a private message to another User by name. -func (u *User) PrivateMessage(userName string, message interface{}) { - user, userErr := Get(userName) - if userErr != nil { - return - } - - //CONSTRUCT MESSAGE - theMessage := make(map[string]interface{}) - theMessage[helpers.ServerActionPrivateMessage] = make(map[string]interface{}) - theMessage[helpers.ServerActionPrivateMessage].(map[string]interface{})["f"] = u.name // from - theMessage[helpers.ServerActionPrivateMessage].(map[string]interface{})["t"] = user.name // to - theMessage[helpers.ServerActionPrivateMessage].(map[string]interface{})["m"] = message // message - - //SEND MESSAGES - user.mux.Lock() - for _, conn := range user.conns { - (*conn).socket.WriteJSON(theMessage) - } - user.mux.Unlock() - u.mux.Lock() - for _, conn := range u.conns { - (*conn).socket.WriteJSON(theMessage) - } - u.mux.Unlock() - - return -} - -////////////////////////////////////////////////////////////////////////////////////////////////////// -// SEND A DATA MESSAGE /////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////////////////////////// - -// DataMessage sends a data message directly to the User. -func (u *User) DataMessage(data interface{}, connID string) { - //CONSTRUCT MESSAGE - message := make(map[string]interface{}) - message[helpers.ServerActionDataMessage] = data - - //SEND MESSAGE TO USER - u.mux.Lock() - if connID == "" { - for _, conn := range u.conns { - (*conn).socket.WriteJSON(message) - } - } else { - if conn, ok := u.conns[connID]; ok { - (*conn).socket.WriteJSON(message) - } - } - u.mux.Unlock() -} From 00ec17d1eed3b0b12e752d21fbc20c9de90c8916 Mon Sep 17 00:00:00 2001 From: hewiefreeman Date: Tue, 23 Jul 2019 23:30:07 -0700 Subject: [PATCH 063/132] Minor map allocation/performance improvements --- actions/actions.go | 16 +++--- core/core.go | 22 +++++++- core/friending.go | 49 ++++++++++-------- core/messaging.go | 51 +++++++++++-------- core/rooms.go | 37 ++++---------- core/users.go | 101 ++++++++++++++++++------------------- core/vars.go | 29 +++++++---- helpers/clientResponses.go | 25 +++++---- server.go | 10 ++-- sockets.go | 35 ++++++++----- 10 files changed, 209 insertions(+), 166 deletions(-) diff --git a/actions/actions.go b/actions/actions.go index 507760d..188dc90 100644 --- a/actions/actions.go +++ b/actions/actions.go @@ -207,17 +207,19 @@ func (c *Client) Respond(response interface{}, err ClientError) { } (*c).responded = true //CONSTRUCT MESSAGE - r := make(map[string]map[string]interface{}) - r[helpers.ServerActionCustomClientActionResponse] = make(map[string]interface{}) - r[helpers.ServerActionCustomClientActionResponse]["a"] = (*c).action + r := map[string]map[string]interface{}{ + helpers.ServerActionCustomClientActionResponse: map[string]interface{}{ + "a": (*c).action, + }, + } if err.id != -1 { - r[helpers.ServerActionCustomClientActionResponse]["e"] = make(map[string]interface{}) - r[helpers.ServerActionCustomClientActionResponse]["e"].(map[string]interface{})["m"] = err.message - r[helpers.ServerActionCustomClientActionResponse]["e"].(map[string]interface{})["id"] = err.id + r[helpers.ServerActionCustomClientActionResponse]["e"] = map[string]interface{}{ + "m": err.message, + "id": err.id, + } } else { r[helpers.ServerActionCustomClientActionResponse]["r"] = response } - //SEND MESSAGE TO CLIENT (*c).socket.WriteJSON(r) } diff --git a/core/core.go b/core/core.go index b668a5c..9e6edb3 100644 --- a/core/core.go +++ b/core/core.go @@ -1,3 +1,22 @@ +// Package core contains all the tools to make and work with Users and Rooms. +// +// A User is a client who has successfully logged into the server. You can think of clients who are not attached to a User +// as, for instance, someone in the login screen, but are still connected to the server. A client doesn't +// have to be a User to be able to call your CustomClientActions, so keep that in mind when making them (Refer to the Usage for CustomClientActions). +// +// Users have their own variables which can be accessed and changed anytime. A User variable can +// be anything compatible with interface{}, so pretty much anything. +// +// A Room represents a place on the server where a User can join other Users. Rooms can either be public or private. Private Rooms must be assigned an "owner", which is the name of a User, or the ServerName +// from ServerSettings. The server's name that will be used for ownership of private Rooms can be set with the ServerSettings +// option ServerName when starting the server. Though keep in mind, setting the ServerName in ServerSettings will prevent a User who wants to go by that name +// from logging in. Public Rooms will accept a join request from any User, and private Rooms will only +// accept a join request from someone who is on it's invite list. Only the owner of the Room or the server itself can invite +// Users to a private Room. But remember, just because a User owns a private room doesn't mean the server cannot also invite +// to the room via *Room.AddInvite() function. +// +// Rooms have their own variables which can be accessed and changed anytime. Like User variables, a Room variable can +// be anything compatible with interface{}. package core import ( @@ -93,11 +112,10 @@ func Resume() { // GetState is only for internal Gopher Game Server mechanics. func GetState() map[string]map[string]interface{} { - state := make(map[string]map[string]interface{}) + state := map[string]map[string]interface{}{room.name: map[string]interface{}{}} roomsMux.Lock() for _, room := range rooms { room.mux.Lock() - state[room.name] = make(map[string]interface{}) state[room.name]["t"] = room.rType state[room.name]["p"] = room.private state[room.name]["o"] = room.owner diff --git a/core/friending.go b/core/friending.go index 21e5f55..fa96aa0 100644 --- a/core/friending.go +++ b/core/friending.go @@ -50,9 +50,11 @@ func (u *User) FriendRequest(friendName string) error { //SEND A FRIEND REQUEST TO THE USER IF THEY ARE ONLINE if friendOnline { - message := make(map[string]map[string]interface{}) - message[helpers.ServerActionFriendRequest] = make(map[string]interface{}) - message[helpers.ServerActionFriendRequest]["n"] = u.name + message := map[string]map[string]interface{}{ + helpers.ServerActionFriendRequest: map[string]interface{}{ + "n": u.name, + }, + } friend.mux.Lock() for _, conn := range friend.conns { (*conn).socket.WriteJSON(message) @@ -114,27 +116,30 @@ func (u *User) AcceptFriendRequest(friendName string) error { return errors.New("Unexpected friend error") } - //SEND A FRIEND REQUEST TO THE USER IF THEY ARE ONLINE - var status int = StatusOffline + //SEND ACCEPT MESSAGE TO THE USER IF THEY ARE ONLINE + var fStatus int = StatusOffline if friendOnline { - message := make(map[string]map[string]interface{}) - message[helpers.ServerActionFriendAccept] = make(map[string]interface{}) - message[helpers.ServerActionFriendAccept]["n"] = u.name - message[helpers.ServerActionFriendAccept]["s"] = u.status + message := map[string]map[string]interface{}{ + helpers.ServerActionFriendAccept: map[string]interface{}{ + "n": u.name, + "s": u.status, + }, + } friend.mux.Lock() for _, conn := range friend.conns { (*conn).socket.WriteJSON(message) } - status = friend.status + fStatus = friend.status friend.mux.Unlock() } //MAKE RESPONSE - responseMap := make(map[string]interface{}) - responseMap["n"] = friendName - responseMap["s"] = status + responseMap := map[string]interface{}{ + "n": friendName, + "s": fStatus, + } - //SEND RESPONSE TO CLIENT + //SEND RESPONSE TO ALL CLIENT CONNECTIONS clientResp := helpers.MakeClientResponse(helpers.ClientActionAcceptFriend, responseMap, helpers.NoError()) u.mux.Lock() for _, conn := range u.conns { @@ -191,9 +196,11 @@ func (u *User) DeclineFriendRequest(friendName string) error { //SEND A FRIEND REQUEST TO THE USER IF THEY ARE ONLINE if friendOnline { - message := make(map[string]map[string]interface{}) - message[helpers.ServerActionFriendRemove] = make(map[string]interface{}) - message[helpers.ServerActionFriendRemove]["n"] = u.name + message := map[string]map[string]interface{}{ + helpers.ServerActionFriendRemove: map[string]interface{}{ + "n": u.name, + }, + } friend.mux.Lock() for _, conn := range friend.conns { (*conn).socket.WriteJSON(message) @@ -258,9 +265,11 @@ func (u *User) RemoveFriend(friendName string) error { //SEND A FRIEND REQUEST TO THE USER IF THEY ARE ONLINE if friendOnline { - message := make(map[string]map[string]interface{}) - message[helpers.ServerActionFriendRemove] = make(map[string]interface{}) - message[helpers.ServerActionFriendRemove]["n"] = u.name + message := map[string]map[string]interface{}{ + helpers.ServerActionFriendRemove: map[string]interface{}{ + "n": u.name, + }, + } friend.mux.Lock() for _, conn := range friend.conns { (*conn).socket.WriteJSON(message) diff --git a/core/messaging.go b/core/messaging.go index 38b7715..53c2abd 100644 --- a/core/messaging.go +++ b/core/messaging.go @@ -31,11 +31,13 @@ func (u *User) PrivateMessage(userName string, message interface{}) { } //CONSTRUCT MESSAGE - theMessage := make(map[string]map[string]interface{}) - theMessage[helpers.ServerActionPrivateMessage] = make(map[string]interface{}) - theMessage[helpers.ServerActionPrivateMessage]["f"] = u.name // from - theMessage[helpers.ServerActionPrivateMessage]["t"] = user.name // to - theMessage[helpers.ServerActionPrivateMessage]["m"] = message // message + theMessage := map[string]map[string]interface{}{ + helpers.ServerActionPrivateMessage: map[string]interface{}{ + "f": u.name, // from + "t": user.name, // to + "m": message, + }, + } //SEND MESSAGES user.mux.Lock() @@ -55,8 +57,9 @@ func (u *User) PrivateMessage(userName string, message interface{}) { // DataMessage sends a data message directly to the User. func (u *User) DataMessage(data interface{}, connID string) { //CONSTRUCT MESSAGE - message := make(map[string]interface{}) - message[helpers.ServerActionDataMessage] = data + message := map[string]interface{}{ + helpers.ServerActionDataMessage: data, + } //SEND MESSAGE TO USER u.mux.Lock() @@ -108,8 +111,9 @@ func (r *Room) DataMessage(message interface{}, recipients []string) error { } //CONSTRUCT MESSAGE - theMessage := make(map[string]interface{}) - theMessage[helpers.ServerActionDataMessage] = message + theMessage := map[string]interface{}{ + helpers.ServerActionDataMessage: message, + } //SEND MESSAGE TO USERS if recipients == nil || len(recipients) == 0 { @@ -144,15 +148,19 @@ func (r *Room) sendMessage(mt int, st int, rec []string, a string, m interface{} } //CONSTRUCT MESSAGE - message := make(map[string]map[string]interface{}) - message[helpers.ServerActionRoomMessage] = make(map[string]interface{}) + message := map[string]map[string]interface{}{ + helpers.ServerActionRoomMessage: make(map[string]interface{}), + } + // Server messages come with a sub-type if mt == MessageTypeServer { message[helpers.ServerActionRoomMessage]["s"] = st - } // Server messages come with a sub-type + } + // Non-server messages have authors if len(a) > 0 && mt != MessageTypeServer { message[helpers.ServerActionRoomMessage]["a"] = a - } // Non-server messages have authors - message[helpers.ServerActionRoomMessage]["m"] = m // The message + } + // The message + message[helpers.ServerActionRoomMessage]["m"] = m //SEND MESSAGE TO USERS if rec == nil || len(rec) == 0 { @@ -191,10 +199,12 @@ func (r *Room) VoiceStream(userName string, userSocket *websocket.Conn, stream i } //CONSTRUCT VOICE MESSAGE - theMessage := make(map[string]map[string]interface{}) - theMessage[helpers.ServerActionVoiceStream] = make(map[string]interface{}) - theMessage[helpers.ServerActionVoiceStream]["u"] = userName - theMessage[helpers.ServerActionVoiceStream]["d"] = stream + theMessage := map[string]map[string]interface{}{ + helpers.ServerActionVoiceStream: map[string]interface{}{ + "u": userName, + "d": stream, + }, + } //REMOVE SENDING USER FROM userMap delete(userMap, userName) // COMMENT OUT FOR ECHO TESTS @@ -207,8 +217,9 @@ func (r *Room) VoiceStream(userName string, userSocket *websocket.Conn, stream i } //CONSTRUCT PING MESSAGE - pingMessage := make(map[string]interface{}) - pingMessage[helpers.ServerActionVoicePing] = nil + pingMessage := map[string]interface{}{ + helpers.ServerActionVoicePing: nil, + } //SEND PING MESSAGE TO SENDING USER userSocket.WriteJSON(pingMessage) diff --git a/core/rooms.go b/core/rooms.go index c33a455..19f6508 100644 --- a/core/rooms.go +++ b/core/rooms.go @@ -1,22 +1,3 @@ -// Package core contains all the tools to make and work with Users and Rooms. -// -// A User is a client who has successfully logged into the server. You can think of clients who are not attached to a User -// as, for instance, someone in the login screen, but are still connected to the server. A client doesn't -// have to be a User to be able to call your CustomClientActions, so keep that in mind when making them (Refer to the Usage for CustomClientActions). -// -// Users have their own variables which can be accessed and changed anytime. A User variable can -// be anything compatible with interface{}, so pretty much anything. -// -// A Room represents a place on the server where a User can join other Users. Rooms can either be public or private. Private Rooms must be assigned an "owner", which is the name of a User, or the ServerName -// from ServerSettings. The server's name that will be used for ownership of private Rooms can be set with the ServerSettings -// option ServerName when starting the server. Though keep in mind, setting the ServerName in ServerSettings will prevent a User who wants to go by that name -// from logging in. Public Rooms will accept a join request from any User, and private Rooms will only -// accept a join request from someone who is on it's invite list. Only the owner of the Room or the server itself can invite -// Users to a private Room. But remember, just because a User owns a private room doesn't mean the server cannot also invite -// to the room via *Room.AddInvite() function. -// -// Rooms have their own variables which can be accessed and changed anytime. Like User variables, a Room variable can -// be anything compatible with interface{}. package core import ( @@ -270,10 +251,12 @@ func (r *Room) AddUser(user *User, connID string) error { roomType := roomTypes[r.rType] if roomType.BroadcastUserEnter() { //BROADCAST ENTER TO USERS IN ROOM - message := make(map[string]map[string]interface{}) - message[helpers.ServerActionUserEnter] = make(map[string]interface{}) - message[helpers.ServerActionUserEnter]["u"] = userName - message[helpers.ServerActionUserEnter]["g"] = user.isGuest + message := map[string]map[string]interface{}{ + helpers.ServerActionUserEnter: map[string]interface{}{ + "u": userName, + "g": user.isGuest, + }, + } for _, u := range r.usersMap { u.mux.Lock() if u.user.Name() != userName { @@ -350,9 +333,11 @@ func (r *Room) RemoveUser(user *User, connID string) error { } } else if roomType.BroadcastUserLeave() { //CONSTRUCT LEAVE MESSAGE - message := make(map[string]map[string]interface{}) - message[helpers.ServerActionUserLeave] = make(map[string]interface{}) - message[helpers.ServerActionUserLeave]["u"] = userName + message := map[string]map[string]interface{}{ + helpers.ServerActionUserLeave: map[string]interface{}{ + "u": userName, + }, + } //SEND MESSAGE TO USERS for _, u := range userList { diff --git a/core/users.go b/core/users.go index d3bec8b..f6a86fd 100644 --- a/core/users.go +++ b/core/users.go @@ -1,22 +1,3 @@ -// Package core contains all the tools to make and work with Users and Rooms. -// -// A User is a client who has successfully logged into the server. You can think of clients who are not attached to a User -// as, for instance, someone in the login screen, but are still connected to the server. A client doesn't -// have to be a User to be able to call your CustomClientActions, so keep that in mind when making them (Refer to the Usage for CustomClientActions). -// -// Users have their own variables which can be accessed and changed anytime. A User variable can -// be anything compatible with interface{}, so pretty much anything. -// -// A Room represents a place on the server where a User can join other Users. Rooms can either be public or private. Private Rooms must be assigned an "owner", which is the name of a User, or the ServerName -// from ServerSettings. The server's name that will be used for ownership of private Rooms can be set with the ServerSettings -// option ServerName when starting the server. Though keep in mind, setting the ServerName in ServerSettings will prevent a User who wants to go by that name -// from logging in. Public Rooms will accept a join request from any User, and private Rooms will only -// accept a join request from someone who is on it's invite list. Only the owner of the Room or the server itself can invite -// Users to a private Room. But remember, just because a User owns a private room doesn't mean the server cannot also invite -// to the room via *Room.AddInvite() function. -// -// Rooms have their own variables which can be accessed and changed anytime. Like User variables, a Room variable can -// be anything compatible with interface{}. package core import ( @@ -203,10 +184,12 @@ func Login(userName string, dbID int, autologPass string, isGuest bool, remMe bo friends = make([]map[string]interface{}, 0, len(friendsMap)) //MAKE FRINDS LIST FOR SERVER RESPONSE for _, val := range friendsMap { - friendEntry := make(map[string]interface{}) - friendEntry["n"] = val.Name() - friendEntry["rs"] = val.RequestStatus() - if val.RequestStatus() == database.FriendStatusAccepted { + frs := val.RequestStatus() + friendEntry := map[string]interface{}{ + "n": val.Name(), + "rs": frs, + } + if frs == database.FriendStatusAccepted { //GET THE User STATUS if friend, ok := users[val.Name()]; ok { friendEntry["s"] = friend.Status() @@ -225,10 +208,12 @@ func Login(userName string, dbID int, autologPass string, isGuest bool, remMe bo //MAKE FRINDS LIST FOR SERVER RESPONSE friends = make([]map[string]interface{}, 0, len(friendsMap)) for _, val := range friendsMap { - friendEntry := make(map[string]interface{}) - friendEntry["n"] = val.Name() - friendEntry["rs"] = val.RequestStatus() - if val.RequestStatus() == database.FriendStatusAccepted { + frs := val.RequestStatus() + friendEntry := map[string]interface{}{ + "n": val.Name(), + "rs": frs, + } + if frs == database.FriendStatusAccepted { //GET THE User STATUS if friend, ok := users[val.Name()]; ok { friendEntry["s"] = friend.Status() @@ -240,8 +225,9 @@ func Login(userName string, dbID int, autologPass string, isGuest bool, remMe bo } } } - conns := make(map[string]*userConn) - conns[connID] = &conn + conns := map[string]*userConn{ + connID: &conn, + } newUser := User{name: userName, databaseID: databaseID, isGuest: isGuest, status: 0, friends: friendsMap, conns: conns} users[userName] = &newUser @@ -253,10 +239,12 @@ func Login(userName string, dbID int, autologPass string, isGuest bool, remMe bo usersMux.Unlock() //SEND ONLINE MESSAGE TO FRIENDS - statusMessage := make(map[string]map[string]interface{}) - statusMessage[helpers.ServerActionFriendStatusChange] = make(map[string]interface{}) - statusMessage[helpers.ServerActionFriendStatusChange]["n"] = userName - statusMessage[helpers.ServerActionFriendStatusChange]["s"] = 0 + statusMessage := map[string]map[string]interface{}{ + helpers.ServerActionFriendStatusChange: map[string]interface{}{ + "n": userName, + "s": 0, + }, + } for key, val := range friendsMap { if val.RequestStatus() == database.FriendStatusAccepted { friend, friendErr := GetUser(key) @@ -271,9 +259,10 @@ func Login(userName string, dbID int, autologPass string, isGuest bool, remMe bo } //SUCCESS, SEND RESPONSE TO CLIENT - responseVal := make(map[string]interface{}) - responseVal["n"] = userName - responseVal["f"] = friends + responseVal := map[string]interface{}{ + "n": userName, + "f": friends, + } if rememberMe && len(autologPass) > 0 && remMe { responseVal["ai"] = dbID responseVal["ap"] = autologPass @@ -342,10 +331,12 @@ func (u *User) Logout(connID string) { if len(u.conns) == 1 { //SEND STATUS CHANGE TO FRIENDS - statusMessage := make(map[string]map[string]interface{}) - statusMessage[helpers.ServerActionFriendStatusChange] = make(map[string]interface{}) - statusMessage[helpers.ServerActionFriendStatusChange]["n"] = u.name - statusMessage[helpers.ServerActionFriendStatusChange]["s"] = StatusOffline + statusMessage := map[string]map[string]interface{}{ + helpers.ServerActionFriendStatusChange: map[string]interface{}{ + "n": u.name, + "s": StatusOffline, + }, + } for key, val := range u.friends { if val.RequestStatus() == database.FriendStatusAccepted { friend, friendErr := GetUser(key) @@ -392,10 +383,12 @@ func (u *User) Kick() { u.mux.Lock() //SEND STATUS CHANGE TO FRIENDS - statusMessage := make(map[string]map[string]interface{}) - statusMessage[helpers.ServerActionFriendStatusChange] = make(map[string]interface{}) - statusMessage[helpers.ServerActionFriendStatusChange]["n"] = u.name - statusMessage[helpers.ServerActionFriendStatusChange]["s"] = StatusOffline + statusMessage := map[string]map[string]interface{}{ + helpers.ServerActionFriendStatusChange: map[string]interface{}{ + "n": u.name, + "s": StatusOffline, + }, + } for key, val := range u.friends { if val.RequestStatus() == database.FriendStatusAccepted { friend, friendErr := GetUser(key) @@ -556,10 +549,12 @@ func (u *User) SetStatus(status int) { u.mux.Unlock() //SEND STATUS CHANGE MESSAGE TO User's FRIENDS WHOM ARE "ACCEPTED" - message := make(map[string]map[string]interface{}) - message[helpers.ServerActionFriendStatusChange] = make(map[string]interface{}) - message[helpers.ServerActionFriendStatusChange]["n"] = u.name - message[helpers.ServerActionFriendStatusChange]["s"] = status + message := map[string]map[string]interface{}{ + helpers.ServerActionFriendStatusChange: map[string]interface{}{ + "n": u.name, + "s": status, + }, + } for key, val := range friends { if val.RequestStatus() == database.FriendStatusAccepted { friend, friendErr := GetUser(key) @@ -614,10 +609,12 @@ func (u *User) Invite(invUser *User, connID string) error { } //MAKE INVITE MESSAGE - invMessage := make(map[string]map[string]interface{}) - invMessage[helpers.ServerActionRoomInvite] = make(map[string]interface{}) - invMessage[helpers.ServerActionRoomInvite]["u"] = u.name - invMessage[helpers.ServerActionRoomInvite]["r"] = currRoom.Name() + invMessage := map[string]map[string]interface{}{ + helpers.ServerActionRoomInvite: map[string]interface{}{ + "u": u.name, + "r": currRoom.Name(), + }, + } //SEND MESSAGE invUser.mux.Lock() diff --git a/core/vars.go b/core/vars.go index 4b8e1b9..f596127 100644 --- a/core/vars.go +++ b/core/vars.go @@ -21,21 +21,26 @@ func (u *User) SetVariable(key string, value interface{}, connID string) { } else if !multiConnect { connID = "1" } - //MAKE CLIENT MESSAGE - resp := make(map[string]interface{}) - resp["k"] = key - resp["v"] = value + // Set the variable u.mux.Lock() if _, ok := u.conns[connID]; !ok { u.mux.Unlock() return } (*u.conns[connID]).vars[key] = value - //SEND RESPONSE TO CLIENT - clientResp := helpers.MakeClientResponse(helpers.ClientActionSetVariable, resp, helpers.NoError()) - (*u.conns[connID]).socket.WriteJSON(clientResp) + socket := (*u.conns[connID]).socket u.mux.Unlock() + + //MAKE CLIENT MESSAGE + resp := map[string]interface{}{ + "k": key, + "v": value, + } + clientResp := helpers.MakeClientResponse(helpers.ClientActionSetVariable, resp, helpers.NoError()) + + //SEND RESPONSE TO CLIENT + socket.WriteJSON(clientResp) } // SetVariables sets all the specified User variables at once. The client API of the User will also receive these changes. If you are using MultiConnect in ServerSettings, the connID @@ -50,6 +55,8 @@ func (u *User) SetVariables(values map[string]interface{}, connID string) { } else if !multiConnect { connID = "1" } + + // Set the variables u.mux.Lock() if _, ok := u.conns[connID]; !ok { u.mux.Unlock() @@ -58,10 +65,13 @@ func (u *User) SetVariables(values map[string]interface{}, connID string) { for key, val := range values { (*u.conns[connID]).vars[key] = val } + socket := (*u.conns[connID]).socket + u.mux.Unlock() + //SEND RESPONSE TO CLIENT clientResp := helpers.MakeClientResponse(helpers.ClientActionSetVariables, values, helpers.NoError()) - (*u.conns[connID]).socket.WriteJSON(clientResp) - u.mux.Unlock() + socket.WriteJSON(clientResp) + } // GetVariable gets one of the User's variables by it's key. If you are using MultiConnect in ServerSettings, the connID @@ -72,6 +82,7 @@ func (u *User) GetVariable(key string, connID string) interface{} { if len(key) == 0 { return nil } + u.mux.Lock() val := (*u.conns[connID]).vars[key] u.mux.Unlock() diff --git a/helpers/clientResponses.go b/helpers/clientResponses.go index c2bc994..8b0efd3 100644 --- a/helpers/clientResponses.go +++ b/helpers/clientResponses.go @@ -53,17 +53,24 @@ const ( // MakeClientResponse is used for Gopher Game Server inner mechanics only. func MakeClientResponse(action string, responseVal interface{}, err GopherError) map[string]map[string]interface{} { - var response map[string]map[string]interface{} = make(map[string]map[string]interface{}) + var response map[string]map[string]interface{} if err.ID != 0 { - response[ServerActionClientActionResponse] = make(map[string]interface{}) - response[ServerActionClientActionResponse]["a"] = action - response[ServerActionClientActionResponse]["e"] = make(map[string]interface{}) - response[ServerActionClientActionResponse]["e"].(map[string]interface{})["m"] = err.Message - response[ServerActionClientActionResponse]["e"].(map[string]interface{})["id"] = err.ID + response = map[string]map[string]interface{}{ + ServerActionClientActionResponse: map[string]interface{}{ + "a": action, + "e": map[string]interface{}{ + "m": err.Message, + "is": err.ID, + }, + }, + } } else { - response[ServerActionClientActionResponse] = make(map[string]interface{}) - response[ServerActionClientActionResponse]["a"] = action - response[ServerActionClientActionResponse]["r"] = responseVal + response = map[string]map[string]interface{}{ + ServerActionClientActionResponse: map[string]interface{}{ + "a": action, + "r": responseVal, + }, + } } // diff --git a/server.go b/server.go index 62f4412..3809865 100644 --- a/server.go +++ b/server.go @@ -372,13 +372,9 @@ func saveState() { } func getState() map[string]interface{} { - state := make(map[string]interface{}) - - //GET CORE STATE - state["rooms"] = core.GetState() - - // - return state + return map[string]interface{}{ + "rooms": core.GetState(), + } } func recoverState() { diff --git a/sockets.go b/sockets.go index 8e7b7ac..8a2dcd1 100644 --- a/sockets.go +++ b/sockets.go @@ -84,8 +84,9 @@ func clientActionListener(conn *websocket.Conn) { for { if !sentTagRequest { //SEND TAG RETRIEVAL MESSAGE - tagMessage := make(map[string]interface{}) - tagMessage[helpers.ServerActionRequestDeviceTag] = nil + tagMessage := map[string]interface{}{ + helpers.ServerActionRequestDeviceTag: nil, + } writeErr := conn.WriteJSON(tagMessage) if writeErr != nil { conn.WriteControl(websocket.CloseMessage, []byte{}, time.Now().Add(time.Second*1)) @@ -112,8 +113,9 @@ func clientActionListener(conn *websocket.Conn) { return } deviceTag = string(newDeviceTag) - tagMessage := make(map[string]interface{}) - tagMessage[helpers.ServerActionSetDeviceTag] = deviceTag + tagMessage := map[string]interface{}{ + helpers.ServerActionSetDeviceTag: deviceTag, + } writeErr := conn.WriteJSON(tagMessage) if writeErr != nil { conn.WriteControl(websocket.CloseMessage, []byte{}, time.Now().Add(time.Second*1)) @@ -130,8 +132,9 @@ func clientActionListener(conn *websocket.Conn) { return } //SEND AUTO-LOG NOT FILED MESSAGE - notFiledMessage := make(map[string]interface{}) - notFiledMessage[helpers.ServerActionAutoLoginNotFiled] = nil + notFiledMessage := map[string]interface{}{ + helpers.ServerActionAutoLoginNotFiled: nil, + } writeErr := conn.WriteJSON(notFiledMessage) if writeErr != nil { conn.WriteControl(websocket.CloseMessage, []byte{}, time.Now().Add(time.Second*1)) @@ -185,8 +188,9 @@ func clientActionListener(conn *websocket.Conn) { return } //CHANGE THE CLIENT'S PASS - newPassMessage := make(map[string]interface{}) - newPassMessage[helpers.ServerActionSetAutoLoginPass] = devicePass + newPassMessage := map[string]interface{}{ + helpers.ServerActionSetAutoLoginPass: devicePass, + } writeErr := conn.WriteJSON(newPassMessage) if writeErr != nil { conn.WriteControl(websocket.CloseMessage, []byte{}, time.Now().Add(time.Second*1)) @@ -210,12 +214,15 @@ func clientActionListener(conn *websocket.Conn) { conn.Close() return } - autologMessage := make(map[string]map[string]interface{}) - autologMessage[helpers.ServerActionAutoLoginFailed] = make(map[string]interface{}) - autologMessage[helpers.ServerActionAutoLoginFailed]["dt"] = newTag - autologMessage[helpers.ServerActionAutoLoginFailed]["e"] = make(map[string]interface{}) - autologMessage[helpers.ServerActionAutoLoginFailed]["e"].(map[string]interface{})["m"] = gErr.Message - autologMessage[helpers.ServerActionAutoLoginFailed]["e"].(map[string]interface{})["id"] = gErr.ID + autologMessage := map[string]map[string]interface{}{ + helpers.ServerActionAutoLoginFailed: map[string]interface{}{ + "dt": newTag, + "e": map[string]interface{}{ + "m": gErr.Message, + "id": gErr.ID, + }, + }, + } writeErr := conn.WriteJSON(autologMessage) if writeErr != nil { conn.WriteControl(websocket.CloseMessage, []byte{}, time.Now().Add(time.Second*1)) From e0ab29eeb026cf824c90195884a54d66c9c24ba3 Mon Sep 17 00:00:00 2001 From: hewiefreeman Date: Wed, 24 Jul 2019 03:37:45 -0700 Subject: [PATCH 064/132] Gofmt, lint, spellcheck, ineffassign --- actions/actions.go | 4 ++-- core/core.go | 1 - core/messaging.go | 2 +- core/roomTypes.go | 4 ++-- core/rooms.go | 3 ++- core/users.go | 8 ++++---- core/vars.go | 2 +- database/authentication.go | 10 ++++------ database/database.go | 8 ++++---- helpers/clientResponses.go | 2 +- helpers/crypto.go | 6 ------ helpers/crypto_test.go | 27 +-------------------------- sockets.go | 2 +- 13 files changed, 23 insertions(+), 56 deletions(-) diff --git a/actions/actions.go b/actions/actions.go index 188dc90..ce922ca 100644 --- a/actions/actions.go +++ b/actions/actions.go @@ -4,8 +4,8 @@ package actions import ( "errors" "github.com/gorilla/websocket" - "github.com/hewiefreeman/GopherGameServer/helpers" "github.com/hewiefreeman/GopherGameServer/core" + "github.com/hewiefreeman/GopherGameServer/helpers" ) // CustomClientAction is an action that you can handle on the server from @@ -214,7 +214,7 @@ func (c *Client) Respond(response interface{}, err ClientError) { } if err.id != -1 { r[helpers.ServerActionCustomClientActionResponse]["e"] = map[string]interface{}{ - "m": err.message, + "m": err.message, "id": err.id, } } else { diff --git a/core/core.go b/core/core.go index 9e6edb3..994bd80 100644 --- a/core/core.go +++ b/core/core.go @@ -105,7 +105,6 @@ func Resume() { } } - /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // GET STATE FOR RECOVERY ///////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/core/messaging.go b/core/messaging.go index 53c2abd..e824769 100644 --- a/core/messaging.go +++ b/core/messaging.go @@ -33,7 +33,7 @@ func (u *User) PrivateMessage(userName string, message interface{}) { //CONSTRUCT MESSAGE theMessage := map[string]map[string]interface{}{ helpers.ServerActionPrivateMessage: map[string]interface{}{ - "f": u.name, // from + "f": u.name, // from "t": user.name, // to "m": message, }, diff --git a/core/roomTypes.go b/core/roomTypes.go index 61dc763..99235f0 100644 --- a/core/roomTypes.go +++ b/core/roomTypes.go @@ -15,8 +15,8 @@ type RoomType struct { broadcastUserEnter bool broadcastUserLeave bool - createCallback func(*Room) // roomCreated - deleteCallback func(*Room) // roomDeleted + createCallback func(*Room) // roomCreated + deleteCallback func(*Room) // roomDeleted userEnterCallback func(*Room, *RoomUser) // roomFrom, user userLeaveCallback func(*Room, *RoomUser) // roomFrom, user } diff --git a/core/rooms.go b/core/rooms.go index 19f6508..a1b9729 100644 --- a/core/rooms.go +++ b/core/rooms.go @@ -25,6 +25,7 @@ type Room struct { vars map[string]interface{} } +// RoomUser represents a User inside of a Room. Use the *RoomUser.User() function to get a *User from a *RoomUser type RoomUser struct { user *User @@ -377,7 +378,7 @@ func (r *Room) RemoveUser(user *User, connID string) error { // NOTE: Remember that private rooms are designed to have an "owner", // and only the owner should be able to send an invite and revoke an invitation for their Rooms. Also, *User.Invite() // will send an invite notification message to the invited User that the client API can easily receive. Though if you wish to make -// your own implementations for sending and recieving these notifications, this function is safe to use. +// your own implementations for sending and receiving these notifications, this function is safe to use. func (r *Room) AddInvite(userName string) error { if !r.private { return errors.New("Room is not private") diff --git a/core/users.go b/core/users.go index f6a86fd..0d90ee3 100644 --- a/core/users.go +++ b/core/users.go @@ -40,8 +40,8 @@ type userConn struct { socket *websocket.Conn //MUST LOCK User's mux FIRST - room *Room - vars map[string]interface{} + room *Room + vars map[string]interface{} } var ( @@ -186,7 +186,7 @@ func Login(userName string, dbID int, autologPass string, isGuest bool, remMe bo for _, val := range friendsMap { frs := val.RequestStatus() friendEntry := map[string]interface{}{ - "n": val.Name(), + "n": val.Name(), "rs": frs, } if frs == database.FriendStatusAccepted { @@ -210,7 +210,7 @@ func Login(userName string, dbID int, autologPass string, isGuest bool, remMe bo for _, val := range friendsMap { frs := val.RequestStatus() friendEntry := map[string]interface{}{ - "n": val.Name(), + "n": val.Name(), "rs": frs, } if frs == database.FriendStatusAccepted { diff --git a/core/vars.go b/core/vars.go index f596127..dd97e11 100644 --- a/core/vars.go +++ b/core/vars.go @@ -1,8 +1,8 @@ package core import ( - "github.com/hewiefreeman/GopherGameServer/helpers" "errors" + "github.com/hewiefreeman/GopherGameServer/helpers" ) /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/database/authentication.go b/database/authentication.go index 632e04c..11db159 100644 --- a/database/authentication.go +++ b/database/authentication.go @@ -156,8 +156,6 @@ func checkCustomRequirements(customCols map[string]interface{}, requirements map // QUERY HELPERS ///////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////// - - ////////////////////////////////////////////////////////////////////////////////////////////////////// // SIGN A USER UP //////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -343,7 +341,7 @@ func LoginClient(userName string, password string, deviceTag string, remMe bool, devicePass, devicePassErr = helpers.GenerateSecureString(32) if devicePassErr == nil { _, exErr := database.Exec("INSERT INTO " + tableAutologs + " (" + autologsColumnID + ", " + autologsColumnDeviceTag + ", " + autologsColumnDevicePass + - ") VALUES (" + strconv.Itoa(*dbIndex) + ", \"" + deviceTag + "\", \"" + devicePass + "\");") + ") VALUES (" + strconv.Itoa(*dbIndex) + ", \"" + deviceTag + "\", \"" + devicePass + "\");") if exErr != nil { ////// LOG ERROR!!!!!! } @@ -476,7 +474,7 @@ func ChangePassword(userName string, password string, newPassword string, custom vals = append(vals, new(interface{})) valsList = append(valsList, []interface{}{val, customAccountInfo[key].dataType, key}) } - }else{ + } else { vals = make([]interface{}, 0, 2) vals = append(vals, new(int), new([]byte)) } @@ -575,7 +573,7 @@ func ChangeAccountInfo(userName string, password string, customCols map[string]i vals = append(vals, new(interface{})) valsList = append(valsList, []interface{}{val, customAccountInfo[key].dataType, key}) } - }else{ + } else { vals = make([]interface{}, 0, 2) vals = append(vals, new(int), new([]byte)) } @@ -677,7 +675,7 @@ func DeleteAccount(userName string, password string, customCols map[string]inter //MAINTAIN THE ORDER IN WHICH THE COLUMNS WERE DECLARED VIA A SLICE vals = append(vals, new(interface{})) } - }else{ + } else { vals = make([]interface{}, 0, 2) vals = append(vals, new(int), new([]byte)) } diff --git a/database/database.go b/database/database.go index 44ed785..396513f 100644 --- a/database/database.go +++ b/database/database.go @@ -17,11 +17,11 @@ var ( database *sql.DB //SERVER SETTINGS - serverStarted bool = false - serverPaused bool = false - rememberMe bool = false + serverStarted bool = false + serverPaused bool = false + rememberMe bool = false databaseName string = "gopherDB" - inited bool = false + inited bool = false ) //TABLE & COLUMN NAMES diff --git a/helpers/clientResponses.go b/helpers/clientResponses.go index 8b0efd3..e5d9cf5 100644 --- a/helpers/clientResponses.go +++ b/helpers/clientResponses.go @@ -59,7 +59,7 @@ func MakeClientResponse(action string, responseVal interface{}, err GopherError) ServerActionClientActionResponse: map[string]interface{}{ "a": action, "e": map[string]interface{}{ - "m": err.Message, + "m": err.Message, "is": err.ID, }, }, diff --git a/helpers/crypto.go b/helpers/crypto.go index 7fbd56e..64fa2a2 100644 --- a/helpers/crypto.go +++ b/helpers/crypto.go @@ -38,9 +38,3 @@ func CompareEncryptedData(str string, hash []byte) bool { err := bcrypt.CompareHashAndPassword(hash, []byte(str)) return err == nil } - -func UserHashNumber(s string) int { - h := fnv.New32a() - h.Write([]byte(s)) - return int(h.Sum32()) -} diff --git a/helpers/crypto_test.go b/helpers/crypto_test.go index 9fe9cb8..c89f2c8 100644 --- a/helpers/crypto_test.go +++ b/helpers/crypto_test.go @@ -1,8 +1,8 @@ package helpers import ( - "testing" "fmt" + "testing" ) /*func TestHashNumber(t *testing.T) { @@ -47,28 +47,3 @@ import ( fmt.Println("Min:", fullMin) fmt.Println("Max:", fullMax) }*/ - -func TestSameID(t *testing.T) { - names := make(map[int]string) - - fmt.Println(UserHashNumber("wBQl")) - fmt.Println(UserHashNumber("S3Sk")) - - for i := 0; i < 50000; i++ { - str, err := GenerateSecureString(3) - if err != nil { - fmt.Println(err) - return - } - - numb := UserHashNumber(str) - - if name, ok := names[numb]; ok { - if str != name { - fmt.Println("fault: '"+str+"' and '"+name+"'") - } - continue - } - names[numb] = str - } -} diff --git a/sockets.go b/sockets.go index 8a2dcd1..61bad92 100644 --- a/sockets.go +++ b/sockets.go @@ -218,7 +218,7 @@ func clientActionListener(conn *websocket.Conn) { helpers.ServerActionAutoLoginFailed: map[string]interface{}{ "dt": newTag, "e": map[string]interface{}{ - "m": gErr.Message, + "m": gErr.Message, "id": gErr.ID, }, }, From 172f8ccddf5a29efe06388ef56b796f3a70d07e9 Mon Sep 17 00:00:00 2001 From: Dominique Debergue Date: Wed, 24 Jul 2019 03:45:27 -0700 Subject: [PATCH 065/132] Update README.md --- README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index 189f6cd..5e9da88 100644 --- a/README.md +++ b/README.md @@ -85,9 +85,7 @@ Then install the server: [Package gopher](https://godoc.org/github.com/hewiefreeman/GopherGameServer) - Main server package for startup and settings -[Package rooms](https://godoc.org/github.com/hewiefreeman/GopherGameServer/rooms) - Package for using the Room, RoomType, and RoomUser types - -[Package users](https://godoc.org/github.com/hewiefreeman/GopherGameServer/users) - Package for using the User type +[Package core](https://godoc.org/github.com/hewiefreeman/GopherGameServer/core) - Package for all User and Room functionality [Package actions](https://godoc.org/github.com/hewiefreeman/GopherGameServer/actions) - Package for making custom client actions From 1509b3e60ed18bd4e1d9d817a796d4d32f6f6a57 Mon Sep 17 00:00:00 2001 From: Dominique Debergue Date: Wed, 24 Jul 2019 18:59:25 -0700 Subject: [PATCH 066/132] Update README.md --- README.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 5e9da88..f598ea5 100644 --- a/README.md +++ b/README.md @@ -19,11 +19,10 @@ Moreover, Gopher has a built-in, fully customizable SQL client authentication me ### Upcoming features - - Customizable sharding mechanism for accounts, freinds, and auto-login databases - - Support for master-slave and master-master replication (or MySQL Group Replication) - - Distributed load balancer/monitor + - Distributed load balancer/server coordinator/monitor - Secure server cluster broadcasts with caching optimizations - - Tools for administrating and monitoring servers + - GUI for administrating and monitoring servers + - Integration with [GopherDB](https://github.com/hewiefreeman/GopherDB) # Client APIs From 53e48e916899b091917254759003c7ed80946999 Mon Sep 17 00:00:00 2001 From: hewiefreeman Date: Wed, 24 Jul 2019 20:00:52 -0700 Subject: [PATCH 067/132] Gofmt, error fixes --- actions/actions.go | 3 +- clientActions.go | 2 +- core/core.go | 16 ++++---- core/roomTypes.go | 2 +- core/rooms.go | 84 +++++++++++++++++--------------------- helpers/clientResponses.go | 2 +- helpers/crypto.go | 1 - helpers/errors.go | 4 +- helpers/saveState.go | 3 +- sockets.go | 19 ++++++++- 10 files changed, 73 insertions(+), 63 deletions(-) diff --git a/actions/actions.go b/actions/actions.go index ce922ca..8f5b94c 100644 --- a/actions/actions.go +++ b/actions/actions.go @@ -94,7 +94,8 @@ func New(actionType string, dataType int, callback func(interface{}, *Client)) e } customClientActions[actionType] = CustomClientAction{ dataType: dataType, - callback: callback} + callback: callback, + } return nil } diff --git a/clientActions.go b/clientActions.go index 5d82cd8..7233a69 100644 --- a/clientActions.go +++ b/clientActions.go @@ -35,7 +35,7 @@ const ( func clientActionHandler(action clientAction, user **core.User, conn *websocket.Conn, deviceTag *string, devicePass *string, deviceUserID *int, connID *string, clientMux *sync.Mutex) (interface{}, bool, helpers.GopherError) { - switch _action := action.A; _action { + switch action.A { // HIGH LOOK-UP PRIORITY ITEMS diff --git a/core/core.go b/core/core.go index 994bd80..6a854cd 100644 --- a/core/core.go +++ b/core/core.go @@ -111,16 +111,18 @@ func Resume() { // GetState is only for internal Gopher Game Server mechanics. func GetState() map[string]map[string]interface{} { - state := map[string]map[string]interface{}{room.name: map[string]interface{}{}} + state := make(map[string]map[string]interface{}) roomsMux.Lock() for _, room := range rooms { room.mux.Lock() - state[room.name]["t"] = room.rType - state[room.name]["p"] = room.private - state[room.name]["o"] = room.owner - state[room.name]["m"] = room.maxUsers - state[room.name]["i"] = room.inviteList - state[room.name]["v"] = room.vars + state[room.name] = map[string]interface{}{ + "t": room.rType, + "p": room.private, + "o": room.owner, + "m": room.maxUsers, + "i": room.inviteList, + "v": room.vars, + } room.mux.Unlock() } roomsMux.Unlock() diff --git a/core/roomTypes.go b/core/roomTypes.go index 99235f0..5a3572f 100644 --- a/core/roomTypes.go +++ b/core/roomTypes.go @@ -151,7 +151,7 @@ func (r *RoomType) SetUserLeaveCallback(callback func(*Room, *RoomUser)) *RoomTy } ////////////////////////////////////////////////////////////////////////////////////////////////////// -// RoomType ATTRIBUTE READERS //////////////////////////////////////////////////////////////////// +// RoomType ATTRIBUTE & CALLBACK READERS ///////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////// // ServerOnly returns true if the RoomType can only be manipulated by the server. diff --git a/core/rooms.go b/core/rooms.go index a1b9729..f389fdc 100644 --- a/core/rooms.go +++ b/core/rooms.go @@ -6,7 +6,7 @@ import ( "sync" ) -// Room represents a room on the server that Users can join and leave. Use rooms.New() to make a new Room. +// Room represents a room on the server that Users can join and leave. Use core.NewRoom() to make a new Room. // // WARNING: When you use a *Room object in your code, DO NOT dereference it. Instead, there are // many methods for *Room for maniupulating and retrieving any information about them you could possibly need. @@ -57,7 +57,7 @@ var ( func NewRoom(name string, rType string, isPrivate bool, maxUsers int, owner string) (*Room, error) { //REJECT INCORRECT INPUT if len(name) == 0 { - return &Room{}, errors.New("rooms.New() requires a name") + return &Room{}, errors.New("core.NewRoom() requires a name") } else if maxUsers < 0 { maxUsers = 0 } else if owner == "" { @@ -148,7 +148,7 @@ func (r *Room) Delete() error { func GetRoom(roomName string) (*Room, error) { //REJECT INCORRECT INPUT if len(roomName) == 0 { - return &Room{}, errors.New("rooms.Get() requires a room name") + return &Room{}, errors.New("core.GetRoom() requires a room name") } var room *Room @@ -445,9 +445,43 @@ func (r *Room) RemoveInvite(userName string) error { } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// GET A ROOM's inviteList //////////////////////////////////////////////////////////////////////////////////// +// Room ATTRIBUTE READERS ///////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Name gets the name of the Room. +func (r *Room) Name() string { + return r.name +} + +// Type gets the type of the Room. +func (r *Room) Type() string { + return r.rType +} + +// IsPrivate returns true of the Room is private. +func (r *Room) IsPrivate() bool { + return r.private +} + +// Owner gets the name of the owner of the room +func (r *Room) Owner() string { + return r.owner +} + +// MaxUsers gets the maximum User capacity of the Room. +func (r *Room) MaxUsers() int { + return r.maxUsers +} + +// NumUsers gets the number of Users in the Room. +func (r *Room) NumUsers() int { + m, e := r.GetUserMap() + if e != nil { + return 0 + } + return len(m) +} + // InviteList gets a private Room's invite list. func (r *Room) InviteList() ([]string, error) { r.mux.Lock() @@ -461,10 +495,6 @@ func (r *Room) InviteList() ([]string, error) { return list, nil } -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// GET A Room's usersMap ////////////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // GetUserMap retrieves all the RoomUsers as a map[string]*RoomUser. func (r *Room) GetUserMap() (map[string]*RoomUser, error) { var err error @@ -481,10 +511,6 @@ func (r *Room) GetUserMap() (map[string]*RoomUser, error) { return userMap, err } -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Room ATTRIBUTE READERS ///////////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // RoomCount returns the number of Rooms created on the server. func RoomCount() int { roomsMux.Lock() @@ -493,40 +519,6 @@ func RoomCount() int { return length } -// Name gets the name of the Room. -func (r *Room) Name() string { - return r.name -} - -// Type gets the type of the Room. -func (r *Room) Type() string { - return r.rType -} - -// IsPrivate returns true of the Room is private. -func (r *Room) IsPrivate() bool { - return r.private -} - -// Owner gets the name of the owner of the room -func (r *Room) Owner() string { - return r.owner -} - -// MaxUsers gets the maximum User capacity of the Room. -func (r *Room) MaxUsers() int { - return r.maxUsers -} - -// NumUsers gets the number of Users in the Room. -func (r *Room) NumUsers() int { - m, e := r.GetUserMap() - if e != nil { - return 0 - } - return len(m) -} - /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // RoomUser ATTRIBUTE READERS ///////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/helpers/clientResponses.go b/helpers/clientResponses.go index e5d9cf5..0dc8d0c 100644 --- a/helpers/clientResponses.go +++ b/helpers/clientResponses.go @@ -60,7 +60,7 @@ func MakeClientResponse(action string, responseVal interface{}, err GopherError) "a": action, "e": map[string]interface{}{ "m": err.Message, - "is": err.ID, + "id": err.ID, }, }, } diff --git a/helpers/crypto.go b/helpers/crypto.go index 64fa2a2..74dc137 100644 --- a/helpers/crypto.go +++ b/helpers/crypto.go @@ -4,7 +4,6 @@ import ( "crypto/rand" "encoding/base64" "golang.org/x/crypto/bcrypt" - "hash/fnv" ) // GenerateRandomBytes uses the `crypto/rand` library to create a secure random `[]byte` at a given size `n`. diff --git a/helpers/errors.go b/helpers/errors.go index 66cf9eb..e155f22 100644 --- a/helpers/errors.go +++ b/helpers/errors.go @@ -60,7 +60,7 @@ const ( ErrorAuthConversion // 1048. There was an error while converting data to be stored on the database // Misc errors - ErrorActionDenied // 1049. The callback for this action denied it's completion + ErrorActionDenied // 1049. A callback has denied the server action ErrorServerPaused // 1050. The server is paused ) @@ -71,5 +71,5 @@ func NewError(message string, id int) GopherError { // NoError creates a new GopherError that represents a state in which no error occurred. func NoError() GopherError { - return GopherError{Message: "", ID: 0} + return GopherError{} } diff --git a/helpers/saveState.go b/helpers/saveState.go index 3cf02e3..a00cb21 100644 --- a/helpers/saveState.go +++ b/helpers/saveState.go @@ -9,11 +9,10 @@ import ( // SaveState is only for internal Gopher Server mechanics. func SaveState(stateObj map[string]interface{}, saveFolder string) error { //WRITE THE STATE - stateStr, err := json.Marshal(stateObj) + state, err := json.Marshal(stateObj) if err != nil { return err } - state := []byte(stateStr) err = ioutil.WriteFile(saveFolder+"/Gopher Recovery - "+time.Now().Format("2006-01-02 15-04-05")+".grf", state, 0644) if err != nil { return err diff --git a/sockets.go b/sockets.go index 61bad92..eb5fa7b 100644 --- a/sockets.go +++ b/sockets.go @@ -78,7 +78,6 @@ func clientActionListener(conn *websocket.Conn) { var ok bool var err error var gErr helpers.GopherError - var pMap map[string]interface{} var oldPass string //PING-PONG FOR TAGGING DEVICE - BREAKS WHEN THE DEVICE HAS BEEN PROPERLY TAGGED OR AUTHENTICATED. for { @@ -91,6 +90,7 @@ func clientActionListener(conn *websocket.Conn) { if writeErr != nil { conn.WriteControl(websocket.CloseMessage, []byte{}, time.Now().Add(time.Second*1)) conn.Close() + conns.subtract() return } sentTagRequest = true @@ -100,6 +100,7 @@ func clientActionListener(conn *websocket.Conn) { if readErr != nil || action.A == "" { conn.WriteControl(websocket.CloseMessage, []byte{}, time.Now().Add(time.Second*1)) conn.Close() + conns.subtract() return } @@ -110,6 +111,7 @@ func clientActionListener(conn *websocket.Conn) { if newDeviceTagErr != nil { conn.WriteControl(websocket.CloseMessage, []byte{}, time.Now().Add(time.Second*1)) conn.Close() + conns.subtract() return } deviceTag = string(newDeviceTag) @@ -120,6 +122,7 @@ func clientActionListener(conn *websocket.Conn) { if writeErr != nil { conn.WriteControl(websocket.CloseMessage, []byte{}, time.Now().Add(time.Second*1)) conn.Close() + conns.subtract() return } } else if action.A == "1" { @@ -129,6 +132,7 @@ func clientActionListener(conn *websocket.Conn) { //CLIENT DIDN'T USE THE PROVIDED DEVICE CODE FROM THE SERVER conn.WriteControl(websocket.CloseMessage, []byte{}, time.Now().Add(time.Second*1)) conn.Close() + conns.subtract() return } //SEND AUTO-LOG NOT FILED MESSAGE @@ -139,11 +143,13 @@ func clientActionListener(conn *websocket.Conn) { if writeErr != nil { conn.WriteControl(websocket.CloseMessage, []byte{}, time.Now().Add(time.Second*1)) conn.Close() + conns.subtract() return } } else { conn.WriteControl(websocket.CloseMessage, []byte{}, time.Now().Add(time.Second*1)) conn.Close() + conns.subtract() return } @@ -152,32 +158,38 @@ func clientActionListener(conn *websocket.Conn) { } else if action.A == "2" { //THE CLIENT HAS A LOGIN KEY PAIR - MAKE A NEW PASS FOR THEM + var pMap map[string]interface{} devicePass, err = helpers.GenerateSecureString(32) if err != nil { conn.WriteControl(websocket.CloseMessage, []byte{}, time.Now().Add(time.Second*1)) conn.Close() + conns.subtract() return } //GET PARAMS if pMap, ok = action.P.(map[string]interface{}); !ok { conn.WriteControl(websocket.CloseMessage, []byte{}, time.Now().Add(time.Second*1)) conn.Close() + conns.subtract() return } if deviceTag, ok = pMap["dt"].(string); !ok { conn.WriteControl(websocket.CloseMessage, []byte{}, time.Now().Add(time.Second*1)) conn.Close() + conns.subtract() return } if oldPass, ok = pMap["da"].(string); !ok { conn.WriteControl(websocket.CloseMessage, []byte{}, time.Now().Add(time.Second*1)) conn.Close() + conns.subtract() return } var deviceUserIDStr string if deviceUserIDStr, ok = pMap["di"].(string); !ok { conn.WriteControl(websocket.CloseMessage, []byte{}, time.Now().Add(time.Second*1)) conn.Close() + conns.subtract() return } //CONVERT di TO INT @@ -185,6 +197,7 @@ func clientActionListener(conn *websocket.Conn) { if err != nil { conn.WriteControl(websocket.CloseMessage, []byte{}, time.Now().Add(time.Second*1)) conn.Close() + conns.subtract() return } //CHANGE THE CLIENT'S PASS @@ -195,6 +208,7 @@ func clientActionListener(conn *websocket.Conn) { if writeErr != nil { conn.WriteControl(websocket.CloseMessage, []byte{}, time.Now().Add(time.Second*1)) conn.Close() + conns.subtract() return } } else if action.A == "3" { @@ -202,6 +216,7 @@ func clientActionListener(conn *websocket.Conn) { //IRRESPONSIBLE USAGE conn.WriteControl(websocket.CloseMessage, []byte{}, time.Now().Add(time.Second*1)) conn.Close() + conns.subtract() return } //AUTO-LOG THE CLIENT @@ -212,6 +227,7 @@ func clientActionListener(conn *websocket.Conn) { if newTagErr != nil { conn.WriteControl(websocket.CloseMessage, []byte{}, time.Now().Add(time.Second*1)) conn.Close() + conns.subtract() return } autologMessage := map[string]map[string]interface{}{ @@ -227,6 +243,7 @@ func clientActionListener(conn *websocket.Conn) { if writeErr != nil { conn.WriteControl(websocket.CloseMessage, []byte{}, time.Now().Add(time.Second*1)) conn.Close() + conns.subtract() return } oldPass = "" From ee2664ad9bc2a12204040559ba540fec46f96d8d Mon Sep 17 00:00:00 2001 From: hewiefreeman Date: Wed, 24 Jul 2019 20:09:41 -0700 Subject: [PATCH 068/132] Gofmt --- actions/actions.go | 2 +- core/friending.go | 8 ++++---- core/messaging.go | 4 ++-- core/rooms.go | 4 ++-- core/users.go | 10 +++++----- helpers/clientResponses.go | 4 ++-- sockets.go | 2 +- 7 files changed, 17 insertions(+), 17 deletions(-) diff --git a/actions/actions.go b/actions/actions.go index 8f5b94c..6c318db 100644 --- a/actions/actions.go +++ b/actions/actions.go @@ -209,7 +209,7 @@ func (c *Client) Respond(response interface{}, err ClientError) { (*c).responded = true //CONSTRUCT MESSAGE r := map[string]map[string]interface{}{ - helpers.ServerActionCustomClientActionResponse: map[string]interface{}{ + helpers.ServerActionCustomClientActionResponse: { "a": (*c).action, }, } diff --git a/core/friending.go b/core/friending.go index fa96aa0..46b7fae 100644 --- a/core/friending.go +++ b/core/friending.go @@ -51,7 +51,7 @@ func (u *User) FriendRequest(friendName string) error { //SEND A FRIEND REQUEST TO THE USER IF THEY ARE ONLINE if friendOnline { message := map[string]map[string]interface{}{ - helpers.ServerActionFriendRequest: map[string]interface{}{ + helpers.ServerActionFriendRequest: { "n": u.name, }, } @@ -120,7 +120,7 @@ func (u *User) AcceptFriendRequest(friendName string) error { var fStatus int = StatusOffline if friendOnline { message := map[string]map[string]interface{}{ - helpers.ServerActionFriendAccept: map[string]interface{}{ + helpers.ServerActionFriendAccept: { "n": u.name, "s": u.status, }, @@ -197,7 +197,7 @@ func (u *User) DeclineFriendRequest(friendName string) error { //SEND A FRIEND REQUEST TO THE USER IF THEY ARE ONLINE if friendOnline { message := map[string]map[string]interface{}{ - helpers.ServerActionFriendRemove: map[string]interface{}{ + helpers.ServerActionFriendRemove: { "n": u.name, }, } @@ -266,7 +266,7 @@ func (u *User) RemoveFriend(friendName string) error { //SEND A FRIEND REQUEST TO THE USER IF THEY ARE ONLINE if friendOnline { message := map[string]map[string]interface{}{ - helpers.ServerActionFriendRemove: map[string]interface{}{ + helpers.ServerActionFriendRemove: { "n": u.name, }, } diff --git a/core/messaging.go b/core/messaging.go index e824769..992a9ce 100644 --- a/core/messaging.go +++ b/core/messaging.go @@ -32,7 +32,7 @@ func (u *User) PrivateMessage(userName string, message interface{}) { //CONSTRUCT MESSAGE theMessage := map[string]map[string]interface{}{ - helpers.ServerActionPrivateMessage: map[string]interface{}{ + helpers.ServerActionPrivateMessage: { "f": u.name, // from "t": user.name, // to "m": message, @@ -200,7 +200,7 @@ func (r *Room) VoiceStream(userName string, userSocket *websocket.Conn, stream i //CONSTRUCT VOICE MESSAGE theMessage := map[string]map[string]interface{}{ - helpers.ServerActionVoiceStream: map[string]interface{}{ + helpers.ServerActionVoiceStream: { "u": userName, "d": stream, }, diff --git a/core/rooms.go b/core/rooms.go index f389fdc..99af68c 100644 --- a/core/rooms.go +++ b/core/rooms.go @@ -253,7 +253,7 @@ func (r *Room) AddUser(user *User, connID string) error { if roomType.BroadcastUserEnter() { //BROADCAST ENTER TO USERS IN ROOM message := map[string]map[string]interface{}{ - helpers.ServerActionUserEnter: map[string]interface{}{ + helpers.ServerActionUserEnter: { "u": userName, "g": user.isGuest, }, @@ -335,7 +335,7 @@ func (r *Room) RemoveUser(user *User, connID string) error { } else if roomType.BroadcastUserLeave() { //CONSTRUCT LEAVE MESSAGE message := map[string]map[string]interface{}{ - helpers.ServerActionUserLeave: map[string]interface{}{ + helpers.ServerActionUserLeave: { "u": userName, }, } diff --git a/core/users.go b/core/users.go index 0d90ee3..de57b2e 100644 --- a/core/users.go +++ b/core/users.go @@ -240,7 +240,7 @@ func Login(userName string, dbID int, autologPass string, isGuest bool, remMe bo //SEND ONLINE MESSAGE TO FRIENDS statusMessage := map[string]map[string]interface{}{ - helpers.ServerActionFriendStatusChange: map[string]interface{}{ + helpers.ServerActionFriendStatusChange: { "n": userName, "s": 0, }, @@ -332,7 +332,7 @@ func (u *User) Logout(connID string) { if len(u.conns) == 1 { //SEND STATUS CHANGE TO FRIENDS statusMessage := map[string]map[string]interface{}{ - helpers.ServerActionFriendStatusChange: map[string]interface{}{ + helpers.ServerActionFriendStatusChange: { "n": u.name, "s": StatusOffline, }, @@ -384,7 +384,7 @@ func (u *User) Kick() { //SEND STATUS CHANGE TO FRIENDS statusMessage := map[string]map[string]interface{}{ - helpers.ServerActionFriendStatusChange: map[string]interface{}{ + helpers.ServerActionFriendStatusChange: { "n": u.name, "s": StatusOffline, }, @@ -550,7 +550,7 @@ func (u *User) SetStatus(status int) { //SEND STATUS CHANGE MESSAGE TO User's FRIENDS WHOM ARE "ACCEPTED" message := map[string]map[string]interface{}{ - helpers.ServerActionFriendStatusChange: map[string]interface{}{ + helpers.ServerActionFriendStatusChange: { "n": u.name, "s": status, }, @@ -610,7 +610,7 @@ func (u *User) Invite(invUser *User, connID string) error { //MAKE INVITE MESSAGE invMessage := map[string]map[string]interface{}{ - helpers.ServerActionRoomInvite: map[string]interface{}{ + helpers.ServerActionRoomInvite: { "u": u.name, "r": currRoom.Name(), }, diff --git a/helpers/clientResponses.go b/helpers/clientResponses.go index 0dc8d0c..5d0ea18 100644 --- a/helpers/clientResponses.go +++ b/helpers/clientResponses.go @@ -56,7 +56,7 @@ func MakeClientResponse(action string, responseVal interface{}, err GopherError) var response map[string]map[string]interface{} if err.ID != 0 { response = map[string]map[string]interface{}{ - ServerActionClientActionResponse: map[string]interface{}{ + ServerActionClientActionResponse: { "a": action, "e": map[string]interface{}{ "m": err.Message, @@ -66,7 +66,7 @@ func MakeClientResponse(action string, responseVal interface{}, err GopherError) } } else { response = map[string]map[string]interface{}{ - ServerActionClientActionResponse: map[string]interface{}{ + ServerActionClientActionResponse: { "a": action, "r": responseVal, }, diff --git a/sockets.go b/sockets.go index eb5fa7b..e9771ba 100644 --- a/sockets.go +++ b/sockets.go @@ -231,7 +231,7 @@ func clientActionListener(conn *websocket.Conn) { return } autologMessage := map[string]map[string]interface{}{ - helpers.ServerActionAutoLoginFailed: map[string]interface{}{ + helpers.ServerActionAutoLoginFailed: { "dt": newTag, "e": map[string]interface{}{ "m": gErr.Message, From 94d3e443caf58cf2de731045bb1a7f661d374e05 Mon Sep 17 00:00:00 2001 From: Dominique Debergue Date: Wed, 24 Jul 2019 20:14:18 -0700 Subject: [PATCH 069/132] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f598ea5..283685e 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Gopher Game Server -[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) [![GoDoc](https://godoc.org/github.com/hewiefreeman/GopherGameServer?status.svg)](https://godoc.org/github.com/hewiefreeman/GopherGameServer) [![Go Report Card](https://goreportcard.com/badge/github.com/hewiefreeman/GopherGameServer)](https://goreportcard.com/report/github.com/hewiefreeman/GopherGameServer) +[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) [![GoDoc](https://godoc.org/github.com/hewiefreeman/GopherGameServer?status.svg)](https://godoc.org/github.com/hewiefreeman/GopherGameServer) [![Go Report Card](https://goreportcard.com/badge/github.com/hewiefreeman/GopherGameServer)](https://goreportcard.com/badge/github.com/hewiefreeman/GopherGameServer) Gopher Game Server is designed to provide all necessary tools to greatly ease developments of any type of online game (or any real-time app/chat). Gopher will handle all server-side synchronizing and data type conversions, therefore, client actions receiving, variable setting, messaging, and other functionalities are unproblematic. From f389c3c1c4a895271260a8948767d846a153afd0 Mon Sep 17 00:00:00 2001 From: Dominique Debergue Date: Wed, 24 Jul 2019 20:14:50 -0700 Subject: [PATCH 070/132] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 283685e..f598ea5 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Gopher Game Server -[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) [![GoDoc](https://godoc.org/github.com/hewiefreeman/GopherGameServer?status.svg)](https://godoc.org/github.com/hewiefreeman/GopherGameServer) [![Go Report Card](https://goreportcard.com/badge/github.com/hewiefreeman/GopherGameServer)](https://goreportcard.com/badge/github.com/hewiefreeman/GopherGameServer) +[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) [![GoDoc](https://godoc.org/github.com/hewiefreeman/GopherGameServer?status.svg)](https://godoc.org/github.com/hewiefreeman/GopherGameServer) [![Go Report Card](https://goreportcard.com/badge/github.com/hewiefreeman/GopherGameServer)](https://goreportcard.com/report/github.com/hewiefreeman/GopherGameServer) Gopher Game Server is designed to provide all necessary tools to greatly ease developments of any type of online game (or any real-time app/chat). Gopher will handle all server-side synchronizing and data type conversions, therefore, client actions receiving, variable setting, messaging, and other functionalities are unproblematic. From e3d18edd3158228659290c1efc61db28e9eaa2f7 Mon Sep 17 00:00:00 2001 From: Dominique Debergue Date: Wed, 24 Jul 2019 21:21:06 -0700 Subject: [PATCH 071/132] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f598ea5..bd60e05 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Gopher Game Server -[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) [![GoDoc](https://godoc.org/github.com/hewiefreeman/GopherGameServer?status.svg)](https://godoc.org/github.com/hewiefreeman/GopherGameServer) [![Go Report Card](https://goreportcard.com/badge/github.com/hewiefreeman/GopherGameServer)](https://goreportcard.com/report/github.com/hewiefreeman/GopherGameServer) +[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) [![GoDoc](https://godoc.org/github.com/hewiefreeman/GopherGameServer?status.svg)](https://godoc.org/github.com/hewiefreeman/GopherGameServer) [![Go Report Card](https://goreportcard.com/badge/github.com/hewiefreeman/GopherGameServer?f=v1006)](https://goreportcard.com/report/github.com/hewiefreeman/GopherGameServer) Gopher Game Server is designed to provide all necessary tools to greatly ease developments of any type of online game (or any real-time app/chat). Gopher will handle all server-side synchronizing and data type conversions, therefore, client actions receiving, variable setting, messaging, and other functionalities are unproblematic. From 141dab3e7b538531a3d3f3dae900bf0100b31d27 Mon Sep 17 00:00:00 2001 From: Dominique Debergue Date: Wed, 24 Jul 2019 21:27:04 -0700 Subject: [PATCH 072/132] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bd60e05..8223c31 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Gopher Game Server -[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) [![GoDoc](https://godoc.org/github.com/hewiefreeman/GopherGameServer?status.svg)](https://godoc.org/github.com/hewiefreeman/GopherGameServer) [![Go Report Card](https://goreportcard.com/badge/github.com/hewiefreeman/GopherGameServer?f=v1006)](https://goreportcard.com/report/github.com/hewiefreeman/GopherGameServer) +[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) [![GoDoc](https://godoc.org/github.com/hewiefreeman/GopherGameServer?status.svg)](https://godoc.org/github.com/hewiefreeman/GopherGameServer) [![Go Report Card](https://goreportcard.com/badge/github.com/hewiefreeman/GopherGameServer?f=v101&style=plastic)](https://goreportcard.com/report/github.com/hewiefreeman/GopherGameServer) Gopher Game Server is designed to provide all necessary tools to greatly ease developments of any type of online game (or any real-time app/chat). Gopher will handle all server-side synchronizing and data type conversions, therefore, client actions receiving, variable setting, messaging, and other functionalities are unproblematic. From d08ed85e8e5f8c6742594b6cffd71a22834aeef4 Mon Sep 17 00:00:00 2001 From: Dominique Debergue Date: Fri, 26 Jul 2019 18:33:14 -0700 Subject: [PATCH 073/132] Clarified error definitions --- helpers/errors.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helpers/errors.go b/helpers/errors.go index e155f22..6938e07 100644 --- a/helpers/errors.go +++ b/helpers/errors.go @@ -14,7 +14,7 @@ const ( ErrorGopherNotLoggedIn // 1004. The client must be logged in to take action ErrorGopherLoggedIn // 1005. The client must be logged out to take action ErrorGopherStatusChange // 1006. Error while changing User's status - ErrorGopherFeatureDisabled // 1007. The feature required for the action is disabled + ErrorGopherFeatureDisabled // 1007. A server feature must be explicitly enabled to take action ErrorGopherColumnsFormat // 1008. The client's custom columns data is not a map/object ErrorGopherNameFormat // 1009. The client's user name data is not a string ErrorGopherPasswordFormat // 1010. The client's password data is not a string From 177b21d0ac40548c4bdbca22d50d1e583b1881a7 Mon Sep 17 00:00:00 2001 From: hewiefreeman Date: Fri, 26 Jul 2019 18:38:49 -0700 Subject: [PATCH 074/132] Testing, bug fixes, and server response error clarifications --- clientActions.go | 4 ++-- core/rooms.go | 12 ++++------- database/friending.go | 16 ++++++++------ helpers/crypto_test.go | 49 ------------------------------------------ server.go | 2 +- sockets.go | 10 +++++---- 6 files changed, 23 insertions(+), 70 deletions(-) delete mode 100644 helpers/crypto_test.go diff --git a/clientActions.go b/clientActions.go index 7233a69..9624db5 100644 --- a/clientActions.go +++ b/clientActions.go @@ -13,7 +13,7 @@ const ( errorInvalidAction = "Invalid action" errorLoggedIn = "You must be logged out" errorNotLoggedIn = "You must be logged in" - errorFeatureDisabled = "Server feature is disabled" + errorFeatureDisabled = "Server feature not enabled" errorRoomControl = "Clients cannot control rooms" errorServerRoom = "Clients cannot control that room type" errorNotOwner = "You are not the owner of the room" @@ -336,7 +336,7 @@ func clientActionLogin(params interface{}, user **core.User, deviceTag *string, connID *string, clientMux *sync.Mutex) (interface{}, bool, helpers.GopherError) { (*clientMux).Lock() if *user != nil { - defer (*clientMux).Unlock() + (*clientMux).Unlock() return nil, true, helpers.NewError(errorLoggedIn, helpers.ErrorGopherLoggedIn) } (*clientMux).Unlock() diff --git a/core/rooms.go b/core/rooms.go index 99af68c..3d97795 100644 --- a/core/rooms.go +++ b/core/rooms.go @@ -76,21 +76,17 @@ func NewRoom(name string, rType string, isPrivate bool, maxUsers int, owner stri roomsMux.Unlock() return &Room{}, errors.New("A Room with the name '" + name + "' already exists") } - userMap := make(map[string]*RoomUser) - roomVars := make(map[string]interface{}) - invList := []string{} - theRoom := Room{name: name, private: isPrivate, inviteList: invList, usersMap: userMap, maxUsers: maxUsers, vars: roomVars, - owner: owner, rType: rType} + theRoom := Room{name: name, private: isPrivate, inviteList: []string{}, usersMap: make(map[string]*RoomUser), maxUsers: maxUsers, + vars: make(map[string]interface{}), owner: owner, rType: rType} rooms[name] = &theRoom - room := rooms[name] roomsMux.Unlock() //CALLBACK if roomType.HasCreateCallback() { - roomType.CreateCallback()(room) + roomType.CreateCallback()(&theRoom) } - return room, nil + return &theRoom, nil } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/database/friending.go b/database/friending.go index 7e25447..d431f91 100644 --- a/database/friending.go +++ b/database/friending.go @@ -99,30 +99,34 @@ func GetFriends(userIndex int) (map[string]*Friend, error) { //EXECUTE SELECT QUERY friendRows, friendRowsErr := database.Query("Select " + friendsColumnFriend + ", " + friendsColumnStatus + " FROM " + tableFriends + " WHERE " + friendsColumnUser + "=" + strconv.Itoa(userIndex) + ";") if friendRowsErr != nil { - return friends, friendRowsErr + return nil, friendRowsErr } - defer friendRows.Close() // for friendRows.Next() { var friendName string var friendID int var friendStatus int if scanErr := friendRows.Scan(&friendID, &friendStatus); scanErr != nil { - return friends, scanErr + friendRows.Close() + return nil, scanErr } // friendInfoRows, friendInfoErr := database.Query("Select " + usersColumnName + " FROM " + tableUsers + " WHERE " + usersColumnID + "=" + strconv.Itoa(friendID) + " LIMIT 1;") if friendInfoErr != nil { - return friends, friendInfoErr + friendRows.Close() + return nil, friendInfoErr } - defer friendInfoRows.Close() friendInfoRows.Next() if scanErr := friendInfoRows.Scan(&friendName); scanErr != nil { - return friends, scanErr + friendRows.Close() + friendInfoRows.Close() + return nil, scanErr } + friendInfoRows.Close() aFriend := Friend{name: friendName, dbID: friendID, status: friendStatus} friends[friendName] = &aFriend } + friendRows.Close() // return friends, nil } diff --git a/helpers/crypto_test.go b/helpers/crypto_test.go deleted file mode 100644 index c89f2c8..0000000 --- a/helpers/crypto_test.go +++ /dev/null @@ -1,49 +0,0 @@ -package helpers - -import ( - "fmt" - "testing" -) - -/*func TestHashNumber(t *testing.T) { - - // The amount of databases - amount := 5 - lst := make([]int, amount, amount) - - // Maximum ID - max := 4294967295 - - // Max/Min generated IDs - fullMin := 0 - fullMax := 0 - - for i := 0; i < 4000000; i++ { - str, err := GenerateSecureString(32) - if err != nil { - fmt.Println(err) - return - } - - numb := UserHashNumber(str) - if fullMin == 0 || numb < fullMin { - fullMin = numb - } - if numb > fullMax { - fullMax = numb - } - for i := 0; i < amount; i++ { - if numb <= (max/amount)*(i+1) { - lst[i]++ - break - } - } - } - - for i := 0; i < len(lst); i++ { - fmt.Println("Database", i, "would have", lst[i], "entries") - } - - fmt.Println("Min:", fullMin) - fmt.Println("Max:", fullMax) -}*/ diff --git a/server.go b/server.go index 3809865..1682245 100644 --- a/server.go +++ b/server.go @@ -83,7 +83,7 @@ var ( clientConnectCallback func(*http.ResponseWriter, *http.Request) bool //SERVER VERSION NUMBER - version string = "1.0-ALPHA.4" + version string = "1.0-ALPHA.5" ) ////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/sockets.go b/sockets.go index e9771ba..307159a 100644 --- a/sockets.go +++ b/sockets.go @@ -55,7 +55,7 @@ func socketInitializer(w http.ResponseWriter, r *http.Request) { return } - // + // START WEBSOCKET LOOP go clientActionListener(conn) } @@ -306,12 +306,13 @@ func sockedDropped(user *core.User, connID string, clientMux *sync.Mutex) { func (c *connections) add() bool { c.connsMux.Lock() - defer c.connsMux.Unlock() // if (*settings).MaxConnections != 0 && c.conns == (*settings).MaxConnections { + c.connsMux.Unlock() return false } c.conns++ + c.connsMux.Unlock() // return true } @@ -326,6 +327,7 @@ func (c *connections) subtract() { // not logged in as a User. To get the number of Users logged in, use the core.UserCount() function. func ClientsConnected() int { conns.connsMux.Lock() - defer conns.connsMux.Unlock() - return conns.conns + c := conns.conns + conns.connsMux.Unlock() + return c } From d2ed615397c58151b61bdff2e5414e75df350132 Mon Sep 17 00:00:00 2001 From: hewiefreeman Date: Sat, 27 Jul 2019 17:20:23 -0700 Subject: [PATCH 075/132] Ineffassign fix --- sockets.go | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/sockets.go b/sockets.go index 307159a..3993967 100644 --- a/sockets.go +++ b/sockets.go @@ -73,7 +73,17 @@ func clientActionListener(conn *websocket.Conn) { var deviceUserID int if (*settings).RememberMe { - var sentTagRequest bool = false + //SEND TAG RETRIEVAL MESSAGE + tagMessage := map[string]interface{}{ + helpers.ServerActionRequestDeviceTag: nil, + } + writeErr := conn.WriteJSON(tagMessage) + if writeErr != nil { + conn.WriteControl(websocket.CloseMessage, []byte{}, time.Now().Add(time.Second*1)) + conn.Close() + conns.subtract() + return + } //PARAMS var ok bool var err error @@ -81,20 +91,6 @@ func clientActionListener(conn *websocket.Conn) { var oldPass string //PING-PONG FOR TAGGING DEVICE - BREAKS WHEN THE DEVICE HAS BEEN PROPERLY TAGGED OR AUTHENTICATED. for { - if !sentTagRequest { - //SEND TAG RETRIEVAL MESSAGE - tagMessage := map[string]interface{}{ - helpers.ServerActionRequestDeviceTag: nil, - } - writeErr := conn.WriteJSON(tagMessage) - if writeErr != nil { - conn.WriteControl(websocket.CloseMessage, []byte{}, time.Now().Add(time.Second*1)) - conn.Close() - conns.subtract() - return - } - sentTagRequest = true - } //READ INPUT BUFFER readErr := conn.ReadJSON(&action) if readErr != nil || action.A == "" { @@ -222,7 +218,7 @@ func clientActionListener(conn *websocket.Conn) { //AUTO-LOG THE CLIENT connID, gErr = core.AutoLogIn(deviceTag, oldPass, devicePass, deviceUserID, conn, &user, &clientMux) if gErr.ID != 0 { - //ERROR AUTO-LOGGING - RUN AUTOLOGCOMPLETE AND DELETE KEYS FOR CLIENT, AND SILENTLY CHANGE DEVICE KEY + //ERROR AUTO-LOGGING - RUN AUTOLOGCOMPLETE AND DELETE KEYS FOR CLIENT, AND SILENTLY CHANGE DEVICE TAG newTag, newTagErr := helpers.GenerateSecureString(32) if newTagErr != nil { conn.WriteControl(websocket.CloseMessage, []byte{}, time.Now().Add(time.Second*1)) @@ -246,7 +242,6 @@ func clientActionListener(conn *websocket.Conn) { conns.subtract() return } - oldPass = "" devicePass = "" deviceUserID = 0 deviceTag = newTag From a272cd23b671fa3ea7ebc87f146ac9ce59af0eb7 Mon Sep 17 00:00:00 2001 From: Dominique Debergue Date: Sat, 27 Jul 2019 17:47:55 -0700 Subject: [PATCH 076/132] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 8223c31..881954f 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Gopher Game Server is designed to provide all necessary tools to greatly ease developments of any type of online game (or any real-time app/chat). Gopher will handle all server-side synchronizing and data type conversions, therefore, client actions receiving, variable setting, messaging, and other functionalities are unproblematic. -Moreover, Gopher has a built-in, fully customizable SQL client authentication mechanism that creates and manages users' accounts for you. It even ties in a friending tool, so users can befriend and invite one another to groups, check each other's status, and more. All components are easily configurable and customizable for specific project's needs. +Moreover, Gopher has a built-in, fully customizable SQL client authentication mechanism that creates and manages users' accounts for you. It even ties in a friending tool, so users can befriend and invite one another to groups, check each other's status, and more. All components are easily configurable and customizable for any specific project's needs. ### Main features @@ -22,12 +22,12 @@ Moreover, Gopher has a built-in, fully customizable SQL client authentication me - Distributed load balancer/server coordinator/monitor - Secure server cluster broadcasts with caching optimizations - GUI for administrating and monitoring servers - - Integration with [GopherDB](https://github.com/hewiefreeman/GopherDB) + - Integration with [GopherDB](https://github.com/hewiefreeman/GopherDB) when stable # Client APIs - JavaScript: [GopherClientJS](https://github.com/hewiefreeman/GopherClientJS) - - Java: [GopherClientJava](https://github.com/hewiefreeman/GopherClientJava) + - Java: [GopherClientJava](https://github.com/hewiefreeman/GopherClientJava) ( **In development** ) > If you want to make a client API in an unsupported language and want to know where to start and/or have any questions, feel free to [email me](mailto:dominiquedebergue@gmail.com?subject=[GitHub]%20Gopher%20Game%20Server)! From c49507ca620d414e85e952bd47ec86a02f636ed5 Mon Sep 17 00:00:00 2001 From: Dominique Debergue Date: Sat, 27 Jul 2019 18:20:36 -0700 Subject: [PATCH 077/132] Update README.md --- README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 881954f..94df49a 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Gopher Game Server is designed to provide all necessary tools to greatly ease de Moreover, Gopher has a built-in, fully customizable SQL client authentication mechanism that creates and manages users' accounts for you. It even ties in a friending tool, so users can befriend and invite one another to groups, check each other's status, and more. All components are easily configurable and customizable for any specific project's needs. -### Main features +### :star: Main features - Super easy and flexible APIs for server, database, and client coding - Chat, private messaging, and voice chat @@ -24,14 +24,14 @@ Moreover, Gopher has a built-in, fully customizable SQL client authentication me - GUI for administrating and monitoring servers - Integration with [GopherDB](https://github.com/hewiefreeman/GopherDB) when stable -# Client APIs +# :video_game: Client APIs - JavaScript: [GopherClientJS](https://github.com/hewiefreeman/GopherClientJS) - Java: [GopherClientJava](https://github.com/hewiefreeman/GopherClientJava) ( **In development** ) > If you want to make a client API in an unsupported language and want to know where to start and/or have any questions, feel free to [email me](mailto:dominiquedebergue@gmail.com?subject=[GitHub]%20Gopher%20Game%20Server)! -# Installing +# :file_folder: Installing Gopher Game Server requires at least **Go v1.8+** (and **MySQL v5.7+** for the authentication and friending features). First, install the dependencies: @@ -44,7 +44,7 @@ Then install the server: go get github.com/hewiefreeman/GopherGameServer -# Usage +# :books: Usage ### Table of Contents @@ -80,7 +80,7 @@ Then install the server: - [Auto-Login (Remember Me)](https://github.com/hewiefreeman/GopherGameServer/wiki/SQL-Features#auto-login-remember-me) - [Friending](https://github.com/hewiefreeman/GopherGameServer/wiki/SQL-Features#friending) -# Documentation +# :scroll: Documentation [Package gopher](https://godoc.org/github.com/hewiefreeman/GopherGameServer) - Main server package for startup and settings @@ -90,8 +90,8 @@ Then install the server: [Package database](https://godoc.org/github.com/hewiefreeman/GopherGameServer/database) - Package for customizing your database -# Contributions -Contributions are open and welcomed! Help is needed for everything from documentation, cleaning up code, performance enhancements, client APIs and more. Don't forget to show your support by starring or following the project! +# :milky_way: Contributions +Contributions are open and welcomed! Help is needed for everything from documentation, cleaning up code, performance enhancements, client APIs and more. Don't forget to show your support with a :star:! If you want to make a client API in an unsupported language and want to know where to start and/or have any questions, feel free to [email me](mailto:dominiquedebergue@gmail.com?subject=[GitHub]%20Gopher%20Game%20Server)! From 28e76732810501e232fa3037bf80317d8cc45246 Mon Sep 17 00:00:00 2001 From: Dominique Debergue Date: Sat, 27 Jul 2019 19:01:04 -0700 Subject: [PATCH 078/132] Update README.md --- README.md | 50 +++++++++++++++++++++++++------------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index 94df49a..3d46e3d 100644 --- a/README.md +++ b/README.md @@ -49,36 +49,36 @@ Then install the server: ### Table of Contents 1) [**Getting Started**](https://github.com/hewiefreeman/GopherGameServer/wiki/Getting-Started) - - [Set-Up](https://github.com/hewiefreeman/GopherGameServer/wiki/Getting-Started#set-up) - - [Core Server Settings](https://github.com/hewiefreeman/GopherGameServer/wiki/Getting-Started#core-server-settings) - - [Server Callbacks](https://github.com/hewiefreeman/GopherGameServer/wiki/Getting-Started#server-callbacks) - - [Macro Commands](https://github.com/hewiefreeman/GopherGameServer/wiki/Getting-Started#macro-commands) + - [Set-Up](https://github.com/hewiefreeman/GopherGameServer/wiki/Getting-Started#blue_book-set-up) + - [Core Server Settings](https://github.com/hewiefreeman/GopherGameServer/wiki/Getting-Started#blue_book-core-server-settings) + - [Server Callbacks](https://github.com/hewiefreeman/GopherGameServer/wiki/Getting-Started#blue_book-server-callbacks) + - [Macro Commands](https://github.com/hewiefreeman/GopherGameServer/wiki/Getting-Started#blue_book-macro-commands) 2) [**Rooms**](https://github.com/hewiefreeman/GopherGameServer/wiki/Rooms) - - [Room Types](https://github.com/hewiefreeman/GopherGameServer/wiki/Rooms#room-types) - - [Room Broadcasts](https://github.com/hewiefreeman/GopherGameServer/wiki/Rooms#room-broadcasts) - - [Room Callbacks](https://github.com/hewiefreeman/GopherGameServer/wiki/Rooms#room-callbacks) - - [Creating & Deleting Rooms](https://github.com/hewiefreeman/GopherGameServer/wiki/Rooms#creating--deleting-rooms) - - [Room Variables](https://github.com/hewiefreeman/GopherGameServer/wiki/Rooms#room-variables) - - [Messaging](https://github.com/hewiefreeman/GopherGameServer/wiki/Rooms#messaging) + - [Room Types](https://github.com/hewiefreeman/GopherGameServer/wiki/Rooms#blue_book-room-types) + - [Room Broadcasts](https://github.com/hewiefreeman/GopherGameServer/wiki/Rooms#blue_book-room-broadcasts) + - [Room Callbacks](https://github.com/hewiefreeman/GopherGameServer/wiki/Rooms#blue_book-room-callbacks) + - [Creating & Deleting Rooms](https://github.com/hewiefreeman/GopherGameServer/wiki/Rooms#blue_book-creating--deleting-rooms) + - [Room Variables](https://github.com/hewiefreeman/GopherGameServer/wiki/Rooms#blue_book-room-variables) + - [Messaging](https://github.com/hewiefreeman/GopherGameServer/wiki/Rooms#blue_book-messaging) 3) [**Users**](https://github.com/hewiefreeman/GopherGameServer/wiki/Users) - - [Login & Logout](https://github.com/hewiefreeman/GopherGameServer/wiki/Users#login-and-logout) - - [Joining & Leaving Rooms](https://github.com/hewiefreeman/GopherGameServer/wiki/Users#joining--leaving-rooms) - - [User Variables](https://github.com/hewiefreeman/GopherGameServer/wiki/Users#user-variables) - - [Initiating and Revoking Room Invites](https://github.com/hewiefreeman/GopherGameServer/wiki/Users#initiating-and-revoking-room-invites) - - [User Status](https://github.com/hewiefreeman/GopherGameServer/wiki/Users#user-status) - - [Messaging](https://github.com/hewiefreeman/GopherGameServer/wiki/Users#messaging) + - [Login & Logout](https://github.com/hewiefreeman/GopherGameServer/wiki/Users#blue_book-login-and-logout) + - [Joining & Leaving Rooms](https://github.com/hewiefreeman/GopherGameServer/wiki/Users#blue_book-joining--leaving-rooms) + - [User Variables](https://github.com/hewiefreeman/GopherGameServer/wiki/Users#blue_book-user-variables) + - [Initiating and Revoking Room Invites](https://github.com/hewiefreeman/GopherGameServer/wiki/Users#blue_book-initiating-and-revoking-room-invites) + - [User Status](https://github.com/hewiefreeman/GopherGameServer/wiki/Users#blue_book-user-status) + - [Messaging](https://github.com/hewiefreeman/GopherGameServer/wiki/Users#blue_book-messaging) 4) [**Custom Client Actions**](https://github.com/hewiefreeman/GopherGameServer/wiki/Custom-Client-Actions) - - [Creating a Custom Client Action](https://github.com/hewiefreeman/GopherGameServer/wiki/Custom-Client-Actions#creating-a-custom-client-action) - - [Responding to a Custom Client Action](https://github.com/hewiefreeman/GopherGameServer/wiki/Custom-Client-Actions#responding-to-a-custom-client-action) + - [Creating a Custom Client Action](https://github.com/hewiefreeman/GopherGameServer/wiki/Custom-Client-Actions#blue_book-creating-a-custom-client-action) + - [Responding to a Custom Client Action](https://github.com/hewiefreeman/GopherGameServer/wiki/Custom-Client-Actions#blue_book-responding-to-a-custom-client-action) 6) [**Saving & Restoring**](https://github.com/hewiefreeman/GopherGameServer/wiki/Saving-&-Restoring) - - [Set-Up](https://github.com/hewiefreeman/GopherGameServer/wiki/Saving-&-Restoring#set-up) + - [Set-Up](https://github.com/hewiefreeman/GopherGameServer/wiki/Saving-&-Restoring#blue_book-set-up) 5) [**SQL Features**](https://github.com/hewiefreeman/GopherGameServer/wiki/SQL-Features) - - [Set-Up](https://github.com/hewiefreeman/GopherGameServer/wiki/SQL-Features#set-up) - - [Authenticating Clients](https://github.com/hewiefreeman/GopherGameServer/wiki/SQL-Features#authenticating-clients) - - [Custom Account Info](https://github.com/hewiefreeman/GopherGameServer/wiki/SQL-Features#custom-account-info) - - [Customizing Authentication Features](https://github.com/hewiefreeman/GopherGameServer/wiki/SQL-Features#customizing-authentication-features) - - [Auto-Login (Remember Me)](https://github.com/hewiefreeman/GopherGameServer/wiki/SQL-Features#auto-login-remember-me) - - [Friending](https://github.com/hewiefreeman/GopherGameServer/wiki/SQL-Features#friending) + - [Set-Up](https://github.com/hewiefreeman/GopherGameServer/wiki/SQL-Features#blue_book-set-up) + - [Authenticating Clients](https://github.com/hewiefreeman/GopherGameServer/wiki/SQL-Features#blue_book-authenticating-clients) + - [Custom Account Info](https://github.com/hewiefreeman/GopherGameServer/wiki/SQL-Features#blue_book-custom-account-info) + - [Customizing Authentication Features](https://github.com/hewiefreeman/GopherGameServer/wiki/SQL-Features#blue_book-customizing-authentication-features) + - [Auto-Login (Remember Me)](https://github.com/hewiefreeman/GopherGameServer/wiki/SQL-Features#blue_book-auto-login-remember-me) + - [Friending](https://github.com/hewiefreeman/GopherGameServer/wiki/SQL-Features#blue_book-friending) # :scroll: Documentation From 5cc5680955a325e701a557b2fc9b022f2ccf3179 Mon Sep 17 00:00:00 2001 From: Dominique Debergue Date: Sat, 27 Jul 2019 19:20:44 -0700 Subject: [PATCH 079/132] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 3d46e3d..cc61dbd 100644 --- a/README.md +++ b/README.md @@ -46,6 +46,8 @@ Then install the server: # :books: Usage +[:bookmark: Wiki Home](https://github.com/hewiefreeman/GopherGameServer/wiki) + ### Table of Contents 1) [**Getting Started**](https://github.com/hewiefreeman/GopherGameServer/wiki/Getting-Started) From 3f335262426192b5062f42d5c8d9ae1b38b859b5 Mon Sep 17 00:00:00 2001 From: Dominique Debergue Date: Sun, 28 Jul 2019 19:49:51 -0700 Subject: [PATCH 080/132] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index cc61dbd..16123cb 100644 --- a/README.md +++ b/README.md @@ -17,10 +17,10 @@ Moreover, Gopher has a built-in, fully customizable SQL client authentication me > (**\***) A MySQL (or similar SQL) database is required for the authentication/friending feature, but is an optional (like most) feature that can be enabled or disabled to use your own implementations. -### Upcoming features +### :construction: Upcoming features - - Distributed load balancer/server coordinator/monitor - - Secure server cluster broadcasts with caching optimizations + - Distributed load balancer and server coordinator + - Distributed server broadcasts - GUI for administrating and monitoring servers - Integration with [GopherDB](https://github.com/hewiefreeman/GopherDB) when stable From a32ab0e786a738d965bcae427ebe5a6ef09380d9 Mon Sep 17 00:00:00 2001 From: Dominique Debergue Date: Sun, 28 Jul 2019 19:50:26 -0700 Subject: [PATCH 081/132] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 16123cb..5ebfbf8 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ Moreover, Gopher has a built-in, fully customizable SQL client authentication me > (**\***) A MySQL (or similar SQL) database is required for the authentication/friending feature, but is an optional (like most) feature that can be enabled or disabled to use your own implementations. -### :construction: Upcoming features +### Upcoming features - Distributed load balancer and server coordinator - Distributed server broadcasts From d07b460a16efaed1e1db995de45412a70097b9fd Mon Sep 17 00:00:00 2001 From: Dominique Debergue Date: Wed, 31 Jul 2019 23:13:14 -0700 Subject: [PATCH 082/132] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5ebfbf8..2ca6078 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Gopher Game Server -[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) [![GoDoc](https://godoc.org/github.com/hewiefreeman/GopherGameServer?status.svg)](https://godoc.org/github.com/hewiefreeman/GopherGameServer) [![Go Report Card](https://goreportcard.com/badge/github.com/hewiefreeman/GopherGameServer?f=v101&style=plastic)](https://goreportcard.com/report/github.com/hewiefreeman/GopherGameServer) +[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) [![GoDoc](https://godoc.org/github.com/hewiefreeman/GopherGameServer?status.svg)](https://godoc.org/github.com/hewiefreeman/GopherGameServer) [![Go Report Card](https://goreportcard.com/badge/github.com/hewiefreeman/GopherGameServer?f=v101)](https://goreportcard.com/report/github.com/hewiefreeman/GopherGameServer) Gopher Game Server is designed to provide all necessary tools to greatly ease developments of any type of online game (or any real-time app/chat). Gopher will handle all server-side synchronizing and data type conversions, therefore, client actions receiving, variable setting, messaging, and other functionalities are unproblematic. From 56428cd62ec8b92a5dd31d373032d2cbec9b7d9a Mon Sep 17 00:00:00 2001 From: Dominique Debergue Date: Thu, 1 Aug 2019 00:29:36 -0700 Subject: [PATCH 083/132] Create FUNDING.yml --- .github/FUNDING.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .github/FUNDING.yml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..ffa3938 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,5 @@ +# These are supported funding model platforms + +github: hewiefreeman +patreon: hewiefreeman +custom: paypal.me/hewiefreeman From da66ab14eed0ea25315cace38f5bca152d5be8c3 Mon Sep 17 00:00:00 2001 From: Dominique Debergue Date: Thu, 1 Aug 2019 03:48:48 -0700 Subject: [PATCH 084/132] Update README.md --- README.md | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 2ca6078..a78a6c4 100644 --- a/README.md +++ b/README.md @@ -2,20 +2,22 @@ [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) [![GoDoc](https://godoc.org/github.com/hewiefreeman/GopherGameServer?status.svg)](https://godoc.org/github.com/hewiefreeman/GopherGameServer) [![Go Report Card](https://goreportcard.com/badge/github.com/hewiefreeman/GopherGameServer?f=v101)](https://goreportcard.com/report/github.com/hewiefreeman/GopherGameServer) -Gopher Game Server is designed to provide all necessary tools to greatly ease developments of any type of online game (or any real-time app/chat). Gopher will handle all server-side synchronizing and data type conversions, therefore, client actions receiving, variable setting, messaging, and other functionalities are unproblematic. +Gopher Game Server provides a flexible and diverse set of tools that greatly ease developments of any type of online multiplayer game, or real-time application. GGS does all the heavy lifting for you, ensuring you never need to worry about syncronizing or data type conversions. Moreover, Gopher has a built-in, fully customizable SQL client authentication mechanism that creates and manages users' accounts for you. It even ties in a friending tool, so users can befriend and invite one another to groups, check each other's status, and more. All components are easily configurable and customizable for any specific project's needs. ### :star: Main features - - Super easy and flexible APIs for server, database, and client coding + - Super easy APIs for server, database, and client coding - Chat, private messaging, and voice chat - - Customizable client authentication (**\***) - - Built-in friending mechanism (**\***) + - Customizable client authentication (:one:) + - Built-in friending mechanism (:one:) - Supports multiple connections on the same User - - Server saves state on shut-down and restores on reboot + - Server saves state on shut-down and restores on reboot (:two:) -> (**\***) A MySQL (or similar SQL) database is required for the authentication/friending feature, but is an optional (like most) feature that can be enabled or disabled to use your own implementations. +> (:one:) A MySQL (or similar SQL) database is required for the authentication/friending feature, but is an optional (like most) feature that can be enabled or disabled to use your own implementations. + +> (:two:) ### Upcoming features From 45ec1d0202ac586bd558928b0ec390260d5a4eaa Mon Sep 17 00:00:00 2001 From: Dominique Debergue Date: Thu, 1 Aug 2019 04:20:49 -0700 Subject: [PATCH 085/132] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a78a6c4..f240614 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ Moreover, Gopher has a built-in, fully customizable SQL client authentication me > (:one:) A MySQL (or similar SQL) database is required for the authentication/friending feature, but is an optional (like most) feature that can be enabled or disabled to use your own implementations. -> (:two:) +> (:two:) When updating and restarting your server, you might need to be able to recover any rooms that were in the middle of a game. This enables you to do so with minimal effort. ### Upcoming features From 4fad0fa9d79b26aa43b8556ffcdb6d087439035d Mon Sep 17 00:00:00 2001 From: Dominique Debergue Date: Thu, 1 Aug 2019 04:21:48 -0700 Subject: [PATCH 086/132] Update README.md --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index f240614..75b485c 100644 --- a/README.md +++ b/README.md @@ -10,14 +10,14 @@ Moreover, Gopher has a built-in, fully customizable SQL client authentication me - Super easy APIs for server, database, and client coding - Chat, private messaging, and voice chat - - Customizable client authentication (:one:) - - Built-in friending mechanism (:one:) + - Customizable client authentication (1) + - Built-in friending mechanism (1) - Supports multiple connections on the same User - - Server saves state on shut-down and restores on reboot (:two:) + - Server saves state on shut-down and restores on reboot (2) -> (:one:) A MySQL (or similar SQL) database is required for the authentication/friending feature, but is an optional (like most) feature that can be enabled or disabled to use your own implementations. +> (1) A MySQL (or similar SQL) database is required for the authentication/friending feature, but is an optional (like most) feature that can be enabled or disabled to use your own implementations. -> (:two:) When updating and restarting your server, you might need to be able to recover any rooms that were in the middle of a game. This enables you to do so with minimal effort. +> (2) When updating and restarting your server, you might need to be able to recover any rooms that were in the middle of a game. This enables you to do so with minimal effort. ### Upcoming features From 87b0ffa9505b6a60a19ca42468533ba2d740f94e Mon Sep 17 00:00:00 2001 From: Dominique Debergue Date: Thu, 1 Aug 2019 18:38:13 -0700 Subject: [PATCH 087/132] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 75b485c..771b0c4 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ Moreover, Gopher has a built-in, fully customizable SQL client authentication me - Supports multiple connections on the same User - Server saves state on shut-down and restores on reboot (2) -> (1) A MySQL (or similar SQL) database is required for the authentication/friending feature, but is an optional (like most) feature that can be enabled or disabled to use your own implementations. +
(1) A MySQL (or similar SQL) database is required for the authentication/friending feature, but is an optional (like most) feature that can be enabled or disabled to use your own implementations.
> (2) When updating and restarting your server, you might need to be able to recover any rooms that were in the middle of a game. This enables you to do so with minimal effort. From 61a46656946f07b0676f0628c99fb19171276ada Mon Sep 17 00:00:00 2001 From: Dominique Debergue Date: Thu, 1 Aug 2019 18:50:42 -0700 Subject: [PATCH 088/132] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 771b0c4..420992a 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ Moreover, Gopher has a built-in, fully customizable SQL client authentication me - Supports multiple connections on the same User - Server saves state on shut-down and restores on reboot (2) -
(1) A MySQL (or similar SQL) database is required for the authentication/friending feature, but is an optional (like most) feature that can be enabled or disabled to use your own implementations.
+
(1) A MySQL (or similar SQL) database is required for the authentication/friending feature, but is an optional (like most) feature that can be enabled or disabled to use your own implementations.
> (2) When updating and restarting your server, you might need to be able to recover any rooms that were in the middle of a game. This enables you to do so with minimal effort. From 0f77195b18a58ba7715c3797a8218fa3fa35345b Mon Sep 17 00:00:00 2001 From: Dominique Debergue Date: Thu, 1 Aug 2019 18:55:56 -0700 Subject: [PATCH 089/132] Update README.md --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 420992a..de6d392 100644 --- a/README.md +++ b/README.md @@ -10,14 +10,14 @@ Moreover, Gopher has a built-in, fully customizable SQL client authentication me - Super easy APIs for server, database, and client coding - Chat, private messaging, and voice chat - - Customizable client authentication (1) - - Built-in friending mechanism (1) + - Customizable client authentication (\*1) + - Built-in friending mechanism (\*1) - Supports multiple connections on the same User - Server saves state on shut-down and restores on reboot (2) -
(1) A MySQL (or similar SQL) database is required for the authentication/friending feature, but is an optional (like most) feature that can be enabled or disabled to use your own implementations.
+> (\*1) A MySQL (or similar SQL) database is required for the authentication/friending feature, but is an optional (like most) feature that can be enabled or disabled to use your own implementations. -> (2) When updating and restarting your server, you might need to be able to recover any rooms that were in the middle of a game. This enables you to do so with minimal effort. +> (\*2) When updating and restarting your server, you might need to be able to recover any rooms that were in the middle of a game. This enables you to do so with minimal effort. ### Upcoming features From d10096ab2422036fdbab2240d514f28434c0fd67 Mon Sep 17 00:00:00 2001 From: Dominique Debergue Date: Thu, 1 Aug 2019 18:56:12 -0700 Subject: [PATCH 090/132] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index de6d392..55d5bf0 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ Moreover, Gopher has a built-in, fully customizable SQL client authentication me - Customizable client authentication (\*1) - Built-in friending mechanism (\*1) - Supports multiple connections on the same User - - Server saves state on shut-down and restores on reboot (2) + - Server saves state on shut-down and restores on reboot (\*2) > (\*1) A MySQL (or similar SQL) database is required for the authentication/friending feature, but is an optional (like most) feature that can be enabled or disabled to use your own implementations. From 531124ab23dad350f583d9fd39dadd658df34716 Mon Sep 17 00:00:00 2001 From: Dominique Debergue Date: Thu, 1 Aug 2019 20:32:26 -0700 Subject: [PATCH 091/132] Set theme jekyll-theme-slate --- docs/_config.yml | 1 + 1 file changed, 1 insertion(+) create mode 100644 docs/_config.yml diff --git a/docs/_config.yml b/docs/_config.yml new file mode 100644 index 0000000..c741881 --- /dev/null +++ b/docs/_config.yml @@ -0,0 +1 @@ +theme: jekyll-theme-slate \ No newline at end of file From 8360d5143b3dc7c0ad7f3727637505f9538ca40a Mon Sep 17 00:00:00 2001 From: Dominique Debergue Date: Thu, 1 Aug 2019 20:49:07 -0700 Subject: [PATCH 092/132] Set theme jekyll-theme-slate From cff4ffef78ba529d88a871dfd503257656765157 Mon Sep 17 00:00:00 2001 From: hewiefreeman Date: Thu, 1 Aug 2019 20:53:37 -0700 Subject: [PATCH 093/132] Creating tests & project site --- docs/index.html | 6 +++--- startandstop_test.go | 14 ++++++++++++++ 2 files changed, 17 insertions(+), 3 deletions(-) create mode 100644 startandstop_test.go diff --git a/docs/index.html b/docs/index.html index 38410e9..b2978f8 100644 --- a/docs/index.html +++ b/docs/index.html @@ -7,7 +7,7 @@ - + @@ -18,13 +18,13 @@ - + - +
diff --git a/startandstop_test.go b/startandstop_test.go new file mode 100644 index 0000000..e1c9fbc --- /dev/null +++ b/startandstop_test.go @@ -0,0 +1,14 @@ +package gopher + +import ( + "testing" + "time" +) + +func TestStartAndStop(t *testing.T) { + go Start(nil) + time.Sleep(time.Second*2) + if sdErr := ShutDown(); sdErr != nil { + t.Errorf(sdErr.Error()) + } +} \ No newline at end of file From 2059d803e8c335ec51e02232d7c9c3a5b03d2554 Mon Sep 17 00:00:00 2001 From: hewiefreeman Date: Fri, 2 Aug 2019 00:08:34 -0700 Subject: [PATCH 094/132] Working on project site shell --- docs/css/shell.css | 232 +++++++++++++++++++++++++++++++++++ docs/images/GitHub_Dark.png | Bin 0 -> 4268 bytes docs/images/GitHub_Light.png | Bin 0 -> 4044 bytes docs/images/icon.png | Bin 0 -> 18943 bytes docs/images/icon_large.png | Bin 0 -> 403299 bytes docs/index.html | 18 ++- docs/site.css | 39 ------ 7 files changed, 245 insertions(+), 44 deletions(-) create mode 100644 docs/css/shell.css create mode 100644 docs/images/GitHub_Dark.png create mode 100644 docs/images/GitHub_Light.png create mode 100644 docs/images/icon.png create mode 100644 docs/images/icon_large.png delete mode 100644 docs/site.css diff --git a/docs/css/shell.css b/docs/css/shell.css new file mode 100644 index 0000000..1e449ea --- /dev/null +++ b/docs/css/shell.css @@ -0,0 +1,232 @@ +body { + font-family: 'Open Sans', sans-serif; + font-weight: 600; + font-size: 16px; + color: #ffffff; + + background: #e3e3e3; + + margin: 0px; + padding: 0px; +} + +br { + margin: 0px; + padding: 0px; +} + +p { + margin: 0px; + padding: 0px; +} + +a { + color: #ffffff; + text-decoration: none; +} + +a:link { + color: #ffffff; +} + +a:hover { + color: #000000; +} + +a:visited { + color: #ffffff; +} + +a:active { + color: #ffffff; +} + +h1 { + font-family: 'Open Sans', sans-serif; + font-weight: 700; + font-size: 36px; + line-height: 36px; + + margin: 0px; + padding: 0px; + + color: #85d681; +} + +h2 { + font-family: 'Open Sans', sans-serif; + font-weight: 600; + font-size: 30px; + + margin: 0px; + padding: 0px; +} + +h3 { + font-family: 'Open Sans', sans-serif; + font-weight: 650; + font-size: 24px; + line-height: 24px; + + margin-top: 5px; + margin-bottom: 0px; + padding: 0px; + + color: #3f3f3f; +} + +h4 { + font-family: 'Open Sans', sans-serif; + font-weight: 650; + font-size: 16px; + line-height: 16px; + + margin: 0px; + padding: 0px; + + color: #3f3f3f; +} + +h5 { + font-family: 'Open Sans', sans-serif; + font-weight: 600; + font-size: 12px; + line-height: 12px; + + margin-top: 5px; + margin-bottom: 0px; + padding: 0px; + + color: #ffffff; +} + +.wrapper { + display: flex; + position: relative; + + top: 0px; + left: 0px; + + min-width: 350px; + + width: 100%; + + background: rgba(255,255,255,0); + + flex-direction: column; + flex-wrap: nowrap; + justify-content: flex-start; + align-items: stretch; + + z-index: 2; +} + +.shadowWrapper { + display: flex; + position: fixed; + + top: 0px; + left: 0px; + + width: 100%; + height: 100%; + + overflow: hidden; + + flex-direction: column; + flex-wrap: nowrap; + justify-content: flex-start; + align-items: stretch; + + z-index: 1; +} + +.shadowObj { + display: block; + + max-width: 1000px; + height: 1500; + + background: #ffffff; + background-color: #ffffff; + + box-shadow: 0px 0px 20px rgba(0, 0, 0, 0.4); +} + +.innerWrapper { + display: flex; + + max-width: 1000px; + + flex-direction: column; + flex-wrap: nowrap; + justify-content: flex-start; + align-items: stretch; +} + +.topBar { + display: block; + position: relative; + + height: 200px; + width: 100%; + + /*background-image: url("../images/bg.jpg");*/ + background-color: #7a7a7a; + + z-index: 6; +} + +.content { + display: block; + position: relative; + + width: 100%; + min-height: 100px; + height: 10px; + + background: #ffffff; + + overflow: hidden; +} + +.logoHolder { + display: block; + position: absolute; + + bottom: -30px; + left: 0px; + + width: 230px; + height: 230px; + + background-image: url('../images/icon_large.png'); + background-repeat: no-repeat; + background-position: 0px -30px; + background-size: 100%; +} + +.titleHolder { + display: block; + position: absolute; + + bottom: 0px; + left: 220px; + + margin-top: 10px; + + width: 180px; + height: 160px; + + vertical-align: center; + text-align: center; +} + +.titleGhub { + display: block; + position: relative; + + height: 50px; + + margin-top: 10px; +} \ No newline at end of file diff --git a/docs/images/GitHub_Dark.png b/docs/images/GitHub_Dark.png new file mode 100644 index 0000000000000000000000000000000000000000..ea6ff545a246caa64074ba809bbc86fcb8589071 GIT binary patch literal 4268 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 XLyRvu{aX3a{{tgEGu={c*U0|?Dtn-9 literal 0 HcmV?d00001 diff --git a/docs/images/GitHub_Light.png b/docs/images/GitHub_Light.png new file mode 100644 index 0000000000000000000000000000000000000000..192846a12085914cc0e38d9b48036b11d2a4d7c4 GIT binary patch literal 4044 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 ZsK8ky_?39l4gAjkwLQ)WTW#Z?@NW_mBhUZ< literal 0 HcmV?d00001 diff --git a/docs/images/icon.png b/docs/images/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..46b83c747de5ef62d660bd78e856fddf4261b8d2 GIT binary patch literal 18943 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 literal 0 HcmV?d00001 diff --git a/docs/images/icon_large.png b/docs/images/icon_large.png new file mode 100644 index 0000000000000000000000000000000000000000..4dfd7d80b867076338181d9d11ad7c542f405c32 GIT binary patch literal 403299 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 z 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'K!&BC@^Ig~F8cb2mzY|3$F6t)@a>Q2x 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%0ANy&6bdcXHAu! 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�)i1UUPa-}{qc3SOYrV$*km*cjS4ld6<#(b* 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

}?*8?%OUO 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

t&Oxh%iL-(ttJ&5EINkg0^L+;RjEx9X+Bgjn=A= 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⩔0YdB2cCFg3sPDCdstX!9(?|Bo>b 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%0DA3(dMz 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 literal 0 HcmV?d00001 diff --git a/docs/index.html b/docs/index.html index b2978f8..f96e979 100644 --- a/docs/index.html +++ b/docs/index.html @@ -18,18 +18,26 @@ - + - + -

-
-
+
+
diff --git a/docs/site.css b/docs/site.css deleted file mode 100644 index d93ce32..0000000 --- a/docs/site.css +++ /dev/null @@ -1,39 +0,0 @@ -body { - font-family: 'Open Sans', sans-serif; - font-weight: 600; - font-size: 16px; - color: #ffffff; - - background: #1c1c1c; -} - -.flexWrap { - display: flex; - flex-direction: column; - justify-content: flex-start; - align-items: stretch; - align-content: flex-start; - - top: 0; - left: 0; - - width: 100%; - height: 100%; -} - -.topBar { - display: flex; - flex-direction: column; - - height: 0px; - min-height: 0px; - - background: orange; - z-index: 2; -} - -.content { - display: block; - - background: #1c1c1c; -} From 7cced41b5987ad6b791fee5ff36c4f7e938e1105 Mon Sep 17 00:00:00 2001 From: Dominique Debergue Date: Fri, 2 Aug 2019 22:10:53 -0700 Subject: [PATCH 095/132] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 55d5bf0..d8c6685 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) [![GoDoc](https://godoc.org/github.com/hewiefreeman/GopherGameServer?status.svg)](https://godoc.org/github.com/hewiefreeman/GopherGameServer) [![Go Report Card](https://goreportcard.com/badge/github.com/hewiefreeman/GopherGameServer?f=v101)](https://goreportcard.com/report/github.com/hewiefreeman/GopherGameServer) -Gopher Game Server provides a flexible and diverse set of tools that greatly ease developments of any type of online multiplayer game, or real-time application. GGS does all the heavy lifting for you, ensuring you never need to worry about syncronizing or data type conversions. +Gopher Game Server provides a flexible and diverse set of tools that greatly ease developments of any type of online multiplayer game, or real-time application. GGS does all the heavy lifting for you, ensuring you never need to worry about synchronizing or data type conversions. Moreover, Gopher has a built-in, fully customizable SQL client authentication mechanism that creates and manages users' accounts for you. It even ties in a friending tool, so users can befriend and invite one another to groups, check each other's status, and more. All components are easily configurable and customizable for any specific project's needs. From 0ca3d6566db31e9707f1cb4a488c971680aecabf Mon Sep 17 00:00:00 2001 From: Dominique Debergue Date: Fri, 2 Aug 2019 22:40:40 -0700 Subject: [PATCH 096/132] Update README.md --- README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index d8c6685..0f39b32 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,5 @@ -# Gopher Game Server - -[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) [![GoDoc](https://godoc.org/github.com/hewiefreeman/GopherGameServer?status.svg)](https://godoc.org/github.com/hewiefreeman/GopherGameServer) [![Go Report Card](https://goreportcard.com/badge/github.com/hewiefreeman/GopherGameServer?f=v101)](https://goreportcard.com/report/github.com/hewiefreeman/GopherGameServer) +

Gopher Game Server

+

Gopher Game Server provides a flexible and diverse set of tools that greatly ease developments of any type of online multiplayer game, or real-time application. GGS does all the heavy lifting for you, ensuring you never need to worry about synchronizing or data type conversions. From 68ac11b7973a5e4a8fb13f4429de3822e9288415 Mon Sep 17 00:00:00 2001 From: Dominique Debergue Date: Fri, 2 Aug 2019 22:45:58 -0700 Subject: [PATCH 097/132] Add files via upload --- docs/images/Gopher Title.png | Bin 0 -> 106028 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/images/Gopher Title.png diff --git a/docs/images/Gopher Title.png b/docs/images/Gopher Title.png new file mode 100644 index 0000000000000000000000000000000000000000..f59ceb9d2a28106c84d611771492949298579a2e GIT binary patch literal 106028 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 Z&gr*>?5exf?jT=JMNvbc Date: Fri, 2 Aug 2019 22:48:03 -0700 Subject: [PATCH 098/132] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0f39b32..fc45bd1 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -

Gopher Game Server

+

Gopher Game Server provides a flexible and diverse set of tools that greatly ease developments of any type of online multiplayer game, or real-time application. GGS does all the heavy lifting for you, ensuring you never need to worry about synchronizing or data type conversions. From a898bdb2fda3690f57b5b5a5f9301ab70db30d25 Mon Sep 17 00:00:00 2001 From: hewiefreeman Date: Fri, 2 Aug 2019 22:54:16 -0700 Subject: [PATCH 099/132] Removing unused image --- Server Gopher.png | Bin 403299 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 Server Gopher.png diff --git a/Server Gopher.png b/Server Gopher.png deleted file mode 100644 index 4dfd7d80b867076338181d9d11ad7c542f405c32..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 403299 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 z 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'K!&BC@^Ig~F8cb2mzY|3$F6t)@a>Q2x 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%0ANy&6bdcXHAu! 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�)i1UUPa-}{qc3SOYrV$*km*cjS4ld6<#(b* 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

}?*8?%OUO zS6uN#0+^fUK;B+?e7J;M%vnMJtzPORHzW-D`CM4HaV)aqc$Fs4!YqA0HHEhBpEo_W z3!ROn7CkPtd%7H$>cSfoKq183r56XH-tWOg{H#HzL$?Cwhj31vEW`1WUmR=&ECp&! zIQgz3wcKi{g`foAZ32yzjx&aCRbLj~ww)EQX-XytX5f_XYCYQ3>NOl(NA+*oQ>9Ql zee-io%5lC@vebPBt^IP56y4hsj~;+$DDY#cdOFi8d& zhzy3rvgJ|TZ{i(VN0AxgF{0M91DS#$u7X6Mvx8Z?d}B?PVhhv*Bx{0KIl)B8AdgXD zIOeG0IcmPosx+{Dyfi7siv#~N1Ee?_Q;=&D8A12TZmjd`ev=lFu3!o>*zL;o%gl$h zNp4G6F{;Z6cR&k6I0*(qe+e_fH+uYpZLm)Lkquc6gG`*q^vC25_;mr=)O3)}g#9#X zZBlp*zqFu%FSQVSiHXlHgPS+xAA!yxUWs72ubk9VtD1jy3SKz23V-N6|nZ~-7{>r4EgteWDe=S=G zW9ArDaB*^Wfr8-NgM8(ZjfwFCxy4Wyi_oe*6#2hyvHwtJF9@U!Kw<>yCfr*H=%>LQ z7sKy>+ZlN~4r?eZN?WRbD@Lh0-P$nODgIX>G!How26_a_uIUb2ZgEb_=$N(3%yuSd zK?q2)Y$%sBB4}8`=qw?1)8Skjbjt<@=S7q6j2qPD=50V_HNuPT|21{}^y1;(Yj@=l z)yV4rVlkR-`q>LnTiy(zmQu>xc{5V#@^a!%_~n&3mkok2y$n@gK-vugQ<3``yXSm-T_ccB~+=k|c)L23%KG!B^Wm$T8wcLn+ zUSh&~G^&u?ZSd~4&8=2C9LU&|YJvqbY=$NZ@Nc0R)~}kudawUr|8@U=+Em8%S&=pi zhJTeWS>JWmZCm@I%TfvHqk_4IGa?m`kHyCjl!aC8ZEPa2U%ow>HH|)QZoh37y55Kf zps8q*DlGT(8^*tV=8T}VX}j+=-ed8soTVK~mJskSfQ^(i@@Xc_(EdrSOWd39ec%-W zngdyUdM&RVNkAO*UR|AhZy)|QUCIyKHQ-CZCH(ylhCRI7I^Xry@cg8(Xr2d-iD%h% zD5Aa3VW>V4#xbW{ZS59a-)pRinEDJfY_b`rkiQ`;(C1NN;>Mif*ntas_3$UihB#Bi zkUe=2V@Z-jlzZZDSn-%(celwqTeGXgki8WY^MXKL&6R3n6;1br7N(zS^$p>h$Hew8 z7`n@)KHD@3XPGYf9kGZjmjkEib91`Dn0(bm)YhThc0$;8GhM;S!y_F>qv;S}g}U=G ztdu8D-dOUNa6ZK(Qesh2krg*7Z~_h1aSc@O`7h!9(W>5nXk`p-+8`Fi^-gR%eRgz= zgWm{Xc&RvH1h!5@RYJXOWy?2N9t8u)8e8w(cARHwsN_$4LDPfF9)R!VO*;U*#<}Qi+hOW_p1>yv?I$G-r%^FDLrET%`(dfc1&$i;Mi1|B z+Rxs#gWL?>&nn~<&`+kHh?bR-N~=xJFMi?{Ng74oXR+?nc6*I1-T_?e)1mC!$=fqN zi_>3|+EonhZVL)tJAVW_$o{2I4wM6jD%`8a_ISdkL4ZQ9lDPr;0yOPq1v@RWi=3mx zF}O(RBla2bF-o4yIN0Y)W}3@sw#|q?4@5vgxm{j{hT>Cjwz@wDT0dQJFoT)`85OdG z^LK%Kt{k>e3lMQ;Vp!gs&qy1s^0QjSoeW3&3_spR+Bt4m2HVG=p}c;Bi$O+Xm9Cmk z(gw>bDGyw0|0og4nNs45#Q0b-=*g!ZV`+7M11hy+>-Gz4FhS$)Y5j_iAh7ELgJL70 z)5Ci}I~@e^tcl`yN*RkPru6BR^@5hGyu3V3ho04+45#-*)v-SpW2FZl*0aoYUD|*` z-<-#X`>FhZe|eros>O7IRq`2%)KXwF1|?S||>M;D^Q7z0WKt@9HE5I9q5cG$9n zJzw-W;K-VPUqdk$3`56g7jv-+3|uZex$HPiAB=U&a4dFA z%BL~Q=Pcmh>1}LuV$p3%Fn&m^sN8pY=1-8%B+D1qqTf*(F&Zdw_APO~5gnuuk5vqS zbGqHVBPQupjsp(8qKSM?Sh$Lyczmp{kz~b{o)SQmUzu}vk(N7y|7Kt5^mupTZLIg{ zbApLv>AZM!6kWVE{y3SuPWXNU?e-f@I3>2XXG5!9RJ-P)$$jSYnD`InNGVP7(a?$` z1Sj*KE$EvsO+h0nz4>E^)xAfPCRKUHz=Yms0s{{r5$rjIId_R?>91V%@?Krkw~rhw zH3KkMmQNMzGHAehV=!GOdbXiE)E9I>deeDzb@d2cPLrL3BwDt$w_ft5U#FAO=*H9P z$I(K5IhT~~Vc&svvq;-5+gDB(+V z;m+eAZ_nBaJ$dV3DtJO^{fp)uPo`6w!-{BIjhnY7X$jZ`QT@x;sIRER`QLkQy_*Y< zOP}RSh{$a}b@bhPw5kRi`rz(0dpxC;B%g_DtnYJ)0)#cXySP7|NO-Z zK{}hazqeL3&^m#E*L^Z=`S-%ggKHPN*~gDvQFNCc(%IR^-*^q}^sJdF6L<+_SNhq= zYIKi!#jt2WUFzTh$`=$j3I623IsIbB>b!s)Y;r;-_Ed8$V|?zjqw zJ-1;D`6Ru+=6ETcok*xx2lZ`3D~k^Fx}t?fr8(=)-^exo&kK;Cijwc(UqqPse!~i* zkxn(hgI2+&;Y4k`8uyuva@QUY^AXKUs7N?qgkyo<>(y6KR{K*{)&|}0qxzTU6!Rts zZ?go?j*_{uDl7iySA$3PU6(HQUz6#DuBjEhjKPxMi}=Z-9Pdp@sfTGIen5uXxfnjD zIU3rw(JN`Rog`Kq(fgjz@6FeS8&z1gw-FEDrlFHlGYrp${Wy6r1HkpZe{5{*@|F9l z-$AZV<$vcHg|fz^5WJ3JcJCoz<Ma#TVbJLE$~?T=hwm) zpG|F_pv%@n?{wdXYtRw&VLblX=IUF?Yy0U-@4tL?7f+mI4<@+_^vWh|-U2k~o(X%~ z6s7Sk_?1TpsH;ywl_{FDu>U%+@`VxTxw~ppiKChN%yZI$3(E&he@~ZcWb<&zxnuH< znN1vg8MkG;{Xh4g^BO?w>RZvLC+2rK<6QBN&ufc+1_N$}!|CP((ey*k{hjm~o zOwEv7snNaI%^%$D;F0}{uHO+EsmhU3uTUN5_dCB6p{6B~>CcJ9MEDHPVmAYQf^4c) zm@!jkeUnA+Cq*|w;uBY!Ldj$yWs7f<6G?BA<`ibtJDP9;{VtoXZg!`0$zM)N*rY2;k>hJ>icMlhblh z@qQ=mJwi|t3JTb>ht+2dps@#XHZHsWN(#+nUw>o<1A#S-=h$?)Z%P`IaB%Q8RPRj- zcIN%y#l8k=(sngD4*dOL*{7g`*Y~?OGSb{Z$k8+N6q=~sc5G~nb?;;5ggw0R75#nb zd#1BnY1X+OBI9AZ#|t}nkHYwlGoSrx2RgbOmr4J(lP!HT6W((ZV!bq?8r=(_=(V*q zT?BvI_&vTvovM#0U~dDGe4PFE7!_!^vpLjQxjgm`Qjg<{dU_dFiE5^JVGY!ZF{O+ripo4KUeI)IN7L%0PGto0O^|5e|_a%j=f2d^-1<*c!VH36K?$;~o8y`9~H=N0h3F@e3joLtXrq^!I(TUad^~OSNOkzec|Y z*EaXOo#}n=>>guo4;#Oi5UFD`^&7Droa#RO--;tLB0D=HBV=b} zWv@euWJVd;iR>+V?~$E^kd?iaaY#tw7$G4ddwuWI^Zov=-*a6(|2)^j>3u$*`+eW9 zbvKsjR^91wmf~?#RU^b@VbiksEX+cTyDg=FKm_?m@;CdV8&BOU8kffbNG~ofwm*1V z^Rn?y&nW%%J|v%U1RS* zJyFro7*7VAiAIY_y;rmVvFe!Hh(7sOA327;n)Qdd18o~FLCE@PuZIj}zdj`o^^si7 zkZIPR{0(&zzP^{3uddT`h40qlmig{6@=a`-&JPN6OZKAt>5cr_x)jCM%|t6&AWWlT zVzvWFz5Qdof3O+5jVe7UPtVA}c{Og!_kwuppeIw))$`~T!`Zz$9ALEX6vzPwH*QOg z*Fj!~h4~WiZb`+K!8)5{o_p1>4ixhx?oh+OA8}s!M1`xy4Q;>mvqHv~?K|EH!u&E6 zI7>X$yh|hVkEhzsu?R>Q%{D&N^2%CXNSsl{k!|0(GB(3#e*YTkg1mZgy8Lank&uv= zW+{AxgW-fYoE+i|B{vf+TKYpcs1uA4$GrF-f1B%=Ti8e4xz84j{5Fo?vdX{vsuOkI zcj|qJJ{O$!JESqENmyx={z71_iC~Ddtp!_y0CD-I*P)jbs;17ZbrXi$-d9`^JEP<@L z|7q8kfx5OIxC6`&!XTQqwh_<=P!DghRAd@vKh|$}yp&D!GkT z$;8}j)8@Ro-+}V_QP@@e(}?n`pVrXw9Jrr_YY7rDr0VF~k%{VupFm@I_@zXq2WS=( z0O(+tg+(<+#|7zY8C6ln_E#lqPx_Zx8Oo*}IruC&HQ!J3 zi(ESDK|o;volPgKvkKWfwnw*SgNFp1HN;(VR7utQCFwc>o!{hzl$W*E)6kEd&{>Ja zM{i1UY-Qk|TB7^LD@p%dXlzcH@5=2p--C&)HrJK;8(um4ZArIcv8P`))BM`SpK+LU zP$}TbH>up|6>E);^*dPvfx=WMcP4+mL%p4H0(E9O7K32C*`3@SsrnfoD{?>$rZwA* zvFGp0eIn^oPi9wr>r`C397^v1uVj_avAg@`tWps&&!Eh(V@Tsz|9Ud)brl}k@*y2T z7=G7w&R|YrpX8RKd1tvY2J(f-ak~kD58e{0S!74pstNh}It(YPpC1K|xDF~>M-tYw z`op6TGe&;tN$JPnG(vZ33$s`bGL`ElD&HcXOwxsmD;EXkp8oJ{-SRs{D^f^H)>6q6 z(c9-1mzHZTi09Pr$f#a^AWP%L>iUXM0MbXm$v$c7C!Gr-Nb!{{SIoLN1qB6+0?WP0 za)V}w<*|gndsRB2a^_%gx|S^$ha%_@;rg!g71ATx+dSgx3@wXixFOnNf|?cUW!12I zx~cvzEwB04-AW4}I56g5u$hi-xDyyM_xz3aY-xNhje4L{qj!iJm@vmL`m*gS>-)5v zYJH}ms_iuWu}aF18=aVLGG>etQ$f_*`ReC3r^UQIDPPLQBTe-AUkrr(jx0jQuJ;P7 zUdHH7%j;)9HK9)(pvCNs&}4Qg7`@FcGJu>r6q@|}TB_LoLv+Rv2UKtnuz92F(GN(p zvyKJmaqG?9o0C@En?#$scci@99=d$IX6)2)0f-0^P~HQnq+fQosT6=$Y3ZjSA(kwP zqaD9I84WW6v1GSi79gT~cf1SZ*1zuxgL!0O5M0--78g7-$PM27G-i9BRwZ%0gfG=E z#)p53VZJlJ! zQ4z7Z(W}?`kPXBL%<9FjDVA>y-gtnm%3a=L3DMtbA48~3`oWyl9VUBXekJAzZKE+X>S{DIV$=w9m<^!K zIqc??=@>BC6T;lGC1hq|->nAnC`LW+ot+L$U;)WqISKj-kQ#LgNOj)y_`Q$XKZ6(Q zl4~q&Q*`x(_D{(?oRhIpo zXvJOoA{+O3zXtdf%-Fg;dZo}Nl+4!babY=u&t_d5<#7Bx~ z3fojzdTTYlGZx+*OF$_~8$6+VFe?dcRyLerlS=OONd$ z-9Uv}QD>RS?sb#1?NnE^&pwNy;Eb7lbX3~DF=tSWNUdeC1Zw9*T&rSZpJ)6E&xdnp zCOEnNeOJz`n9}ELK}f>5-kdkB*=k%lnOb7=BKR5V<#z;!>L)ngMhKNT+%-La2BIS{ zU>S%DjA2_Rq3so+*41G}cDQ}-7z~}X)b8*-uDk*qNklUMglTz?zGP=aHHwxbZb z@9QA^3sTH4!K;Ij`@Cq$sa4$e@sk@fhvBgj`UVG%#+XvAQEeR$C+pZ7sm4{$oTt?w8FZ)XIB7)wdOdmTo{GS;EFx3) z=C3qm6E2#Lid8N-0i~X=4)&XE$FI*G4nMDcjB)_^io;r}u;zx(hq%F{>ic5*x;a=k zG>?sG`;x~C3TE1_(igNP`HB5&(z8g!G1sdz9=+&WA07|Cg=60Wsf7o{Qgy!XCW& zYs4)0R|61**MIw5inH0~?b^Xf`pZ1I?)`$3AV;FVw+2-_@mjZBKRglP5>2U7X3)PK z#r`s0`K@V?0^fWvy!UQ*h*U;`lP^k+{S;QP2^kd5`}?v4_Q@^{JNl)z9aQ>Z02H1} z)m$ubXRmVnrE;G}BW{KTTO$W{q#mGYG!%kY&4#O^{$&~P)o(#di`9-VlnHMI-%Wz- znwktMx)WpT-o7Ko6huWb9WB5-_n z?^XU2E&H9HPE0t1YgnzwVl!TVI3WF{bq%%A&$FWDN$x#{?R@sqhfYh$Jgqz36k#*L zf&Y4g$aYK*PG~lM-8Oreb~7U#SuR7odVtFfFUuispw=zwNDG}#4qo#6|ri& z6mxK5n#D{p$2&x?L(Kn>;DGh#_1&@`lFFYt55f&MVUEyx{vPYfQOLFUm3cx{X6ZLV zitHIWT&+7R=pRk!BYsaYxn%(nQMnc)o?n;w`X$Z+%-YZ;2uP+n4GZb_a!ZXdbY)Gx`FlQkVpD66h*{S={sgV#O@ZfR#}*EE)N9 zy6z9aLGQrU3&jI;Dibce5v)z5*!IN{jcBUBddnKJj}6_2bEL;A8&-==kM}^rGxG3F znJcC`E$a7S4xhDgOa7P5hocSMq_YwM;-2qX^^1b_Y<|C2tS#RpSpZrMK?WGn)-Cj* zmP6~I_4`o3d#ZVBW~6#|#3J%3EG&iVcV08R=PfD(LyeTwAV3;#hnl9jZZYf#y1q^- z4zZeo+paH&RHh#^!|QaP*LM4>qYTQdZn;Eym1jAd84t+)WW|llN@29UW zIOJxSvQWyf4&>!-r9NBJ`Xg1_og=#a>jAnaYjZH zkNFVqtstf!e2$((stF^T%6M{SM2@cQj-qcPrANdvmt6J&t0a(WAW)^DqXQW@-;ojY zKC$ViWfI1349c2;{sZU7DF(Ox;i(10eFW>a6oh6h>_*5P2;mau9fW_r=O(lDgQ~h; zXJqbBrj_`kTW`+ey?3trS``foOCC8EPQ78Vl5rA z>ngIny{!GL^o_sU^@YsyCDh?>vGa)4DpiB13g+mWQbmZai!COksQr(z)j5MocA5~m z7i0NZxM+0I=m7t*2H=X}1! z?*rv?*6tFJFnG)qrJ5W~LcCjAH{r#9Uw{;6R@$7Cl%FlQSzbJ^q&_Fmn@hQ6PGu*E z_jP~Wy~)^XqxR(Y<{3Xo?O34elt*-IZ6Pqb+|xz&n3P7F(=QNpAP`ov=G@m{f`rho zpFdwqf6wAE%X&?w5VrWm%KGmtB6K;Yaqk;uUx+f3PZEevuP0wrO@J(W7`?3td&*NX zJ@E=fnJ#q)6T4heyPl-;NcB!i@z1wptj#*xUt&0EWxdmQDjEX0eitOMYhj`-l~I=| zK4o`X-|m=q%JM}p|5eB@mAM}FhB`sx@4>98Po|^KVrDoV&OF8Laj*$cLVsWQbQ)bL zRL&S?dS}0FE`=%>TNMx#3_wPhRQ6%=Gl+gkSv;dFv0_2r$i32Cu{?*$Oj!T zWQrtI6$tBP$dP@WOb$vJK(7_Uh%8p4B+h*e4sY>jtrAQ|Oqf5MF^h%<7E5MJo@k%A zR3u3-|8)QLC6*#%XdchRvRsEDN^ZJ-(=hAR90rT&3v}l6A?e$hOL^e%=lSOBDP#Gr zpK!Kyv5H7*E62M74+hjizrBoC3!~Vq2OHD*K_9fO?nZKUL*3nlyZ9u5uY@~!tV7sk zO+U?t^wz&0w}nEa0WWK1z*NVmKgDH+7|+p(Pi({r&u%@=SMwwt{{JLcp3}H(%{+Y zF-DwG{v_2Zea4bcIJmJ{OfXgoMHo2py{!xG3dd&XRW?0-m6rV9cYxzu0^fnFq8*?x$^SgP)~waa_cjw{QVj&<4Ya%A@h64i>-3P#^$ds<(gPd4ukH4R7s-@(vf1H)} z^4#01G4}0Qg6$Z=Nj+{|y4}Iv?rzXhh!4flu}4U$5(cBLq7UuPeyyR|HK&3mkc*%X6$V1C{l`eJx4=P?}E6!?&#Vf{1C@TB(m0H4rY$A6w97-Vjy5iv(mN3 zxii%AXd-?GC7X+(O2=}~lEBA7@_Qg_VJ|2C@_UIaiXK6~O0<&a8#4TE=AVWuKMdtF zO7wZI2-CT!R!%QYJ?ss*B9q2?$BxQoK;W`6Rx8TqVYj<|p(Or(&t%%(aP*FR`M7T@?vbv6hLVk32CRaPQ*uzx zD0&hhsY+U07y|+r@c0)Y%|TXxsetI?7PO^@2Mub+9^!AT-06gg70mK3U5$LulE9t^ zB~3^uaPzpvR*a2q@W@6v9SI-gUNvv_HR7~YR@BbAJ_>VRNUUUaVN3xq*%F{r`JOnM zZ!c<85DvByj0x9ttl~;S5@aP{cQ-dBJ+|g%iyEx|(QR7SzN_YT{b9J@@?z>%aNK$9 zrdPCY+haa|v)<)C%8K5yG5hNSmYc=ucfwhd1W+PIK@)N8++e$3$UO)74YU`!ZYUZ* z?GUoht$R;q9E-(G!{f|+{l>=cQ3-2MDL|ksWEu!(4jFD5o_%$rPIi_L>=I<^oSj^@ zB-?Y{spTC2xgFa|_H&uGlO;BQO|&`%+Vy0d8RG3O1(gQ#qCRfFO;g;uLidp2EHW#L zxRCM5r9i2$_Odw6Il|o1Km1L(--doImEEtm=2OkOq8x^NB_($!!hrVk7`tjPr+3nj zjmK}&jo~j0G1M3Mn3FR!mMJadW8|6LVp53;LvMThu)#Nam84y9?Gx!%&~;t0yzGz@ z)Uj{JWb5BtTCZh+yKQRE^VJJR743AtaLebD|9D}R$raIcD|>}Y_Yr5B2x`ZB+c?oG z1Qrq&?x8Rw0OoR~xTBmJ&%XNVEMBE_z3Yn_k!e6o>_<7SY1;H}YTP}*UP9z(-5!tZ z@`R~tkQp>LS8H<9uNjj3UfiBUNx5FVXY73KcuyLVollaC%41dzpJb1%?b_qsp$Rp( z&#SGOx~ZLJ^L1NF$y_A8;8_gWt0acsyTz5pP40hZg9!Sv|MwnpcEZ#^9K%}MM-MW# zD+`m#s6KED>){o5p~H#g$cRt;;4vgFO4`tn0qr&jXk>@LfSn@s3U&W-ve3H<^lvu*@tI- zyTX<1#UAbsug>R!TeRc{*Z~(yC+Re_wP0YODgloZa z{{49Jvgab7FpYd

NE+2P!%ijrSiIzfxbBu(3(VFO;8yM0&MDMb*xOZpt#{;ki-* zrp30C(R)*EE3{Ip@jcwpFA{xaSy8)lx3^RVN6ixo0Y)fH>UP#hU!5t z4sZAW!y+x`0PC{E&T_u9LdOz#eiPBjw=8hlh{vm}OD=3JTJkSA&^c?wwiYTlyK2MV z&+3Pm;t25f)6^lP1qU~lmvpaV0|+Ld8=wj8BaU#Ve-dW7N+v(DxeqKiqjfge{4jou ze`-+17jf1#FOd;k5$mo^Gj(>u&a>HE5v7y#%)+{q@r8uu*B*JhWL>?LYq6Ul^47Q} zgDYkWCzmTmrBHxB33RGs&@VyK}<9G zCRLu6R92t*$w=~4-sZN-q+AA>#@L4Y)2ELzC^crrR^2>yGSLtwKWkgA2@i;l#wFfo zr{)~|Lz{(3z$ys}3qNu#7<~4@sDEDk4~?!aH!%K-5j+)UP&iJ0D$BA)9Jy~k!n;tD z0!g;0TUQ_EhzcElNZ1&)Wodq+fwH) zP$OfUWmvG^T|GBiGc>%od>r)ZYatO!!_lv@a;A6W^eHcdIw({En~C1j zhbB&4IcLSdpHdz`x11GBTo5Ml0TdM;2lHVzwMKAPPmfP;xR)O|*(=W5#aP?E$S`V= zFV?H(WqEDzwe~S5iczwEVyFJ|lkt~hc+tJ2K1pPSs-c%V@{tsn4!v1Cyd#_EnP9X| z9V12ff}vU*;}cLED2}`lOA{9!zIV12+pywzeyeMU1gZ9*@6*+n|1TE+$g1*y<+AvQ z@2M8Z8iwNUoBIF}EP>LR2ew=(gPcwZ^)wnsd4f$n;Eq?`ilA2 zQ`O48Zlr11zw7;m2#!Nl`*8iSta`1{HBCK#!vJ6PkScSWw<|xZtuT=p?V}2LSAoG)km&wypOV+$ zI0+`{6uwN)qtz16pLt<03U=;D(f^e4!}6Nf&SEF@C1b`r$jPVPh1cayS;wq&)60Z3 z%@un^BDq>4mdOmM$paJre(GguU*3NQ?!k4NB=Adg)~lXDwg^3M6k7~MQcCdW0w^YX84h6zjibw1jJ-A)zzd`TFR-$+Tj@8W z#ZzQs^o2hf-!Ns!>pZ!H*57ciJgAbed}`fucXWXN!CqHM4&B;~KUR_$UiVKzC#E1e zi+jA=zs5aI?}NT)lVRli>U+7n)TfZrbQOWj6#zACYb70DjAdeMq))8_lM;-|t(8KG zx=#lGnGQi;m}OM%4(nq2{IRF6HGD~=An98LFEFT)p?P)aavNUq9R8I2_}%|$sy!A6 z3n8b)g7Zp@>~bYR;A>WdH2htV7rjw^`_f0wQB)YDrn!CPWM^1eP3|)155t%esfeY2 z7?}E{Qn}Ry+S`c!kVei(dc6pF2Skx}Pvxt{sJ4?Mv4)*#beFR3zWitQ>|}ykvSVea z!@}BWuNEPI7FxYcpG_~%m0M_=HHw?bcgqbh=?owUf`rp26T$7sxMFUwJm%%G&_#zz zyYWsJ4EAU`N-}VUN}*QwBX_)R9_r_qd}}^rsAxU1ZG||zcy>b1oPwn4wU6FwBgT={ zjg?Fqp=z){I%l=ExWvoPXQA@*zZ#ti>KG^Sm=4;-$ZQl$2~h3Rva*bIRvd~93Z^rQ(Ho=o!aB&f zLc-69in>foJjGsP>ofJSkh(QyTd$**2Lta)za`#V{(sEY4HBF!mw*wR;M=6dmv6@r zy`&0cejRs>JC8cf?f4{?3EgAryFnk$#i=hdmZ zT*Rrg8T#DcG}&i!6v2D`S=byCybA2{t=|nnAVIR@ZW__JVyR%4cFS3~0ev@TEiz-s z=$Y-CQj%gM(Qt>(@dNPc6`~|MM6?avPt!^Dn zw&j3ep}-(XfC8tu$uW;5G_u2k;syw3S%RfsXRWc=%7{*yo$m3_+?@^GlDRPbzM5*NWU}Aw^IFnX`D4}GIQbd8sJK? zPKN_GfOseOz?N5WsS>9b#Sn=%ND?fr%OUXu*E$~I2#{T2Ru^KAcuVbSHYszqg+B8t z?&Cn{7M{|eD+fQ>3KIDEmtTv~CKo`j?XD|!LZHr*Td~rpny{BP8E}x0$8HAWBA8V9 zJbm874Fl=~yNYxK?s~^^)q0Gv&krZwn8hWTD_+$LXO#eZL7?MGpX`}n7%3ANye^1X zrXRiWX3D&Csb=M-yK3vEmrX`?38kX0%Oqiw%716ui8RbOSt4nXSBV$crAF<9m zaKFa-QuLj!2wbc9xhDYwec!}yF~m@4d%8Y2`!-lpw}1xBW$L{R1>lA^VA>Fs?f71! z#*N|YyG9)1LMWeP7wmj*y_d7XwHm;9pO#RLj+5P{b9Tn-YxR;b&J9HmrFyf3YkTcO z8s$gpx&?=?0=-1TmjilclDkWG!KdV)%hR8SoqGK2z{$ z4CGR{h%L{GANFgh_afW%wAzyXFtxW&b&HU+!dhI%D{WwH`G`>v*b&-H$hdwjNn%C0 zHdSPYAN8LwjP2S>O#%UGH}O{D*I%nfe3#w0u0NeZUQ9wYvh;Lx3*YQ2mtcXw3WNmg znS@SBa41oPij_IPX--KhsT`uigI`A%nmja+O3Ebe_T+^6#(MHCOzn2w#t@tZ-RX}> zawpf8&Q;YKty!>NK)AkD`lTCMV@aT-yS2L@UTjn@Bq%6XISCxaHptPUNqx71g2+#c z(BUb!RtGof@vy-iEkL|+=jcg8baj`rP(is9>@&hddchm#4Yd+By@JIBSqeI9X!^jW zEGR8~iI{iT4gX2E?gUE!R(2u>H{{m~YtqU};TyqiMExp2;}PO6!&!38)lLESi2TEw zR^PW5oSL~1%)k3oieBsUD9yQCE^v*$d^y`rG2y1~mVn=0QROx%sjONYk6RYm3nib# zc^67jJzUh+&uSbyowFVlmN!UDFtjp zVpOu8;B3Yr6~GFZo9KM^YI6VlNYn;x-^<0X%e-m3eLrptKKDb_>e6fQzAq{9dXUOz zcjo5p{bCYnlKZa-;k<<@*VZ%_1HXv{F@MD&LMd{!RoL55Dv`t1ASH4&Zg2Do24-&C zebA;G&0mbtISlSpew<;? zm|4S&un&7zsu0yL0gpqDoy^HR=}yjma~Ry_JDGz&z91KmTc6_V{x3GpO0012Se$`V z`kNN_1v!7RKv1$@xo6x_@vzBbtAl_R(DTW)cq`guwIvBn5n91{u0)jrn>RPUeb{Yw z+<;VO+n4;q|1Q2nMofKc?~M*dlK2!MOO0{AYM~G9B{l9v{rP)Eo-8!)>MCmIyAgfM z;?>Q$NxxGJ(;gKYOWNvZBkiY&A9N^=z=4~4!+kmevE&`R?csPh1xT*93b*~fWBqh( zA~s;E@N{EbPvoI_*(yR*tZ;cQ5n3M#CK4_ig8e6Z2~V#7%NJoaHQVIt6p4xJ)2GC1 zD9K1GyHtwDf;lTwK?+==^SxTD9+;};;XES0aLhuRA+8=T|EdtL{7-Qk_HxCL&;F?=>y=dD4ncl0io(EbWX;DjoAXyUJqX~EgMNCFb1beZ zj%=kTfjva?0qEVvRtKw#L7l~UQ)yYQ(bF96Nyu#6s!nZ*0)Q1moCE8=9_#^1J@+W0 zbSYV*t~7|HW-*A4)i(b7QQLRBOcuVoRNp+8f9w={H}r4>`ftXU+9>dnA0#2Gy|HAO zdYQi4CoGEBxibNb2(3?HQuCi^#~-*%2UwWweaI&kAST#+_rAo2gPrW1JlIsyuPjSa zr$)p4pg$sNKN6nWTek?fBU=Qk?{;Et+=>LSHSWuvIRx^cU~yO>$IBWP4e%+S{_H1sI6qFsX~EQAmj$PcU%llbkpnL-n`s3cDY8H34lhg^o> z8oS;;8Q90<86|sKa07GEN%4`D78{h0ZtRg$t_A7zwFMM#L1RAMVCGT;a5P2_Cx$+u z2iY8tTZU0jc!K)FpufkbhR@&speuj5H=#{n1J8fQ+53_ZKoidi!?KDoqf^ie zz2Qh&YYaX~ZrX$v=fVcu^U%1{J2V7fcob(^YCfsR@OZ-p*h_asJ)dEY zH$Rf!0^`m9JE9;;(4!HD5|gmWs94rgNtaGYQoG19T&aJZV#Z=aEgHQ+nF94$^3b#{mx}c?dVj- zoCX+xKR$kBIv?KGzanI?6Q&c@f9L(wb%#7F4jx%I9W^8D8hcWROEIT`u$W5kB_50c zY^u?f6aL?|-H2o3C-hMQmX5+~99Sx=@hfq~v&wpK4{E?v(!d3cnmla|J zY!U(}2cNrJ2WwHhF)r0__?aJhuz@~%D*E(WFp?22BX(6V<$)0fZsO4=gBkkwuZM<) zf}%rNgFP*G1Mc$0N5$_XgmBo+Tn#n&^eZPD;YWOh&kyMp0&Hw-?$Q~KK7xreOZ)tj z!bU;&?BAHk2nlT`R#jD%r2G*2C$kn;1(agZ&AJwOc3zhBT+l28Pfv=DX?T&PsBm&k zx7^?6nY?J>HW;hiM!QFpodsabLZ4j zf!EUgVh8FzL%NrNn#~52G|CcSp|=m}V=xF;?%CfG5JrI}ai3AFv)fqE+`3X<>bTW3 za`E67yJ~A<@#_4wCgcB*ZXvjg#rY(T*K4NB4c08>!}njxS>2a0GktQ;IK?J7uF&RA z%98&pbZo<1AkpDLpKQm`?qilBR#fCAe6bM0aX}wBsud39w8HnBBJoI z<49#DiqJFjPEyqG)6$8^XjtS5g!?ErC?WGo*aMEOPLHQNr#rMOblFDj=#^s^(^$t(Z>t~ucy>9$84f+p5 zx(w}GRtmV$#P*L*{oW+Kqnc_RK$K!bp~f0`kLciyf{CO!CH0{2hVhb$SBpu2(9V3 zsNZnChqJ&*zZqm<<0?H?7Xf9%TIf=Kv569Ti9|WPlAyuMQ_Q> z=;%PUw#!F==!zrt`Ke&+xs+U&*pT+x=$jWh{4xjDHw|0x@UP`!BsZFaZa9>B-yUZ_ zqk{MRJLEcHw6mk5;LJLcz@7^oV@SU4_{4(|E2vf4> zJ*qGTaVmJaJpK@RqnQ)<{&0 z+roA`h>75pTZDlQp5rgwh)8)v5)uO;KhE_@!5C|N+qB6J_RO@ol_-@wa)9XE(SH0= z?so(w@b4r5alWZ7GkmseyTIN-L~zI}&n93I=*d5g*C5hA?=j4vq>=VaEctCu@D*}v z`@upg{Uq(r(K;%v``Me@1xzP=hFQ$D%qSr|4h1FDQT*rd2xPt##CNRcWlX%7m~Tl+ zsBb&nXkL-t%$u@@`$3K1P~B@2g;zvnXGVqxEyl0iqqnl4BrRd=JsSNYi&TS(qERw7 z56KZ$=++jf4$uwM#T73LdVM(L+H6Te0yPj~BzErW?fonMT8sF9#Q_IX9Lj+O+s%+d z$*y_MiYO_cFWgxTNn7n-+dl@I1k?P7wTes;zIRDUoa7qMUy)z#6vz^ZcY1G(SD)@K zuJv&68y=wWK!5*BV*p1iaPc%K9z{G$RdBD6zmxoG%#_R8ZCIe&s-0E1KHCkIHK*1e@c1oAgcAx-yfwMcdPR>=^5g3lEVAdTsKal$XSAmu zZQhuN2&>`Sh0%HE=IquCt~B!hieOi@=YzCMNFn=Y{F=+KtC+{!9IzM@^iBRqvtOSl zn3foLAu1S#0+UK6^1@&6>`4#4ulx8m$O85L*_uHT^1ILeL${`fAiwg=nYM;8dN8$A zU|%H2=YH*EB>!)>z$Q-4f)@1`0so=x{m_Ry8-X_AL~bq!`RUbGw=o>#alq9?pXuq@ zUcUP87DR&-OUGVPp90L5F1ePwyX|v4cK+d%C6grffkVgF!y^sD)nZ6$jAR-vXlDkt z;8#ZF3G9T1DN{iWi!AKys%j~Z*(EK#Ef{WWHEeYfg(uLkVE?_XBcL3X?eBIUI!IdKNwuY}Wes3^!1 zJeb+j!pK021vW8^|HgZPBG(MI-TZwaoxsjQ47-K7TOaanoH~Ah-VP?0&kpq)-N9vk zpeo0$fkzEMML9Ce7#(ND?YIBj?=k1i=&dLAcGT5=de<`Rk+{9#WV1Ro>F8S$=`lA} zd;Yaoe^?hV?N!&$pFimflfWhG_r;!rnukMC7YM3m@YwwTMFPP^zd7p8SwzHe8q9;( zQlQi-8<$*Oo5BA!FW$nX&7Qsjnn$2cx^ZDw9i(d0KpSXzYGfyc%B<(9^k`d1)AgL4 zQ`EzRTTW!x=3t2VpZM>?az4O;Z9^O0V-|v|_8e(Lm)EaiCUBcwj*>O-3#Gg~KSCy5tg>@Po@n!JAI5LjyzY9{1vj;>g+74C{M{&lY8`~1iWP-8(X_lD5@%T)hUVw_{vt@)&u57d83!DdB6>zNALQ?`p!Wj zyBwkec+Q`@A3&SX_Ku|p)Dd37V;x>nZX}=dxKLd?l&UF0BGNtGKg3tE{rG_?Rm9s7 z$o`C9Pa?s9%9OC^{Qf|FdXh4cP@d?^ZH+jit+`X##WmC8%I+3Kx{dr2g~|nqpT^T< zd)~~93{QnR7;@6Pgelx!0LJRlbx90#O6F_it{#pgdnVyn%V5{Ws0`P+(tOA;qlk1h zFB>AzkV-ieG9qg;z&?`R$K;m5Xb_<#-uWx*mDxW&a-emA~v$x-_ zDr%7VSI>p4~qtxs5fjk}8BWjLfsm0FiFU3rgKGI;Zz_7 zl$5lMG}Zggs43+X2!iPsI=|n7gIfxGNeUkidrnBM0Tm{I7|2g2q1MM;_KzYx?C!Y8MEu=cN%!Q zgDqIGn*-9e9M6ZS(-<>@*-K1HFKg~^6)HZFyGH!6+FM{lCqsivpAavk#}LM;Iwf67 zmZBd}f)_!o!=ZZlmb767m{AxtIC(dy6xA@>6wPTE|2(cZa~9Wn`j77g@rqh0dUNsk z>{T7NJyShcfA-tXeE^Uwf4DARoTAZQ^RYOCM+UYaWMup*R~ef6p)lHmim*>V+=~8Ep%52@NW>;VxQH{7kX(2GIb6+Hatp^W3kuX1P zkatoE1XIlr{jd!BG;`opU_4)dbO^(og`3ZY7S`f~H3{s7*Pp4|4FPQK)2)cX$9%Y$ zwuo4^eA@n&^t^EHrG1QP2?3;JB2$WgTF9mCnz=6|l3Z2Ix5*uAfI4Vxt1~EDv76L7 zg_V9LH0KZgJ5^@PsTNIv0OAAm#iv9p-JZ&_w`I@FQ#OyG?!w?I-JYA1gFko4(E}I4 z4mNLD;N%&V4{xK4iHp-jHt&)=m@tCz6STuXygm3SS=B!8#EXa0b3bi>2#QtARH{{k zG#rs@n+PJi%Mv;JSdilHb$_@6E1I{}K1<=Uyj%!3Xwpou`q4Oj?-m1RV09YIU)VXD ziAxfaV_bMSI>Mb7+dSr0ypM0R-Tg{`X`3P`=c9gF_ETgyLGNl+Xzf2Hmo8nC5FZ=wgQ2neJ1D#mXZJCnoOs zOb%zmAeJ#+cCWxHzB29+VZXe`?IvUSu*E|p!wD)bRrv~Dox$tSyN^;7l14Mr7Rvli zta7~9os<5O;SR7-4BA&;d3$xLed0C4x_x)>YAH~ZbYMUPxx_!dY3A7^_Q-}iwb_;G z10ySkeW#oi_)b9>ZrolChsJ>%*04Ql1q%4V*P6!wIiI|{WD}MimFl9YpMxjMh}%(v zZ*jN0S6WZ6s^%63W$WV(!k8R+!Gtz!whTgSlKJQCA$Mem7Y0UJF=K&9|Fz*sM%B zss3-82mqVUV$vfIkA~!xLqCYuzpF+#)*?E2%e%FUcg%-1m>J~?E#jsp$_s<`p=6GE zb5_7ptCG+i(?xea3qN^=_8!&c_Y>~hU|IwjxAoJs=(Kqb3iw>|amcT$WssbKF$;l7 zedWg|1|mT=)}IUhx;XN7g%eMNKiy*x_wYAp`nb&ZAbcmuwpKoZV+dLJ;0;I@hRm=! zEV@z&O#e!ea^pFRbt=0!p>BE~lAg0kYLVN>q}`^`;PAh4<&)g1m0*W~dJxv~otBO~ zg|G%#$8=bZKH`Ik)dp8_#&0Ep$f=mfq|fl?#)L}0$}}%l48X=|CXkn!Q1;C zfcZ86J_V-wT+gBjAj8YYk512;qm4PV&COy9laP<2qu%dFM{7zpv0+};tjm~=SPjTM z*`lNmqdQU;7~*eX5s{kV!yATR`G<|pxKXHa1Gbl}mdq7lKl-}1PVXWo>rL!4zrEj5 zDiv$3)W`e0&sVKPd26tPe6Yyy+Fte!SDQ3LqRgcO2ge?8!)^j~sue7^# zUwhm1*J)x~g4*F-32x3xlPv1v((RK+d{kC1^HoMEts=`5?b)#}uW8)apRM^3JH0Zv z(Mwz$kj^-W)uug8i64}n<8bBpXV%WNbtrd}8JNv~Zf@=qSnq#}Ab5U}i%fpmvfKtL z3~+mJdH#W@+C!p_#wD>-VjNNGV0aGVe2aWDt zY&<~?o8g?aE&H{({khCBp*s$o`diTj;3J6;>00ok#RTJ0s19QBoV*4$RA+%29f!+*|C=EGKQ z@b}oU2b0Oaco|6eBc%p}+7D}uHvCeMdrg&%zXBJq799c!jqFU-+WcT%+^{q4g2)=D zKMP8LuYFmt!`e47jpV7Yr_ymyZCh64t4DGzT4t}PmRKg{W zB6O4*%s+Z5E33a-wN)~k`B!l`N)!i7ntEP2|9yTSs~gXv&!)r>+`lrr+&p#C~V zd&N}^r)0uGp_7h#=U9EQO#2%##`uoT57VbR_c(ikqt%K6J32b*Y?1PabRx@}k9q5@ z8|rKTYCQN^5bFeSYV4}8?uxkxdi2Sv)>>4R-Dx944ctM0(cf_N+W!P-d|Z)S2cC=i zVK(~k>L2LF&MI{&H=djFSZ|oNU^nk6r4W%36BEzTqYv;IVauHH2RFhZq)9xPQq}qQ zyBrPG6FoF%E24S)H9c3;f|%1p;^tc0YAyzm$x9M;oL+l1kPpke@54%+)}8Fl_f~YK ze54%re~cppM9&kkqg(}sfN>; zG5xJjFo8#nowh4-@k|>3UGwKWwlsmAiGh7h0#b(V$@8CUT&V-TDD!fqM&q2v8%|Vv zB+FUHb!rY;I2%3)7O+tk2S&KY@D7|zU5{Xe8Rvpy^B;VGBBal6R*c)9?M#|jMyzO2 zzcz~^v>cr1=-8&eSMdeiw2VszG{*qL1&V&YYXi2X@2JjOYVqZru&APzS~_;33j%h7 zWcjK!*ofJlJjD_~u$V_(Siv!(cj6b2e%LkHc6NzD`iQbq0LPNSu$U~AJPFzQ0y}LL zJ^hq9@BXv7>Z9*bcxJ`{q7>+#Tb)7lX+@^S9CcFm5+GPz#!$C)d!P z+}g=)yXen?kmoAG7EqyWPn%%&D(*1bj`YF5egEqOGu|ctKg}=HcyP@n_)QyvXA+;A zX`-3&@Gd*Vx62#iPTNK&718DkV7$5UhleU3NHs#CKw3@$hAL7Sp7`_j3dbb5ZaF zT`x_N+BL|4NgA+{HI5gz*XrCSFv5O6bc;-Wu8UN*`_E$EAFsB3FB&E$h_K$jdHKT{q4(38OQHM@w=owt3auAhTc(cov_JBKQW5C zGTC(^P~nDeXV3U`oXRl4;@LSFVD@;Hm)y8I7RUl!pA@vGV?Fl&A?29-=q--{7Os&T zUij3x|;5B&%H*x4j}q_5;

t&Oxh%iL-(ttJ&5EINkg0^L+;RjEx9X+Bgjn=A= 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⩔0YdB2cCFg3sPDCdstX!9(?|Bo>b z?Hk;~^vS^jDI(-g`eit!XY`>-J7IH>1`d-kA5C<0^z1VaA~-Xw-7tUEj9rcdA=SOk7c#1OZY8%PXFrLbllx@rb> z12_mAa}oF#aQS6QJBzjUrQjvy0PsdZ4KC=&M?homV7SHpEw*li8~Rqs8} zW%&IVlUq1UDlMiJX8df%q7RB46DLO-u4=M$DVnG)!Ux3Z~UgP>#N7t_%e)2x)0=_p7Lgde?UCc)9wfhiVT5 zwGsp5ncuy8ml^x;go7=63!93AzXHCLArCeDiooAfMS8XOh}AWPuaSr;Nfs|oay$rb ztGn7_Q2~&1U|(sVPxP)JBQi}{bFqaGuTDOSZ0kqzUE<>B04Pt-$e91b zNAe;lZ)Pr8@Wm>Ov^<4nWn{p$Iq={aKR5YC!9C`XqkAC(|0BVgTrW2yab%xtBhs1=%(X z>)#JPU{2BrJjpQq+`(9vvZ?uOyMpQG_uz~yoBOeV8OCQWE55YidOCgWYJrp~ii9aC zc}+TzEkzyIuT8svTv9E`>9vd|4rLCn`cOnAJ~f9Simj3NEtiF>=F`;3Tc7H1wZ+-1 z{8R`G*eLi%oY(4xf+uqZ-1)0qvm{9q=f=zzNUyPq&FH=m;3&A_%_t@={>Vbl8n&q; zAg~>L&6UP{El*!}gx=tHhL;rZd#maMK=>$R@vC&vka57V2=qOhJ^ zuWy|~K?&uPFm6%R17!mc0Q1W(!wH6b8KAd!rnvCxOnl$FMLArS7iRseF$fT$`>Z}5 z@|8?9vHYv_-Tx>*^Dw$}MF>k}K7Q1E7*!%3kg9=?=`GR7mTJM?tiFv=L9I5UVZzQg zE%N*HbgsigNa*#MsF2q}|C0xYt7_pdK2c+r>oE_cQ_hT{GZfc~CmtJ6Oh>$-)Ozva z1u=GS!`13&?S7atiZ+Jv_G3Cpb;jCx(f4R#hf)d3)5G$25wd}&q@9XPp zc9CP)@Xn`zjeP+54TAxnWpQaZyrj zsPi^Cit}*>wiWL_Q@x?05xGa?)-4UmAJl1B{&XBnm6VBC+6C63Z>eJ`EvaexTq{zV z_Guk=qD9S7+C0q$uGI!@6fyZEj*Ia zOaVoskB31;-~j(|5_lDLmvO+qFw2E6o0tR*Q`E~}7m@YJOl?tvHmONMO8Nu9d+rPX zgX%tLB|q*YIuEztXMn>+Z*>=(^A_ZS6iLNxt8tG7<$<7EbepkF|SP#*- zzK=gst^Wa8!`hdufb*yev#oxYptgGNq12{RYs47`B5V2`YlGr4Fbw!!kWIA^SIJ78 z#$^-W=`+-^(&u6tXIS#vZ)cp3YP>HobjhHt;#8c5!YHlBt5xR-?i-^L)wJ9c9iHa9 zLd-Q;6OU4(ZjCv(zFI&Rg5Ku6*Ny|E-#dVSomhtB?s7}o(?Oqy{MTQ>;?M1f*L%3$`KDk@(N=Ki$2?LJ|Hvq!ENzKJ z5H(A^*=sQf5J2{B`^bmdh0Ucue6qm@mcA0&-#8L(uf~+mGMK6m22*fv0Ci(1p>q=k zzAW8Cd61-H`Mzj6q_4*q|zj*1_2QBUZE-lbM^qwOLK z-or+m%uuzaeIJJE(y)H!+N)Awouq3}`Fgs5r{jPEczWmL+kWs)+)|l0Lysd{4mZ6-IGxe`_nXOi??Sxx1?4>gwO6bdIu<&@M+KS&!kM?s zOM2vNe&ptzPF>5a7O}Q0L#ob&TdzDbTi*gA;1^5$kPDSg|G>b$oY3g?1`?UfY9FLI zp`|`3vBhJi3Fzu-e)oUhA_ijF9flddtK$qmU1gZ5lK)Chbn)|uTPWg0vT@zQIZ-a# zLn~@xYD=`OSX!UzYE78+NpS>!SH66Qm^ydXJBH!>r1FvqZ`4id0_%aRam6GH3{$nF z%dY|+tC5H8zHsxe+>N&MccLMm#^~7{+*(D#lu~cY-s_r@gbjQ{uC7XX zg?~qIl!loY)bI*sd34`-)bO@7-(Yw3zCF?NaaBrhexhhpo?MwV3Pa%WwEJ;q5pBE9 z%&Uz6xBf75uxoCt#tXRs!P&lTy{nCV^;uZg+^v9X26JtGmzGXH9Uae&1*=yWl^F1p ze~?-C4i&eXL(#31`5e&of8fa)rcg8dEgK&dkbQZq?B+n*7uC{}PdSY4sh{d39t}If4S#Pja?mcGUICI$c%_lI zdtcVmtE;Di-i#I7Uej9)IWn2jy03m&-qjX8c^O~;h9kh2(0jsrrT_n@kZ!&bK)}UK zg5L5KU6c~QP$0+x1j4HOaOHLQWS~Zq9b4(kMf=Q$Ykh*l@ zhZhgsX=&Rg!UTPdHfgnJtR<8~bn#zhvi;id60-8Jf6GhdH_mPA>(RoX)KchcA#=-O zIl)**#1^B8XIvjwe*Jt+)5kSZZ|9KfiA|4-*MN zm!Z(!k3*)Phlgo*s6^OMxvdg~=~ub&!7ap2`Z{E)K>Cj#8J-s*44;uqiWR_3(q0V!Oq~Pd(F4A>uOU;%v&KHQ4!TjWN35#DRiu) zc}kMz-1NULfP6iv1NSto|MC#~j_fPvPj|}g@1rS+m@tde9h!MHJutl|S&E)MF(jf$ zbpKg*-Bwp_w?j_zp#@z@xUc|D@=r3>3Xa_``#~&A-VBSIGK~y`)P+SlD1Yf3IU{21 zj-Z`|UwmU%8gqhVj~X5v-BMSlL@yo%m8aoMGx%A1MhZRvIh~zyg)NS1=|{V)^u@TS zxFJ4}{oG~(;7AfpgIvlJXQ0j5YG9vzK4JM}+JAA|W&oj=VZ|>k^paVA@bn=`z)iIW zO6en*)6ceFpI?HEe<;VrqKHzGFB!o9Pj3d4C%_d)vcIIJo@DZA~9XlD9 z5nUlxjxp)QmfxqjSFU1KCn_a1_@P#4f9Kg)6R@Ar_zzL;Xlom8Z}OJe&)ItVGk#*{ zpJQXlxr5b^e%zzjUes`j2v+$1moYpud?m$dV_2mkzR)#G&;g$EFJeU}#Mf;Coa1Zt z5biS|!81czo$Sg_@}=J&p3gSBQ5k7#R~XGtcqG+Q&;WsGRLy^^$K?3sJ#;b^oo^LY zKKH1d3X;vs?zu75+I!d7l0O>sfDd3in|&Rk05(pqkkbWz>$XP-%UvJz%>y4-@W#P~ zo$|5R|0$>zF8ix}fj`oVn$g1$9hyQLN=7rcZo~STJJ6r@?m>5g(T(P1m-p%H0Rz7@2X^vT9pZeac)v9{sG~mo?wYt7E+k%{8fT5J! z9RK>|vu`bxW;|?>%U{0L?;)}m;^Nx*^fDftAncJUB?g*={C-g=@#zLELPi|EYoXpu zECb$;O`Z%L#(%EhbEQ_ykXcoY#)TduE*VDdUmFiO=w1S3m6J=@ZgZp9sd-Yj`mE>= zKVVm{p>>Q&D`Lk33bi5ML4~tkg*~sohh7j(Rs)!UF5#&FF~}`-{!EOD5>z#Q+NtFo zIQjm^;}7NEfd9APQ{gD9G%cOdAgzKxrs>Foijy6yj{6ctryn;UP6WlLj3)(MDR{wC z0aN2H|N8x&YumKWYN*EK$;}%zz&Y_7G?k1(XRym9v!ubiPd~XjPe#3(Tt*py11+iM z|1G`zwqGHy45)c5Q?UEHJu+H+c%XN=Rn@|&<0q%9k|Q(b_4_CRatpR`&03|ak0v$I zmVs&IdT$8UzU;mX;Gm>&^L?bleO#BkCL`6UZpz-{p3zw-kJyt7?|qM%yjM#GMz@pg!vTwjW`XG9MS>OA^~O;#GThaO3X7 zBD>EA0pYB!1P3I&9Ae$xj38Qqr9AIeTdeGEdpc;z64sL2RbIl|{=j#f>?eneAbqX| z)y9)rkruW6gM+A~wemyO!Yni6K5re+C^~nq)tW+g#&PGBV0ig~zya&mU&P!r8<)>X zp@B*%Dv7{~v{#shiZBYx_T=sL$=D}PXLI`q3AnkG$j6ryQqC4daZPJ2`Xpwo#I9O8 z19r(gi5@j=(8&aFf1z^^_np*Q!qzPFHx3HwU@@XR7hqv`WLuqW(gO=JicKhUKOX)u zb-i7oD%q3El&XV)!bzG$p)F<3Dl%DfyStR#9>pmV5x!)s+xA)R!VEs`iEnTJrDhZS zUG4Du$L_sx6yPvk)|qW`x7#!Umm7NwTVgbEQJni$_!`oi7Eq~hW(}`sKWtzYmY0eC zkQ>;kd81mj!$`NMLQ7_r3GE&E=2u#2>#quVIhVgq9j~Lv`7N4bKq1;2fL9j?B2@X4 zCzrmZU7o_K+h&W@j9&l=6X7!c0RAzQi0H*@yI-b%Z@h_x~Ocd6F?|Y{?+*vtk@^JG`SI4s!PugMSH<12M z;xj{4i87ox%AXUFk1Cp!IIr0{cyX*nKYxZ*yFkQ@Rb9}p&sw2UYvFkGeNhhCd~-VD zViWYs#JvUMy2nS&WmmO_wyFaRG|``#$W}PJ+u6pYES9xcwg{VV`8R3gYWDg139@~N zlS;VF_^_@{5Tlf*acJl?xXiU|iXYeVIA0EwyOlOB@t+WW*O6?{%W^Jk^ww8~^h+G^#)$0y7GY zjm-vuW%*I9AH;X1e$Nvem&%~rl$dUMKqauEsP=kAzXnGb8lV_Y`icC2|F;w&= zq3Fw`u8g$D%;G(z>3wUgH=nAn66WCXU*(8#8ru2Ur(`im5dF_qRAD4NsIlbl_p0tH zISvY)0_^`cdphu7PUeT-c_;l);q;lp8hBf^va*bf>Sv&Ll?F>k=>hmr5dSuk@ZFe| z83*9h!PX2|icQ^~7$PM;w(vAD^<>WXKoAEFMB&dC&PY~b6{u|l+U56S^+8ccHLAQu zu>K-@*ilJx=VOdtEBXCRVRx}=N9jh9f!TKM+#@MRFQ-p`n>MuWYIlpi7D*3KQNgdw zPqy<+gjd}sYCX~n?X4&XOklaj-R~F@l}_q`(+WMbqsaUI^0;yLZDv3sIZ%i0R$Nqs zq{^D&Q0)*}Gc6uZYRIHLw&6~|Zo6vz{;dQ@oJGZ3XbZAA`$ly3b*O3%6f&jSX!3A} zx`<*c&iZ`y##Ghj7%FczL$Z7wn}`yMjr>t>#nzAd4x%hiO(sf&ts7rjk&Yce@t_Db zRwILGlmM?Y9|yqAy0));@&`F%x96O*Du#2Hu-%G9In#doUI+Z5o+LUtrk}vn1 zyu7T&>YUM<t6@|yi_x`jP}Uo6khcmEcWT$IFsU*8Q12WaWa9tE_$iBS&)Bw6UiQth7VC$Iw3 z`v!jcK6qKVnK!{PH7SG|Xu{^b$l)Pd0}f&38!{&-;HuVOpI=j}IvgX19Befu+Z%uU2%QI%WLkYg zi9`Dm7r*ip==B~25tEX#<>;`*u|b=1Y^!)+sDwTb)C*t}UWSm+{ZQe|-cXtxc-U&{ zPzS7TaozoWWQYjt&7gq3#EWSh=nU;{KWnqhC@MWEOhfAKqj&*kZOcoBd08v_tp;*# z*whif(z*5fq4SDp?0|LH$NUwwe0piKL;1YAk32Ry@_kcTPBLOm0q;gBEF_O4SB{G| zy;MHsrtOgIz2(aQRl&f!0@=np8}GD*`Zsv;iI;~>EEv!viD?Aobu{=q7s`%A;*XMb zV~(<&LOU#XQDKwfjada4t6ssi}1agh6B~KZ`w0Pow4^ws>lEn&+;u3piaj>|g zH@{!j!bu|2{UEOU(@T#lU9-Z7j*(GSFbhC#=$aHVf}+8DO+6omjWr17a$S-R;3oPHHN`%f=qok>Y&XTq$j|10rUO5n-4y z@pq`qv>sUtwhDgzwiT6@lB(rQK`-BfA)LsOA5PL|Q1Z5K$ndhBvDJhJHrg%34d2Fs^z zvsJxV6HHpB4t&F_I3a;!NW4TA7qn+WV#Iji3HjAf~LRHGs1EU*Nc4ix~y*hqD7cgyX804MJwj?-V)Egc< zf2BKj*;6%R!rsa8+SB2MvyvZR46gKfC%~!mQOtCz?#C2Y8UsKQJLPIJ3$L7# zvCL8!9~BDi*gZjPQ79iI1HNI+T22&PTw?by)zDSODA*S72qAa&*$w@Q3wiPIZ%D`O zT$K5gQ-zJDxb);2H8Q`@YNe60&nw){LAy{o5TJ6}UlWF6@`qDiNGA~a>`+xAj3G|Y z$-tKB5UQ4fS)N93mPw*Dp-M!HVPMihr%GJr@PJ8esi@qJt!pe|u&s_gA#9b$>E-7& zO#Cz~e1-SrQh4R$ls$xkA)Cv5Dvr-(9TJ$t^N+xoI#4D5ix+Vz!**3A;YZtT$P93x z9m9f74`bJNL{w)YDU2CnXlh_`yND1R;Rl->OHO}2Cf zko`LN)5`A0BXKQ>O3m;w?j+qIj0CU)@T}pJ8ccnOnx{l@Q24QE*n4p;qxU>~t-^eN zpNG6@d~~kyco;Sdp*20Bp9TH~-6@5RXeg&g~odBS)y{1B-u*$Auqt`1Fx^?_b{e>u{2nzoP8dQmC22f!xC* z*wozkTg8yt@IIdwCF1}l#zb7q82_^8ZGXl4-Ql>fk3d%V-uI79mm?|!e2(+6b*GS# z297`kfxHZ@wO!|5)BX$`s48vg`C>SCd!46Vzx0TUpC?sVPIs!9hmdg~td!@)mrTny zLBhV9-fq%AG&w1cgU0ahANcJbI6UR)=(t*cx^fGT~wC5wKSZhn%1B z)y9x3qoh0Goy~%-``jM1o!M4T%Zdv_n8yNfG=%!5NCd;W&&AoYS>D>(D&Wni@0{RF z7I?B8`sxi80e)Zm;qGIaJ48-ACNU)1JX$U>d{OLvo2pm_r$gZ@n{A}SOq- zFbDaz_4Q^FBNLidPj(bmb8D-^?c3x60s^-g@i+4CkRoHltb8ZbP~pW-IZ5@gBJFuB zE_6W8!wZ<%05w;ll_01rh;ILCr8-gf*ZwJ2hV}}qC4K{zx;H_FMA~CflgW|flY=1J z81fj)<&#&sIRFzW&JsqhtZB_KkHwoe8aL-z-Y8(+ghR!p)0HV;ndBsVK*hsF%Um9{yaf(VWhMz8Q&i^+B%VqbuBL0H%zKkt!tg=)Am6p@)R z@2XRKFR9Tvnt`b!H!rX6dq}_8=%b6*hWQ|RPE1W*&j*t_L$eMFU7qS+h*Wa9PlTgK z3a^~H;)yB5tnx=)ta&b~{PhASmFB1xS9)oP%&w>Y*L42jWvvpaB#1yx=KagdtUbb! zZn+q7G{lgpAUeV-n10>Mi;gwj!4UyUVTgwbvfgW5YcxFH^7*dZV-X({eIU)}4 zW6+C;myXcGqJc{qqB*LfIn)u4!W>Q+`pxEwon@ZaBro;D_zs#Q1r~psOR+c@Y%6^; zvXj`w1nBbIB(Bu)PoI+d;xAnHHi0lQxOq|LddbU|IcbC>d|#Yy8=e2eAK0y8)Hw_A0u&+mT(Z4Qu& zbCzz^RD-7_v4Ts&3M5yF&L0`|%V52v64!-EG;myMYS_|;x>`MfH_}Yw!1~b67FKpw zgPlFe(dn5v;+8AzFciSs3UJ11k!6b%XIMI#n47cSzmw;d>+0oIr8ErB-T!FvCE<`$ zTC~LF1~5iaT&vQ%lGZ(P2lI^j-{aoUFuFsnmg*s~shLDfHvgay9~P%-a=@Z4xv>a) zI{5z#fJq=AAJ!*g#1R1YXB`$5*Ht0MDedU7^y-Luu-kFrFH{kvQ{ph-&}t^iEf@9? zLk2wx67C=W_>p+VZ@9*iLyPa?C!HGoG>$;9imFKF!Rk2&7d(~`t4m(vZbua8atbD0 zwlF*aDrFS?Hc$2Vagu}ZffYu`++S}mi5YdxE5#_nYUw8a8zv@Em2PDn)IJHNJmGG+ z!n#y&1&LJv$wd)eSk1U@(+&E!1SH&2R838fFtKZHG*4Wy8^fodBWq+2_KUM0!}~Bu z6$UKLwhG)$!zLFaKTe2-83cd|dE&b0s60K4O={;B_Y*Y@sXs#NR_QcNh|a-jwW(&B zDgl?Wrb>w_7CMsL=jP3Yewa=bUs%YT`(-xNWvno9H1Bejp9Y;eX_p|zoto!-%3rbJ z9_s!GDza(VR%9H2o2Eprn8smf(iL&mej$h)$1cGhkkBl64Ut`j2zJ6yJuN8_qX5S4 z{QK@XDFUTHF2sdNunVn^wJ}(OZ)`E*6pHg$x;U3s0E|v5D-z)#D&JtxfH$KR@TAj!wAOliG3EzP6O(0AnUV%>e0hsRyw-0dQrpXu;7RLC(Li_;p17c`E zC4k9n0dQd{K4v)6E0MD%t>rQ-%bL37Mk|-Fu7j}wV@kZ6E~3)ycvC}xP|XlZA&i)0 z#cv!`818peQErTYX`jSX5+K)de_e{St*s3P=xJ$1;fZ?Ai_4uKuL0_IhlCYIN$8YN zhMb&)#?P+xVaDod9K!v3pC0U@(}!TX>EoI>sGyX74uJ5lkhBDrvwvw*@2>R>1bDeI z6}sqBz7^z9LGMnZ^DymkXEG!nePWxWQdF!eRy!`ONnJwcWXapWnfvlZ5BZ19Uff0_ zcshe=?2>xuJmE4~tsOctkygy|Ax zT0H!Z=Sxx5_AOMSfc2Pqg;TUEQbt|+F2XwFJ@DMvt@K3sZ&hUNEk}?+3EAV#IM|dR zOsv)i`9_!+`!%rP4R^m;AU@Dza4;qt^Wj3Y{qVu`gL0Ml=61lR$5uCdFdT{7>atp% zuO5(psI}y_*w`a{WYM?ajmhItqJ~2MT6Lu)0G<4iCMyD;jNFX6Tfa@%kV>onUtI|9 zEQ>8Qf8~|8H3D%d3?{Nv!US{4d{kdGpmPkeq89Few{Y;8|IMXNCQx9OB}}HoMFO+9 z@mHn#f$5F_!GsQ(fd)sMLo0mu)FHcRO=>U5_Gj}^5KHH-ipli9<4|40w{8H}S1JjT zstA18e7_Iob_uaHR7*$jbpT06GhLG`Z5@YM%r$Cy0m` z&m9E~Hu29h?=$T?`NBSA>lr`BlNJGyWeeM5K~snM(26w1Yus_n7ri|X>@^AK!0lWlaLu4$@2P#TdF z9;QP<%gA+lk***zD$naa2CG%DrX@9nBIu%YBN+*2+QWE5T zYBl&kx2-QAW6)HEZPGZrmwtRsF6D8!eMbP6164*V!RzP5!~3D}NE1;8x%3OIzL+4j zeB_!K4RLRAxpIL;lM?|3qnq-I5Qfc@x8bO23Th>^1b2bnFvc$d7J|Tm7o|LVK`c-p zo0zB?a$t4Jx$a7lLME@<2G|cU0|>%>BBbPo(Y!kwqWu`u5kr~Ih`fu8h(xG-4oU)w zn}VJK*JPe%J?~9*ez|iRI10X4wi3L(4{A_i=yf1|I8TJE7Oxe4W?$zM&_-rwRx2Gsh4(3uJcj4nDm2txQbRQ;Xy z`B1XabFg?uXJ%%$c~GeyP(Z+OuwxBTjm4??7jWEF+$xj>v&u%j{XU~EQM*QCx%ndq z{NX%fVt!^OEr20FKX1JGwS_zv@GzW2=~WFQg^5?B{uK*>=Lba^bkPnseCVQ6oaqxp z02IQ12j|P`CEF81n~*<#2>X`g2*Vp=-r_GE!2`O6`V_3mo&d6d_}$_@tz^RetGL;y zwD5y2irx|rpXk3x_%(kc0GTh6HpG#eoBMe6x!zu64{)Y-<}@w2fmnUzJ-bNCSI58N zK_MFbY;NK+c#Zg#RS23wpO#{@47P8oLCg89#*HItF_nad9x#kHExsKU&BYe8Wv3 z=ow5j*4Ea(pGU%9wKvdRt)AL^?^8h$v-|qK8o5xHba~FGyOa%-!^G*niYUA5F%B5- zURDO;Vj5Gf8gk7)o(Do1QiQ|6GNfmcnY+OEKR8$_K&(#*0~-~<&SnO>Z6`DtJ3_?< zEYR8UJ``<9YpgjsnIxul8J#DeH;0;l=74Fa5SAfS%8fmF)v5&FGV;ABJnh1Q?L=dx z+bVQ_v2ju&*-*xQK@!1fKY#vYCGLfkL*L)*HU)G1*0ssTO0o@#=?TkA44`Ib>^Jji zo)I=JH{u18qlrl$#yqql!m)rx2V$g;r~zgc?pO8;6MLHjoE_VM)6sfsG4Am2?ioy9 zNv3nn)8rUmTqKziPt~iMn3;it&?kK3lTqw@A)6f0TOXzPZ95qgL>d>0$X4p`<#G(j zrm2DT`=Uuj03EZ+qFP=sVhYkatUv)UaRqqX>FFgS*r_)6EZK=i42fnXGJMMY4d>^< z@K}I#L{NO`L(4#r_t0FoLSvm9QY%5hN5~t;2DlR%=9UqKJ)9LOm&2_j~hY8Cl@N!PQjVC&GhpY_KvjIZu5?z%Z+anhjBEj_ITaa08V_whr# z8OscKx|;amf;frhwEceN&TkGej7ujwRKT*;c=AUKH}yK!tmU^B3M0>-PgRkV&|GmV zQd~j;9Qp89cm$;L^cb3HA420trU~g@rmCEwu#{AcP|(&@q(KD`5`<(34*bJ#&O3MG z=?TwBQc8Is8Mb;xh^WU#;sGCFY=Y>^*bA*_tu)k|nQMxjg&(w0^cNvAdwJQa4H$W_ zBc);E8}9^&D=^8kYVy;W6E#xQYFaXX!x}g4prH^I<;hWWPpaF#?`Dw3c*Q&uYRkFe zIi5Jx`UhhN@VijP;vk=xyU-tt<+uy~?OVPzsp#EPjJR5lyStwfA$P5S1uFugeiD|W zjxqCIcl+7VLD7Zi5>1(u`RnsdP-2OY!4D1JLzq~^>yuo5;Ey5vmg&b2C#^cw0TFJ? z&^a1VM-@KcGtMRF?-<=YWdA%1i16LJ?{O|K4gUKnyn)&SZWV4_1N+SY@e6%~xY|4^ zZR(a01a5Y%p7AeHa$yLl8`~(U;p5Qi0iI$HY=I=)`M1MgFxIO=q)-%@ou8hLLOdn@ z=O-KR`;r(itN4c&;3vb6~zZyAdJNgsO4tnP1BfYid$IhtI1p<=_QgA*PtF+wC7=%%=$hdil@aD@^C3O7og zJRt)6Lg@pHY7(&Gc0>0Q-<3eYQ2Zw^7?o?{_^31mN_l>HgLrC}%XRo|;o<(;K(9BW zaQ|%>bF~VCf4KCdzfg-<(PO|FpmPK^6=M%-R(e3{LWetZ5m2B_lp+<-&=tJBP+G4$ z9K)i>RzSMC?Nv~tB7qTNg~zlKijAB+w5{lt)#d?Cn!%B{pkT3-ZSRkP8dC3xwn`^q z4|u2Oa7}#tsB`g;`x}$%)=|cMCT>y61Lw(?jlI+&jq$InrC6wLeDN-=;RDnrY~O^t2I|fglSl6WsU+t?#R??vS5uN<~8;?($149uMh<`DZ91ECw zq)@Q4D;9M5kcf-CP$*!`w^o=iKA3n(z%!a~rR4U~4SyJZw{9`;@Y2!Ikz;=X{V}X2 zj{+NQgoBjm-@#<;P&hyzp}O~ndBV`D2>_N_4W6uXH;a>|l!xJqho(9fS@S`1TehjZJ98sE%2`-|tQ*_$9R)MsD=?{{7!}3wPB9>MWm=f|^wOBMv@0xslMS zlscH$09ydfm8xB#{y@v|6AUUt4L5KPV#odD}WnTDL2`1dZVrJ~L{;oZG}KlkT7>N7YAeXSqDVO=vbmNjNLX8m`ASAk++&sw-*n(xdEG7m8 zt0^^Z=PttB9)IRmhy}5Q3fiy!F*|X0B`V#*5hdXb#*N8Ye`Up)Urmzgaiw-q@Fg(@w~z*57!0+iJwPg#=bjru`a8=tSw$I1^2&tMHBWoLiPjNg+j>7$Lc_E?5KJFE!?)7pur~UIyU-p~$ z+0QBknxJnd<4#lJ!@=h)=X?0jCrb-KgK7v1{?$CIRvHJMghy^PD~j*?H=VB+yzD|q>u^9YIQJq}Xz{L8@ zc8XXt4a?jVtwqS8rNnr(fge9Kfl5C==Hjj6izE5c7o+XjP;7%uglZFS1It!Qc}`a!GCXpr0+lu-bCzNtkdU;DYu)8ZND_B z2z95eY0v{nE?neBz1sKu4{*Yr%~8GN{}fbofgU@t3gAFi_?sLZ2beB@3}d+-3^oC0 z1qCLx8U;ZZC}KQ>z`sO+p@0m&ql!!csAGVQ?GnJ34ByPK6L-+nApxD_xY;HceMiGE za#--y)4DX=-jcUCqO|*x{&m~RGk)2X1Y-w4F2yO$gr4J`4hw%tL zwLSl0y9dn{IB@(0uHHKMd=Kgy`JxNh3-mBXl^m1FG3-~|B1DUTqH+l(5<=sl)&3`qT`DRE@^ z^fHo4Hv)jggk+Q;!jZ1!U&wveJ-sphdikDHcqxw*45ZqhyecGNED9a%WCt5#7m}%L zaNlogMXQ+D?bU?8naqQQZl*q^8%-q z=zlMVaHAGB;Lv&|-du>T+lJ_8Pv@{cl7sm3ydg8kV+fOxYo*~Vv_dXNNGKqT5fTY{ zWT1PbbP}Da$%?|FP`ylvi`zpx5Mcz&49dw_W- zdFi=RZW=+007_XZDMFPEQ!7oi2gbh(_X~Tks(!q`U5mJ>k$LMc>Mq%^_)ky1@Lsz; z#F=FWiEeXis~ZN4Tu7C2y>$!Ekr+U{JslfRp&TzN-7xxHEWmLKLEW_oMwk-?`4YuD#E08{XghtY@uzT0bM^{fdR}-MdG|6C%Ig z+cMxuHA6Gk_N_SPLY_|GNOFefVDviHok!s4Cj+gA|6&LLsOIeErWY7klT`IS?*Fs^d_}FR*Z}^RNp-8d znYub^#|Q8h9U;7pU{Z~Oibq#^#=m`V9zh^`#!5tFHm)jEvOB)V(&nDzi#g-xUTHGi*1&nF+hz)Bb2BtkN!#lzbd~4 z!Vj_32%KNXiSb{J`X=EHpYBh2aRk4U)D4A@L%yH6!9m`B)o_P;Qk(md&Qr6Tni+!^ zTL;3BJ>Kedg4+I}6x(zD2rA4YFFSy_`42E3uKo7Y zW?W$?8RwQ{aZ9_uZN9~kb9{W95HLoav<@s~vO1|w0ArJ00G-6U#t>2#MwM09j&_n5 zXGl9qx`QZM+B>^VExGZAMC6?RA*WC#+gjw)|KtDAr+=5rwYR^eQVh*DePTF^4CQ~f z@;H47d+kI~g{XEs`zF10_oKv37p8vbWNP*|BvX+YlOSUdjiSO!yx#*vqvMMd19j!p zlVzVf7(2PM2M(qJ&Bmk&OD<>zT>k?V@^~#IlZkEO5u=0P9ku?J8yGpLohyHBy3WnR zMZ3-+d`JZks!Y}a2xvKW$S62GVbL|CCFcV`u5*T@FmI|;^gR6y3nndgj6EGpw*gKQ z#D^pT^`{@rtb+|u5fzN!$%%X~1tS_B{&s=SEbq?A>|BRS8xHS|Ce3qLT$)r2US&Hg zo)>%g#2$V;EkJrsjA$%poLQUZ8JVdpejQ1=z@f>p%G~u6@ME!DrN`oWX0?1WqYiSo z4CM|+L<*l}cz3*1z`})c&ns#S-!{M@2FA zc~F7?c+a;5#((*8B+=UW;xt-i{*6bXn$JrZSfp#FFs?MQ^ft=U5F&w8B%0DA3(dMz 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 From 0f297cacbdc71af52f450e623db24a2dfd78395b Mon Sep 17 00:00:00 2001 From: Dominique Debergue Date: Fri, 2 Aug 2019 22:55:51 -0700 Subject: [PATCH 100/132] Update README.md --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index fc45bd1..3d3e4b0 100644 --- a/README.md +++ b/README.md @@ -9,14 +9,14 @@ Moreover, Gopher has a built-in, fully customizable SQL client authentication me - Super easy APIs for server, database, and client coding - Chat, private messaging, and voice chat - - Customizable client authentication (\*1) - - Built-in friending mechanism (\*1) + - Customizable client authentication (\***1**) + - Built-in friending mechanism (\***1**) - Supports multiple connections on the same User - - Server saves state on shut-down and restores on reboot (\*2) + - Server saves state on shut-down and restores on reboot (\***2**) -> (\*1) A MySQL (or similar SQL) database is required for the authentication/friending feature, but is an optional (like most) feature that can be enabled or disabled to use your own implementations. +> (\***1**) A MySQL (or similar SQL) database is required for the authentication/friending feature, but is an optional (like most) feature that can be enabled or disabled to use your own implementations. -> (\*2) When updating and restarting your server, you might need to be able to recover any rooms that were in the middle of a game. This enables you to do so with minimal effort. +> (\***2**) When updating and restarting your server, you might need to be able to recover any rooms that were in the middle of a game. This enables you to do so with minimal effort. ### Upcoming features From 8e03768d06ad2e28b0d22d30f240bebd9a536ead Mon Sep 17 00:00:00 2001 From: Dominique Debergue Date: Sat, 3 Aug 2019 13:19:19 -0700 Subject: [PATCH 101/132] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 3d3e4b0..45b8483 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@

+
+ Gopher Game Server provides a flexible and diverse set of tools that greatly ease developments of any type of online multiplayer game, or real-time application. GGS does all the heavy lifting for you, ensuring you never need to worry about synchronizing or data type conversions. Moreover, Gopher has a built-in, fully customizable SQL client authentication mechanism that creates and manages users' accounts for you. It even ties in a friending tool, so users can befriend and invite one another to groups, check each other's status, and more. All components are easily configurable and customizable for any specific project's needs. From d5cc77a833dd5da59dbe29fca32d776bdfcea0c9 Mon Sep 17 00:00:00 2001 From: hewiefreeman Date: Sat, 3 Aug 2019 16:40:46 -0700 Subject: [PATCH 102/132] Working on project site shell --- docs/css/nav.css | 38 ++++++++++++++++++++ docs/css/shell.css | 75 ++++++++++++++++++++++++++++----------- docs/images/zip_file.png | Bin 0 -> 3646 bytes docs/index.html | 7 +++- docs/js/init.js | 12 +++++++ docs/js/resize.js | 30 ++++++++++++++++ 6 files changed, 141 insertions(+), 21 deletions(-) create mode 100644 docs/css/nav.css create mode 100644 docs/images/zip_file.png create mode 100644 docs/js/init.js create mode 100644 docs/js/resize.js diff --git a/docs/css/nav.css b/docs/css/nav.css new file mode 100644 index 0000000..ed0607b --- /dev/null +++ b/docs/css/nav.css @@ -0,0 +1,38 @@ +.nav { + display: block; + position: absolute; + + top: 0px; + right: 0px; + + height: 40px; + + margin-right: 10px; + + overflow: hidden; +} + +.navButton { + display: inline-block; + position: relative; + + height: 30px; + + line-height: 30px; + text-align: center; + vertical-align: center; + align-self: right; + + padding-left: 5px; + padding-right: 5px; + margin-right: 3px; + + color: #ffffff; + background: #3f3f3f; + box-shadow: 0px 3px 3px rgba(0, 0, 0, 0.4); + + border-bottom: 3px solid #85d681; + border-radius: 0px 0px 2px 2px; + + cursor: pointer; +} \ No newline at end of file diff --git a/docs/css/shell.css b/docs/css/shell.css index 1e449ea..820ad70 100644 --- a/docs/css/shell.css +++ b/docs/css/shell.css @@ -8,6 +8,8 @@ body { margin: 0px; padding: 0px; + + overflow: scroll; } br { @@ -30,11 +32,7 @@ a:link { } a:hover { - color: #000000; -} - -a:visited { - color: #ffffff; + color: #dedede; } a:active { @@ -101,8 +99,10 @@ h5 { } .wrapper { - display: flex; - position: relative; + display: block; + position: absolute; + + text-align: center; top: 0px; left: 0px; @@ -113,18 +113,15 @@ h5 { background: rgba(255,255,255,0); - flex-direction: column; - flex-wrap: nowrap; - justify-content: flex-start; - align-items: stretch; - z-index: 2; } .shadowWrapper { - display: flex; + display: block; position: fixed; + text-align: center; + top: 0px; left: 0px; @@ -133,19 +130,17 @@ h5 { overflow: hidden; - flex-direction: column; - flex-wrap: nowrap; - justify-content: flex-start; - align-items: stretch; - z-index: 1; } .shadowObj { display: block; + align-self: center; + + width: 100%; max-width: 1000px; - height: 1500; + height: 100%; background: #ffffff; background-color: #ffffff; @@ -154,8 +149,11 @@ h5 { } .innerWrapper { - display: flex; + display: block; + + align-self: center; + width: 100%; max-width: 1000px; flex-direction: column; @@ -229,4 +227,41 @@ h5 { height: 50px; margin-top: 10px; +} + +.downloadHolder { + display: block; + position: absolute; + + text-align: center; + vertical-align: center; + + bottom: 0px; + right: 0px; + left: 410px; + + height: 145px; +} + +.downloadButton { + display: block; + position: relative; + + margin-left: auto; + margin-right: auto; + + width: 100px; + height: 100px; + + background-image: url('../images/zip_file.png'); + background-repeat: no-repeat; + background-size: 100%; +} + +.filler { + display: block; + position: relative; + + width: 100%; + height: 100%; } \ No newline at end of file diff --git a/docs/images/zip_file.png b/docs/images/zip_file.png new file mode 100644 index 0000000000000000000000000000000000000000..5143a05b3783f319ef65d3a5b43dc68b32199637 GIT binary patch literal 3646 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 literal 0 HcmV?d00001 diff --git a/docs/index.html b/docs/index.html index f96e979..50f2c70 100644 --- a/docs/index.html +++ b/docs/index.html @@ -19,6 +19,7 @@ + @@ -31,7 +32,9 @@
-

Gopher

Game Server

Hewiefreeman

+

Gopher

Game Server

Source on GitHub

+ +
@@ -39,5 +42,7 @@
+ + diff --git a/docs/js/init.js b/docs/js/init.js new file mode 100644 index 0000000..dde5b1a --- /dev/null +++ b/docs/js/init.js @@ -0,0 +1,12 @@ +window.addEventListener("load", init); +var download_nav, + download_btn; + +function init() { + download_nav = document.getElementById("downloadNav"); + download_btn = document.getElementById("downloadBtn"); + + window.addEventListener("resize", resized); + // + resize_init(); +} \ No newline at end of file diff --git a/docs/js/resize.js b/docs/js/resize.js new file mode 100644 index 0000000..97caf77 --- /dev/null +++ b/docs/js/resize.js @@ -0,0 +1,30 @@ +var download_btn_hidden = false; +var download_btn_switch = 520; + +function resized(e) { + if (document.documentElement.clientWidth <= download_btn_switch && !download_btn_hidden) { + download_nav.style.display = "inline-block"; + download_btn.style.display = "none"; + + download_btn_hidden = true; + } else if (document.documentElement.clientWidth > download_btn_switch && download_btn_hidden) { + download_nav.style.display = "none"; + download_btn.style.display = "block"; + + download_btn_hidden = false; + } +} + +function resize_init() { + if (document.documentElement.clientWidth <= download_btn_switch) { + download_nav.style.display = "inline-block"; + download_btn.style.display = "none"; + + download_btn_hidden = true; + } else if (document.documentElement.clientWidth > download_btn_switch) { + download_nav.style.display = "none"; + download_btn.style.display = "block"; + + download_btn_hidden = false; + } +} \ No newline at end of file From c9d40659820f4e6fb056ce0067b1988db8fefa29 Mon Sep 17 00:00:00 2001 From: hewiefreeman Date: Sat, 3 Aug 2019 17:18:18 -0700 Subject: [PATCH 103/132] Adding site responsiveness --- docs/css/shell.css | 12 ++++++------ docs/index.html | 4 ++-- docs/js/init.js | 6 +++++- docs/js/resize.js | 20 ++++++++++++++++++-- 4 files changed, 31 insertions(+), 11 deletions(-) diff --git a/docs/css/shell.css b/docs/css/shell.css index 820ad70..083343b 100644 --- a/docs/css/shell.css +++ b/docs/css/shell.css @@ -29,14 +29,17 @@ a { a:link { color: #ffffff; + text-decoration: none; } a:hover { color: #dedede; + text-decoration: underline; } a:active { color: #ffffff; + text-decoration: none; } h1 { @@ -107,8 +110,7 @@ h5 { top: 0px; left: 0px; - min-width: 350px; - + min-width: 310px; width: 100%; background: rgba(255,255,255,0); @@ -136,8 +138,6 @@ h5 { .shadowObj { display: block; - align-self: center; - width: 100%; max-width: 1000px; height: 100%; @@ -151,8 +151,6 @@ h5 { .innerWrapper { display: block; - align-self: center; - width: 100%; max-width: 1000px; @@ -172,6 +170,8 @@ h5 { /*background-image: url("../images/bg.jpg");*/ background-color: #7a7a7a; + border-bottom: 3px solid #85d681; + z-index: 6; } diff --git a/docs/index.html b/docs/index.html index 50f2c70..6ef5a99 100644 --- a/docs/index.html +++ b/docs/index.html @@ -31,8 +31,8 @@
-
-

Gopher

Game Server

Source on GitHub

+ +

Gopher

Game Server

Source on GitHub

diff --git a/docs/js/init.js b/docs/js/init.js index dde5b1a..ab9a238 100644 --- a/docs/js/init.js +++ b/docs/js/init.js @@ -1,10 +1,14 @@ window.addEventListener("load", init); var download_nav, - download_btn; + download_btn, + logo, + title; function init() { download_nav = document.getElementById("downloadNav"); download_btn = document.getElementById("downloadBtn"); + logo = document.getElementById("logo"); + title = document.getElementById("title"); window.addEventListener("resize", resized); // diff --git a/docs/js/resize.js b/docs/js/resize.js index 97caf77..0597206 100644 --- a/docs/js/resize.js +++ b/docs/js/resize.js @@ -1,7 +1,10 @@ -var download_btn_hidden = false; -var download_btn_switch = 520; +var download_btn_hidden = false, + download_btn_switch = 520, + logo_resize = false, + logo_switch = 350; function resized(e) { + // Resize and replace download button if (document.documentElement.clientWidth <= download_btn_switch && !download_btn_hidden) { download_nav.style.display = "inline-block"; download_btn.style.display = "none"; @@ -13,6 +16,19 @@ function resized(e) { download_btn_hidden = false; } + + // Resize logo + if (document.documentElement.clientWidth <= download_btn_switch) { + logo_resize = true; + logo.style.width = (document.documentElement.clientWidth/2)+"px"; + logo.style.height = (document.documentElement.clientWidth/2)+"px"; + title.style.left = ((document.documentElement.clientWidth/2)-30)+"px"; + } else if (document.documentElement.clientWidth > download_btn_switch && logo_resize) { + logo.style.width = "230px"; + logo.style.height = "230px"; + title.style.left = "220px"; + logo_resize = false; + } } function resize_init() { From bf8ae0b98edb9d8da474f1cb96e0c31e19a169e2 Mon Sep 17 00:00:00 2001 From: hewiefreeman Date: Sat, 3 Aug 2019 17:21:05 -0700 Subject: [PATCH 104/132] Adding site responsiveness --- docs/js/resize.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/docs/js/resize.js b/docs/js/resize.js index 0597206..ae93282 100644 --- a/docs/js/resize.js +++ b/docs/js/resize.js @@ -43,4 +43,17 @@ function resize_init() { download_btn_hidden = false; } + + // Resize logo + if (document.documentElement.clientWidth <= download_btn_switch) { + logo_resize = true; + logo.style.width = (document.documentElement.clientWidth/2)+"px"; + logo.style.height = (document.documentElement.clientWidth/2)+"px"; + title.style.left = ((document.documentElement.clientWidth/2)-30)+"px"; + } else if (document.documentElement.clientWidth > download_btn_switch) { + logo.style.width = "230px"; + logo.style.height = "230px"; + title.style.left = "220px"; + logo_resize = false; + } } \ No newline at end of file From 8715eab833ae823c1d2cfc764273433636066ec4 Mon Sep 17 00:00:00 2001 From: hewiefreeman Date: Sat, 3 Aug 2019 17:50:28 -0700 Subject: [PATCH 105/132] Fixing site shell for mobile. --- docs/css/shell.css | 10 ++++++---- docs/index.html | 2 +- docs/js/resize.js | 8 ++++---- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/docs/css/shell.css b/docs/css/shell.css index 083343b..50a889c 100644 --- a/docs/css/shell.css +++ b/docs/css/shell.css @@ -142,8 +142,7 @@ h5 { max-width: 1000px; height: 100%; - background: #ffffff; - background-color: #ffffff; + background: #ECFFEB; box-shadow: 0px 0px 20px rgba(0, 0, 0, 0.4); } @@ -183,7 +182,7 @@ h5 { min-height: 100px; height: 10px; - background: #ffffff; + background: #ECFFEB; overflow: hidden; } @@ -260,7 +259,10 @@ h5 { .filler { display: block; - position: relative; + position: absolute; + + top: 0px; + left: 0px; width: 100%; height: 100%; diff --git a/docs/index.html b/docs/index.html index 6ef5a99..05f901a 100644 --- a/docs/index.html +++ b/docs/index.html @@ -33,7 +33,7 @@

Gopher

Game Server

Source on GitHub

- +
diff --git a/docs/js/resize.js b/docs/js/resize.js index ae93282..4637444 100644 --- a/docs/js/resize.js +++ b/docs/js/resize.js @@ -24,8 +24,8 @@ function resized(e) { logo.style.height = (document.documentElement.clientWidth/2)+"px"; title.style.left = ((document.documentElement.clientWidth/2)-30)+"px"; } else if (document.documentElement.clientWidth > download_btn_switch && logo_resize) { - logo.style.width = "230px"; - logo.style.height = "230px"; + logo.style.width = "250px"; + logo.style.height = "250px"; title.style.left = "220px"; logo_resize = false; } @@ -51,8 +51,8 @@ function resize_init() { logo.style.height = (document.documentElement.clientWidth/2)+"px"; title.style.left = ((document.documentElement.clientWidth/2)-30)+"px"; } else if (document.documentElement.clientWidth > download_btn_switch) { - logo.style.width = "230px"; - logo.style.height = "230px"; + logo.style.width = "250px"; + logo.style.height = "250px"; title.style.left = "220px"; logo_resize = false; } From 805c55f4a30147d0d50db16a3e84e81563174255 Mon Sep 17 00:00:00 2001 From: hewiefreeman Date: Sat, 3 Aug 2019 19:39:40 -0700 Subject: [PATCH 106/132] Added 'version' macro, changed start-up graphic, uploading site example images. --- docs/images/minimal_code_ex.png | Bin 0 -> 7128 bytes docs/images/running_ex.png | Bin 0 -> 7329 bytes macros.go | 2 ++ server.go | 4 ++-- 4 files changed, 4 insertions(+), 2 deletions(-) create mode 100644 docs/images/minimal_code_ex.png create mode 100644 docs/images/running_ex.png diff --git a/docs/images/minimal_code_ex.png b/docs/images/minimal_code_ex.png new file mode 100644 index 0000000000000000000000000000000000000000..a0268c6e6de31826f36dedd9f7683f13f9b47d31 GIT binary patch literal 7128 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 O0IH__2&ZE8`hNkk0k^9F literal 0 HcmV?d00001 diff --git a/docs/images/running_ex.png b/docs/images/running_ex.png new file mode 100644 index 0000000000000000000000000000000000000000..ab152fbfd527c18a5987d315e54b2cf1ea7e8020 GIT binary patch literal 7329 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 Kdg=W~um2a^kyiQu literal 0 HcmV?d00001 diff --git a/macros.go b/macros.go index 81fd45e..ebb1bd5 100644 --- a/macros.go +++ b/macros.go @@ -30,6 +30,8 @@ func handleMacro(macro string) bool { } else if macro == "shutdown" { ShutDown() return true + } else if macro == "version" { + fmt.Println(version) } else if macro == "roomcount" { fmt.Println("Room count: ", core.RoomCount()) } else if macro == "usercount" { diff --git a/server.go b/server.go index 1682245..f983b4f 100644 --- a/server.go +++ b/server.go @@ -83,7 +83,7 @@ var ( clientConnectCallback func(*http.ResponseWriter, *http.Request) bool //SERVER VERSION NUMBER - version string = "1.0-ALPHA.5" + version string = "1.0-BETA.1" ) ////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -102,7 +102,7 @@ func Start(s *ServerSettings) { return } serverStarted = true - fmt.Println(" _____ _ _____\n| __ \\ | | / ___|\n| | \\/ ___ _ __ | |__ ___ _ __\\ `--. ___ _ ____ _____ _ __\n| | __ / _ \\| '_ \\| '_ \\ / _ \\ '__|`--. \\/ _ \\ '__\\ \\ / / _ \\ '__|\n| |_\\ \\ (_) | |_) | | | | __/ | /\\__/ / __/ | \\ V / __/ |\n \\____/\\___/| .__/|_| |_|\\___|_| \\____/ \\___|_| \\_/ \\___|_|\n | |\n |_| v" + version + "\n\n") + fmt.Println(" _______ __\n | _ |.-----..-----.| |--..-----..----.\n |. |___||. _ ||. _ ||. ||. -__||. _|\n |. | ||:. . ||:. __||: |: ||: ||: |\n |: | |'-----'|: | '--'--''-----''--'\n |::.. . | '--' - Game Server -\n '-------'\n\n") fmt.Println("Starting server...") //SET SERVER SETTINGS if s != nil { From 3d626c157c91325049bc9320a9bded0001a2194e Mon Sep 17 00:00:00 2001 From: hewiefreeman Date: Sun, 4 Aug 2019 01:21:06 -0700 Subject: [PATCH 107/132] Added button for wiki to top bar --- actions/actions.go | 4 ++-- docs/css/nav.css | 3 +++ docs/css/shell.css | 26 ++++++++++++++++++-------- docs/images/wiki_img.png | Bin 0 -> 8616 bytes docs/index.html | 19 ++++++++++++++++--- docs/js/init.js | 4 ++++ docs/js/resize.js | 33 +++++++++++++++++++++++++++++++-- 7 files changed, 74 insertions(+), 15 deletions(-) create mode 100644 docs/images/wiki_img.png diff --git a/actions/actions.go b/actions/actions.go index 6c318db..ab80bd0 100644 --- a/actions/actions.go +++ b/actions/actions.go @@ -199,8 +199,8 @@ func typesMatch(data interface{}, theType int) bool { // is needed. // // NOTE: A response can only be sent once to a Client. Any more calls to Respond() on the same Client will not send a response, -// nor do anything at all. If you want to send a stream of messages to the Client, first get their User object with core.GetUser() using -// the Client's Name(). Then you can send Data messages directly to the User with the *User.DataMessage() function. +// nor do anything at all. If you want to send a stream of messages to the Client, first get their User object with *Client.User(), +// then you can send data messages directly to the User with the *User.DataMessage() function. func (c *Client) Respond(response interface{}, err ClientError) { //YOU CAN ONLY RESPOND ONCE if (*c).responded { diff --git a/docs/css/nav.css b/docs/css/nav.css index ed0607b..8fbdd1b 100644 --- a/docs/css/nav.css +++ b/docs/css/nav.css @@ -6,6 +6,9 @@ right: 0px; height: 40px; + min-width: 320px; + + text-align: right; margin-right: 10px; diff --git a/docs/css/shell.css b/docs/css/shell.css index 50a889c..c59189c 100644 --- a/docs/css/shell.css +++ b/docs/css/shell.css @@ -228,31 +228,41 @@ h5 { margin-top: 10px; } -.downloadHolder { +.headerBtnsHolder { display: block; position: absolute; - text-align: center; vertical-align: center; + line-height: 155px; bottom: 0px; right: 0px; left: 410px; - height: 145px; + height: 140px; + + white-space: nowrap; } -.downloadButton { - display: block; +.headerBtn { + display: inline-block; position: relative; - margin-left: auto; - margin-right: auto; + width: 100px; + height: 140px; + + margin-right: 20px; + + align-self: center; +} + +.headerBtnImage { + display: block; + position: relative; width: 100px; height: 100px; - background-image: url('../images/zip_file.png'); background-repeat: no-repeat; background-size: 100%; } diff --git a/docs/images/wiki_img.png b/docs/images/wiki_img.png new file mode 100644 index 0000000000000000000000000000000000000000..2819403800f9b6545e8c7b7fa9c96ad988ae553b GIT binary patch literal 8616 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
  • <(8`}3w^w6lqZDX>NdybSzrmYTq=Air*s*wz|mL)@f4;?lbqHyrHg+QEX+tEZPVT+BB ztjM>+JL629Ub!3M&5swywp-LSpM{Br6q@7`-Dz>dYAv|L|kma8Y(&zyrsp{h@-eUO{K}#i1tgy9Cz-|CRa1o$vZQuFn_zn^L-@YU}2#EwcRPA3>{&W(yyQ8vUww zOV|a>kQiOguA8}-ZlNO|Hb($ud>0j{BF3njIl4V*XHFnbMS`-BvPqXYn7`vTp`mzU z@;EwI7;alREE(#*^qo|OQ}<|`#kfi$kOKJpkxG?qT1RsA51o%P6KB6A@teWfNYc_F zDgPD%=t=y2?PZY%;xdlILEq64mOBcdsOiMV<-eu*N?RT01Tj&<2_5;PS3~>*pZV9t zm${>;ygyH3q!Y`S+bl`N(Ih>MXtAi{YuF=F8kKcqleo7z0ko`3s#~}Kqbmpk4d*(@ zq8z|Pbfhvi=_3AWK^z%5B3pj|kF&7?XV?1O>_}cJ@(o;+b>yEVo36XVVR$|Z;@zd_ zPwUBT{w-%HHPMlUx5fyaj;oiwE#>n8t7Mpf8%0x7R%M@=Ym+%e~sa8npXoi#g@ig#HmSJrKmE6diE z@LDmfgR*-*GucZ1lXEJWie`vRbuIS6kS^2tD}q1LsquJ_iLOQjG;DUr5FBOVt{1zs z*U{|c|K#O3Anoqib|YGiPaVu#%-_hkf51}uXYS7(KwfsZ3aAtA$Eeclz~1)L`cDxw zZ`$$G06jbJ524hKh0dMJnJY@t$u7?KhlostILpTpk(ND|dmXoGiObsgZ@7!~8LJRW z9V37E6~urkt@g(6UM9LWd*@0^#_;}d?a^2rRe3zCpZFs2j*Rs%a*5=LxvF2mT$yQJ zw<>DJLfAk>fT4&PDr|3KQ-IwIIHQ`szFxbDw7Q;W+`mTT__;Mv>ypb%V50bCWo1oX zy&?ep=&^J|y>rKhRD%6o#-J`f-Jj>@=es+IWaVdx=zC92;Rcbq#0GYz@42-=kS<-V zOOCz-6DuykK7v>JpAGyn!jmHLaWCZu3~Uf5UB>N>TbGkwV4{RZTJ>n0`0tH}a`<;3jft7oc#B`ML=X;PGZGiG4v ze}C)Hsku77Es1ffg#8ntoo+u=DPP^f#Qe`e)8CDE1#RH6A02=9&ecZ;xn3nV}*mvzo9z7qvec> zwt>Ri1y%k@H`8Z-Q+bAyB~Jf6l0|B~F=unb<2rwuEDYsn6Hfel-PX2XJBhrPug3v( zZgHnGpd`l8eZF@H*^F&U_9Kwu&%DMS-9>HL=qp`W7F1|sR z7<$6xmt?Y5Yz<%dqA(0pG{muLmzr3nr951NNRJX%@<8#uwo}U(zPP$lsIbP`y70=S z*?s|uJF!&_TrN;}&W91dYw}Wy_C>#+JC$tH?q2}qh74_)Gw721wBc}1~-Fp)Bl|1PHK)sawnJzxFqayR}ey}9Q08n&a}E@vT$(O7K&u-D?YUUR45g^ zF172j<4E1jw#zSkK5s9AiK^D6Q;VIhx>i+xjv{%Yly3j4+hSvhpCzu4i~vd%sajQ` z?)WW?qWYeX!>v;k=v;?OT#9>}U&~E^2s)$4%n9PyhtJ~u%hJx$_Tqtw|LJBh1{Hqx zL&DA`^cE6&|7SXhkQ9&~WBezJIyhh84A3X~>TdvDf@n_URMOaf(tCQb zPI?J$IQ`zAQ80ae5tV5j&Z69bj{Xw8S}Mz_E9~x%^ACHre`HuuibPE9{al
    - - - +
    +

    Gopher

    +

    Game Server

    +
    +

    Source on GitHub

    +
    + +
    + + +
    diff --git a/docs/js/init.js b/docs/js/init.js index ab9a238..f5d75d6 100644 --- a/docs/js/init.js +++ b/docs/js/init.js @@ -1,12 +1,16 @@ window.addEventListener("load", init); var download_nav, download_btn, + wiki_nav, + wiki_btn, logo, title; function init() { download_nav = document.getElementById("downloadNav"); download_btn = document.getElementById("downloadBtn"); + wiki_nav = document.getElementById("wikiNav"); + wiki_btn = document.getElementById("wikiBtn"); logo = document.getElementById("logo"); title = document.getElementById("title"); diff --git a/docs/js/resize.js b/docs/js/resize.js index 4637444..fc2d9be 100644 --- a/docs/js/resize.js +++ b/docs/js/resize.js @@ -1,5 +1,7 @@ var download_btn_hidden = false, download_btn_switch = 520, + wiki_btn_hidden = false, + wiki_btn_switch = 640, logo_resize = false, logo_switch = 350; @@ -12,11 +14,24 @@ function resized(e) { download_btn_hidden = true; } else if (document.documentElement.clientWidth > download_btn_switch && download_btn_hidden) { download_nav.style.display = "none"; - download_btn.style.display = "block"; + download_btn.style.display = "inline-block"; download_btn_hidden = false; } + // Resize and replace wiki button + if (document.documentElement.clientWidth <= wiki_btn_switch && !wiki_btn_hidden) { + wiki_nav.style.display = "inline-block"; + wiki_btn.style.display = "none"; + + wiki_btn_hidden = true; + } else if (document.documentElement.clientWidth > wiki_btn_switch && wiki_btn_hidden) { + wiki_nav.style.display = "none"; + wiki_btn.style.display = "inline-block"; + + wiki_btn_hidden = false; + } + // Resize logo if (document.documentElement.clientWidth <= download_btn_switch) { logo_resize = true; @@ -32,6 +47,7 @@ function resized(e) { } function resize_init() { + // Resize and replace download button if (document.documentElement.clientWidth <= download_btn_switch) { download_nav.style.display = "inline-block"; download_btn.style.display = "none"; @@ -39,11 +55,24 @@ function resize_init() { download_btn_hidden = true; } else if (document.documentElement.clientWidth > download_btn_switch) { download_nav.style.display = "none"; - download_btn.style.display = "block"; + download_btn.style.display = "inline-block"; download_btn_hidden = false; } + // Resize and replace wiki button + if (document.documentElement.clientWidth <= wiki_btn_switch) { + wiki_nav.style.display = "inline-block"; + wiki_btn.style.display = "none"; + + wiki_btn_hidden = true; + } else if (document.documentElement.clientWidth > wiki_btn_switch) { + wiki_nav.style.display = "none"; + wiki_btn.style.display = "inline-block"; + + wiki_btn_hidden = false; + } + // Resize logo if (document.documentElement.clientWidth <= download_btn_switch) { logo_resize = true; From f628f95aa1609c77f9645588adb8a0a8a34c8c4b Mon Sep 17 00:00:00 2001 From: Dominique Debergue Date: Wed, 7 Aug 2019 19:00:27 -0700 Subject: [PATCH 108/132] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 45b8483..83e7c44 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ Moreover, Gopher has a built-in, fully customizable SQL client authentication me # :video_game: Client APIs - JavaScript: [GopherClientJS](https://github.com/hewiefreeman/GopherClientJS) - - Java: [GopherClientJava](https://github.com/hewiefreeman/GopherClientJava) ( **In development** ) + - Java: ( **In development** ) > If you want to make a client API in an unsupported language and want to know where to start and/or have any questions, feel free to [email me](mailto:dominiquedebergue@gmail.com?subject=[GitHub]%20Gopher%20Game%20Server)! From 941c558bfe44f237f150918187785cceb8aafecd Mon Sep 17 00:00:00 2001 From: hewiefreeman Date: Mon, 26 Aug 2019 16:07:41 -0700 Subject: [PATCH 109/132] Simplified server restoring logic, clean-up, and testing --- callbacks.go | 35 ++++++-------- core/core.go | 45 +++++++++++------- core/rooms.go | 12 +++-- core/users.go | 2 +- docs/index.html | 4 +- helpers/saveState.go | 23 --------- server.go | 110 ++++++++++++++++++------------------------- sockets.go | 82 ++++++++++---------------------- 8 files changed, 124 insertions(+), 189 deletions(-) delete mode 100644 helpers/saveState.go diff --git a/callbacks.go b/callbacks.go index 6a72c2f..8a6304a 100644 --- a/callbacks.go +++ b/callbacks.go @@ -97,10 +97,9 @@ func SetClientConnectCallback(cb interface{}) error { return errors.New(ErrorServerRunning) } else if callback, ok := cb.(func(*http.ResponseWriter, *http.Request) bool); ok { clientConnectCallback = callback - } else { - return errors.New(ErrorIncorrectFunction) + return nil } - return nil + return errors.New(ErrorIncorrectFunction) } // SetLoginCallback sets the callback that triggers when a client logs in as a User. The @@ -128,10 +127,9 @@ func SetLoginCallback(cb interface{}) error { } else { core.LoginCallback = callback } - } else { - return errors.New(ErrorIncorrectFunction) + return nil } - return nil + return errors.New(ErrorIncorrectFunction) } // SetLogoutCallback sets the callback that triggers when a client logs out from a User. The @@ -147,10 +145,9 @@ func SetLogoutCallback(cb interface{}) error { return errors.New(ErrorServerRunning) } else if callback, ok := cb.(func(string, int)); ok { core.LogoutCallback = callback - } else { - return errors.New(ErrorIncorrectFunction) + return nil } - return nil + return errors.New(ErrorIncorrectFunction) } // SetSignupCallback sets the callback that triggers when a client makes an account. The @@ -170,10 +167,9 @@ func SetSignupCallback(cb interface{}) error { return errors.New(ErrorServerRunning) } else if callback, ok := cb.(func(string, map[string]interface{}) bool); ok { database.SignUpCallback = callback - } else { - return errors.New(ErrorIncorrectFunction) + return nil } - return nil + return errors.New(ErrorIncorrectFunction) } // SetDeleteAccountCallback sets the callback that triggers when a client deletes their account. The @@ -197,10 +193,9 @@ func SetDeleteAccountCallback(cb interface{}) error { return errors.New(ErrorServerRunning) } else if callback, ok := cb.(func(string, int, map[string]interface{}, map[string]interface{}) bool); ok { database.DeleteAccountCallback = callback - } else { - return errors.New(ErrorIncorrectFunction) + return nil } - return nil + return errors.New(ErrorIncorrectFunction) } // SetAccountInfoChangeCallback sets the callback that triggers when a client changes an `AccountInfoColumn`. The @@ -224,10 +219,9 @@ func SetAccountInfoChangeCallback(cb interface{}) error { return errors.New(ErrorServerRunning) } else if callback, ok := cb.(func(string, int, map[string]interface{}, map[string]interface{}) bool); ok { database.AccountInfoChangeCallback = callback - } else { - return errors.New(ErrorIncorrectFunction) + return nil } - return nil + return errors.New(ErrorIncorrectFunction) } // SetPasswordChangeCallback sets the callback that triggers when a client changes their password. The @@ -251,8 +245,7 @@ func SetPasswordChangeCallback(cb interface{}) error { return errors.New(ErrorServerRunning) } else if callback, ok := cb.(func(string, int, map[string]interface{}, map[string]interface{}) bool); ok { database.PasswordChangeCallback = callback - } else { - return errors.New(ErrorIncorrectFunction) + return nil } - return nil + return errors.New(ErrorIncorrectFunction) } diff --git a/core/core.go b/core/core.go index 6a854cd..ac99e75 100644 --- a/core/core.go +++ b/core/core.go @@ -24,17 +24,27 @@ import ( ) var ( - serverStarted bool = false - serverPaused bool = false + serverStarted bool + serverPaused bool serverName string - kickOnLogin bool = false - sqlFeatures bool = false - rememberMe bool = false - multiConnect bool = false + kickOnLogin bool + sqlFeatures bool + rememberMe bool + multiConnect bool + maxUserConns uint8 deleteRoomOnLeave bool = true ) +type RoomRecoveryState struct { + T string // rType + P bool // private + O string // owner + M int // maxUsers + I []string // inviteList + V map[string]interface{} // vars +} + ////////////////////////////////////////////////////////////////////////////////////////////////////// // SERVER STARTUP FUNCTIONS ////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -47,13 +57,14 @@ func SetServerStarted(val bool) { } // SettingsSet is for Gopher Game Server internal mechanics only. -func SettingsSet(kickDups bool, name string, deleteOnLeave bool, sqlFeat bool, remMe bool, multiConn bool) { +func SettingsSet(kickDups bool, name string, deleteOnLeave bool, sqlFeat bool, remMe bool, multiConn bool, maxConns uint8) { if !serverStarted { kickOnLogin = kickDups serverName = name sqlFeatures = sqlFeat rememberMe = remMe multiConnect = multiConn + maxUserConns = maxConns deleteRoomOnLeave = deleteOnLeave } } @@ -106,22 +117,22 @@ func Resume() { } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// GET STATE FOR RECOVERY ///////////////////////////////////////////////////////////////////////////////////// +// GET STATES FOR GENERATING RECOVERY FILE //////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // GetState is only for internal Gopher Game Server mechanics. -func GetState() map[string]map[string]interface{} { - state := make(map[string]map[string]interface{}) +func GetRoomsState() map[string]RoomRecoveryState { + state := make(map[string]RoomRecoveryState) roomsMux.Lock() for _, room := range rooms { room.mux.Lock() - state[room.name] = map[string]interface{}{ - "t": room.rType, - "p": room.private, - "o": room.owner, - "m": room.maxUsers, - "i": room.inviteList, - "v": room.vars, + state[room.name] = RoomRecoveryState{ + T: room.rType, + P: room.private, + O: room.owner, + M: room.maxUsers, + I: room.inviteList, + V: room.vars, } room.mux.Unlock() } diff --git a/core/rooms.go b/core/rooms.go index 3d97795..a5f69b6 100644 --- a/core/rooms.go +++ b/core/rooms.go @@ -288,7 +288,7 @@ func (r *Room) RemoveUser(user *User, connID string) error { userName := user.Name() //REJECT INCORRECT INPUT if user == nil || len(userName) == 0 { - return errors.New("*Room.RemoveUser() requires a valid user") + return errors.New("*Room.RemoveUser() requires a valid *User") } else if multiConnect && len(connID) == 0 { return errors.New("Must provide a connID when MultiConnect is enabled") } else if !multiConnect { @@ -300,19 +300,21 @@ func (r *Room) RemoveUser(user *User, connID string) error { r.mux.Unlock() return errors.New("The room '" + r.name + "' does not exist") } - if _, ok := r.usersMap[userName]; !ok { + var ok bool + var ru *RoomUser + if ru, ok = r.usersMap[userName]; !ok { r.mux.Unlock() return errors.New("User '" + userName + "' is not in room '" + r.name + "'") } - ru := r.usersMap[userName] ru.mux.Lock() - if _, ok := ru.conns[connID]; !ok { + var uConn *userConn + if uConn, ok = ru.conns[connID]; !ok { r.mux.Unlock() ru.mux.Unlock() return errors.New("Invalid connID") } - uConn := ru.conns[connID] delete(ru.conns, connID) + // Remove user when no conns are left in room if len(ru.conns) == 0 { delete(r.usersMap, userName) } diff --git a/core/users.go b/core/users.go index de57b2e..ed3ecc1 100644 --- a/core/users.go +++ b/core/users.go @@ -115,7 +115,7 @@ func Login(userName string, dbID int, autologPass string, isGuest bool, remMe bo if userOnline, ok := users[userName]; ok { userExists = true if kickOnLogin { - //REMOVE USER FROM THEIR CURRENT ROOM IF ANY + // KICK USER AND REMOVE FROM THEIR CURRENT ROOM IF ANY userOnline.mux.Lock() for connKey, conn := range userOnline.conns { userRoom := (*conn).room diff --git a/docs/index.html b/docs/index.html index a7d37b5..cded8e9 100644 --- a/docs/index.html +++ b/docs/index.html @@ -45,8 +45,8 @@
    diff --git a/helpers/saveState.go b/helpers/saveState.go deleted file mode 100644 index a00cb21..0000000 --- a/helpers/saveState.go +++ /dev/null @@ -1,23 +0,0 @@ -package helpers - -import ( - "encoding/json" - "io/ioutil" - "time" -) - -// SaveState is only for internal Gopher Server mechanics. -func SaveState(stateObj map[string]interface{}, saveFolder string) error { - //WRITE THE STATE - state, err := json.Marshal(stateObj) - if err != nil { - return err - } - err = ioutil.WriteFile(saveFolder+"/Gopher Recovery - "+time.Now().Format("2006-01-02 15-04-05")+".grf", state, 0644) - if err != nil { - return err - } - - // - return nil -} diff --git a/server.go b/server.go index f983b4f..4a65c98 100644 --- a/server.go +++ b/server.go @@ -11,11 +11,11 @@ import ( "github.com/hewiefreeman/GopherGameServer/actions" "github.com/hewiefreeman/GopherGameServer/core" "github.com/hewiefreeman/GopherGameServer/database" - "github.com/hewiefreeman/GopherGameServer/helpers" "io/ioutil" "net/http" "os" "strconv" + "time" ) /////////// TO DOs: @@ -42,8 +42,9 @@ type ServerSettings struct { OriginOnly bool // When enabled, the server declines connections made from outside the origin server (Admin logins always check origin). IMPORTANT: Enable this for web apps and LAN servers. - MultiConnect bool // Enables multiple connections under the same User. When enabled, will override KickDupOnLogin's functionality. - KickDupOnLogin bool // When enabled, a logged in User will be disconnected from service when another User logs in with the same name. + MultiConnect bool // Enables multiple connections under the same User. When enabled, will override KickDupOnLogin's functionality. + MaxUserConns uint8 // Overrides the default (255) of maximum simultaneous connections on a single User + KickDupOnLogin bool // When enabled, a logged in User will be disconnected from service when another User logs in with the same name. UserRoomControl bool // Enables Users to create Rooms, invite/uninvite(AKA revoke) other Users to their owned private rooms, and destroy their owned rooms. RoomDeleteOnLeave bool // When enabled, Rooms created by a User will be deleted when the owner leaves. WARNING: If disabled, you must remember to at some point delete the rooms created by Users, or they will pile up endlessly! @@ -66,6 +67,10 @@ type ServerSettings struct { AdminPassword string // The password for the Admin Tools (Required for Admin Tools) } +type serverRestore struct { + R map[string]core.RoomRecoveryState +} + var ( httpServer *http.Server @@ -83,7 +88,7 @@ var ( clientConnectCallback func(*http.ResponseWriter, *http.Request) bool //SERVER VERSION NUMBER - version string = "1.0-BETA.1" + version string = "1.0-BETA.2" ) ////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -102,7 +107,7 @@ func Start(s *ServerSettings) { return } serverStarted = true - fmt.Println(" _______ __\n | _ |.-----..-----.| |--..-----..----.\n |. |___||. _ ||. _ ||. ||. -__||. _|\n |. | ||:. . ||:. __||: |: ||: ||: |\n |: | |'-----'|: | '--'--''-----''--'\n |::.. . | '--' - Game Server -\n '-------'\n\n") + fmt.Println(" _______ __\n | _ |.-----..-----.| |--..-----..----.\n |. |___||. _ ||. _ ||. ||. -__||. _|\n |. | ||:. . ||:. __||: |: ||: ||: |\n |: | |'-----'|: | '--'--''-----''--'\n |::.. . | '--' - Game Server -\n '-------'\n\n ") fmt.Println("Starting server...") //SET SERVER SETTINGS if s != nil { @@ -191,7 +196,7 @@ func Start(s *ServerSettings) { //UPDATE SETTINGS IN users PACKAGE, THEN users WILL UPDATE SETTINGS FOR rooms PACKAGE core.SettingsSet((*settings).KickDupOnLogin, (*settings).ServerName, (*settings).RoomDeleteOnLeave, (*settings).EnableSqlFeatures, - (*settings).RememberMe, (*settings).MultiConnect) + (*settings).RememberMe, (*settings).MultiConnect, (*settings).MaxUserConns) //NOTIFY PACKAGES OF SERVER START core.SetServerStarted(true) @@ -363,7 +368,7 @@ func ShutDown() error { func saveState() { fmt.Println("Saving server state...") - saveErr := helpers.SaveState(getState(), settings.RecoveryLocation) + saveErr := writeState(getState(), settings.RecoveryLocation) if saveErr != nil { fmt.Println("Error saving state:", saveErr) return @@ -371,9 +376,24 @@ func saveState() { fmt.Println("Save state successful") } -func getState() map[string]interface{} { - return map[string]interface{}{ - "rooms": core.GetState(), +func writeState(stateObj serverRestore, saveFolder string) error { + //WRITE THE STATE + state, err := json.Marshal(stateObj) + if err != nil { + return err + } + err = ioutil.WriteFile(saveFolder+"/Gopher Recovery - "+time.Now().Format("2006-01-02 15-04-05")+".grf", state, 0644) + if err != nil { + return err + } + + // + return nil +} + +func getState() serverRestore { + return serverRestore{ + R: core.GetRoomsState(), } } @@ -412,67 +432,31 @@ func recoverState() { } //CONVERT JSON TO MAP - var recovery map[string]interface{} + var recovery serverRestore if err = json.Unmarshal(r, &recovery); err != nil { fmt.Println("Error recovering state:", err) return } + if recovery.R == nil || len(recovery.R) == 0 { + fmt.Println("No rooms to restore!") + return + } + //RECOVER ROOMS - var roomsMap map[string]interface{} - var ok bool - if roomsMap, ok = recovery["rooms"].(map[string]interface{}); ok { - for name, val := range roomsMap { - var m map[string]interface{} - if m, ok = val.(map[string]interface{}); !ok { - fmt.Println("Error recovering room '" + name + "': Incorrect room format") - continue - } - var rType string - var isPrivate bool - var maxUsers float64 - var inviteList []interface{} - var owner string - if rType, ok = m["t"].(string); !ok { - fmt.Println("Error recovering room '" + name + "': Incorrect room type format") - continue - } - if isPrivate, ok = m["p"].(bool); !ok { - fmt.Println("Error recovering room '" + name + "': Incorrect private format") - continue - } - if maxUsers, ok = m["m"].(float64); !ok { - fmt.Println("Error recovering room '" + name + "': Incorrect maximum users format") - continue - } - if inviteList, ok = m["i"].([]interface{}); !ok { - fmt.Println("Error recovering room '" + name + "': Incorrect invite list format") - continue - } - if owner, ok = m["o"].(string); !ok { - fmt.Println("Error recovering room '" + name + "': Incorrect owner format") - continue - } - room, roomErr := core.NewRoom(name, rType, isPrivate, int(maxUsers), owner) - if roomErr != nil { - fmt.Println("Error recovering room '"+name+"':", roomErr) - continue - } - for i := 0; i < len(inviteList); i++ { - var userName string - if userName, ok = inviteList[i].(string); !ok { - fmt.Println("Error recovering room '" + name + "': Incorrect user name format in invite list") - continue - } - invErr := room.AddInvite(userName) - if invErr != nil { - fmt.Println("Error inviting '"+userName+"' to the room '"+name+"':", invErr) - } + for name, val := range recovery.R { + room, roomErr := core.NewRoom(name, val.T, val.P, val.M, val.O) + if roomErr != nil { + fmt.Println("Error recovering room '"+name+"':", roomErr) + continue + } + for _, userName := range val.I { + invErr := room.AddInvite(userName) + if invErr != nil { + fmt.Println("Error inviting '"+userName+"' to the room '"+name+"':", invErr) } } - } else { - fmt.Println("Error recovering state: Error interpreting JSON in recovery file") - return + room.SetVariables(val.V) } // diff --git a/sockets.go b/sockets.go index 3993967..3626edc 100644 --- a/sockets.go +++ b/sockets.go @@ -79,9 +79,7 @@ func clientActionListener(conn *websocket.Conn) { } writeErr := conn.WriteJSON(tagMessage) if writeErr != nil { - conn.WriteControl(websocket.CloseMessage, []byte{}, time.Now().Add(time.Second*1)) - conn.Close() - conns.subtract() + closeSocket(conn) return } //PARAMS @@ -94,9 +92,7 @@ func clientActionListener(conn *websocket.Conn) { //READ INPUT BUFFER readErr := conn.ReadJSON(&action) if readErr != nil || action.A == "" { - conn.WriteControl(websocket.CloseMessage, []byte{}, time.Now().Add(time.Second*1)) - conn.Close() - conns.subtract() + closeSocket(conn) return } @@ -105,9 +101,7 @@ func clientActionListener(conn *websocket.Conn) { //NO DEVICE TAG. MAKE ONE AND SEND IT. newDeviceTag, newDeviceTagErr := helpers.GenerateSecureString(32) if newDeviceTagErr != nil { - conn.WriteControl(websocket.CloseMessage, []byte{}, time.Now().Add(time.Second*1)) - conn.Close() - conns.subtract() + closeSocket(conn) return } deviceTag = string(newDeviceTag) @@ -116,9 +110,7 @@ func clientActionListener(conn *websocket.Conn) { } writeErr := conn.WriteJSON(tagMessage) if writeErr != nil { - conn.WriteControl(websocket.CloseMessage, []byte{}, time.Now().Add(time.Second*1)) - conn.Close() - conns.subtract() + closeSocket(conn) return } } else if action.A == "1" { @@ -126,9 +118,7 @@ func clientActionListener(conn *websocket.Conn) { if sentDeviceTag, ohK := action.P.(string); ohK { if len(deviceTag) > 0 && sentDeviceTag != deviceTag { //CLIENT DIDN'T USE THE PROVIDED DEVICE CODE FROM THE SERVER - conn.WriteControl(websocket.CloseMessage, []byte{}, time.Now().Add(time.Second*1)) - conn.Close() - conns.subtract() + closeSocket(conn) return } //SEND AUTO-LOG NOT FILED MESSAGE @@ -137,15 +127,11 @@ func clientActionListener(conn *websocket.Conn) { } writeErr := conn.WriteJSON(notFiledMessage) if writeErr != nil { - conn.WriteControl(websocket.CloseMessage, []byte{}, time.Now().Add(time.Second*1)) - conn.Close() - conns.subtract() + closeSocket(conn) return } } else { - conn.WriteControl(websocket.CloseMessage, []byte{}, time.Now().Add(time.Second*1)) - conn.Close() - conns.subtract() + closeSocket(conn) return } @@ -157,43 +143,31 @@ func clientActionListener(conn *websocket.Conn) { var pMap map[string]interface{} devicePass, err = helpers.GenerateSecureString(32) if err != nil { - conn.WriteControl(websocket.CloseMessage, []byte{}, time.Now().Add(time.Second*1)) - conn.Close() - conns.subtract() + closeSocket(conn) return } //GET PARAMS if pMap, ok = action.P.(map[string]interface{}); !ok { - conn.WriteControl(websocket.CloseMessage, []byte{}, time.Now().Add(time.Second*1)) - conn.Close() - conns.subtract() + closeSocket(conn) return } if deviceTag, ok = pMap["dt"].(string); !ok { - conn.WriteControl(websocket.CloseMessage, []byte{}, time.Now().Add(time.Second*1)) - conn.Close() - conns.subtract() + closeSocket(conn) return } if oldPass, ok = pMap["da"].(string); !ok { - conn.WriteControl(websocket.CloseMessage, []byte{}, time.Now().Add(time.Second*1)) - conn.Close() - conns.subtract() + closeSocket(conn) return } var deviceUserIDStr string if deviceUserIDStr, ok = pMap["di"].(string); !ok { - conn.WriteControl(websocket.CloseMessage, []byte{}, time.Now().Add(time.Second*1)) - conn.Close() - conns.subtract() + closeSocket(conn) return } //CONVERT di TO INT deviceUserID, err = strconv.Atoi(deviceUserIDStr) if err != nil { - conn.WriteControl(websocket.CloseMessage, []byte{}, time.Now().Add(time.Second*1)) - conn.Close() - conns.subtract() + closeSocket(conn) return } //CHANGE THE CLIENT'S PASS @@ -202,17 +176,13 @@ func clientActionListener(conn *websocket.Conn) { } writeErr := conn.WriteJSON(newPassMessage) if writeErr != nil { - conn.WriteControl(websocket.CloseMessage, []byte{}, time.Now().Add(time.Second*1)) - conn.Close() - conns.subtract() + closeSocket(conn) return } } else if action.A == "3" { if deviceTag == "" || oldPass == "" || deviceUserID == 0 || devicePass == "" { //IRRESPONSIBLE USAGE - conn.WriteControl(websocket.CloseMessage, []byte{}, time.Now().Add(time.Second*1)) - conn.Close() - conns.subtract() + closeSocket(conn) return } //AUTO-LOG THE CLIENT @@ -221,9 +191,7 @@ func clientActionListener(conn *websocket.Conn) { //ERROR AUTO-LOGGING - RUN AUTOLOGCOMPLETE AND DELETE KEYS FOR CLIENT, AND SILENTLY CHANGE DEVICE TAG newTag, newTagErr := helpers.GenerateSecureString(32) if newTagErr != nil { - conn.WriteControl(websocket.CloseMessage, []byte{}, time.Now().Add(time.Second*1)) - conn.Close() - conns.subtract() + closeSocket(conn) return } autologMessage := map[string]map[string]interface{}{ @@ -237,9 +205,7 @@ func clientActionListener(conn *websocket.Conn) { } writeErr := conn.WriteJSON(autologMessage) if writeErr != nil { - conn.WriteControl(websocket.CloseMessage, []byte{}, time.Now().Add(time.Second*1)) - conn.Close() - conns.subtract() + closeSocket(conn) return } devicePass = "" @@ -262,8 +228,7 @@ func clientActionListener(conn *websocket.Conn) { //DISCONNECT USER clientMux.Lock() sockedDropped(user, connID, &clientMux) - conn.WriteControl(websocket.CloseMessage, []byte{}, time.Now().Add(time.Second*1)) - conn.Close() + closeSocket(conn) return } @@ -276,8 +241,7 @@ func clientActionListener(conn *websocket.Conn) { //DISCONNECT USER clientMux.Lock() sockedDropped(user, connID, &clientMux) - conn.WriteControl(websocket.CloseMessage, []byte{}, time.Now().Add(time.Second*1)) - conn.Close() + closeSocket(conn) return } } @@ -287,14 +251,18 @@ func clientActionListener(conn *websocket.Conn) { } } +func closeSocket(conn *websocket.Conn) { + conn.WriteControl(websocket.CloseMessage, []byte{}, time.Now().Add(time.Second*1)) + conn.Close() + conns.subtract() +} + func sockedDropped(user *core.User, connID string, clientMux *sync.Mutex) { if user != nil { //CLIENT WAS LOGGED IN. LOG THEM OUT (*clientMux).Unlock() user.Logout(connID) } - conns.subtract() - } /////////////////////// HELPERS FOR connections From 3d2c27203d95803182968db8d56a30d9acc7c51e Mon Sep 17 00:00:00 2001 From: Dominique Debergue Date: Mon, 26 Aug 2019 16:35:17 -0700 Subject: [PATCH 110/132] Create CHANGE_LOG.md --- CHANGE_LOG.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 CHANGE_LOG.md diff --git a/CHANGE_LOG.md b/CHANGE_LOG.md new file mode 100644 index 0000000..6610fda --- /dev/null +++ b/CHANGE_LOG.md @@ -0,0 +1,22 @@ +# Change Log +This is where all important changes and bug fixes will be described in detail. Each entry is labeled with a patch version number, and that is the version in which the changes and/or fixes were made. All prior versions will lack the described changes and/or fixes described. + +> If you are experiencing any bugs or errors because of an update, please report them by [opening an issue](https://github.com/hewiefreeman/GopherGameServer/issues/new/choose)! + +### Key + :wrench: : Bug fix + + :warning: : Code-breaking change + + :newspaper: : New feature + + :monorail: : Optimization +

    +## v1.0-BETA.2 + - :newspaper: Added a `version` macro to display current running server version + - :monorail: :warning: ([commit](https://github.com/hewiefreeman/GopherGameServer/commit/941c558bfe44f237f150918187785cceb8aafecd)) Restoring logic has been simplified, but any previous version restore files will fail to restore! + +## v1.0-ALPHA.5 + - :monorail: :warning: ([commit](https://github.com/hewiefreeman/GopherGameServer/commit/a5edd57bcc61fc6f5d10b194f4a433e7a5ed51da)) Merged the `rooms` and `users` packages into one `core` package. **Requires refactoring your server code)** + +> Version **1.0-ALPHA.5** merged the packages `users` and `rooms` into a single package `core`. If you've updated your server from **1.0-ALPHA.4** or below, you will need to edit your code and replace any instance of `rooms` or `users` with `core`. This also changes how [Rooms](https://github.com/hewiefreeman/GopherGameServer/wiki/Rooms#blue_book-creating--deleting-rooms) are **created** and **retrieved** ([core.GetRoom](https://godoc.org/github.com/hewiefreeman/GopherGameServer/core#GetRoom)), and how [Users](https://godoc.org/github.com/hewiefreeman/GopherGameServer/core#GetUser) are **retrieved**. From e0da9f8265d6ecbb18b567fac44aa21bfafecc39 Mon Sep 17 00:00:00 2001 From: Dominique Debergue Date: Mon, 26 Aug 2019 16:36:44 -0700 Subject: [PATCH 111/132] Update README.md --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 83e7c44..3ef1128 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,9 @@ Moreover, Gopher has a built-in, fully customizable SQL client authentication me - GUI for administrating and monitoring servers - Integration with [GopherDB](https://github.com/hewiefreeman/GopherDB) when stable +### Change Log +[CHANGE_LOG.md](https://github.com/hewiefreeman/GopherGameServer/blob/master/CHANGE_LOG.md) + # :video_game: Client APIs - JavaScript: [GopherClientJS](https://github.com/hewiefreeman/GopherClientJS) From e12d808412b116163e3499bf9198dbff82153d74 Mon Sep 17 00:00:00 2001 From: Dominique Debergue Date: Mon, 26 Aug 2019 16:37:47 -0700 Subject: [PATCH 112/132] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3ef1128..21baea0 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ Moreover, Gopher has a built-in, fully customizable SQL client authentication me ### Change Log [CHANGE_LOG.md](https://github.com/hewiefreeman/GopherGameServer/blob/master/CHANGE_LOG.md) - +


    # :video_game: Client APIs - JavaScript: [GopherClientJS](https://github.com/hewiefreeman/GopherClientJS) From a26b8ba0c518aa366d981b51d4a640d3c7e717cf Mon Sep 17 00:00:00 2001 From: hewiefreeman Date: Fri, 13 Sep 2019 15:36:38 -0700 Subject: [PATCH 113/132] Added messaging callbacks --- core/messaging.go | 68 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/core/messaging.go b/core/messaging.go index 992a9ce..3f6ffd1 100644 --- a/core/messaging.go +++ b/core/messaging.go @@ -19,6 +19,15 @@ const ( ServerMessageImportant ) +var ( + privateMessageCallback func(*User, *User, interface{}) + privateMessageCallbackSet bool + chatMessageCallback func(string, *Room, interface{}) + chatMessageCallbackSet bool + serverMessageCallback func(*Room, int, interface{}) + serverMessageCallbackSet bool +) + ////////////////////////////////////////////////////////////////////////////////////////////////////// // Messaging Users /////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -51,6 +60,10 @@ func (u *User) PrivateMessage(userName string, message interface{}) { } u.mux.Unlock() + if privateMessageCallbackSet { + privateMessageCallback(u, user, message) + } + return } @@ -86,6 +99,10 @@ func (r *Room) ServerMessage(message interface{}, messageType int, recipients [] return errors.New("*Room.ServerMessage() requires a message") } + if serverMessageCallbackSet { + serverMessageCallback(r, messageType, message) + } + return r.sendMessage(MessageTypeServer, messageType, recipients, "", message) } @@ -98,6 +115,10 @@ func (r *Room) ChatMessage(author string, message interface{}) error { return errors.New("*Room.ChatMessage() requires a message") } + if chatMessageCallbackSet { + chatMessageCallback(author, r, message) + } + return r.sendMessage(MessageTypeChat, 0, nil, author, message) } @@ -227,3 +248,50 @@ func (r *Room) VoiceStream(userName string, userSocket *websocket.Conn, stream i // return } + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Callback Setters /////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +// SetPrivateMessageCallback sets the callback function for when a *User sends a private message to another *User. +// The function passed must have the same parameter types as the following example: +// +// func onPrivateMessage(from *core.User, to *core.User, message interface{}) { +// //code... +// } +func SetPrivateMessageCallback(cb func(*User, *User, interface{})) { + if !serverStarted { + privateMessageCallback = cb + privateMessageCallbackSet = true + } + +} + +// SetChatMessageCallback sets the callback function for when a *User sends a chat message to a *Room. +// The function passed must have the same parameter types as the following example: +// +// func onChatMessage(userName string, room *core.Room, message interface{}) { +// //code... +// } +func SetChatMessageCallback(cb func(string, *Room, interface{})) { + if !serverStarted { + chatMessageCallback = cb + chatMessageCallbackSet = true + } +} + +// SetServerMessageCallback sets the callback function for when the server sends a message to a *Room. +// The function passed must have the same parameter types as the following example: +// +// func onServerMessage(room *core.Room, messageType int, message interface{}) { +// //code... +// } +// +// The messageType value can be one of: core.ServerMessageGame, core.ServerMessageNotice, +// core.ServerMessageImportant, or a custom value you have set. +func SetServerMessageCallback(cb func(*Room, int, interface{})) { + if !serverStarted { + serverMessageCallback = cb + serverMessageCallbackSet = true + } +} \ No newline at end of file From f4aab21cd54216e37f10cb0f58f08603cf223ede Mon Sep 17 00:00:00 2001 From: hewiefreeman Date: Fri, 13 Sep 2019 15:45:17 -0700 Subject: [PATCH 114/132] Go lint and fmt --- core/core.go | 13 +++++++------ core/messaging.go | 12 ++++++------ startandstop_test.go | 4 ++-- 3 files changed, 15 insertions(+), 14 deletions(-) diff --git a/core/core.go b/core/core.go index ac99e75..8b6210f 100644 --- a/core/core.go +++ b/core/core.go @@ -36,12 +36,13 @@ var ( deleteRoomOnLeave bool = true ) +// RoomRecoveryState is used internally for persisting room states on shutdown. type RoomRecoveryState struct { - T string // rType - P bool // private - O string // owner - M int // maxUsers - I []string // inviteList + T string // rType + P bool // private + O string // owner + M int // maxUsers + I []string // inviteList V map[string]interface{} // vars } @@ -120,7 +121,7 @@ func Resume() { // GET STATES FOR GENERATING RECOVERY FILE //////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// GetState is only for internal Gopher Game Server mechanics. +// GetRoomsState is only for internal Gopher Game Server mechanics. func GetRoomsState() map[string]RoomRecoveryState { state := make(map[string]RoomRecoveryState) roomsMux.Lock() diff --git a/core/messaging.go b/core/messaging.go index 3f6ffd1..102d09e 100644 --- a/core/messaging.go +++ b/core/messaging.go @@ -20,12 +20,12 @@ const ( ) var ( - privateMessageCallback func(*User, *User, interface{}) + privateMessageCallback func(*User, *User, interface{}) privateMessageCallbackSet bool - chatMessageCallback func(string, *Room, interface{}) - chatMessageCallbackSet bool - serverMessageCallback func(*Room, int, interface{}) - serverMessageCallbackSet bool + chatMessageCallback func(string, *Room, interface{}) + chatMessageCallbackSet bool + serverMessageCallback func(*Room, int, interface{}) + serverMessageCallbackSet bool ) ////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -294,4 +294,4 @@ func SetServerMessageCallback(cb func(*Room, int, interface{})) { serverMessageCallback = cb serverMessageCallbackSet = true } -} \ No newline at end of file +} diff --git a/startandstop_test.go b/startandstop_test.go index e1c9fbc..f79089a 100644 --- a/startandstop_test.go +++ b/startandstop_test.go @@ -7,8 +7,8 @@ import ( func TestStartAndStop(t *testing.T) { go Start(nil) - time.Sleep(time.Second*2) + time.Sleep(time.Second * 2) if sdErr := ShutDown(); sdErr != nil { t.Errorf(sdErr.Error()) } -} \ No newline at end of file +} From 446d398a065ca24e37a6beceefbd06a1e70b6d25 Mon Sep 17 00:00:00 2001 From: hewiefreeman Date: Sat, 21 Sep 2019 14:04:03 -0700 Subject: [PATCH 115/132] Refactoring and gocyclo/lint cleanup --- clientActions.go | 153 ++++++++++++++-------------- database/setup.go | 246 ++++++++++++++++++++++++---------------------- server.go | 90 +++++++++-------- 3 files changed, 257 insertions(+), 232 deletions(-) diff --git a/clientActions.go b/clientActions.go index 9624db5..ee3774c 100644 --- a/clientActions.go +++ b/clientActions.go @@ -37,40 +37,40 @@ func clientActionHandler(action clientAction, user **core.User, conn *websocket. deviceTag *string, devicePass *string, deviceUserID *int, connID *string, clientMux *sync.Mutex) (interface{}, bool, helpers.GopherError) { switch action.A { - // HIGH LOOK-UP PRIORITY ITEMS + // Custom actions and voice streams case helpers.ClientActionCustomAction: return clientCustomAction(action.P, user, conn, *connID, clientMux) case helpers.ClientActionVoiceStream: return clientActionVoiceStream(action.P, user, conn, *connID, clientMux) - // USER VARIABLES + // User variables case helpers.ClientActionSetVariable: return clientActionSetVariable(action.P, user, *connID, clientMux) case helpers.ClientActionSetVariables: return clientActionSetVariables(action.P, user, *connID, clientMux) - // CHAT + // Chat case helpers.ClientActionChatMessage: return clientActionChatMessage(action.P, user, *connID, clientMux) case helpers.ClientActionPrivateMessage: return clientActionPrivateMessage(action.P, user, *connID, clientMux) - // CHANGE STATUS + // Change user status case helpers.ClientActionChangeStatus: return clientActionChangeStatus(action.P, user, clientMux) - // LOGIN/LOGOUT + // Log in/out case helpers.ClientActionLogin: return clientActionLogin(action.P, user, deviceTag, devicePass, deviceUserID, conn, connID, clientMux) case helpers.ClientActionLogout: return clientActionLogout(user, deviceTag, devicePass, deviceUserID, connID, clientMux) - // ROOM ACTIONS + // Room actions case helpers.ClientActionJoinRoom: return clientActionJoinRoom(action.P, user, *connID, clientMux) @@ -85,7 +85,7 @@ func clientActionHandler(action clientAction, user **core.User, conn *websocket. case helpers.ClientActionRevokeInvite: return clientActionRevokeInvite(action.P, user, *connID, clientMux) - // FRIENDING + // Friending case helpers.ClientActionFriendRequest: return clientActionFriendRequest(action.P, user, clientMux) @@ -96,7 +96,7 @@ func clientActionHandler(action clientAction, user **core.User, conn *websocket. case helpers.ClientActionRemoveFriend: return clientActionRemoveFriend(action.P, user, clientMux) - // DATABASE + // Database case helpers.ClientActionSignup: return clientActionSignup(action.P, user, clientMux) @@ -107,7 +107,7 @@ func clientActionHandler(action clientAction, user **core.User, conn *websocket. case helpers.ClientActionChangeAccountInfo: return clientActionChangeAccountInfo(action.P, user, clientMux) - // INVALID CLIENT ACTION + // Invalid client action default: return nil, true, helpers.NewError(errorInvalidAction, helpers.ErrorGopherInvalidAction) @@ -147,7 +147,7 @@ func clientActionChangeStatus(params interface{}, user **core.User, clientMux *s } userRef := *user (*clientMux).Unlock() - //GET PARAMS + // Get param map and extract values var ok bool var statusF float64 if statusF, ok = params.(float64); !ok { @@ -174,7 +174,7 @@ func clientActionSignup(params interface{}, user **core.User, clientMux *sync.Mu return nil, true, helpers.NewError(errorFeatureDisabled, helpers.ErrorGopherFeatureDisabled) } (*clientMux).Unlock() - //GET ITEMS FROM PARAMS + // Get param map and extract values var ok bool var pMap map[string]interface{} var customCols map[string]interface{} @@ -194,7 +194,7 @@ func clientActionSignup(params interface{}, user **core.User, clientMux *sync.Mu if pass, ok = pMap["p"].(string); !ok { return nil, true, helpers.NewError(errorIncorrectFormatPass, helpers.ErrorGopherPasswordFormat) } - //SIGN CLIENT UP + // Sign client up signupErr := database.SignUpClient(userName, pass, customCols) if signupErr.ID != 0 { return nil, true, signupErr @@ -214,7 +214,7 @@ func clientActionDeleteAccount(params interface{}, user **core.User, clientMux * return nil, true, helpers.NewError(errorFeatureDisabled, helpers.ErrorGopherFeatureDisabled) } (*clientMux).Unlock() - //GET ITEMS FROM PARAMS + // Get param map and extract values var ok bool var pMap map[string]interface{} var customCols map[string]interface{} @@ -235,13 +235,13 @@ func clientActionDeleteAccount(params interface{}, user **core.User, clientMux * return nil, true, helpers.NewError(errorIncorrectFormatPass, helpers.ErrorGopherPasswordFormat) } - //CHECK IF USER IS ONLINE + // Check if online _, err := core.GetUser(userName) if err == nil { return nil, true, helpers.NewError(err.Error(), helpers.ErrorGopherLoggedIn) } - //DELETE ACCOUNT + // Delete account deleteErr := database.DeleteAccount(userName, pass, customCols) if deleteErr.ID != 0 { return nil, true, deleteErr @@ -261,7 +261,7 @@ func clientActionChangePassword(params interface{}, user **core.User, clientMux } userRef := *user (*clientMux).Unlock() - //GET ITEMS FROM PARAMS + // Get param map and extract values var ok bool var pMap map[string]interface{} var customCols map[string]interface{} @@ -281,7 +281,7 @@ func clientActionChangePassword(params interface{}, user **core.User, clientMux if newPass, ok = pMap["n"].(string); !ok { return nil, true, helpers.NewError(errorIncorrectFormatNewPass, helpers.ErrorGopherNewPasswordFormat) } - //CHANGE PASSWORD + // Change password changeErr := database.ChangePassword(userRef.Name(), pass, newPass, customCols) if changeErr.ID != 0 { return nil, true, changeErr @@ -302,7 +302,7 @@ func clientActionChangeAccountInfo(params interface{}, user **core.User, clientM } userRef := *user (*clientMux).Unlock() - //GET ITEMS FROM PARAMS + // Get param map and extract values var ok bool var pMap map[string]interface{} var customCols map[string]interface{} @@ -318,7 +318,7 @@ func clientActionChangeAccountInfo(params interface{}, user **core.User, clientM if pass, ok = pMap["p"].(string); !ok { return nil, true, helpers.NewError(errorIncorrectFormatPass, helpers.ErrorGopherPasswordFormat) } - //CHANGE ACCOUNT INFO + // Change account info changeErr := database.ChangeAccountInfo(userRef.Name(), pass, customCols) if changeErr.ID != 0 { return nil, true, changeErr @@ -340,7 +340,7 @@ func clientActionLogin(params interface{}, user **core.User, deviceTag *string, return nil, true, helpers.NewError(errorLoggedIn, helpers.ErrorGopherLoggedIn) } (*clientMux).Unlock() - //MAKE A MAP FROM PARAMS + // Get param map and extract values var ok bool var pMap map[string]interface{} var name string @@ -354,11 +354,11 @@ func clientActionLogin(params interface{}, user **core.User, deviceTag *string, if name, ok = pMap["n"].(string); !ok { return nil, true, helpers.NewError(errorIncorrectFormatName, helpers.ErrorGopherNameFormat) } - if (*settings).EnableSqlFeatures { + if settings.EnableSqlFeatures { if pass, ok = pMap["p"].(string); !ok { return nil, true, helpers.NewError(errorIncorrectFormatPass, helpers.ErrorGopherPasswordFormat) } - if (*settings).RememberMe { + if settings.RememberMe { if remMe, ok = pMap["r"].(bool); !ok { return nil, true, helpers.NewError(errorIncorrectFormatRemember, helpers.ErrorGopherRememberFormat) } @@ -374,31 +374,39 @@ func clientActionLogin(params interface{}, user **core.User, deviceTag *string, return nil, true, helpers.NewError(errorIncorrectFormatCols, helpers.ErrorGopherColumnsFormat) } } - //LOG IN + // Log socket in + if dbIndex, dPass, cID, lErr := loginClient(settings, guest, name, pass, *deviceTag, remMe, customCols, user, + conn, clientMux); lErr.ID != 0 { + return nil, false, lErr + } + + // Update socket + *devicePass = dPass + *deviceUserID = dbIndex + *connID = cID + + // + return nil, false, helpers.NoError() +} + +func loginClient(s *ServerSettings, guest bool, name string, pass string, deviceTag string, remMe bool, + customCols map[string]interface{}, user **core.User, conn *websocket.Conn, clientMux *sync.Mutex) (int, string, string, helpers.GopherError) { var dbIndex int - var uName string var dPass string var cID string var err helpers.GopherError - if (*settings).EnableSqlFeatures && !guest { - uName, dbIndex, dPass, err = database.LoginClient(name, pass, *deviceTag, remMe, customCols) + if s.EnableSqlFeatures && !guest { + var uName string + uName, dbIndex, dPass, err = database.LoginClient(name, pass, deviceTag, remMe, customCols) if err.ID != 0 { - return nil, true, err + return 0, "", "", err } cID, err = core.Login(uName, dbIndex, dPass, guest, remMe, conn, user, clientMux) } else { cID, err = core.Login(name, -1, "", guest, false, conn, user, clientMux) } - if err.ID != 0 { - return nil, true, err - } - //CHANGE SOCKET'S userName - *devicePass = dPass - *deviceUserID = dbIndex - *connID = cID - // - return nil, false, helpers.NoError() + return dbIndex, dPass, cID, err } func clientActionLogout(user **core.User, deviceTag *string, devicePass *string, deviceUserID *int, connID *string, clientMux *sync.Mutex) (interface{}, bool, helpers.GopherError) { @@ -409,13 +417,13 @@ func clientActionLogout(user **core.User, deviceTag *string, devicePass *string, } userRef := *user (*clientMux).Unlock() - //LOG User OUT AND RESET + // Log user out userRef.Logout(*connID) - //REMOVE AUTO-LOG IF ANY + // Remove any auto-logins for this device tag if (*settings).EnableSqlFeatures && (*settings).RememberMe { database.RemoveAutoLog(*deviceUserID, *deviceTag) } - // + // Update socket *devicePass = "" *deviceUserID = 0 *connID = "" @@ -436,18 +444,18 @@ func clientActionJoinRoom(params interface{}, user **core.User, connID string, c } userRef := *user (*clientMux).Unlock() - //GET ROOM NAME FROM PARAMS + // Get room name from params var ok bool var roomName string if roomName, ok = params.(string); !ok { return nil, true, helpers.NewError(errorIncorrectFormat, helpers.ErrorGopherIncorrectFormat) } - //GET ROOM + // Get room room, roomErr := core.GetRoom(roomName) if roomErr != nil { return nil, true, helpers.NewError(roomErr.Error(), helpers.ErrorGopherJoin) } - //MAKE User JOIN THE Room + // Make user join the room joinErr := userRef.Join(room, connID) if joinErr != nil { return nil, true, helpers.NewError(joinErr.Error(), helpers.ErrorGopherJoin) @@ -465,7 +473,7 @@ func clientActionLeaveRoom(user **core.User, connID string, clientMux *sync.Mute } userRef := *user (*clientMux).Unlock() - //MAKE USER LEAVE ROOM + // Make user leave room leaveErr := userRef.Leave(connID) if leaveErr != nil { return nil, true, helpers.NewError(leaveErr.Error(), helpers.ErrorGopherLeave) @@ -486,7 +494,7 @@ func clientActionCreateRoom(params interface{}, user **core.User, connID string, } userRef := *user (*clientMux).Unlock() - //GET PARAMS + // Get param map and extract values var ok bool var pMap map[string]interface{} var roomName string @@ -509,23 +517,18 @@ func clientActionCreateRoom(params interface{}, user **core.User, connID string, return nil, true, helpers.NewError(errorIncorrectFormatMaxRoomUsers, helpers.ErrorGopherMaxRoomFormat) } maxUsers := int(maxUsersF) - // + // Verify type if rType, ok := core.GetRoomTypes()[roomType]; !ok { return nil, true, helpers.NewError(errorRoomType, helpers.ErrorGopherMaxRoomFormat) } else if rType.ServerOnly() { return nil, true, helpers.NewError(errorServerRoom, helpers.ErrorGopherServerRoom) } - //CHECK IF USER IS IN A ROOM - /*currRoom := user.RoomIn() - if currRoom != nil && currRoom.Name() != "" { - return nil, true, errors.New("You must leave your current room to create a room") - }*/ - //MAKE THE Room + // Make the room room, roomErr := core.NewRoom(roomName, roomType, private, maxUsers, userRef.Name()) if roomErr != nil { return nil, true, helpers.NewError(roomErr.Error(), helpers.ErrorGopherCreateRoom) } - //ADD THE User TO THE ROOM + // Add user to the new room joinErr := userRef.Join(room, connID) if joinErr != nil { return nil, true, helpers.NewError(joinErr.Error(), helpers.ErrorGopherJoin) @@ -546,13 +549,13 @@ func clientActionDeleteRoom(params interface{}, user **core.User, clientMux *syn } userRef := *user (*clientMux).Unlock() - //GET PARAMS + // Get room name from params var ok bool var roomName string if roomName, ok = params.(string); !ok { return nil, true, helpers.NewError(errorIncorrectFormat, helpers.ErrorGopherIncorrectFormat) } - //GET ROOM + // Get room room, roomErr := core.GetRoom(roomName) if roomErr != nil { return nil, true, helpers.NewError(roomErr.Error(), helpers.ErrorGopherDeleteRoom) @@ -564,7 +567,7 @@ func clientActionDeleteRoom(params interface{}, user **core.User, clientMux *syn if rType.ServerOnly() { return nil, true, helpers.NewError(errorServerRoom, helpers.ErrorGopherServerRoom) } - //DELETE ROOM + // Delete the room deleteErr := room.Delete() if deleteErr != nil { return nil, true, helpers.NewError(deleteErr.Error(), helpers.ErrorGopherDeleteRoom) @@ -584,18 +587,18 @@ func clientActionRoomInvite(params interface{}, user **core.User, connID string, } userRef := *user (*clientMux).Unlock() - //GET PARAMS + // Get name from params var ok bool var name string if name, ok = params.(string); !ok { return nil, true, helpers.NewError(errorIncorrectFormat, helpers.ErrorGopherIncorrectFormat) } - //GET INVITED USER + // Get invited user invUser, invUserErr := core.GetUser(name) if invUserErr != nil { return nil, true, helpers.NewError(invUserErr.Error(), helpers.ErrorGopherInvite) } - //INVITE + // Invite user invUserErr = userRef.Invite(invUser, connID) if invUserErr != nil { return nil, true, helpers.NewError(invUserErr.Error(), helpers.ErrorGopherInvite) @@ -615,13 +618,13 @@ func clientActionRevokeInvite(params interface{}, user **core.User, connID strin } userRef := *user (*clientMux).Unlock() - //GET PARAMS + // Get name from params var ok bool var name string if name, ok = params.(string); !ok { return nil, true, helpers.NewError(errorIncorrectFormat, helpers.ErrorGopherIncorrectFormat) } - //REVOKE INVITE + // Revoke invite revokeErr := userRef.RevokeInvite(name, connID) if revokeErr != nil { return nil, true, helpers.NewError(revokeErr.Error(), helpers.ErrorGopherRevokeInvite) @@ -642,17 +645,17 @@ func clientActionVoiceStream(params interface{}, user **core.User, conn *websock } userRef := *user (*clientMux).Unlock() - //GET CURRENT ROOM + // Get current room currRoom := userRef.RoomIn(connID) if currRoom == nil || currRoom.Name() == "" { return nil, false, helpers.NoError() } - //CHECK IF VOICE CHAT ROOM + // Check for voice chat rType := core.GetRoomTypes()[currRoom.Type()] if !rType.VoiceChatEnabled() { return nil, false, helpers.NoError() } - //SEND VOICE STREAM + // Send voice stream currRoom.VoiceStream(userRef.Name(), conn, params) // return nil, false, helpers.NoError() @@ -666,12 +669,12 @@ func clientActionChatMessage(params interface{}, user **core.User, connID string } userRef := *user (*clientMux).Unlock() - //GET CURRENT ROOM + // Get current room currRoom := userRef.RoomIn(connID) if currRoom == nil || currRoom.Name() == "" { return nil, false, helpers.NoError() } - //SEND CHAT MESSAGE + // Send chat message currRoom.ChatMessage(userRef.Name(), params) // return nil, false, helpers.NoError() @@ -685,7 +688,7 @@ func clientActionPrivateMessage(params interface{}, user **core.User, connID str } userRef := *user (*clientMux).Unlock() - //GET PARAMS + // Get param map and extract values var ok bool var pMap map[string]interface{} var userName string @@ -695,12 +698,12 @@ func clientActionPrivateMessage(params interface{}, user **core.User, connID str if userName, ok = pMap["u"].(string); !ok { return nil, false, helpers.NoError() } - //GET CURRENT ROOM + // Get current room currRoom := userRef.RoomIn(connID) if currRoom == nil || currRoom.Name() == "" { return nil, false, helpers.NoError() } - //SEND CHAT MESSAGE + // Send chat message userRef.PrivateMessage(userName, pMap["m"]) // return nil, false, helpers.NoError() @@ -718,7 +721,7 @@ func clientActionSetVariable(params interface{}, user **core.User, connID string } userRef := *user (*clientMux).Unlock() - //GET PARAMS + // Get param map and extract values var ok bool var pMap map[string]interface{} var varKey string @@ -730,7 +733,7 @@ func clientActionSetVariable(params interface{}, user **core.User, connID string return nil, false, helpers.NoError() } varVal = pMap["v"] - //SET THE VARIABLE + // Set the variable userRef.SetVariable(varKey, varVal, connID) // return nil, false, helpers.NoError() @@ -744,7 +747,7 @@ func clientActionSetVariables(params interface{}, user **core.User, connID strin } userRef := *user (*clientMux).Unlock() - //GET PARAMS + // Get variables map from params var ok bool var pMap map[string]interface{} if pMap, ok = params.(map[string]interface{}); !ok { @@ -771,7 +774,7 @@ func clientActionFriendRequest(params interface{}, user **core.User, clientMux * } userRef := *user (*clientMux).Unlock() - //GET PARAMS AS A MAP + // Get name from params var ok bool var friendName string @@ -799,7 +802,7 @@ func clientActionAcceptFriend(params interface{}, user **core.User, clientMux *s } userRef := *user (*clientMux).Unlock() - //GET PARAMS AS A MAP + // Get name from params var ok bool var friendName string @@ -827,7 +830,7 @@ func clientActionDeclineFriend(params interface{}, user **core.User, clientMux * } userRef := *user (*clientMux).Unlock() - //GET PARAMS AS A MAP + // Get name from params var ok bool var friendName string @@ -855,7 +858,7 @@ func clientActionRemoveFriend(params interface{}, user **core.User, clientMux *s } userRef := *user (*clientMux).Unlock() - //GET PARAMS AS A MAP + // Get name from params var ok bool var friendName string diff --git a/database/setup.go b/database/setup.go index 4ebd0b3..1c7bf1f 100644 --- a/database/setup.go +++ b/database/setup.go @@ -5,119 +5,21 @@ import ( "strconv" ) -// CONFIGURES THE DATABASE FOR Gopher Game Server USAGE +// Configures the SQL database for Gopher Game Server func setUp() error { - //CHECK IF THE TABLE users HAS BEEN MADE + // Check if the users table has been created _, checkErr := database.Exec("SELECT " + usersColumnName + " FROM " + tableUsers + " WHERE " + usersColumnID + "=1;") if checkErr != nil { fmt.Println("Making all tables...") - //MAKE THE users TABLE QUERY - createQuery := "CREATE TABLE " + tableUsers + " (" + - usersColumnID + " INTEGER NOT NULL AUTO_INCREMENT, " + - usersColumnName + " VARCHAR(255) UNIQUE NOT NULL, " + - usersColumnPassword + " VARCHAR(255) NOT NULL, " - - //APPEND custom AccountInfoColumn ITEMS - for key, val := range customAccountInfo { - createQuery = createQuery + key + " " + dataTypes[val.dataType] - //CHECK IF NEEDS maxSize/precision - if isSizeDataType(val.dataType) { - createQuery = createQuery + "(" + strconv.Itoa(val.maxSize) + ")" - } else if isPrecisionDataType(val.dataType) { - createQuery = createQuery + "(" + strconv.Itoa(val.maxSize) + ", " + strconv.Itoa(val.precision) + ")" - } - //CHECK IF UNIQUE - if val.unique { - createQuery = createQuery + " UNIQUE" - } - //CHECK IF NOT NULL - if val.notNull { - createQuery = createQuery + " NOT NULL, " - } else { - createQuery = createQuery + ", " - } - } - - createQuery = createQuery + "PRIMARY KEY (" + usersColumnID + "));" - - //EXECUTE users TABLE QUERY - _, createErr := database.Exec(createQuery) - if createErr != nil { - return createErr - } - - //ADJUST AUTO_INCREMENT TO 1 - _, adjustErr := database.Exec("ALTER TABLE " + tableUsers + " AUTO_INCREMENT=1;") - if adjustErr != nil { - return adjustErr - } - - //MAKE THE friends TABLE - _, friendsErr := database.Exec("CREATE TABLE " + tableFriends + " (" + - friendsColumnUser + " INTEGER NOT NULL, " + - friendsColumnFriend + " INTEGER NOT NULL, " + - friendsColumnStatus + " INTEGER NOT NULL" + - ");") - if friendsErr != nil { - return friendsErr - } - - if rememberMe { - //MAKE THE autologs TABLE - _, friendsErr = database.Exec("CREATE TABLE " + tableAutologs + " (" + - autologsColumnID + " INTEGER NOT NULL, " + - autologsColumnDevicePass + " VARCHAR(255) NOT NULL, " + - autologsColumnDeviceTag + " VARCHAR(255) NOT NULL, " + - ");") - if friendsErr != nil { - return friendsErr - } + // Make the users table + if cErr := createUserTableSQL(); cErr != nil { + return cErr } } else { - //CHECK IF THERE ARE ANY NEW custom AccountInfoColumn ITEMS - query := "ALTER TABLE " + tableUsers + " " - var execQuery bool = false - // - for key, val := range customAccountInfo { - //CHECK IF COLUMN EXISTS - checkRows, err := database.Query("SHOW COLUMNS FROM " + tableUsers + " LIKE '" + key + "';") - if err != nil { - return err - } - // - checkRows.Next() - _, colsErr := checkRows.Columns() - if colsErr != nil { - fmt.Println("Adding AccountInfoColumn '" + key + "'...") - //THIS customAccountInfo COLUMN DOES NOT EXIST... YET, MY NERD. - query = query + "ADD COLUMN " + key + " " + dataTypes[val.dataType] - if isSizeDataType(val.dataType) { - query = query + "(" + strconv.Itoa(val.maxSize) + ")" - } else if isPrecisionDataType(val.dataType) { - query = query + "(" + strconv.Itoa(val.maxSize) + ", " + strconv.Itoa(val.precision) + ")" - } - //CHECK IF UNIQUE - if val.unique { - query = query + " UNIQUE" - } - //CHECK IF NOT NULL - if val.notNull { - query = query + " NOT NULL, " - } else { - query = query + ", " - } - execQuery = true - } - checkRows.Close() - } - if execQuery { - //MAKE THE NEW COLUMNS - query = query[0:len(query)-2] + ";" - _, colsErr := database.Exec(query) - if colsErr != nil { - return colsErr - } + // Check for new custom AccountInfoColumn items + if newItemsErr := addNewCustomItemsSQL(); newItemsErr != nil { + return newItemsErr } if rememberMe { @@ -125,19 +27,13 @@ func setUp() error { _, checkErr := database.Exec("SELECT " + autologsColumnID + " FROM " + tableAutologs + " WHERE " + autologsColumnID + "=1;") if checkErr != nil { fmt.Println("Making autologs table...") - //MAKE THE autologs TABLE - _, friendsErr := database.Exec("CREATE TABLE " + tableAutologs + " (" + - autologsColumnID + " INTEGER NOT NULL, " + - autologsColumnDevicePass + " VARCHAR(255) NOT NULL, " + - autologsColumnDeviceTag + " VARCHAR(255) NOT NULL" + - ");") - if friendsErr != nil { - return friendsErr + if cErr := createAutologsTableSQL(); cErr != nil { + return cErr } } } } - //MAKE SURE THE customLoginColumn IS UNIQUE IF SET + // Make sure customLoginColumn is unique if it is set if len(customLoginColumn) > 0 { _, alterErr := database.Exec("ALTER TABLE " + tableUsers + " ADD UNIQUE (" + customLoginColumn + ");") if alterErr != nil { @@ -148,3 +44,123 @@ func setUp() error { // return nil } + +func createUserTableSQL() error { + createQuery := "CREATE TABLE " + tableUsers + " (" + + usersColumnID + " INTEGER NOT NULL AUTO_INCREMENT, " + + usersColumnName + " VARCHAR(255) UNIQUE NOT NULL, " + + usersColumnPassword + " VARCHAR(255) NOT NULL, " + + // Append custom AccountInfoColumn items + for key, val := range customAccountInfo { + createQuery = createQuery + key + " " + dataTypes[val.dataType] + // Check for maxSize/precision + if isSizeDataType(val.dataType) { + createQuery = createQuery + "(" + strconv.Itoa(val.maxSize) + ")" + } else if isPrecisionDataType(val.dataType) { + createQuery = createQuery + "(" + strconv.Itoa(val.maxSize) + ", " + strconv.Itoa(val.precision) + ")" + } + // Check for unique + if val.unique { + createQuery = createQuery + " UNIQUE" + } + // Check for not-null + if val.notNull { + createQuery = createQuery + " NOT NULL, " + } else { + createQuery = createQuery + ", " + } + } + + createQuery = createQuery + "PRIMARY KEY (" + usersColumnID + "));" + + // Execute users table query + _, createErr := database.Exec(createQuery) + if createErr != nil { + return createErr + } + + // Adjust auto-increment to 1 + _, adjustErr := database.Exec("ALTER TABLE " + tableUsers + " AUTO_INCREMENT=1;") + if adjustErr != nil { + return adjustErr + } + + // Make friends table + _, friendsErr := database.Exec("CREATE TABLE " + tableFriends + " (" + + friendsColumnUser + " INTEGER NOT NULL, " + + friendsColumnFriend + " INTEGER NOT NULL, " + + friendsColumnStatus + " INTEGER NOT NULL" + + ");") + if friendsErr != nil { + return friendsErr + } + + if rememberMe { + if cErr := createAutologsTableSQL(); cErr != nil { + return cErr + } + } + + return nil +} + +func createAutologsTableSQL() error { + _, friendsErr = database.Exec("CREATE TABLE " + tableAutologs + " (" + + autologsColumnID + " INTEGER NOT NULL, " + + autologsColumnDevicePass + " VARCHAR(255) NOT NULL, " + + autologsColumnDeviceTag + " VARCHAR(255) NOT NULL, " + + ");") + if friendsErr != nil { + return friendsErr + } + return nil +} + +func addNewCustomItemsSQL() error { + query := "ALTER TABLE " + tableUsers + " " + var execQuery bool + // + for key, val := range customAccountInfo { + // Check if item exists + checkRows, err := database.Query("SHOW COLUMNS FROM " + tableUsers + " LIKE '" + key + "';") + if err != nil { + return err + } + // + checkRows.Next() + _, colsErr := checkRows.Columns() + if colsErr != nil { + fmt.Println("Adding AccountInfoColumn '" + key + "'...") + // The item doesn't exist yet... + query = query + "ADD COLUMN " + key + " " + dataTypes[val.dataType] + if isSizeDataType(val.dataType) { + query = query + "(" + strconv.Itoa(val.maxSize) + ")" + } else if isPrecisionDataType(val.dataType) { + query = query + "(" + strconv.Itoa(val.maxSize) + ", " + strconv.Itoa(val.precision) + ")" + } + // Unique check + if val.unique { + query = query + " UNIQUE" + } + // Not-null check + if val.notNull { + query = query + " NOT NULL, " + } else { + query = query + ", " + } + execQuery = true + } + checkRows.Close() + } + if execQuery { + // Make new columns + query = query[0:len(query)-2] + ";" + _, colsErr := database.Exec(query) + if colsErr != nil { + return colsErr + } + } + + return nil +} \ No newline at end of file diff --git a/server.go b/server.go index 4a65c98..55a5843 100644 --- a/server.go +++ b/server.go @@ -19,9 +19,7 @@ import ( ) /////////// TO DOs: -/////////// - Implement WebRTC option for voice chat -/////////// - Make relay for failed P2P connections -/////////// - Switch-out MySQL authentication with GopherGameDB +/////////// - Make authentication for GopherDB /////////// - Admin tools /////////// - More useful command-line macros @@ -111,47 +109,10 @@ func Start(s *ServerSettings) { fmt.Println("Starting server...") //SET SERVER SETTINGS if s != nil { - settings = s - if settings.ServerName == "" { - fmt.Println("ServerName in ServerSettings is required. Shutting down...") - return - - } else if settings.HostName == "" || settings.IP == "" || settings.Port < 1 { - fmt.Println("HostName, IP, and Port in ServerSettings are required. Shutting down...") - return - - } else if settings.TLS == true && (settings.CertFile == "" || settings.PrivKeyFile == "") { - fmt.Println("CertFile and PrivKeyFile in ServerSettings are required for a TLS connection. Shutting down...") - return - - } else if settings.EnableSqlFeatures == true && (settings.SqlIP == "" || settings.SqlPort < 1 || settings.SqlProtocol == "" || - settings.SqlUser == "" || settings.SqlPassword == "" || settings.SqlDatabase == "") { - fmt.Println("SqlIP, SqlPort, SqlProtocol, SqlUser, SqlPassword, and SqlDatabase in ServerSettings are required for the SQL features. Shutting down...") - return - - } else if settings.EnableRecovery == true && settings.RecoveryLocation == "" { - fmt.Println("RecoveryLocation in ServerSettings is required for server recovery. Shutting down...") - return - - } else if settings.EnableRecovery { - //CHECK IF INVALID LOCATION - if _, err := os.Stat(settings.RecoveryLocation); err != nil { - fmt.Println("RecoveryLocation error:", err) - fmt.Println("Shutting down...") - return - } - var d []byte - if err := ioutil.WriteFile(settings.RecoveryLocation+"/test.txt", d, 0644); err != nil { - fmt.Println("RecoveryLocation error:", err) - fmt.Println("Shutting down...") - return - } - os.Remove(settings.RecoveryLocation + "/test.txt") - - } else if settings.AdminLogin == "" || settings.AdminPassword == "" { - fmt.Println("AdminLogin and AdminPassword in ServerSettings are required. Shutting down...") + if !s.verify() { return } + settings = s } else { //DEFAULT localhost SETTINGS fmt.Println("Using default settings...") @@ -267,6 +228,51 @@ func Start(s *ServerSettings) { } } +func (settings *ServerSettings) verify() bool { + if settings.ServerName == "" { + fmt.Println("ServerName in ServerSettings is required. Shutting down...") + return false + + } else if settings.HostName == "" || settings.IP == "" || settings.Port < 1 { + fmt.Println("HostName, IP, and Port in ServerSettings are required. Shutting down...") + return false + + } else if settings.TLS == true && (settings.CertFile == "" || settings.PrivKeyFile == "") { + fmt.Println("CertFile and PrivKeyFile in ServerSettings are required for a TLS connection. Shutting down...") + return false + + } else if settings.EnableSqlFeatures == true && (settings.SqlIP == "" || settings.SqlPort < 1 || settings.SqlProtocol == "" || + settings.SqlUser == "" || settings.SqlPassword == "" || settings.SqlDatabase == "") { + fmt.Println("SqlIP, SqlPort, SqlProtocol, SqlUser, SqlPassword, and SqlDatabase in ServerSettings are required for the SQL features. Shutting down...") + return false + + } else if settings.EnableRecovery == true && settings.RecoveryLocation == "" { + fmt.Println("RecoveryLocation in ServerSettings is required for server recovery. Shutting down...") + return false + + } else if settings.EnableRecovery { + //CHECK IF INVALID LOCATION + if _, err := os.Stat(settings.RecoveryLocation); err != nil { + fmt.Println("RecoveryLocation error:", err) + fmt.Println("Shutting down...") + return false + } + var d []byte + if err := ioutil.WriteFile(settings.RecoveryLocation+"/test.txt", d, 0644); err != nil { + fmt.Println("RecoveryLocation error:", err) + fmt.Println("Shutting down...") + return false + } + os.Remove(settings.RecoveryLocation + "/test.txt") + + } else if settings.AdminLogin == "" || settings.AdminPassword == "" { + fmt.Println("AdminLogin and AdminPassword in ServerSettings are required. Shutting down...") + return false + } + + return true +} + func makeServer(handleDir string, tls bool) *http.Server { server := &http.Server{Addr: settings.IP + ":" + strconv.Itoa(settings.Port)} http.HandleFunc(handleDir, socketInitializer) From b6e4aaa7f49779e6bce957c844bd140027295225 Mon Sep 17 00:00:00 2001 From: hewiefreeman Date: Sat, 21 Sep 2019 14:51:08 -0700 Subject: [PATCH 116/132] Error fixes and ineffassign --- callbacks.go | 2 +- clientActions.go | 10 +++++++--- database/setup.go | 16 ++++++++-------- 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/callbacks.go b/callbacks.go index 8a6304a..16d1a83 100644 --- a/callbacks.go +++ b/callbacks.go @@ -91,7 +91,7 @@ func SetShutDownCallback(cb interface{}) error { // } // // The function returns a boolean. If false is returned, the client will receive an HTTP error `http.StatusForbidden` and -// will be rejected from the server. This can be used to, for instance, make a black/white list for your server. +// will be rejected from the server. This can be used to, for instance, make a black/white list or implement client sessions. func SetClientConnectCallback(cb interface{}) error { if serverStarted { return errors.New(ErrorServerRunning) diff --git a/clientActions.go b/clientActions.go index ee3774c..85815cf 100644 --- a/clientActions.go +++ b/clientActions.go @@ -375,9 +375,13 @@ func clientActionLogin(params interface{}, user **core.User, deviceTag *string, } } // Log socket in - if dbIndex, dPass, cID, lErr := loginClient(settings, guest, name, pass, *deviceTag, remMe, customCols, user, - conn, clientMux); lErr.ID != 0 { - return nil, false, lErr + var dbIndex int + var dPass string + var cID string + var err helpers.GopherError + if dbIndex, dPass, cID, err = loginClient(settings, guest, name, pass, *deviceTag, remMe, customCols, user, + conn, clientMux); err.ID != 0 { + return nil, false, err } // Update socket diff --git a/database/setup.go b/database/setup.go index 1c7bf1f..eb78b1f 100644 --- a/database/setup.go +++ b/database/setup.go @@ -23,7 +23,7 @@ func setUp() error { } if rememberMe { - //CHECK IF THE autologs TABLE HAS BEEN MADE + // Check if autologs table has been made _, checkErr := database.Exec("SELECT " + autologsColumnID + " FROM " + tableAutologs + " WHERE " + autologsColumnID + "=1;") if checkErr != nil { fmt.Println("Making autologs table...") @@ -87,12 +87,12 @@ func createUserTableSQL() error { } // Make friends table - _, friendsErr := database.Exec("CREATE TABLE " + tableFriends + " (" + + if _, friendsErr := database.Exec("CREATE TABLE " + tableFriends + " (" + friendsColumnUser + " INTEGER NOT NULL, " + friendsColumnFriend + " INTEGER NOT NULL, " + friendsColumnStatus + " INTEGER NOT NULL" + - ");") - if friendsErr != nil { + ");"); friendsErr != nil { + return friendsErr } @@ -106,13 +106,13 @@ func createUserTableSQL() error { } func createAutologsTableSQL() error { - _, friendsErr = database.Exec("CREATE TABLE " + tableAutologs + " (" + + if _, aErr := database.Exec("CREATE TABLE " + tableAutologs + " (" + autologsColumnID + " INTEGER NOT NULL, " + autologsColumnDevicePass + " VARCHAR(255) NOT NULL, " + autologsColumnDeviceTag + " VARCHAR(255) NOT NULL, " + - ");") - if friendsErr != nil { - return friendsErr + ");"); aErr != nil { + + return aErr } return nil } From eeae7dead3034dbeeabd7cf01677b5920e4c3341 Mon Sep 17 00:00:00 2001 From: Dominique Debergue Date: Sat, 21 Sep 2019 14:55:31 -0700 Subject: [PATCH 117/132] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 21baea0..7999632 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@

    -

    +


    From 6983daf94ffe568f8937027392ba0633d9ae17a2 Mon Sep 17 00:00:00 2001 From: Dominique Debergue Date: Mon, 23 Sep 2019 15:31:00 -0700 Subject: [PATCH 118/132] Update README.md --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 7999632..f4644ba 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,9 @@ Moreover, Gopher has a built-in, fully customizable SQL client authentication me - Distributed load balancer and server coordinator - Distributed server broadcasts - GUI for administrating and monitoring servers - - Integration with [GopherDB](https://github.com/hewiefreeman/GopherDB) when stable + - Integration with [GopherDB](https://github.com/hewiefreeman/GopherDB) when stable (\***1**) + +> (\***1**) MySQL isn't very scalable on it's own, and the SQL implementation for storing friend info is probably not the most efficient. Hence, it is recommended to put the friends table into a separate database cluster. GopherDB, on the other hand, is a very promising database project that should be able to greatly increase efficiency and outperform MySQL for authentication and friending. It has a built-in authentication table type, which means less round trips to the database for authentication. It also supports nested values, which are deep-validated through table schemas. You can follow, or get more info on the project with the link above! ### Change Log [CHANGE_LOG.md](https://github.com/hewiefreeman/GopherGameServer/blob/master/CHANGE_LOG.md) From bafed1c6be03708f8ba1120f26e23b2de3792f50 Mon Sep 17 00:00:00 2001 From: Dominique Debergue Date: Mon, 23 Sep 2019 15:40:57 -0700 Subject: [PATCH 119/132] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f4644ba..eac4eef 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ Moreover, Gopher has a built-in, fully customizable SQL client authentication me - GUI for administrating and monitoring servers - Integration with [GopherDB](https://github.com/hewiefreeman/GopherDB) when stable (\***1**) -> (\***1**) MySQL isn't very scalable on it's own, and the SQL implementation for storing friend info is probably not the most efficient. Hence, it is recommended to put the friends table into a separate database cluster. GopherDB, on the other hand, is a very promising database project that should be able to greatly increase efficiency and outperform MySQL for authentication and friending. It has a built-in authentication table type, which means less round trips to the database for authentication. It also supports nested values, which are deep-validated through table schemas. You can follow, or get more info on the project with the link above! +> (\***1**) MySQL isn't very scalable on it's own, and the SQL implementation for storing friend info is probably not the most efficient. Hence, it is recommended to put the friends table into a separate database cluster. GopherDB, on the other hand, is a very promising database project that should be able to greatly increase efficiency and outperform MySQL for authentication and friending. It has a built-in authentication table type, which takes a substantial load off the game servers, and further secures your users' private information. It also supports nested values which are deep-validated through table schemas, so you can store complex information using a wide variety of data types and rules. You can follow the project and get more info with the link above! ### Change Log [CHANGE_LOG.md](https://github.com/hewiefreeman/GopherGameServer/blob/master/CHANGE_LOG.md) From 025decfd408c3483910af4a00bfe4cbab740a9dc Mon Sep 17 00:00:00 2001 From: Dominique Debergue Date: Mon, 23 Sep 2019 15:44:57 -0700 Subject: [PATCH 120/132] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index eac4eef..72d5a94 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ Moreover, Gopher has a built-in, fully customizable SQL client authentication me - GUI for administrating and monitoring servers - Integration with [GopherDB](https://github.com/hewiefreeman/GopherDB) when stable (\***1**) -> (\***1**) MySQL isn't very scalable on it's own, and the SQL implementation for storing friend info is probably not the most efficient. Hence, it is recommended to put the friends table into a separate database cluster. GopherDB, on the other hand, is a very promising database project that should be able to greatly increase efficiency and outperform MySQL for authentication and friending. It has a built-in authentication table type, which takes a substantial load off the game servers, and further secures your users' private information. It also supports nested values which are deep-validated through table schemas, so you can store complex information using a wide variety of data types and rules. You can follow the project and get more info with the link above! +> (\***1**) MySQL isn't very scalable on it's own, and the SQL implementation for storing friend info is probably not the most efficient. Hence, it is recommended to put the friends table into a separate database cluster. GopherDB, on the other hand, is a very promising database project that will greatly increase server efficiency, and could possibly even outperform MySQL overall. It has a built-in authentication table type, which takes a substantial load off the game servers, and further secures your users' private information. It also supports nested values which are deep-validated through table schemas, so you can store complex information using a wide variety of data types and rules. You can follow the project and get more info with the link above! ### Change Log [CHANGE_LOG.md](https://github.com/hewiefreeman/GopherGameServer/blob/master/CHANGE_LOG.md) From 096cf2987800005fa05a62459d3302340d5f6e60 Mon Sep 17 00:00:00 2001 From: Dominique Debergue Date: Thu, 5 Dec 2019 10:26:58 -0800 Subject: [PATCH 121/132] Fixed private messaging bug Private messages weren't being sent unless the sending user was inside a Room. This was incorrect behavior, and should now be working as expected. --- clientActions.go | 5 ----- 1 file changed, 5 deletions(-) diff --git a/clientActions.go b/clientActions.go index 85815cf..242d434 100644 --- a/clientActions.go +++ b/clientActions.go @@ -702,11 +702,6 @@ func clientActionPrivateMessage(params interface{}, user **core.User, connID str if userName, ok = pMap["u"].(string); !ok { return nil, false, helpers.NoError() } - // Get current room - currRoom := userRef.RoomIn(connID) - if currRoom == nil || currRoom.Name() == "" { - return nil, false, helpers.NoError() - } // Send chat message userRef.PrivateMessage(userName, pMap["m"]) // From 9a6d8f7154215d666ca5e42a9cc7b9f40df01e51 Mon Sep 17 00:00:00 2001 From: Dominique Debergue Date: Tue, 17 Dec 2019 15:25:44 -0800 Subject: [PATCH 122/132] Update LICENSE --- LICENSE | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/LICENSE b/LICENSE index 191e120..d9a10c0 100644 --- a/LICENSE +++ b/LICENSE @@ -174,28 +174,3 @@ of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [2019] [Dominique Claude Debergue] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. From a53afe652f438701fb995ff9eed7ba98d86f4886 Mon Sep 17 00:00:00 2001 From: Dominique Debergue Date: Tue, 17 Dec 2019 15:27:16 -0800 Subject: [PATCH 123/132] Update README.md --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index 72d5a94..1297074 100644 --- a/README.md +++ b/README.md @@ -109,3 +109,10 @@ Please read the following articles before submitting any contributions or filing - [Contribution Guidlines](https://github.com/hewiefreeman/GopherGameServer/blob/master/CONTRIBUTING.md) - [Code of Conduct](https://github.com/hewiefreeman/GopherGameServer/blob/master/CODE_OF_CONDUCT.md) + +
    GopherDB and all of it's contents Copyright 2020 Dominique Debergue +
    Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at: + + `http://www.apache.org/licenses/LICENSE-2.0` + +
    Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
    From d163896b87091e13092b12b63698b223a7587d6d Mon Sep 17 00:00:00 2001 From: Dominique Debergue Date: Tue, 17 Dec 2019 15:27:45 -0800 Subject: [PATCH 124/132] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 1297074..62e0f1d 100644 --- a/README.md +++ b/README.md @@ -110,6 +110,8 @@ Please read the following articles before submitting any contributions or filing - [Contribution Guidlines](https://github.com/hewiefreeman/GopherGameServer/blob/master/CONTRIBUTING.md) - [Code of Conduct](https://github.com/hewiefreeman/GopherGameServer/blob/master/CODE_OF_CONDUCT.md) +
    +
    GopherDB and all of it's contents Copyright 2020 Dominique Debergue
    Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at: From 7c6fc04cb3c7afeb1bb9a52bd51c682266cc9d7d Mon Sep 17 00:00:00 2001 From: Dominique Debergue Date: Tue, 17 Dec 2019 16:04:21 -0800 Subject: [PATCH 125/132] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 62e0f1d..6dc4621 100644 --- a/README.md +++ b/README.md @@ -112,7 +112,7 @@ Please read the following articles before submitting any contributions or filing
    -
    GopherDB and all of it's contents Copyright 2020 Dominique Debergue +
    GopherGameServer and all of it's contents Copyright 2020 Dominique Debergue
    Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at: `http://www.apache.org/licenses/LICENSE-2.0` From 27a1a121eabadea5f548f6fb62dc506ac2746721 Mon Sep 17 00:00:00 2001 From: hewiefreeman Date: Wed, 12 Aug 2020 18:43:39 -0700 Subject: [PATCH 126/132] Implementing GopherDB --- clientActions.go | 5 - core/friending.go | 23 ++++- core/rooms.go | 33 ++++--- core/users.go | 241 ++++++++++++++++++---------------------------- server.go | 52 +++++----- sockets.go | 2 +- 6 files changed, 157 insertions(+), 199 deletions(-) diff --git a/clientActions.go b/clientActions.go index 85815cf..242d434 100644 --- a/clientActions.go +++ b/clientActions.go @@ -702,11 +702,6 @@ func clientActionPrivateMessage(params interface{}, user **core.User, connID str if userName, ok = pMap["u"].(string); !ok { return nil, false, helpers.NoError() } - // Get current room - currRoom := userRef.RoomIn(connID) - if currRoom == nil || currRoom.Name() == "" { - return nil, false, helpers.NoError() - } // Send chat message userRef.PrivateMessage(userName, pMap["m"]) // diff --git a/core/friending.go b/core/friending.go index 46b7fae..9c63023 100644 --- a/core/friending.go +++ b/core/friending.go @@ -152,7 +152,7 @@ func (u *User) AcceptFriendRequest(friendName string) error { } ////////////////////////////////////////////////////////////////////////////////////////////////////// -// DECLINE A FRIEND REQUEST ////////////////////////////////////////////////////////////////////// +// Decline friend request //////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////// // DeclineFriendRequest declines a friend request from another User by their name. @@ -221,7 +221,7 @@ func (u *User) DeclineFriendRequest(friendName string) error { } ////////////////////////////////////////////////////////////////////////////////////////////////////// -// REMOVE A FRIEND /////////////////////////////////////////////////////////////////////////////// +// Remove a friend /////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////// // RemoveFriend removes a friend from this this User and this User from the friend's Friend list. @@ -288,3 +288,22 @@ func (u *User) RemoveFriend(friendName string) error { // return nil } + +////////////////////////////////////////////////////////////////////////////////////////////////////// +// Send message to all friends /////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////////// + +func (u *User) sendToFriends(message interface{}) { + for key, val := range u.friends { + if val.RequestStatus() == database.FriendStatusAccepted { + friend, friendErr := GetUser(key) + if friendErr == nil { + friend.mux.Lock() + for _, friendConn := range friend.conns { + (*friendConn).socket.WriteJSON(message) + } + friend.mux.Unlock() + } + } + } +} \ No newline at end of file diff --git a/core/rooms.go b/core/rooms.go index a5f69b6..df933e2 100644 --- a/core/rooms.go +++ b/core/rooms.go @@ -208,22 +208,23 @@ func (r *Room) AddUser(user *User, connID string) error { // CHECK IF USER IS ALREADY IN THE ROOM var ru *RoomUser - if u, ok := r.usersMap[userName]; ok { - ru = u + var ok bool + if ru, ok = r.usersMap[userName]; ok { if !multiConnect { r.mux.Unlock() return errors.New("User '" + userName + "' is already in room '" + r.name + "'") } - u.mux.Lock() - if _, ok := u.conns[connID]; ok { + ru.mux.Lock() + if _, ok := ru.conns[connID]; ok { r.mux.Unlock() - u.mux.Unlock() + ru.mux.Unlock() return errors.New("User '" + userName + "' is already in room '" + r.name + "'") } - u.mux.Unlock() + ru.mux.Unlock() } // ADD User TO ROOM - c := user.getConn(connID) + user.mux.Lock() + c := user.conns[connID] if c == nil { r.mux.Unlock() return errors.New("Invalid connection ID") @@ -239,11 +240,12 @@ func (r *Room) AddUser(user *User, connID string) error { r.usersMap[userName] = &newUser ru = r.usersMap[userName] } - r.mux.Unlock() // CHANGE USER'S ROOM - user.mux.Lock() c.room = r + user.mux.Unlock() + r.mux.Unlock() + // roomType := roomTypes[r.rType] if roomType.BroadcastUserEnter() { @@ -285,9 +287,8 @@ func (r *Room) AddUser(user *User, connID string) error { // parameter is the connection ID associated with one of the connections attached to that User. This must // be provided when removing a User from a Room with MultiConnect enabled. Otherwise, an empty string can be used. func (r *Room) RemoveUser(user *User, connID string) error { - userName := user.Name() //REJECT INCORRECT INPUT - if user == nil || len(userName) == 0 { + if user == nil || len(user.name) == 0 { return errors.New("*Room.RemoveUser() requires a valid *User") } else if multiConnect && len(connID) == 0 { return errors.New("Must provide a connID when MultiConnect is enabled") @@ -302,9 +303,9 @@ func (r *Room) RemoveUser(user *User, connID string) error { } var ok bool var ru *RoomUser - if ru, ok = r.usersMap[userName]; !ok { + if ru, ok = r.usersMap[user.name]; !ok { r.mux.Unlock() - return errors.New("User '" + userName + "' is not in room '" + r.name + "'") + return errors.New("User '" + user.name + "' is not in room '" + r.name + "'") } ru.mux.Lock() var uConn *userConn @@ -316,7 +317,7 @@ func (r *Room) RemoveUser(user *User, connID string) error { delete(ru.conns, connID) // Remove user when no conns are left in room if len(ru.conns) == 0 { - delete(r.usersMap, userName) + delete(r.usersMap, user.name) } ru.mux.Unlock() userList := r.usersMap @@ -325,7 +326,7 @@ func (r *Room) RemoveUser(user *User, connID string) error { roomType := roomTypes[r.rType] //DELETE THE ROOM IF THE OWNER LEFT AND UserRoomControl IS ENABLED - if deleteRoomOnLeave && userName == r.owner { + if deleteRoomOnLeave && user.name == r.owner { deleteErr := r.Delete() if deleteErr != nil { return deleteErr @@ -334,7 +335,7 @@ func (r *Room) RemoveUser(user *User, connID string) error { //CONSTRUCT LEAVE MESSAGE message := map[string]map[string]interface{}{ helpers.ServerActionUserLeave: { - "u": userName, + "u": user.name, }, } diff --git a/core/users.go b/core/users.go index ed3ecc1..11114f8 100644 --- a/core/users.go +++ b/core/users.go @@ -25,7 +25,7 @@ type User struct { databaseID int isGuest bool - //mux LOCKS ALL FIELDS BELOW + //mux lock all items below mux sync.Mutex status int friends map[string]*database.Friend @@ -33,13 +33,13 @@ type User struct { } type userConn struct { - //MUST LOCK *clientMux WHEN GETTING/SETTING *user + // Must lock *clientMux when using *user clientMux *sync.Mutex user **User socket *websocket.Conn - //MUST LOCK User's mux FIRST + //Must lock user's mux to use below items room *Room vars map[string]interface{} } @@ -81,7 +81,7 @@ const ( // Login logs a User in to the service. func Login(userName string, dbID int, autologPass string, isGuest bool, remMe bool, socket *websocket.Conn, connUser **User, clientMux *sync.Mutex) (string, helpers.GopherError) { - //REJECT INCORRECT INPUT + // Verify input if serverPaused { return "", helpers.NewError(errorServerPaused, helpers.ErrorServerPaused) } else if len(userName) == 0 { @@ -94,18 +94,18 @@ func Login(userName string, dbID int, autologPass string, isGuest bool, remMe bo return "", helpers.NewError(errorRequiredSocket, helpers.ErrorAuthRequiredSocket) } - //ALWAYS SET A GUEST'S id TO -1 + // Guests always have -1 databaseID databaseID := dbID if isGuest { databaseID = -1 } - //RUN CALLBACK + // Callback if LoginCallback != nil && !LoginCallback(userName, dbID, nil, nil) { return "", helpers.NewError(errorDenied, helpers.ErrorActionDenied) } - //MAKE *User IN users MAP & MAKE connID + // Make *User in users & make connID var connID string var connErr error var userExists bool = false @@ -115,7 +115,7 @@ func Login(userName string, dbID int, autologPass string, isGuest bool, remMe bo if userOnline, ok := users[userName]; ok { userExists = true if kickOnLogin { - // KICK USER AND REMOVE FROM THEIR CURRENT ROOM IF ANY + // Kick user & remove from room userOnline.mux.Lock() for connKey, conn := range userOnline.conns { userRoom := (*conn).room @@ -127,20 +127,20 @@ func Login(userName string, dbID int, autologPass string, isGuest bool, remMe bo (*(*conn).clientMux).Lock() *((*conn).user) = nil (*(*conn).clientMux).Unlock() - //SEND LOGOUT MESSAGE TO CLIENT + // Send logout message to client clientResp := helpers.MakeClientResponse(helpers.ClientActionLogout, nil, helpers.NoError()) (*conn).socket.WriteJSON(clientResp) } userOnline.mux.Unlock() - //DELETE FROM users MAP + // Remove user from users map delete(users, userName) - //MAKE connID + // Make connID connID = "1" userExists = false } else if multiConnect { - //MAKE UNIQUE connID + // Make a unique connID for { connID, connErr = helpers.GenerateSecureString(5) if connErr != nil { @@ -159,70 +159,38 @@ func Login(userName string, dbID int, autologPass string, isGuest bool, remMe bo return "", helpers.NewError(errorAlreadyLogged, helpers.ErrorAuthAlreadyLogged) } } else if multiConnect { - //MAKE UNIQUE connID + // Make connID connID, connErr = helpers.GenerateSecureString(5) if connErr != nil { usersMux.Unlock() return "", helpers.NewError(errorUnexpected, helpers.ErrorAuthUnexpected) } } else { - //MAKE connID + // Make connID connID = "1" } - //MAKE THE userConn + // Make the userConn vars := make(map[string]interface{}) conn := userConn{socket: socket, room: nil, vars: vars, user: connUser, clientMux: clientMux} - //FRIENDS OBJECTS + // Make friends objects + var u *User var friends []map[string]interface{} var friendsMap map[string]*database.Friend - //ADD THE userConn TO THE User OR MAKE THE User + // Add the userConn to the User or make new User if userExists { (*users[userName]).mux.Lock() (*users[userName]).conns[connID] = &conn friendsMap = (*users[userName]).friends (*users[userName]).mux.Unlock() - friends = make([]map[string]interface{}, 0, len(friendsMap)) - //MAKE FRINDS LIST FOR SERVER RESPONSE - for _, val := range friendsMap { - frs := val.RequestStatus() - friendEntry := map[string]interface{}{ - "n": val.Name(), - "rs": frs, - } - if frs == database.FriendStatusAccepted { - //GET THE User STATUS - if friend, ok := users[val.Name()]; ok { - friendEntry["s"] = friend.Status() - } else { - friendEntry["s"] = StatusOffline - } - } - friends = append(friends, friendEntry) - } + // Make friends list for response + friends = makeFriendsResponse(friendsMap) } else { - //GET User's Friend LIST FROM DATABASE + // Get friend list from database if dbID != -1 && sqlFeatures { var friendsErr error - friendsMap, friendsErr = database.GetFriends(dbID) // map[string]Friend - if friendsErr == nil { - //MAKE FRINDS LIST FOR SERVER RESPONSE - friends = make([]map[string]interface{}, 0, len(friendsMap)) - for _, val := range friendsMap { - frs := val.RequestStatus() - friendEntry := map[string]interface{}{ - "n": val.Name(), - "rs": frs, - } - if frs == database.FriendStatusAccepted { - //GET THE User STATUS - if friend, ok := users[val.Name()]; ok { - friendEntry["s"] = friend.Status() - } else { - friendEntry["s"] = StatusOffline - } - } - friends = append(friends, friendEntry) - } + if friendsMap, friendsErr = database.GetFriends(dbID); friendsErr == nil { + // Make friends list for response + friends = makeFriendsResponse(friendsMap) } } conns := map[string]*userConn{ @@ -230,7 +198,8 @@ func Login(userName string, dbID int, autologPass string, isGuest bool, remMe bo } newUser := User{name: userName, databaseID: databaseID, isGuest: isGuest, status: 0, friends: friendsMap, conns: conns} - users[userName] = &newUser + u = &newUser + users[userName] = u } (*conn.clientMux).Lock() *(conn.user) = users[userName] @@ -238,34 +207,29 @@ func Login(userName string, dbID int, autologPass string, isGuest bool, remMe bo // usersMux.Unlock() - //SEND ONLINE MESSAGE TO FRIENDS + // Send online message to friends statusMessage := map[string]map[string]interface{}{ helpers.ServerActionFriendStatusChange: { "n": userName, "s": 0, }, } - for key, val := range friendsMap { - if val.RequestStatus() == database.FriendStatusAccepted { - friend, friendErr := GetUser(key) - if friendErr == nil { - friend.mux.Lock() - for _, friendConn := range friend.conns { - friendConn.socket.WriteJSON(statusMessage) - } - friend.mux.Unlock() - } - } - } + u.sendToFriends(statusMessage) - //SUCCESS, SEND RESPONSE TO CLIENT - responseVal := map[string]interface{}{ - "n": userName, - "f": friends, - } + // Login success, send response to client + var responseVal map[string]interface{} if rememberMe && len(autologPass) > 0 && remMe { - responseVal["ai"] = dbID - responseVal["ap"] = autologPass + responseVal = map[string]interface{}{ + "n": userName, + "f": friends, + "ai": dbID, + "ap": autologPass, + } + } else { + responseVal = map[string]interface{}{ + "n": userName, + "f": friends, + } } clientResp := helpers.MakeClientResponse(helpers.ClientActionLogin, responseVal, helpers.NoError()) socket.WriteJSON(clientResp) @@ -274,6 +238,29 @@ func Login(userName string, dbID int, autologPass string, isGuest bool, remMe bo return connID, helpers.NoError() } +func makeFriendsResponse(friendsMap map[string]*database.Friend) []map[string]interface{} { + friends := make([]map[string]interface{}, len(friendsMap), len(friendsMap)) + i := 0; + for _, val := range friendsMap { + frs := val.RequestStatus() + friendEntry := map[string]interface{}{ + "n": val.Name(), + "rs": frs, + } + if frs == database.FriendStatusAccepted { + // Get the friend's status + if friend, ok := users[val.Name()]; ok { + friendEntry["s"] = friend.Status() + } else { + friendEntry["s"] = StatusOffline + } + } + friends[i] = friendEntry + i++; + } + return friends +} + ////////////////////////////////////////////////////////////////////////////////////////////////////// // AUTOLOG A USER IN ///////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -288,17 +275,17 @@ func AutoLogIn(tag string, pass string, newPass string, dbID int, conn *websocke return "", helpers.NewError(errorServerPaused, helpers.ErrorServerPaused) } - //VERIFY AND GET USER NAME FROM DATABASE + // Verify and get user name from database userName, autoLogErr := database.AutoLoginClient(tag, pass, newPass, dbID) if autoLogErr.ID != 0 { return "", autoLogErr } - // + // Log user in connID, userErr := Login(userName, dbID, newPass, false, true, conn, connUser, clientMux) if userErr.ID != 0 { return "", userErr } - // + return connID, helpers.NoError() } @@ -316,7 +303,7 @@ func (u *User) Logout(connID string) { connID = "1" } - //REMOVE USER FROM THEIR ROOM + // Remove user from their room u.mux.Lock() if _, ok := u.conns[connID]; !ok { u.mux.Unlock() @@ -330,27 +317,16 @@ func (u *User) Logout(connID string) { } if len(u.conns) == 1 { - //SEND STATUS CHANGE TO FRIENDS + // Send status change to friends statusMessage := map[string]map[string]interface{}{ helpers.ServerActionFriendStatusChange: { "n": u.name, "s": StatusOffline, }, } - for key, val := range u.friends { - if val.RequestStatus() == database.FriendStatusAccepted { - friend, friendErr := GetUser(key) - if friendErr == nil { - friend.mux.Lock() - for _, friendConn := range friend.conns { - (*friendConn).socket.WriteJSON(statusMessage) - } - friend.mux.Unlock() - } - } - } + u.sendToFriends(statusMessage) } - //LOG USER OUT + // Log user out (*u.conns[connID]).clientMux.Lock() if *((*u.conns[connID]).user) != nil { *((*u.conns[connID]).user) = nil @@ -359,7 +335,7 @@ func (u *User) Logout(connID string) { socket := (*u.conns[connID]).socket delete(u.conns, connID) if len(u.conns) == 0 { - // DELETE THE USER IF THERE ARE NO MORE CONNS + // Delete user if there are no more conns u.mux.Unlock() usersMux.Lock() delete(users, u.name) @@ -368,11 +344,11 @@ func (u *User) Logout(connID string) { u.mux.Unlock() } - //SEND RESPONSE TO CLIENT + // Send response clientResp := helpers.MakeClientResponse(helpers.ClientActionLogout, nil, helpers.NoError()) socket.WriteJSON(clientResp) - //RUN CALLBACK + // Run callback if LogoutCallback != nil { LogoutCallback(u.Name(), u.DatabaseID()) } @@ -382,32 +358,21 @@ func (u *User) Logout(connID string) { func (u *User) Kick() { u.mux.Lock() - //SEND STATUS CHANGE TO FRIENDS + // Send status change message to friends statusMessage := map[string]map[string]interface{}{ helpers.ServerActionFriendStatusChange: { "n": u.name, "s": StatusOffline, }, } - for key, val := range u.friends { - if val.RequestStatus() == database.FriendStatusAccepted { - friend, friendErr := GetUser(key) - if friendErr == nil { - friend.mux.Lock() - for _, friendConn := range friend.conns { - (*friendConn).socket.WriteJSON(statusMessage) - } - friend.mux.Unlock() - } - } - } + u.sendToFriends(statusMessage) - //MAKE CLIENT RESPONSE + // Make response clientResp := helpers.MakeClientResponse(helpers.ClientActionLogout, nil, helpers.NoError()) - //LOOP THROUGH CONNECTIONS + // Go through all connections for connID, conn := range u.conns { - //REMOVE CONNECTION FROM THEIR ROOM + // Remove from room currRoom := (*conn).room if currRoom != nil && currRoom.Name() != "" { u.mux.Unlock() @@ -415,25 +380,25 @@ func (u *User) Kick() { u.mux.Lock() } - //LOG CONNECTION OUT + // Log connection out (*conn).clientMux.Lock() if *((*conn).user) != nil { *((*conn).user) = nil } (*conn).clientMux.Unlock() - //SEND RESPONSE + // Send response (*conn).socket.WriteJSON(clientResp) } u.mux.Unlock() - //REMOVE USER FROM users + // Remove from users usersMux.Lock() delete(users, u.name) usersMux.Unlock() - //RUN CALLBACK + // Run callback if LogoutCallback != nil { LogoutCallback(u.Name(), u.DatabaseID()) } @@ -445,7 +410,7 @@ func (u *User) Kick() { // GetUser finds a logged in User by their name. Returns an error if the User is not online. func GetUser(userName string) (*User, error) { - //REJECT INCORRECT INPUT + // Verify input if len(userName) == 0 { return &User{}, errors.New("users.Get() requires a user name") } else if serverPaused { @@ -489,14 +454,14 @@ func (u *User) Join(r *Room, connID string) error { u.mux.Unlock() return errors.New("User '" + u.name + "' is already in room '" + r.Name() + "'") } else if currRoom != nil && currRoom.Name() != "" { - //LEAVE USER'S CURRENT ROOM + // Leave current room u.mux.Unlock() u.Leave(connID) u.mux.Lock() } u.mux.Unlock() - //ADD USER TO DESIGNATED ROOM + // Add user to room addErr := r.AddUser(u, connID) if addErr != nil { return addErr @@ -542,31 +507,18 @@ func (u *User) Leave(connID string) error { // SetStatus sets the status of a User. Also sends a notification to all the User's Friends (with the request // status "accepted") that they changed their status. func (u *User) SetStatus(status int) { - u.mux.Lock() - friends := u.friends u.status = status u.mux.Unlock() - //SEND STATUS CHANGE MESSAGE TO User's FRIENDS WHOM ARE "ACCEPTED" + // Send status to friends message := map[string]map[string]interface{}{ helpers.ServerActionFriendStatusChange: { "n": u.name, "s": status, }, } - for key, val := range friends { - if val.RequestStatus() == database.FriendStatusAccepted { - friend, friendErr := GetUser(key) - if friendErr == nil { - friend.mux.Lock() - for _, conn := range friend.conns { - (*conn).socket.WriteJSON(message) - } - friend.mux.Unlock() - } - } - } + u.sendToFriends(message) } ////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -602,13 +554,13 @@ func (u *User) Invite(invUser *User, connID string) error { return errors.New("Only the server can manipulate that type of room") } - //ADD TO INVITE LIST + // Add to invite list addErr := currRoom.AddInvite(invUser.name) if addErr != nil { return addErr } - //MAKE INVITE MESSAGE + // Make response message invMessage := map[string]map[string]interface{}{ helpers.ServerActionRoomInvite: { "u": u.name, @@ -616,7 +568,7 @@ func (u *User) Invite(invUser *User, connID string) error { }, } - //SEND MESSAGE + // Send response to all connections invUser.mux.Lock() for _, conn := range invUser.conns { (*conn).socket.WriteJSON(invMessage) @@ -660,7 +612,7 @@ func (u *User) RevokeInvite(revokeUser string, connID string) error { return errors.New("Only the server can manipulate that type of room") } - //REMOVE FROM INVITE LIST + // Remove from invite list removeErr := currRoom.RemoveInvite(revokeUser) if removeErr != nil { return removeErr @@ -758,11 +710,4 @@ func (u *User) ConnectionIDs() []string { } u.mux.Unlock() return ids -} - -func (u *User) getConn(connID string) *userConn { - u.mux.Lock() - conn := u.conns[connID] - u.mux.Unlock() - return conn -} +} \ No newline at end of file diff --git a/server.go b/server.go index 55a5843..6a50b9e 100644 --- a/server.go +++ b/server.go @@ -90,7 +90,7 @@ var ( ) ////////////////////////////////////////////////////////////////////////////////////////////////////// -// SERVER START-UP /////////////////////////////////////////////////////////////////////////////// +// Server start-up /////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////// // Start will start the server. Call with a pointer to your `ServerSettings` (or nil for defaults) to start the server. The default @@ -107,14 +107,14 @@ func Start(s *ServerSettings) { serverStarted = true fmt.Println(" _______ __\n | _ |.-----..-----.| |--..-----..----.\n |. |___||. _ ||. _ ||. ||. -__||. _|\n |. | ||:. . ||:. __||: |: ||: ||: |\n |: | |'-----'|: | '--'--''-----''--'\n |::.. . | '--' - Game Server -\n '-------'\n\n ") fmt.Println("Starting server...") - //SET SERVER SETTINGS + // Set server settings if s != nil { if !s.verify() { return } settings = s } else { - //DEFAULT localhost SETTINGS + // Default localhost settings fmt.Println("Using default settings...") settings = &ServerSettings{ ServerName: "!server!", @@ -155,16 +155,16 @@ func Start(s *ServerSettings) { AdminPassword: "password"} } - //UPDATE SETTINGS IN users PACKAGE, THEN users WILL UPDATE SETTINGS FOR rooms PACKAGE + // Update package settings core.SettingsSet((*settings).KickDupOnLogin, (*settings).ServerName, (*settings).RoomDeleteOnLeave, (*settings).EnableSqlFeatures, (*settings).RememberMe, (*settings).MultiConnect, (*settings).MaxUserConns) - //NOTIFY PACKAGES OF SERVER START + // Notify packages of server start core.SetServerStarted(true) actions.SetServerStarted(true) database.SetServerStarted(true) - //START UP DATABASE + // Start database if (*settings).EnableSqlFeatures { fmt.Println("Initializing database...") dbErr := database.Init((*settings).SqlUser, (*settings).SqlPassword, (*settings).SqlDatabase, @@ -178,29 +178,29 @@ func Start(s *ServerSettings) { fmt.Println("Database initialized") } - //RECOVER PREVIOUS SERVER STATE + // Recover state if settings.EnableRecovery { recoverState() } - //START HTTP/SOCKET LISTENER + // Start socket listener if settings.TLS { httpServer = makeServer("/wss", settings.TLS) } else { httpServer = makeServer("/ws", settings.TLS) } - //RUN START CALLBACK + // Run callback if startCallback != nil { startCallback() } - //START MACRO COMMAND LISTENER + // Start macro listener go macroListener() fmt.Println("Startup complete") - //BLOCK UNTIL SERVER SHUT-DOWN + // Wait for server shutdown doneErr := <-serverEndChan if doneErr != http.ErrServerClosed { @@ -209,12 +209,12 @@ func Start(s *ServerSettings) { if !serverStopping { fmt.Println("Disconnecting users...") - //PAUSE SERVER + // Pause server core.Pause() actions.Pause() database.Pause() - //SAVE STATE + // Save state if settings.EnableRecovery { saveState() } @@ -251,7 +251,7 @@ func (settings *ServerSettings) verify() bool { return false } else if settings.EnableRecovery { - //CHECK IF INVALID LOCATION + // Check if invalid file location if _, err := os.Stat(settings.RecoveryLocation); err != nil { fmt.Println("RecoveryLocation error:", err) fmt.Println("Shutting down...") @@ -293,7 +293,7 @@ func makeServer(handleDir string, tls bool) *http.Server { } ////////////////////////////////////////////////////////////////////////////////////////////////////// -// SERVER ACTIONS //////////////////////////////////////////////////////////////////////////////// +// Server actions //////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////// // Pause will log all Users off and prevent anyone from logging in. All rooms and their variables created by the server will remain in memory. @@ -308,7 +308,7 @@ func Pause() { actions.Pause() database.Pause() - //RUN CALLBACK + // Run callback if pauseCallback != nil { pauseCallback() } @@ -330,7 +330,7 @@ func Resume() { actions.Resume() database.Resume() - //RUN CALLBACK + // Run callback if resumeCallback != nil { resumeCallback() } @@ -347,17 +347,17 @@ func ShutDown() error { serverStopping = true fmt.Println("Disconnecting users...") - //PAUSE SERVER + // Pause server core.Pause() actions.Pause() database.Pause() - //SAVE STATE + // Save state if settings.EnableRecovery { saveState() } - //SHUT DOWN SERVER + // Shut server down fmt.Println("Shutting server down...") shutdownErr := httpServer.Shutdown(context.Background()) if shutdownErr != http.ErrServerClosed { @@ -369,7 +369,7 @@ func ShutDown() error { } ////////////////////////////////////////////////////////////////////////////////////////////////////// -// SAVING AND RECOVERING STATE /////////////////////////////////////////////////////////////////// +// Saving and recovery /////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////// func saveState() { @@ -383,7 +383,6 @@ func saveState() { } func writeState(stateObj serverRestore, saveFolder string) error { - //WRITE THE STATE state, err := json.Marshal(stateObj) if err != nil { return err @@ -393,7 +392,6 @@ func writeState(stateObj serverRestore, saveFolder string) error { return err } - // return nil } @@ -406,7 +404,7 @@ func getState() serverRestore { func recoverState() { fmt.Println("Recovering previous state...") - //GET LATEST RECOVERY FILE + // Get last recovery file files, fileErr := ioutil.ReadDir(settings.RecoveryLocation) if fileErr != nil { fmt.Println("Error recovering state:", fileErr) @@ -430,14 +428,14 @@ func recoverState() { } } - //READ RECOVERY FILE + // Read file r, err := ioutil.ReadFile(settings.RecoveryLocation + "/" + newestFile) if err != nil { fmt.Println("Error recovering state:", err) return } - //CONVERT JSON TO MAP + // Convert JSON var recovery serverRestore if err = json.Unmarshal(r, &recovery); err != nil { fmt.Println("Error recovering state:", err) @@ -449,7 +447,7 @@ func recoverState() { return } - //RECOVER ROOMS + // Recover rooms for name, val := range recovery.R { room, roomErr := core.NewRoom(name, val.T, val.P, val.M, val.O) if roomErr != nil { diff --git a/sockets.go b/sockets.go index 3626edc..b90c868 100644 --- a/sockets.go +++ b/sockets.go @@ -48,7 +48,7 @@ func socketInitializer(w http.ResponseWriter, r *http.Request) { return } - //UPGRADE CONNECTION + //UPGRADE CONNECTION PING-PONG conn, err := websocket.Upgrade(w, r, w.Header(), 1024, 1024) if err != nil { http.Error(w, "Could not establish a connection.", http.StatusForbidden) From d4495f2b48631abf7159194a84be4b4738b5a8ad Mon Sep 17 00:00:00 2001 From: Dominique Debergue Date: Tue, 25 May 2021 00:10:23 -0700 Subject: [PATCH 127/132] Update README.md --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 6dc4621..dbdca7c 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,6 @@ Moreover, Gopher has a built-in, fully customizable SQL client authentication me # :video_game: Client APIs - JavaScript: [GopherClientJS](https://github.com/hewiefreeman/GopherClientJS) - - Java: ( **In development** ) > If you want to make a client API in an unsupported language and want to know where to start and/or have any questions, feel free to [email me](mailto:dominiquedebergue@gmail.com?subject=[GitHub]%20Gopher%20Game%20Server)! From 1da9c77fc228d4368d9fb953fe07cf9b72e5e4d7 Mon Sep 17 00:00:00 2001 From: Dominique Debergue Date: Sat, 29 May 2021 17:10:45 -0700 Subject: [PATCH 128/132] Create codeql-analysis.yml --- .github/workflows/codeql-analysis.yml | 71 +++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 .github/workflows/codeql-analysis.yml diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml new file mode 100644 index 0000000..91b29ba --- /dev/null +++ b/.github/workflows/codeql-analysis.yml @@ -0,0 +1,71 @@ +# For most projects, this workflow file will not need changing; you simply need +# to commit it to your repository. +# +# You may wish to alter this file to override the set of languages analyzed, +# or to provide custom queries or build logic. +# +# ******** NOTE ******** +# We have attempted to detect the languages in your repository. Please check +# the `language` matrix defined below to confirm you have the correct set of +# supported CodeQL languages. +# +name: "CodeQL" + +on: + push: + branches: [ master ] + pull_request: + # The branches below must be a subset of the branches above + branches: [ master ] + schedule: + - cron: '17 4 * * 3' + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + language: [ 'go' ] + # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] + # Learn more: + # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v1 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + # queries: ./path/to/local/query, your-org/your-repo/queries@main + + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@v1 + + # â„šī¸ Command-line programs to run using the OS shell. + # 📚 https://git.io/JvXDl + + # âœī¸ If the Autobuild fails above, remove it and uncomment the following three lines + # and modify them (or add more) to build your code if your project + # uses a compiled language + + #- run: | + # make bootstrap + # make release + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v1 From 061a1557aeb36edb8892ab89053ace64b7140e63 Mon Sep 17 00:00:00 2001 From: Dominique Debergue Date: Mon, 13 Dec 2021 20:28:59 -0800 Subject: [PATCH 129/132] SQL database setup now adds custom colums and autologs column on inital database setup. --- database/setup.go | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/database/setup.go b/database/setup.go index eb78b1f..5c37215 100644 --- a/database/setup.go +++ b/database/setup.go @@ -10,26 +10,24 @@ func setUp() error { // Check if the users table has been created _, checkErr := database.Exec("SELECT " + usersColumnName + " FROM " + tableUsers + " WHERE " + usersColumnID + "=1;") if checkErr != nil { - fmt.Println("Making all tables...") + fmt.Println("Creating \"" + tableUsers + "\" table...") // Make the users table if cErr := createUserTableSQL(); cErr != nil { return cErr } + } + // Check for new custom AccountInfoColumn items + if newItemsErr := addNewCustomItemsSQL(); newItemsErr != nil { + return newItemsErr + } - } else { - // Check for new custom AccountInfoColumn items - if newItemsErr := addNewCustomItemsSQL(); newItemsErr != nil { - return newItemsErr - } - - if rememberMe { - // Check if autologs table has been made - _, checkErr := database.Exec("SELECT " + autologsColumnID + " FROM " + tableAutologs + " WHERE " + autologsColumnID + "=1;") - if checkErr != nil { - fmt.Println("Making autologs table...") - if cErr := createAutologsTableSQL(); cErr != nil { - return cErr - } + if rememberMe { + // Check if autologs table has been made + _, checkErr := database.Exec("SELECT " + autologsColumnID + " FROM " + tableAutologs + " WHERE " + autologsColumnID + "=1;") + if checkErr != nil { + fmt.Println("Making autologs table...") + if cErr := createAutologsTableSQL(); cErr != nil { + return cErr } } } @@ -131,8 +129,8 @@ func addNewCustomItemsSQL() error { checkRows.Next() _, colsErr := checkRows.Columns() if colsErr != nil { - fmt.Println("Adding AccountInfoColumn '" + key + "'...") // The item doesn't exist yet... + fmt.Println("Adding AccountInfoColumn '" + key + "'...") query = query + "ADD COLUMN " + key + " " + dataTypes[val.dataType] if isSizeDataType(val.dataType) { query = query + "(" + strconv.Itoa(val.maxSize) + ")" From 115b55b298e0dd25b07fe834a3616017b08ce35a Mon Sep 17 00:00:00 2001 From: Dominique Debergue Date: Mon, 13 Dec 2021 20:53:13 -0800 Subject: [PATCH 130/132] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index dbdca7c..c279fda 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ Moreover, Gopher has a built-in, fully customizable SQL client authentication me - JavaScript: [GopherClientJS](https://github.com/hewiefreeman/GopherClientJS) - > If you want to make a client API in an unsupported language and want to know where to start and/or have any questions, feel free to [email me](mailto:dominiquedebergue@gmail.com?subject=[GitHub]%20Gopher%20Game%20Server)! + > If you want to make a client API in an unsupported language and want to know where to start and/or have any questions, feel free to open a new issue! # :file_folder: Installing Gopher Game Server requires at least **Go v1.8+** (and **MySQL v5.7+** for the authentication and friending features). @@ -102,7 +102,7 @@ Then install the server: # :milky_way: Contributions Contributions are open and welcomed! Help is needed for everything from documentation, cleaning up code, performance enhancements, client APIs and more. Don't forget to show your support with a :star:! -If you want to make a client API in an unsupported language and want to know where to start and/or have any questions, feel free to [email me](mailto:dominiquedebergue@gmail.com?subject=[GitHub]%20Gopher%20Game%20Server)! +If you want to make a client API in an unsupported language and want to know where to start and/or have any questions, feel free to open a new issue! Please read the following articles before submitting any contributions or filing an Issue: From c3766451b6599613960834910f4d46609e465f24 Mon Sep 17 00:00:00 2001 From: hewiefreeman <8853880+hewiefreeman@users.noreply.github.com> Date: Mon, 13 Dec 2021 21:00:28 -0800 Subject: [PATCH 131/132] updating info --- CODE_OF_CONDUCT.md | 2 +- CONTRIBUTING.md | 1 - README.md | 4 ++-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index b1e3e68..7616198 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -55,7 +55,7 @@ further defined and clarified by project maintainers. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported by contacting the project team at dominiquedebergue@gmail.com. All +reported by contacting the project team at tbd@gmail.com . All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 46fc380..0611485 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -3,7 +3,6 @@ 1) See if there is an Issue that you can take up to fix or implement 2) Help expand and clarify documentation and/or usage section 3) Have a good idea? Open and submit a detailed Issue -4) Email me with comments or recommendations directly: dominiquedebergue@gmail.com ## Guidlines diff --git a/README.md b/README.md index dbdca7c..c279fda 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ Moreover, Gopher has a built-in, fully customizable SQL client authentication me - JavaScript: [GopherClientJS](https://github.com/hewiefreeman/GopherClientJS) - > If you want to make a client API in an unsupported language and want to know where to start and/or have any questions, feel free to [email me](mailto:dominiquedebergue@gmail.com?subject=[GitHub]%20Gopher%20Game%20Server)! + > If you want to make a client API in an unsupported language and want to know where to start and/or have any questions, feel free to open a new issue! # :file_folder: Installing Gopher Game Server requires at least **Go v1.8+** (and **MySQL v5.7+** for the authentication and friending features). @@ -102,7 +102,7 @@ Then install the server: # :milky_way: Contributions Contributions are open and welcomed! Help is needed for everything from documentation, cleaning up code, performance enhancements, client APIs and more. Don't forget to show your support with a :star:! -If you want to make a client API in an unsupported language and want to know where to start and/or have any questions, feel free to [email me](mailto:dominiquedebergue@gmail.com?subject=[GitHub]%20Gopher%20Game%20Server)! +If you want to make a client API in an unsupported language and want to know where to start and/or have any questions, feel free to open a new issue! Please read the following articles before submitting any contributions or filing an Issue: From 88cc3fabb02ce24eb1c038f4f8ca8ad14317a47f Mon Sep 17 00:00:00 2001 From: Nick Debergue Date: Wed, 15 Dec 2021 16:25:29 -0800 Subject: [PATCH 132/132] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c279fda..451c4f7 100644 --- a/README.md +++ b/README.md @@ -111,7 +111,7 @@ Please read the following articles before submitting any contributions or filing
    -
    GopherGameServer and all of it's contents Copyright 2020 Dominique Debergue +
    GopherGameServer and all of it's contents Copyright 2022 Dominique Debergue
    Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at: `http://www.apache.org/licenses/LICENSE-2.0`