This project is read-only.

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.1

- Changed the Default handler to use a BaseHandler class

- Fixed the OpenChat python script so you can play with it.

- Modified the Sample client to be able to use the OpenChat script. OpenChat messages can be sent from the Sample Client now.

- Minor code changes and scope changes for the scripting engine.

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 (script has been fixed)

#--------------------------------------------#
# Server Side OpenChat script                #
# a script that implements a chatting engine #
# Written by : Ryno Kotzé                    #
#        aka : ravencoder/lemonxah           #
#--------------------------------------------#


#--------------------------------------------#
#        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

    help # displays this help
    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 clr
clr.AddReference("System.Core")
import System
from System.Collections.Generic import List, Dictionary
from System.Collections import *
clr.ImportExtensions(System.Linq)

if msg.Header.MessageType == 'OpenChat':
    if env == 'server':
        helpmsg = '\nCommands help:\n\n/help # displays this help\n/global  # send message to all users connected'
        helpmsg += '\n/channel   # send message to all users that joined that channel'
        helpmsg += '\n/createchannel  # create channel'
        helpmsg += '\n/join  # join channel'
        helpmsg += '\n/part  # leave a channel you have previously subscribed to'
        helpmsg += '\n/msg   # send a private message'
        helpmsg += '\n/nick  # To change your nickname'
        helpmsg += '\n/poke  # pokes a client to let him know someone is looking for him.'
        helpmsg += '\n/list # Lists all connected clients.'
        helpmsg += '\n/clist # Lists all channels.\n\n'
        #print 'Server Script'
        # setting up the Channel list in the vars
        channels = Dictionary[str, List[str]]()
        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:]
        cname = 'unknown'
        if svr.Name is not None:
            if not svr.Name == '':
                cname = svr.Name
        if not msg.Body.Contains(' '): cmd = msg.Body
        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(msg.Header, '::global:'+cname+'::' + rest)
        elif cmd == 'clist':
            clist = ''
            for c in channels:
                clist+=c.Key+', '
            svr.Send(msg.Header, '\n::Channel List::\n'+clist)
        elif cmd == 'list':
            clients = ''
            for c in svr.Parent.Clients:
                ccname = 'unknown'
                if c.Name is not None:
                    if not c.Name == '':
                        ccname = c.Name
                clients += '\n'+ccname+'::'+c.GUID.ToString()
            clients += '\n'
            svr.Send(msg.Header, '\n::Client List::' + clients)
        elif cmd == 'help':
            svr.Send(msg.Header, helpmsg)
        elif cmd == 'channel':
            chname, m = rest[0:rest.IndexOf(' ')], rest[rest.IndexOf(' ')+1:]
            if channels.ContainsKey(chname):
                for c in svr.Parent.Clients:
                    if channels[chname].Contains(c.GUID.ToString()):
                        c.Send(msg.Header, '::'+chname+':'+cname+'::' + m)
            else:
                svr.Send(msg.Header, 'Channel does not exist')
        elif cmd == 'nick':
            newnick = rest
            if svr.Parent.Clients.Any(lambda c: c.Name == newnick):
                svr.Send(msg.Header, 'Nickname is not available')
            else:
                svr.Name = newnick
        elif cmd == 'createchannel':
            chname = rest
            if channels.ContainsKey(chname):
                svr.Send(msg.Header, 'Channel already exists')
            else:
                channels.Add(chname, List[str]())
                channels[chname].Add(svr.GUID.ToString())
        elif cmd == 'join':
            chname = rest
            if channels.ContainsKey(chname):
                if channels[chname].Contains(svr.GUID.ToString()):
                    svr.Send(msg.Header, 'You are already in this channel')
                else:
                    channels[chname].Add(svr.GUID.ToString())
            else:
                svr.Send(msg.Header, '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(msg.Header, '::' + cname + '::' + m)
                    break
                else:
                    svr.Send(msg.Header, 'Client does not exist')
        elif cmd == 'poke':
            to = rest
            for c in svr.Parent.Clients:
                if c.Name == to:
                    c.Send(msg.Header, '~::p0�k3::~')
                    break
                else:
                    svr.Send(msg.Header, 'Client does not exist')
        elif cmd == 'part':
            chname = rest
            if channels.ContainsKey(chname):
                channels[chname].Remove(svr.GUID.ToString())
            else:
                svr.Send(msg.Header, 'Channel does not exist')
        else:
            svr.Send(msg.Header, 'Command does not exist')
    elif env == 'client':
        print msg.Body.ToString()
    else:
        pass    
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!! :)

Last edited Jun 27, 2012 at 8:50 AM by ravencoder, version 18