#if !BESTHTTP_DISABLE_SOCKETIO using System; using System.Collections.Generic; using UnityEngine; using BestHTTP.SocketIO; using BestHTTP.Examples; public sealed class SocketIOChatSample : MonoBehaviour { private readonly TimeSpan TYPING_TIMER_LENGTH = TimeSpan.FromMilliseconds(700); private enum ChatStates { Login, Chat } #region Fields /// /// The Socket.IO manager instance. /// private SocketManager Manager; /// /// Current state of the chat demo. /// private ChatStates State; /// /// The selected nickname /// private string userName = string.Empty; /// /// Currently typing message /// private string message = string.Empty; /// /// Sent and received messages. /// private string chatLog = string.Empty; /// /// Position of the scroller /// private Vector2 scrollPos; /// /// True if the user is currently typing /// private bool typing; /// /// When the message changed. /// private DateTime lastTypingTime = DateTime.MinValue; /// /// Users that typing. /// private List typingUsers = new List(); #endregion #region Unity Events void Start() { // The current state is Login State = ChatStates.Login; // Change an option to show how it should be done SocketOptions options = new SocketOptions(); options.AutoConnect = false; // Create the Socket.IO manager Manager = new SocketManager(new Uri("https://socket-io-chat.now.sh/socket.io/"), options); // SaveLocal up custom chat events Manager.Socket.On("login", OnLogin); Manager.Socket.On("new message", OnNewMessage); Manager.Socket.On("user joined", OnUserJoined); Manager.Socket.On("user left", OnUserLeft); Manager.Socket.On("typing", OnTyping); Manager.Socket.On("stop typing", OnStopTyping); // The argument will be an Error object. Manager.Socket.On(SocketIOEventTypes.Error, (socket, packet, args) => Debug.LogError(string.Format("Error: {0}", args[0].ToString()))); Manager.GetSocket("/nsp").On(SocketIOEventTypes.Connect, (socket, packet, arg) => { Debug.LogWarning("Connected to /nsp"); socket.Emit("testmsg", "Message from /nsp 'on connect'"); }); Manager.GetSocket("/nsp").On("nsp_message", (socket, packet, arg) => { Debug.LogWarning("nsp_message: " + arg[0]); }); // We set SocketOptions' AutoConnect to false, so we have to call it manually. Manager.Open(); } void OnDestroy() { // Leaving this sample, close the socket Manager.Close(); } void Update() { // Go back to the demo selector if (Input.GetKeyDown(KeyCode.Escape)) SampleSelector.SelectedSample.DestroyUnityObject(); // Stop typing if some time passed without typing if (typing) { var typingTimer = DateTime.UtcNow; var timeDiff = typingTimer - lastTypingTime; if (timeDiff >= TYPING_TIMER_LENGTH) { Manager.Socket.Emit("stop typing"); typing = false; } } } void OnGUI() { switch(State) { case ChatStates.Login: DrawLoginScreen(); break; case ChatStates.Chat: DrawChatScreen(); break; } } #endregion #region Chat Logic /// /// Called from an OnGUI event to draw the Login Screen. /// void DrawLoginScreen() { GUIHelper.DrawArea(GUIHelper.ClientArea, true, () => { GUILayout.BeginVertical(); GUILayout.FlexibleSpace(); GUIHelper.DrawCenteredText("What's your nickname?"); userName = GUILayout.TextField(userName); if (GUILayout.Button("Join")) SetUserName(); GUILayout.FlexibleSpace(); GUILayout.EndVertical(); }); } /// /// Called from an OnGUI event to draw the Chat Screen. /// void DrawChatScreen() { GUIHelper.DrawArea(GUIHelper.ClientArea, true, () => { GUILayout.BeginVertical(); scrollPos = GUILayout.BeginScrollView(scrollPos); GUILayout.Label(chatLog, GUILayout.ExpandWidth(true), GUILayout.ExpandHeight(true)); GUILayout.EndScrollView(); string typing = string.Empty; if (typingUsers.Count > 0) { typing += string.Format("{0}", typingUsers[0]); for (int i = 1; i < typingUsers.Count; ++i) typing += string.Format(", {0}", typingUsers[i]); if (typingUsers.Count == 1) typing += " is typing!"; else typing += " are typing!"; } GUILayout.Label(typing); GUILayout.Label("Type here:"); GUILayout.BeginHorizontal(); message = GUILayout.TextField(message); if (GUILayout.Button("Send", GUILayout.MaxWidth(100))) SendMessage(); GUILayout.EndHorizontal(); if (GUI.changed) UpdateTyping(); GUILayout.EndVertical(); }); } void SetUserName() { if (string.IsNullOrEmpty(userName)) return; State = ChatStates.Chat; Manager.Socket.Emit("add user", userName); } void SendMessage() { if (string.IsNullOrEmpty(message)) return; Manager.Socket.Emit("new message", message); chatLog += string.Format("{0}: {1}\n", userName, message); message = string.Empty; } void UpdateTyping() { if (!typing) { typing = true; Manager.Socket.Emit("typing"); } lastTypingTime = DateTime.UtcNow; } void addParticipantsMessage(Dictionary data) { int numUsers = Convert.ToInt32(data["numUsers"]); if (numUsers == 1) chatLog += "there's 1 participant\n"; else chatLog += "there are " + numUsers + " participants\n"; } void addChatMessage(Dictionary data) { var username = data["username"] as string; var msg = data["message"] as string; chatLog += string.Format("{0}: {1}\n", username, msg); } void AddChatTyping(Dictionary data) { var username = data["username"] as string; typingUsers.Add(username); } void RemoveChatTyping(Dictionary data) { var username = data["username"] as string; int idx = typingUsers.FindIndex((name) => name.Equals(username)); if (idx != -1) typingUsers.RemoveAt(idx); } #endregion #region Custom SocketIO Events void OnLogin(Socket socket, Packet packet, params object[] args) { chatLog = "Welcome to Socket.IO Chat — \n"; addParticipantsMessage(args[0] as Dictionary); } void OnNewMessage(Socket socket, Packet packet, params object[] args) { addChatMessage(args[0] as Dictionary); } void OnUserJoined(Socket socket, Packet packet, params object[] args) { var data = args[0] as Dictionary; var username = data["username"] as string; chatLog += string.Format("{0} joined\n", username); addParticipantsMessage(data); } void OnUserLeft(Socket socket, Packet packet, params object[] args) { var data = args[0] as Dictionary; var username = data["username"] as string; chatLog += string.Format("{0} left\n", username); addParticipantsMessage(data); } void OnTyping(Socket socket, Packet packet, params object[] args) { AddChatTyping(args[0] as Dictionary); } void OnStopTyping(Socket socket, Packet packet, params object[] args) { RemoveChatTyping(args[0] as Dictionary); } #endregion } #endif