SocketIOChatSample.cs 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  1. #if !BESTHTTP_DISABLE_SOCKETIO
  2. using System;
  3. using System.Collections.Generic;
  4. using UnityEngine;
  5. using BestHTTP.SocketIO;
  6. using BestHTTP.Examples;
  7. public sealed class SocketIOChatSample : MonoBehaviour
  8. {
  9. private readonly TimeSpan TYPING_TIMER_LENGTH = TimeSpan.FromMilliseconds(700);
  10. private enum ChatStates
  11. {
  12. Login,
  13. Chat
  14. }
  15. #region Fields
  16. /// <summary>
  17. /// The Socket.IO manager instance.
  18. /// </summary>
  19. private SocketManager Manager;
  20. /// <summary>
  21. /// Current state of the chat demo.
  22. /// </summary>
  23. private ChatStates State;
  24. /// <summary>
  25. /// The selected nickname
  26. /// </summary>
  27. private string userName = string.Empty;
  28. /// <summary>
  29. /// Currently typing message
  30. /// </summary>
  31. private string message = string.Empty;
  32. /// <summary>
  33. /// Sent and received messages.
  34. /// </summary>
  35. private string chatLog = string.Empty;
  36. /// <summary>
  37. /// Position of the scroller
  38. /// </summary>
  39. private Vector2 scrollPos;
  40. /// <summary>
  41. /// True if the user is currently typing
  42. /// </summary>
  43. private bool typing;
  44. /// <summary>
  45. /// When the message changed.
  46. /// </summary>
  47. private DateTime lastTypingTime = DateTime.MinValue;
  48. /// <summary>
  49. /// Users that typing.
  50. /// </summary>
  51. private List<string> typingUsers = new List<string>();
  52. #endregion
  53. #region Unity Events
  54. void Start()
  55. {
  56. // The current state is Login
  57. State = ChatStates.Login;
  58. // Change an option to show how it should be done
  59. SocketOptions options = new SocketOptions();
  60. options.AutoConnect = false;
  61. // Create the Socket.IO manager
  62. Manager = new SocketManager(new Uri("https://socket-io-chat.now.sh/socket.io/"), options);
  63. // SaveLocal up custom chat events
  64. Manager.Socket.On("login", OnLogin);
  65. Manager.Socket.On("new message", OnNewMessage);
  66. Manager.Socket.On("user joined", OnUserJoined);
  67. Manager.Socket.On("user left", OnUserLeft);
  68. Manager.Socket.On("typing", OnTyping);
  69. Manager.Socket.On("stop typing", OnStopTyping);
  70. // The argument will be an Error object.
  71. Manager.Socket.On(SocketIOEventTypes.Error, (socket, packet, args) => Debug.LogError(string.Format("Error: {0}", args[0].ToString())));
  72. Manager.GetSocket("/nsp").On(SocketIOEventTypes.Connect, (socket, packet, arg) => {
  73. Debug.LogWarning("Connected to /nsp");
  74. socket.Emit("testmsg", "Message from /nsp 'on connect'");
  75. });
  76. Manager.GetSocket("/nsp").On("nsp_message", (socket, packet, arg) => {
  77. Debug.LogWarning("nsp_message: " + arg[0]);
  78. });
  79. // We set SocketOptions' AutoConnect to false, so we have to call it manually.
  80. Manager.Open();
  81. }
  82. void OnDestroy()
  83. {
  84. // Leaving this sample, close the socket
  85. Manager.Close();
  86. }
  87. void Update()
  88. {
  89. // Go back to the demo selector
  90. if (Input.GetKeyDown(KeyCode.Escape))
  91. SampleSelector.SelectedSample.DestroyUnityObject();
  92. // Stop typing if some time passed without typing
  93. if (typing)
  94. {
  95. var typingTimer = DateTime.UtcNow;
  96. var timeDiff = typingTimer - lastTypingTime;
  97. if (timeDiff >= TYPING_TIMER_LENGTH)
  98. {
  99. Manager.Socket.Emit("stop typing");
  100. typing = false;
  101. }
  102. }
  103. }
  104. void OnGUI()
  105. {
  106. switch(State)
  107. {
  108. case ChatStates.Login: DrawLoginScreen(); break;
  109. case ChatStates.Chat: DrawChatScreen(); break;
  110. }
  111. }
  112. #endregion
  113. #region Chat Logic
  114. /// <summary>
  115. /// Called from an OnGUI event to draw the Login Screen.
  116. /// </summary>
  117. void DrawLoginScreen()
  118. {
  119. GUIHelper.DrawArea(GUIHelper.ClientArea, true, () =>
  120. {
  121. GUILayout.BeginVertical();
  122. GUILayout.FlexibleSpace();
  123. GUIHelper.DrawCenteredText("What's your nickname?");
  124. userName = GUILayout.TextField(userName);
  125. if (GUILayout.Button("Join"))
  126. SetUserName();
  127. GUILayout.FlexibleSpace();
  128. GUILayout.EndVertical();
  129. });
  130. }
  131. /// <summary>
  132. /// Called from an OnGUI event to draw the Chat Screen.
  133. /// </summary>
  134. void DrawChatScreen()
  135. {
  136. GUIHelper.DrawArea(GUIHelper.ClientArea, true, () =>
  137. {
  138. GUILayout.BeginVertical();
  139. scrollPos = GUILayout.BeginScrollView(scrollPos);
  140. GUILayout.Label(chatLog, GUILayout.ExpandWidth(true), GUILayout.ExpandHeight(true));
  141. GUILayout.EndScrollView();
  142. string typing = string.Empty;
  143. if (typingUsers.Count > 0)
  144. {
  145. typing += string.Format("{0}", typingUsers[0]);
  146. for (int i = 1; i < typingUsers.Count; ++i)
  147. typing += string.Format(", {0}", typingUsers[i]);
  148. if (typingUsers.Count == 1)
  149. typing += " is typing!";
  150. else
  151. typing += " are typing!";
  152. }
  153. GUILayout.Label(typing);
  154. GUILayout.Label("Type here:");
  155. GUILayout.BeginHorizontal();
  156. message = GUILayout.TextField(message);
  157. if (GUILayout.Button("Send", GUILayout.MaxWidth(100)))
  158. SendMessage();
  159. GUILayout.EndHorizontal();
  160. if (GUI.changed)
  161. UpdateTyping();
  162. GUILayout.EndVertical();
  163. });
  164. }
  165. void SetUserName()
  166. {
  167. if (string.IsNullOrEmpty(userName))
  168. return;
  169. State = ChatStates.Chat;
  170. Manager.Socket.Emit("add user", userName);
  171. }
  172. void SendMessage()
  173. {
  174. if (string.IsNullOrEmpty(message))
  175. return;
  176. Manager.Socket.Emit("new message", message);
  177. chatLog += string.Format("{0}: {1}\n", userName, message);
  178. message = string.Empty;
  179. }
  180. void UpdateTyping()
  181. {
  182. if (!typing)
  183. {
  184. typing = true;
  185. Manager.Socket.Emit("typing");
  186. }
  187. lastTypingTime = DateTime.UtcNow;
  188. }
  189. void addParticipantsMessage(Dictionary<string, object> data)
  190. {
  191. int numUsers = Convert.ToInt32(data["numUsers"]);
  192. if (numUsers == 1)
  193. chatLog += "there's 1 participant\n";
  194. else
  195. chatLog += "there are " + numUsers + " participants\n";
  196. }
  197. void addChatMessage(Dictionary<string, object> data)
  198. {
  199. var username = data["username"] as string;
  200. var msg = data["message"] as string;
  201. chatLog += string.Format("{0}: {1}\n", username, msg);
  202. }
  203. void AddChatTyping(Dictionary<string, object> data)
  204. {
  205. var username = data["username"] as string;
  206. typingUsers.Add(username);
  207. }
  208. void RemoveChatTyping(Dictionary<string, object> data)
  209. {
  210. var username = data["username"] as string;
  211. int idx = typingUsers.FindIndex((name) => name.Equals(username));
  212. if (idx != -1)
  213. typingUsers.RemoveAt(idx);
  214. }
  215. #endregion
  216. #region Custom SocketIO Events
  217. void OnLogin(Socket socket, Packet packet, params object[] args)
  218. {
  219. chatLog = "Welcome to Socket.IO Chat — \n";
  220. addParticipantsMessage(args[0] as Dictionary<string, object>);
  221. }
  222. void OnNewMessage(Socket socket, Packet packet, params object[] args)
  223. {
  224. addChatMessage(args[0] as Dictionary<string, object>);
  225. }
  226. void OnUserJoined(Socket socket, Packet packet, params object[] args)
  227. {
  228. var data = args[0] as Dictionary<string, object>;
  229. var username = data["username"] as string;
  230. chatLog += string.Format("{0} joined\n", username);
  231. addParticipantsMessage(data);
  232. }
  233. void OnUserLeft(Socket socket, Packet packet, params object[] args)
  234. {
  235. var data = args[0] as Dictionary<string, object>;
  236. var username = data["username"] as string;
  237. chatLog += string.Format("{0} left\n", username);
  238. addParticipantsMessage(data);
  239. }
  240. void OnTyping(Socket socket, Packet packet, params object[] args)
  241. {
  242. AddChatTyping(args[0] as Dictionary<string, object>);
  243. }
  244. void OnStopTyping(Socket socket, Packet packet, params object[] args)
  245. {
  246. RemoveChatTyping(args[0] as Dictionary<string, object>);
  247. }
  248. #endregion
  249. }
  250. #endif