/*
Thor Server Project
Copyright 2008 Joe Hegarty
This file is part of The Thor Server Project.
The Thor Server Project is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
The Thor Server Project is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with The Thor Server Project. If not, see .
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using ThorServer.Core;
using ThorServer.Utilities;
using ThorServer.Game.Users;
using ThorServer.Game.Rooms;
using ThorServer.Game.Messenger;
using ThorServer.Game.Furni;
using ThorServer.Game.Moderation;
using ThorServer.Game.Catalogue;
namespace ThorServer.Session
{
public class SessionHandler : Reactor
{
private class ReactorCollection{
public ReactorCollection(Type rType, Reactor rInstance) { ReactorType = rType; ReactorInstance = rInstance; }
public Type ReactorType;
public Reactor ReactorInstance;
}
private SessionCommunicationStack mStack;
private Dictionary mReactors;
public int mRoomID = 0;
public int authenticatedFlat = 0;
public int authenticatedDoor = 0;
public int waitingFlat;
public bool pingOk = true;
public bool receiveCFH = false;
private int mReactorOffset = 0;
private bool mDirtySession = false;
protected DateTime mLastUpdate = DateTime.Now;
public SessionHandler(long sessionid)
{
mSessionID = sessionid;
mStack = new SessionCommunicationStack();
mReactors = new Dictionary();
RegisterDefaultReactor();
}
public void UpdateLastTime()
{
mLastUpdate = DateTime.Now;
}
public DateTime LastTime
{
get
{
return mLastUpdate;
}
}
public void MakeSessionDirty()
{
mDirtySession = true;
}
private void RegisterDefaultReactor()
{
mReactors.Clear();
ReactorCollection rCol = new ReactorCollection(typeof(LoginReactor), new LoginReactor());
mReactors.Add(0, rCol);
mReactorOffset = 1;
}
public void SessionAuthenticated(UserInfo userInfo)
{
mUserInfo = userInfo;
mReactors.Clear();
ReactorCollection rCol = new ReactorCollection(typeof(UserReactor), new UserReactor());
mReactors.Add(mReactorOffset++, rCol);
rCol = new ReactorCollection(typeof(RoomReactor), new RoomReactor());
mReactors.Add(mReactorOffset++, rCol);
rCol = new ReactorCollection(typeof(MessengerReactor), new MessengerReactor());
mReactors.Add(mReactorOffset++, rCol);
rCol = new ReactorCollection(typeof(HandReactor), new HandReactor());
mReactors.Add(mReactorOffset++, rCol);
rCol = new ReactorCollection(typeof(CatalogueReactor), new CatalogueReactor());
mReactors.Add(mReactorOffset++, rCol);
if (InstanceManager.Game.Roles.HasRight(mUserInfo.iRole, "fuse_trade"))
{
rCol = new ReactorCollection(typeof(TradeReactor), new TradeReactor());
mReactors.Add(mReactorOffset++, rCol);
}
if (InstanceManager.Game.Roles.HasRight(mUserInfo.iRole, "thor_moderator"))
{
rCol = new ReactorCollection(typeof(ModeratorReactor), new ModeratorReactor());
mReactors.Add(mReactorOffset++, rCol);
}
if (InstanceManager.Game.Roles.HasRight(mUserInfo.iRole, "fuse_cfh"))
{
receiveCFH = true;
}
}
public void UpdateUserInfo(UserInfo userInfo)
{
mUserInfo = userInfo;
}
public int AddListener(Type listenerType, Reactor listenerObject)
{
int listenerId = mReactorOffset++;
ReactorCollection rCol = new ReactorCollection(listenerType, listenerObject);
mReactors.Add(listenerId, rCol);
return listenerId;
}
public void RemoveListener(int listenerId)
{
mReactors.Remove(listenerId);
}
public void ConnectionReady()
{
GreetClient();
}
private void GreetClient()
{
if (InstanceManager.Connections.CheckIP(InstanceManager.Connections.GetConnection(mSessionID).GetIP()))
{
mMessage.Init(0); // @@
SendMessage(mMessage);
}
else
{
mDirtySession = true;
mMessage.Init(35); // @c
mMessage.appendString("IP Connection Limit Reached");
SendMessage(mMessage);
InstanceManager.Connections.EndConnection(mSessionID);
}
}
public void ProcessData(string data)
{
mStack.newData(data);
if (mStack.StackReady)
{
NewMessage(mStack.StackData);
}
}
private void NewMessage(string data)
{
string header = data.Substring(0, 2);
int headerId = Base64Encoding.DecodeInt(header);
string body = "";
if (data.Length > 2)
{
body = data.Substring(2);
}
mHeaderBody = header;
mHeaderID = headerId;
mPacketBody = body;
ProcessMessage();
}
private void ProcessMessage()
{
Logging.LogEvent("Received from " + mSessionID.ToString() + ": [" + mHeaderID.ToString() + "] " + mHeaderBody + mPacketBody, Logging.LogLevel.Debug);
if (mPacketBody.Contains(Convert.ToChar(1)))
{
Logging.LogEvent("Client " + mSessionID.ToString() + " sent a char 1. Ignoring packet.", Logging.LogLevel.Warning);
}
else
{
if (!mDirtySession)
{
InvokeMethod("Listener" + mHeaderID.ToString());
}
}
}
public void InvokeMethod(string methodName)
{
StringBuilder sbListeners = new StringBuilder();
Dictionary.Enumerator myEnum = mReactors.GetEnumerator();
while (myEnum.MoveNext())
{
sbListeners.Append(myEnum.Current.Value.ReactorType.Name + ", ");
MethodInfo methodInfo = myEnum.Current.Value.ReactorType.GetMethod(methodName);
if (methodInfo != null)
{
myEnum.Current.Value.ReactorInstance.mHeaderBody = mHeaderBody;
myEnum.Current.Value.ReactorInstance.mHeaderID = mHeaderID;
myEnum.Current.Value.ReactorInstance.mPacketBody = mPacketBody;
myEnum.Current.Value.ReactorInstance.mSessionID = mSessionID;
myEnum.Current.Value.ReactorInstance.mUserInfo = mUserInfo;
try
{
myEnum.Current.Value.ReactorInstance.Ping();
methodInfo.Invoke(myEnum.Current.Value.ReactorInstance, null);
}
catch(Exception e)
{
Logging.LogEvent("weirderror: Client " + mSessionID.ToString() + " caused an error which was not caught in the processing stack.\r\nStack: " + e.ToString(), Logging.LogLevel.Error);
}
return;
}
}
Logging.LogEvent("No listener named '" + methodName + "' for '" + mHeaderBody + mPacketBody + "' was found in this context. Reactors were '" + sbListeners.ToString().Substring(0, sbListeners.Length - 2) + "'", Logging.LogLevel.Warning);
}
public void Cleanup()
{
if (mRoomID > 0)
{
InstanceManager.Game.Rooms.GetRoomInstance(mRoomID).RemoveUser(mSessionID);
}
}
}
}