Project Description
OpenServe.Net - C# .Net - Supports both Asynchronous and Synchronous TCP communication. By using BlockingCollection no Send operation will be blocking and the TCPClient can be used in a multithreaded implementation without the worries of writing to a single
stream.
PLEASE RATE THIS PROJECT
OpenServe.Net 4.0.3
- Fixed the SSL Reading issues as Stream.Read does not work on SslStreams and i had to change it to an async BeginRead/EndRead pair is now fully working
- Implemented a Python Script for a Server Side OpenChat script plugin
#--------------------------------------------------#
# Server Side OpenChat script #
# a script that implements a chatting engine #
# Written by : Ryno Kotz� (ravencoder) #
#--------------------------------------------------#
#--------------------------------------------#
# Implemented Chat commands #
#--------------------------------------------#
'''
commands that reach the server will not be /
pre-pended that is a client side function to
differentiate between normal chat and commands
global # send message to all users connected
channel # send message to all users that joined that channel
createchannel # create channel
join # join channel
part # leave a channel you have previously subscribed to
msg # send a private message
nick # To change your nickname
poke # pokes a client to let him know someone is looking for him.
for now these are the commands that will be
implemented
'''
#--------------------------------------------#
# Impports #
#--------------------------------------------#
import System
import System.Collections.Generic
import System.Collections
if env == 'server':
# setting up the Channel list in the vars
channels = Dictionary>()
if vars.ContainsKey('channels') == false:
vars.Add('channels', channels)
else :
channels = vars['channels']
Console.WriteLine('{0}, channels', channels.Count)
#--------------------------------------------#
# #
#--------------------------------------------#
cmd, rest = msg.Body[0:msg.Body.IndexOf(' ')].ToLower(), msg.Body[msg.Body.IndexOf(' ')+1:]
if cmd == 'global':
# svr.Parent.Clients all clients that is connected
for c in svr.Parent.Clients:
if svr.Name == c.Name:
pass
else:
c.Send(rest)
elif cmd == 'channel':
chname, m = rest[0:rest.IndexOf(' ')], rest[rest.IndexOf(' ')+1:]
if channels.Contains(chname):
for c in svr.Parent.Clients:
if channels[chname].Contains(c.Name):
c.Send(m)
else:
svr.Send('Channel does not exist')
elif cmd == 'nick':
newnick = rest
if svr.Parent.Clients.Contains(newnick):
svr.Send('Nickname is not available')
else:
svr.Name = newnick
elif cmd == 'createchannel':
chname = rest
if channels.Contains(chname):
svr.Send('Channel already exists')
else:
channels.Add(chname, List())
channels[chname].Add(svr.Name)
elif cmd == 'join':
chname = rest
if channels.Contains(chname):
channels[chname].Add(svr.Name)
else:
svr.Send('Channel does not exist')
elif cmd == 'msg':
to, m = rest[0:rest.IndexOf(' ')], rest[rest.IndexOf(' ')+1:]
for c in svr.Parent.Clients:
if c.Name == to:
c.Send(m)
break
else:
svr.Send('Client does not exist')
elif cmd == 'poke':
to = rest
for c in svr.Parent.Clients:
if c.Name == to:
c.Send('~::p0�k3::~')
break
else:
svr.Send('Client does not exist')
elif cmd == 'part':
chname = rest
if channels.Contains(chname):
channels[chname].Remove(svr.Name)
else:
svr.Send('Channel does not exist')
else:
svr.Send('Command does not exist')
else:
pass
#--------------------------------------------#
# #
#--------------------------------------------#
OpenServe.Net 4.0.2
We have made a lot of changes since last we updated this project. This is a completely new code base and doesn't leverage off the old code base. i have implemented JSON as my message transport and you transfer objects, my message handlers
are all new and they use reflection to determine what to call on the server. You will be able to see the use of reflection to determine the methods to call in this example of the Default Message Handler.
To enable SSL, simply set the client and server Secure properties to true:
// create client
client.Secure = true; // then connect
// create server
server.Secure = true;
server.Start(); // start the server
The basics of the reflection i use:
var operation = (new StackTrace()).GetFrame(0).GetMethod().Name;
I use the StackTrace to get the calling method name and because the server side message handler and the client side message handler both implement that message handler's interface they will have the same calls. So you don't have to specify what the operation
is it has to run on the server you just call the method on your handler and the handlers will make sure that when it gets to the server it will run the "same" method on the server, that is the method on the server side handler with the same name. I will paste
the default handler later on so you can see how all this fits together. But in a nutshell you just have to call the methods on the client handlers and pass along the parameters and it will create a message send it to the server find the same method name and
send the parameters to the server side where you will do some processing and depending on the functionality either end the process there or create a new message and send it back to the client with the information requested. And on the client you can handle
the incoming data as events or as Synchronous calls where the client call was blocked until the server responds (check the code below at the methods ServerVersion and ServerVersion_Callback on the the client Handler for a Synchronous client call).
With the new Message Handlers you can have them as Asynchronous and Synchronous if you take a took at the DefaultHandler there is a call for the client ServerVersion and another one called SetName. SetName is Asynchronous where as ServerVersion is Synchronous
in the client app that is consuming the TCPClient you can just call tcpclient.DeafultHandler.ServerVersion() and it will be blocking waiting for the server to respond before continuing, i am going to build in a timeout and a timeout lamba to be passed to the
call so that when the timeout period is reached to do something. i am just not there yet :) there is alot of work i am busy with :|
I have also left the MessageHandlers as generic as possible and you can write your own message handler that does not work like mine does just in case you want to write handlers for files and such. But the basic idea of the Message Handlers to be written has
been encapsulated by the Default Handler
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using OpenServe.Net.Library.Interfaces;
using OpenServe.Net.Client;
using OpenServe.Net.Library.Extentions;
using System.Threading;
using System.Diagnostics;
namespace OpenServe.Net.Messaging {
public interface IDefaultHandler : IMsgHandler {
string ServerVersion(object o);
void SetName(object o);
}
}
namespace OpenServe.Net.Messaging.Server {
using OpenServe.Net.Server;
using System.Reflection;
using System.Threading.Tasks;
public class DefaultHandler : IDefaultHandler {
public object Parent { get; set; }
public string MessageType { get; set; }
public DefaultHandler(Server.Client _parent) : this() { Parent = _parent; }
public DefaultHandler() { MessageType = "DefaultHandler"; }
public void HandleMessage(Message msg) {
if (MessageType == msg.Header.MessageType) {
var meth = this.GetType().GetMethod(msg.Header.Operation);
if (meth != null) meth.Invoke(this, new object[] { msg.Clone() });
}
}
public string ServerVersion(object o) {
var msg = o as Message;
msg.Header.Operation += "_Callback";
msg.Header.Destination = msg.Header.Source;
msg.Header.Source = new Guid();
msg.Body = "OpenServe.Net - " + Assembly.GetCallingAssembly().GetName().Version.ToString(4);
Send(msg);
return null;
}
public void Send(Message msg) {
var p = Parent as Server.Client;
p.Send(msg);
}
public void SetName(object o) {
var m = o as Message;
var p = Parent as Server.Client;
p.Name = m.Body.ToString();
m.Header.Operation += "_Callback";
m.Header.Destination = m.Header.Source;
m.Header.Source = new Guid();
m.Body = p.GUID.ToString();
Send(m);
}
}
}
namespace OpenServe.Net.Messaging.Client {
using OpenServe.Net.Client;
using OpenServe.Net.Library.Utils;
using System.Threading.Tasks;
public class DefaultHandler : IDefaultHandler {
public object Parent { get; set; }
ManualResetEvent mreServerVersion = new ManualResetEvent(false);
string serverVersion = "";
public string MessageType { get; set; }
public DefaultHandler(Client _parent) : this() { Parent = _parent; }
public DefaultHandler() { MessageType = "DefaultHandler"; }
public void HandleMessage(Message msg) {
if (MessageType == msg.Header.MessageType) {
var meth = this.GetType().GetMethod(msg.Header.Operation);
if (meth != null) meth.Invoke(this, new object[] { msg.Clone() });
}
}
public string ServerVersion(object o = null) {
var operation = (new StackTrace()).GetFrame(0).GetMethod().Name;
var p = Parent as Client;
var msg = new Message {
Header = new Header { Source = p.GUID, Operation = operation, ContainingType = typeof(string) },
Body = ""
};
SendAndWait(msg, mreServerVersion);
return serverVersion;
}
public void ServerVersion_Callback(Message msg) {
serverVersion = msg.Body.ToString();
mreServerVersion.Set();
}
#region Sending
public void Send(Message msg) {
var p = Parent as Client;
msg.Header.MessageType = this.MessageType;
p.Send(msg);
}
public void SendAndWait(Message msg, ManualResetEvent mre) {
Send(msg); mre.Reset(); mre.WaitOne();
}
#endregion
public void SetName(object o) {
var p = Parent as Client;
var msg = new Message {
Header = new Header { Source = p.GUID, Operation = Utils.CurrentOperation, ContainingType = typeof(string) },
Body = p.Name ?? ""
};
Send(msg);
}
public void SetName_Callback(Message msg) {
var p = Parent as Client;
p.GUID = Guid.Parse(msg.Body.ToString());
}
}
}
this is to demonstrate the flexibility of the message handlers as both Synchronous and Asynchronous are supported.
please feel free to give me some feedback or rate this project!! :)