#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