using System;
using System.Net;
using System.Net.Sockets;
using System.Collections.Generic;
using Holo.Managers;
using Holo.Virtual.Users;
using Holo.Virtual.Rooms;
using System.Collections;
namespace Holo.Socketservers
{
///
/// Asynchronous socket server for the MUS connections.
///
public static class musSocketServer
{
private static Socket socketHandler;
private static int _Port;
private static string _musHost;
///
/// Initializes the socket listener for MUS connections and starts listening.
///
/// The port where the socket listener should be bound to.
///
internal static bool Init(int bindPort, string musHost)
{
_Port = bindPort;
_musHost = musHost;
socketHandler = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
Out.WriteLine("Starting up asynchronous socket server for MUS connections for port " + bindPort + "...");
try
{
socketHandler.Bind(new IPEndPoint(IPAddress.Any, bindPort));
socketHandler.Listen(25);
socketHandler.BeginAccept(new AsyncCallback(connectionRequest), socketHandler);
Out.WriteLine("Asynchronous socket server for MUS connections running on port " + bindPort);
Out.WriteLine("Listening for MUS connections from " + musHost);
return true;
}
catch
{
Out.WriteError("Error while setting up asynchronous socket server for MUS connections on port " + bindPort);
Out.WriteError("Port " + bindPort + " could be invalid or in use already.");
return false;
}
}
private static void connectionRequest(IAsyncResult iAr)
{
Socket newSocket = ((Socket)iAr.AsyncState).EndAccept(iAr);
if (newSocket.RemoteEndPoint.ToString().Split(':')[0] != _musHost)
{
newSocket.Close();
return;
}
musConnection newConnection = new musConnection(newSocket);
socketHandler.BeginAccept(new AsyncCallback(connectionRequest), socketHandler);
}
///
/// Represents an asynchronous, one time usage, socket connection between the emulator and HoloCMS, used for various live updates between site & server.
///
private class musConnection
{
private Socket Connector;
private byte[] dataBuffer = new byte[10001];
///
/// Initializes the musConnection and listens for one single packet, processes it and closes the connection. On any error, the connection is closed.
///
/// The socket of the musConnection.
internal musConnection(Socket Connector)
{
this.Connector = Connector;
Connector.BeginReceive(dataBuffer, 0, dataBuffer.Length, SocketFlags.None, new AsyncCallback(dataArrival), null);
}
///
/// Called when a packet is received, the packet will be processed and the connection will be closed (after processing packet) in all cases. No errors will be thrown.
///
///
private void dataArrival(IAsyncResult iAr)
{
try
{
int bytesReceived = Connector.EndReceive(iAr);
string Data = System.Text.Encoding.ASCII.GetString(dataBuffer, 0, bytesReceived);
string musHeader = Data.Substring(0, 4);
string[] musData = Data.Substring(4).Split(Convert.ToChar(2));
Out.WriteLine("DATA: " + Data);
#region MUS trigger commands
// Unsafe code, but on any error it jumps to the catch block & disconnects the socket
switch (musHeader)
{
case "HKTM": // Housekeeping - textmessage [BK] :: "HKTM123This is a test message to user with ID 123"
{
int userID = int.Parse(musData[0]);
string Message = musData[1];
if (userManager.containsUser(userID))
userManager.getUser(userID).sendData("BK" + Message);
break;
}
case "HKMW": // Housekeeping - alert user [mod warn] :: "HKMW123This is a test mod warn to user with ID 123"
{
int userID = int.Parse(musData[0]);
string Message = musData[1];
if (userManager.containsUser(userID))
userManager.getUser(userID).sendData("B!" + Message + Convert.ToChar(2));
break;
}
case "HKUK": // Housekeeping - kick user from room [mod warn] :: "HKUK123This is a test kick from room + modwarn for user with ID 123"
{
int userID = int.Parse(musData[0]);
string Message = musData[1];
virtualUser User = userManager.getUser(userID);
if (User.Room != null)
User.Room.removeUser(User.roomUser.roomUID, true, Message);
break;
}
case "HKAR": // Housekeeping - alert certain rank with BK message, contains flag to include users with higher rank :: "HKAR11This is a test message for all users with rank 1 and higher, so kindof a Hotel alert :D"
{
byte Rank = byte.Parse(musData[0]);
bool includeHigher = (musData[1] == "1");
string Message = musData[2];
userManager.sendToRank(Rank, includeHigher, "BK" + Message);
break;
}
case "HKSB": // Housekeeping - ban user & kick from room :: "HKSB123This is a test ban for user with ID 123"
{
int userID = int.Parse(musData[0]);
string Message = musData[1];
virtualUser User = userManager.getUser(userID);
User.sendData("@c" + Message);
User.Disconnect(1000);
break;
}
case "HKRC": // Housekeeping - rehash catalogue :: "HKRC"
{
catalogueManager.Init(false);
break;
}
case "UPRA": // User profile - reload figure, sex and mission (poof!)
{
int userID = int.Parse(musData[0]);
if (userManager.containsUser(userID))
userManager.getUser(userID).refreshAppearance(true, true, true);
break;
}
case "UPRC": // User profile - reload credits
{
int userID = int.Parse(musData[0]);
userManager.getUser(userID).refreshValueables(true, false);
break;
}
case "UPRT": // User profile - reload tickets
{
int userID = int.Parse(musData[0]);
if (userManager.containsUser(userID))
userManager.getUser(userID).refreshValueables(false, true);
break;
}
case "UPRS": // User profile - reload subscription (and badges)
{
int userID = int.Parse(musData[0]);
if (userManager.containsUser(userID))
{
virtualUser User = userManager.getUser(userID);
User.refreshClub();
User.refreshBadges();
}
break;
}
case "UPRH":// User profile - reload hand
{
int userID = int.Parse(musData[0]);
if (userManager.containsUser(userID))
userManager.getUser(userID).refreshHand("new");
break;
}
}
#endregion
}
catch { }
finally {killConnection();}
}
///
/// Closes the connection and destroys the object.
///
private void killConnection()
{
try { Connector.Close(); }
catch { }
}
}
}
}