SocketIOChatSample.cs 9.1 KB

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