Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
박찬영/게임기술팀/NK committed May 11, 2017
2 parents c00b563 + 2912ee8 commit a226f22
Show file tree
Hide file tree
Showing 7 changed files with 178 additions and 65 deletions.
4 changes: 2 additions & 2 deletions Assets/Plugins/socket.io/Socket.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ public class Socket : MonoBehaviour {
onConnect();
}
else if (pkt.socketPktType == SocketPacketTypes.DISCONNECT) {
Debug.Log("Socket disconnected");
Debug.LogFormat("socket.io => {0} disconnected", gameObject.name);
}
else if (pkt.socketPktType == SocketPacketTypes.ACK) {
Debug.Assert(pkt.HasId && pkt.HasBody);
Expand Down Expand Up @@ -145,7 +145,7 @@ public class Socket : MonoBehaviour {
evtName == "reconnecting" ||
evtName == "connectError" ||
evtName == "reconnectError") {
Debug.LogErrorFormat("{0} is reserved for system events :(", evtName);
Debug.LogErrorFormat("socket.io => {0} event is reserved and not allowed to assign as user events :(", evtName);
return;
}

Expand Down
63 changes: 39 additions & 24 deletions Assets/Plugins/socket.io/SocketInitializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,22 +21,27 @@ public class SocketInitializer : MonoBehaviour {
/// <param name="url"> WWW URL of a server </param>
/// <param name="socket"> a socket which will be connected </param>
/// <returns></returns>
public IObservable<Socket> InitAsObservable(string url, Socket socket) {
_connectUrl = url;
public IObservable<Socket> InitAsObservable(string url, bool reconnection, int reconnectionAttempts, Socket socket) {
ConnectUrl = url;
Socket = socket;
Reconnection = reconnection;
ReconnectionAttempts = reconnectionAttempts;

var matches = new Regex(_urlParamRgx).Matches(_connectUrl);
if (Reconnection && Socket.onReconnecting != null)
Socket.onReconnecting(ReconnectionAttempts);

var matches = new Regex(_urlParamRgx).Matches(ConnectUrl);
foreach (var m in matches) {
var tokens = m.ToString().Split('?', '&', '=');
urlParams.Add(tokens[1], tokens[2]);
}

_baseUrl = _connectUrl.Split('?')[0];
var matches2 = new Regex(_urlNamespaceRgx).Matches(_baseUrl);
BaseUrl = ConnectUrl.Split('?')[0];
var matches2 = new Regex(_urlNamespaceRgx).Matches(BaseUrl);
Debug.Assert(matches2.Count <= 2);

if (matches2.Count == 2) {
_baseUrl = matches2[0].ToString();
BaseUrl = matches2[0].ToString();
Socket.nsp = matches2[1].ToString();
}

Expand All @@ -50,7 +55,7 @@ public class SocketInitializer : MonoBehaviour {
/// </summary>
public string PollingUrl {
get {
var builder = new StringBuilder(_baseUrl);
var builder = new StringBuilder(BaseUrl);
builder.Append("/socket.io/");

for (int i = 0; i < urlParams.Count; ++i) {
Expand All @@ -68,7 +73,7 @@ public class SocketInitializer : MonoBehaviour {
/// </summary>
public string WebSocketUrl {
get {
var builder = new StringBuilder(_baseUrl.Replace("http://", "ws://"));
var builder = new StringBuilder(BaseUrl.Replace("http://", "ws://"));
builder.Append("/socket.io/");

for (int i = 0; i < urlParams.Count; ++i) {
Expand All @@ -84,12 +89,12 @@ public class SocketInitializer : MonoBehaviour {
/// <summary>
/// An URL which is given InitAsObservable() method's param.
/// </summary>
string _connectUrl;
public string ConnectUrl { get; private set; }

/// <summary>
/// An URL which has no params and no namespace.
/// An URL which remove params and namespace string from ConnectUrl.
/// </summary>
string _baseUrl;
public string BaseUrl { get; private set; }

/// <summary>
/// Regular expression for extracting params from URL
Expand All @@ -107,7 +112,12 @@ public class SocketInitializer : MonoBehaviour {
public Dictionary<string, string> urlParams = new Dictionary<string, string>();
#endregion

public bool Reconnection { get; private set; }

public int ReconnectionAttempts { get; private set; }

public Socket Socket { get; private set; }


/// <summary>
/// Return weather Socket is current working on initialization process or not
Expand Down Expand Up @@ -139,20 +149,17 @@ class PollingUrlAnswer {
urlParams.Add("t", TimeStamp.Now);

// Try get WebSocketTrigger instance if a connection already established _baseUrl.
var webSocketTrigger = SocketManager.Instance.GetWebSocketTrigger(_baseUrl);
if (webSocketTrigger == null) {
var webSocketTrigger = SocketManager.Instance.GetWebSocketTrigger(BaseUrl);
if (webSocketTrigger == null || !webSocketTrigger.IsConnected) {
var www = new WWW(PollingUrl);
while (!www.isDone && !cancelToken.IsCancellationRequested)
yield return null;

if (cancelToken.IsCancellationRequested) {
CleanUp();
if (cancelToken.IsCancellationRequested)
yield break;
}

if (www.error != null) {
observer.OnError(new Exception(www.error));
CleanUp();
observer.OnError(new WWWErrorException(www, www.text));
yield break;
}

Expand All @@ -163,8 +170,10 @@ class PollingUrlAnswer {
urlParams.Add("sid", answer.sid);
}

webSocketTrigger = new GameObject(string.Format("webSocket - {0}", _baseUrl)).AddComponent<WebSocketTrigger>();
SocketManager.Instance.RegisterWebSocketTrigger(_baseUrl, webSocketTrigger);
if (webSocketTrigger == null) {
webSocketTrigger = new GameObject(string.Format("WebSocket - {0}", BaseUrl)).AddComponent<WebSocketTrigger>();
SocketManager.Instance.RegisterWebSocketTrigger(BaseUrl, webSocketTrigger);
}
}

urlParams["transport"] = "websocket";
Expand All @@ -187,20 +196,26 @@ class PollingUrlAnswer {
webSocketTrigger.WebSocket.Send(new Packet(EnginePacketTypes.MESSAGE, SocketPacketTypes.CONNECT, Socket.nsp, string.Empty).Encode());

// Start to receive a incoming WebSocket packet
var capturedUrl = ConnectUrl;
var capturedSocket = Socket;
webSocketTrigger.OnRecvAsObservable(WebSocketUrl).Subscribe(r => {
capturedSocket.OnRecvWebSocketEvent(r);
}, e => {
Debug.LogErrorFormat("socket.io => {0} got an error: {1}", capturedSocket.gameObject.name, e.ToString());
if (SocketManager.Instance.Reconnection)
SocketManager.Instance.Reconnect(capturedUrl, 1, capturedSocket);
}).AddTo(Socket);

observer.OnNext(Socket);
observer.OnCompleted();

CleanUp();
}

void CleanUp() {
public void CleanUp() {
Socket = null;
_connectUrl = string.Empty;
ConnectUrl = string.Empty;
Reconnection = false;
ReconnectionAttempts = 0;
urlParams.Clear();
}

Expand Down
107 changes: 96 additions & 11 deletions Assets/Plugins/socket.io/SocketManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,24 +13,63 @@ namespace socket.io {
/// </summary>
public class SocketManager : MonoSingleton<SocketManager> {

/// <summary>
/// connection timeout before a connect_error and connect_timeout events are emitted
/// (The default value is 20000 and the unit is millisecond.)
/// </summary>
public int TimeOut { get; set; }

/// <summary>
/// whether to reconnect automatically (The default value is true)
/// </summary>
public bool Reconnection { get; set; }

/// <summary>
/// number of reconnection attempts before giving up (The default value is infinity)
/// </summary>
public int ReconnectionAttempts { get; set; }

/// <summary>
/// how long to initially wait before attempting a new reconnection
/// (The default value is 1000 and the unit is millisecond.)
/// </summary>
public int ReconnectionDelay { get; set; }


public Socket Connect(string url) {
var socket = new GameObject(string.Format("socket.io - {0}", url)).AddComponent<Socket>();
socket.transform.parent = transform;

_connectRequests.Enqueue(Tuple.Create<string, Socket>(url, socket));
_connectRequests.Add(Tuple.Create(url, false, 0, socket, DateTime.Now));

return socket;
}


public void Reconnect(string url, int reconnectionAttempts, Socket socket) {
_connectRequests.Add(Tuple.Create(url, true, reconnectionAttempts, socket, DateTime.Now.AddMilliseconds(ReconnectionDelay)));

if (socket.onReconnectAttempt != null)
socket.onReconnectAttempt();

Debug.LogFormat("socket.io => {0} attempts to reconnect", socket.gameObject.name);
}

void Awake() {
TimeOut = 20000;
Reconnection = true;
ReconnectionAttempts = int.MaxValue;
ReconnectionDelay = 1000;

_socketInit = gameObject.AddComponent<SocketInitializer>();
}

SocketInitializer _socketInit;

/// <summary>
/// The pended requests to connect a server
/// (Item1: Url, Item2: Reconnection, Item3: ReconnectionAttempts, Item4: Socket ref, Item5: TimeStamp)
/// </summary>
readonly Queue<Tuple<string, Socket>> _connectRequests = new Queue<Tuple<string, Socket>>();
readonly List<Tuple<string, bool, int, Socket, DateTime>> _connectRequests = new List<Tuple<string, bool, int, Socket, DateTime>>();

/// <summary>
/// WebSocketTrigger instances (WebSocketTrigger is almost same with a sesstion object)
Expand All @@ -54,24 +93,70 @@ public class SocketManager : MonoSingleton<SocketManager> {
return (go != null) ? go.GetComponent<Socket>() : null;
}

void Update() {
int i = 0;
}

void Start() {
gameObject.UpdateAsObservable()
.Sample(TimeSpan.FromSeconds(1f))
.Where(_ => _connectRequests.Count > 0 && !_socketInit.IsBusy)
.Select(_ => _connectRequests.Dequeue())
.SelectMany(c => _socketInit.InitAsObservable(c.Item1, c.Item2).Timeout(TimeSpan.FromSeconds(10f)))
.Subscribe(_ => {
Debug.LogFormat("{0} has been inited~ :)", _socketInit.Socket.gameObject.name);
}, e => {
.Where(_ => !_socketInit.IsBusy && _connectRequests.Any(c => c.Item5 < DateTime.Now))
.Select(_ => {
var i = _connectRequests.FindIndex(c => c.Item5 < DateTime.Now);
Debug.Assert(i != -1);
var ret = _connectRequests[i];
_connectRequests.RemoveAt(i);
return ret;
})
.SelectMany(c =>
_socketInit.InitAsObservable(c.Item1, c.Item2, c.Item3, c.Item4)
.Timeout(TimeSpan.FromMilliseconds(TimeOut))
)
.OnErrorRetry((Exception e) => {
if (e is TimeoutException) {
if (_socketInit.Socket.onConnectTimeOut != null)
_socketInit.Socket.onConnectTimeOut();
Debug.LogError("The connect trial is timed out!!");
Debug.LogErrorFormat("socket.io => {0} connection timed out!!", _socketInit.Socket.gameObject.name);
}
else if (e is WWWErrorException){
Debug.LogErrorFormat("socket.io => {0} got WWW error: {1}", _socketInit.Socket.gameObject.name, (e as WWWErrorException).RawErrorMessage);
}
else {
Debug.LogError("Unknown exception!!");
Debug.LogErrorFormat("socket.io => {0} got an unknown error: {1}", _socketInit.Socket.gameObject.name, e.ToString());
}
if (_socketInit.Reconnection) {
if (_socketInit.Socket.onReconnectFailed != null)
_socketInit.Socket.onReconnectFailed();
if (_socketInit.Socket.onReconnectError != null)
_socketInit.Socket.onReconnectError(e);
if (Reconnection)
Reconnect(_socketInit.ConnectUrl, _socketInit.ReconnectionAttempts + 1, _socketInit.Socket);
}
else {
if (_socketInit.Socket.onConnectError != null)
_socketInit.Socket.onConnectError(e);
}
_socketInit.CleanUp();
})
.Subscribe(_ => {
if (_socketInit.Reconnection) {
if (_socketInit.Socket.onReconnect != null)
_socketInit.Socket.onReconnect(_socketInit.ReconnectionAttempts);
Debug.LogFormat("socket.io => {0} has been reconnected~ :)", _socketInit.Socket.gameObject.name);
}
else {
Debug.LogFormat("socket.io => {0} has been connected~ :)", _socketInit.Socket.gameObject.name);
}
_socketInit.CleanUp();
});
}

Expand Down
Loading

0 comments on commit a226f22

Please sign in to comment.