diff --git a/CHANGELOG.rst b/CHANGELOG.rst index da38576..1f7f662 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,7 +2,26 @@ Changelog ========= -v2.1.7 (24-10-2017) +v2.1.9 (29-10-2017) +------------------- + +Fix +~~~ +- Fixed server freezing issues. [Jordan Dalton] + + So, apparently the old resource would freeze the server when players left and when writing. A bunch of shit would break it and freeze the main thread. This fixes those issues and should make the resource usable... + + The client list has now been changed to a ConcurrentDictionary because I thought my locks and stuff was breaking.. Turns out wasn't the problem. + + Also fixed a error where the "playerLeft" would trigger when a player isn't in the "playerData" object. +- Fixed changelog. [Jordan Dalton] + +Other +~~~~~ +- Merge branch 'develop' [Jordan Dalton] + + +v2.1.8 (24-10-2017) ------------------- New @@ -10,16 +29,13 @@ New - Add livemap_milliseconds to convars. [Jordan Dalton] Users can now change how often the data gets sent to the websockets by changing a variable in the server.cfg -- Add error handling to update_check. [Jordan Dalton] - - Hopefully the user gets an error if the resource can't read the contents of "version.json". Changes ~~~~~~~ +- Update changelog. [Jordan Dalton] - Update versions.json. [Jordan Dalton] Version is now 2.1.7 -- Update changelog. [Jordan Dalton] Fix ~~~ @@ -30,6 +46,20 @@ Fix Tasks now wait until they have sent the data to one socket before sending data to the next. +v2.1.7 (21-10-2017) +------------------- + +New +~~~ +- Add error handling to update_check. [Jordan Dalton] + + Hopefully the user gets an error if the resource can't read the contents of "version.json". + +Changes +~~~~~~~ +- Update changelog. [Jordan Dalton] + + v2.1.6 (20-10-2017) ------------------- diff --git a/src/Live Map/SocketHandler.cs b/src/Live Map/SocketHandler.cs index 3c71114..511d121 100644 --- a/src/Live Map/SocketHandler.cs +++ b/src/Live Map/SocketHandler.cs @@ -1,5 +1,6 @@ using Newtonsoft.Json.Linq; using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Text; @@ -34,13 +35,12 @@ class SocketHandler WebSocketServer server; JObject playerData; - List clients; + ConcurrentDictionary clients = new ConcurrentDictionary(); public SocketHandler(WebSocketServer server) { this.server = server; playerData = new JObject(); - clients = new List(); server.OnConnect += Server_OnConnect; server.OnDisconnect += Server_OnDisconnect; @@ -57,28 +57,51 @@ private void Server_OnMessage(WebSocket ws, string msg) private void Server_OnError(WebSocket ws, Exception ex) { LiveMap.Log(LiveMap.LogLevel.Basic, "Socket error from {0}: {1}", ws == null ? "Unknown" : ws.RemoteEndpoint.ToString(), ex.Message); - lock (clients) + + if (ws != null) { - clients.Remove(ws); + WebSocket destory; + if (clients.TryRemove(ws.RemoteEndpoint.ToString(), out destory)) + { + destory.Dispose(); + LiveMap.Log(LiveMap.LogLevel.All, "Removed {0} socket because of an error: {1}\nInner: {2}", ws.RemoteEndpoint.ToString(), ex.Message, ex.InnerException); + } + else + { + LiveMap.Log(LiveMap.LogLevel.All, "Couldn't remove {0} from the clients dic.", ws.RemoteEndpoint.ToString()); + } } + } private void Server_OnDisconnect(WebSocket ws) { LiveMap.Log(LiveMap.LogLevel.Basic, "Socket connection was closed at {0}", ws.RemoteEndpoint.ToString()); - lock (clients) + + WebSocket destory; + if (clients.TryRemove(ws.RemoteEndpoint.ToString(), out destory)) + { + destory.Dispose(); + LiveMap.Log(LiveMap.LogLevel.All, "Removed {0} socket because it disconnected", ws.RemoteEndpoint.ToString()); + } + else { - clients.Remove(ws); + LiveMap.Log(LiveMap.LogLevel.All, "Couldn't remove {0} from the clients dic.", ws.RemoteEndpoint.ToString()); } } private void Server_OnConnect(WebSocket ws) { LiveMap.Log(LiveMap.LogLevel.Basic, "Socket connection opened at {0}", ws.RemoteEndpoint.ToString()); - lock (clients) + + if(clients.TryAdd(ws.RemoteEndpoint.ToString(), ws)) + { + LiveMap.Log(LiveMap.LogLevel.All, "Added client {0} to the client dictionary", ws.RemoteEndpoint.ToString()); + }else { - clients.Add(ws); + LiveMap.Log(LiveMap.LogLevel.All, "Couldn't add {0} to the client dic", ws.RemoteEndpoint.ToString()); } + } private void MakeSurePlayerExists(string identifier) @@ -97,6 +120,7 @@ public async Task SendWebsocketData() { while (true) { + // Only send the data every .5 seconds await Task.Delay(TimeSpan.FromMilliseconds(LiveMap.waitSeconds)).ConfigureAwait(false); @@ -118,6 +142,24 @@ public async Task SendWebsocketData() payload["type"] = "playerData"; payload["payload"] = playerDataArray; + foreach(KeyValuePair keyPair in clients) + { + string endpoint = keyPair.Key; + WebSocket socket = keyPair.Value; + LiveMap.Log(LiveMap.LogLevel.All, "Sending data to {0}", endpoint); + + if (!socket.IsConnected) + { + LiveMap.Log(LiveMap.LogLevel.All, "Disposing of websocket {0} because it's closed..", endpoint); + socket.Dispose(); + return; + } + + LiveMap.Log(LiveMap.LogLevel.All, "Waiting async write to {0}", endpoint); + await socket.WriteStringAsync(payload.ToString(Newtonsoft.Json.Formatting.None)).ConfigureAwait(false); + LiveMap.Log(LiveMap.LogLevel.All, "Written to {0}", endpoint); + } + /* lock (clients) { foreach(WebSocket ws in clients) @@ -128,7 +170,7 @@ public async Task SendWebsocketData() } } } - + */ } } @@ -195,39 +237,70 @@ public void RemovePlayerData(string identifier, string key) } } - public void RemovePlayer(string identifier) + public async void RemovePlayer(string identifier) { + bool playerLeftBool = false; lock (playerData) { if (playerData[identifier] != null) { if (playerData.Remove(identifier)) { + playerLeftBool = true; LiveMap.Log(LiveMap.LogLevel.Basic, "Removed player {0}", identifier); - }else + } + else { LiveMap.Log(LiveMap.LogLevel.Basic, "Couldn't remove player {0}... Seriously, there's something fucking wrong here...", identifier); } } } - //LiveMap.Log(LiveMap.LogLevel.All, "Notifying ws clients that a player left."); - // Tell the client's that someone has left - lock (clients) + LiveMap.Log(LiveMap.LogLevel.All, "Notifying ws clients that a player left? {0}", playerLeftBool); + + if (playerLeftBool) + { + // Tell the client's that someone has left + + JObject payload = new JObject(); + payload["type"] = "playerLeft"; + payload["payload"] = identifier; + + foreach (KeyValuePair pair in clients) + { + string endpoint = pair.Key; + WebSocket ws = pair.Value; + + if (!ws.IsConnected) + { + LiveMap.Log(LiveMap.LogLevel.All, "Disposing of websocket {0} because it's closed..", endpoint); + ws.Dispose(); + return; + } + + LiveMap.Log(LiveMap.LogLevel.Basic, "Sending playerleft payload to {0} for player: {1}", endpoint, identifier); + + await ws.WriteStringAsync(payload.ToString(Newtonsoft.Json.Formatting.None)).ConfigureAwait(false); + + LiveMap.Log(LiveMap.LogLevel.All, "Sent playerleft payload to {0}", endpoint); + } + } + + /*lock (clients) { foreach (WebSocket s in clients) { JObject payload = new JObject(); payload["type"] = "playerLeft"; payload["payload"] = identifier; - //LiveMap.Log(LiveMap.LogLevel.All, "Sending playerLeft payload for {0}", identifier); + LiveMap.Log(LiveMap.LogLevel.All, "Sending playerLeft payload for {0} to {1}", identifier, s.RemoteEndpoint); if (s.IsConnected) { - //LiveMap.Log(LiveMap.LogLevel.All, "Sent PlayerLeft payload to {0}", s.RemoteEndpoint); + LiveMap.Log(LiveMap.LogLevel.All, "Sent PlayerLeft payload to {0}", s.RemoteEndpoint); s.WriteStringAsync(payload.ToString(Newtonsoft.Json.Formatting.None), CancellationToken.None).Wait(); } } - } + }*/ } diff --git a/src/Live Map/WebSocketServer.cs b/src/Live Map/WebSocketServer.cs index 0f9ec60..e6e8ca0 100644 --- a/src/Live Map/WebSocketServer.cs +++ b/src/Live Map/WebSocketServer.cs @@ -45,14 +45,14 @@ public WebSocketServer(int port) } - public void Start() + public async void Start() { - listener.StartAsync().Wait(); + await listener.StartAsync(); } - public void Stop() + public async void Stop() { - listener.StopAsync().Wait(); + await listener.StopAsync(); } public async Task ListenAsync() @@ -70,6 +70,7 @@ public async Task ListenAsync() }catch(Exception ex) { + LiveMap.Log(LiveMap.LogLevel.Basic, "Error in ListenAsync:\n{0}\n---Inner:\n{1} ", ex.Message, ex.InnerException); if (OnError != null) OnError.Invoke(null, ex); } @@ -96,6 +97,7 @@ private async Task HandleSocket(WebSocket ws) }catch(Exception e) { + LiveMap.Log(LiveMap.LogLevel.Basic, "Error in HandleSocket:\n{0}\n---Inner:\n{1}", e.Message, e.InnerException); if (OnError != null) OnError.Invoke(ws, e); } diff --git a/version.json b/version.json index acb3408..27624bc 100644 --- a/version.json +++ b/version.json @@ -1,3 +1,3 @@ { - "resource" : "2.1.8" + "resource" : "2.1.10" }