jgauffin / Griffin.Framework

Application framework for Business Applications
http://griffinframework.net
168 stars 63 forks source link

Handle Message without request #65

Closed SheppeR closed 8 years ago

SheppeR commented 8 years ago

Hi, i am just starting to use Griffin.Framework, and i am looking for handle message without sending request on client side

Ex: (CLIENT) request_friendslist (SERVER) reply_friend1 (SERVER) reply_friend2 (SERVER) reply_friend3

Sorry for my bad english. Best regards SheppeR

jgauffin commented 8 years ago

Are you talking about HTTP or some other protocol?

SheppeR commented 8 years ago

Hi, I am using ChannelTcpClient and ChannelTcpListener on WPF and Console project. My server need to send some serialized 'Packets' on all clients connected without a request.

example: Client1 -> connect -> Server Server -> send to -> Client1 FriendsList 'Packet' Client2 -> connect -> Server Server -> send to -> Client2 FriendsList 'Packet'

i am looking for something like OnReceiveMessage event on client side

client = new ChannelTcpClient(
                new MicroMessageEncoder(new JsonMessageSerializer()),
                new MicroMessageDecoder(new JsonMessageSerializer()));

client.MessageReceived += OnMessageReceived;
jgauffin commented 8 years ago

Something like this?

class Program
{
    static List<ITcpChannel> _clients = new List<ITcpChannel>();
    static void Main(string[] args)
    {
        var listener = new ChannelTcpListener();
        listener.ClientConnected += OnConnected;
        listener.ClientDisconnected += OnDisconnect;
    }

    private static void OnDisconnect(object sender, ClientDisconnectedEventArgs e)
    {
        lock (_clients)
        {
            foreach (var client in _clients)
            {
                client.Send("Your message");
            }

            _clients.Remove(e.Channel);
        }
    }

    private static void OnConnected(object sender, ClientConnectedEventArgs e)
    {

        lock (_clients)
            _clients.Add(e.Channel);
    }
}
SheppeR commented 8 years ago

Not exactly, I am sorry if my request is not clear. I am using something similar on my server side, but i am looking for an event on the client side for handle message without a client.Send.

Currently on the client, i can only receive message if i request it but i need to receive a lot of different type of serialized message without the request for each

Like this:

client.MessageReceived += OnMessageReceived;

private void OnMessageReceived(ITcpChannel channel, object message)
{
    var mType = message.GetType();
    if (mType == typeof(Login_Response))
    {
        //TODO
    }
    else if (mType == typeof(Login_Status))
    {
        //TODO
    }
}
jgauffin commented 8 years ago

The client is 100% asynchronous. The request/reply pattern is just a layer on top. Unfortunately there is no straightforward way currently to push messages.

However, it is possible by using the Filterhandler.

var client = new ChannelTcpClient(
    new MicroMessageEncoder(new DataContractMessageSerializer()),
    new MicroMessageDecoder(new DataContractMessageSerializer()));

// this delegate is invoked each time a new message arrives,
// no matter if it's pushed or a reply.
client.Filter = (channel, message) =>
{
    Console.WriteLine("Got a message from the server.");
    return ClientFilterResult.Accept;
};
jgauffin commented 8 years ago

If that doesn't work for you, it's quite easy to build a client from the TcpChannel directly.

public class MyClient : TcpChannel
{
    public MyClient(IBufferSlice readBuffer, IMessageEncoder encoder, IMessageDecoder decoder) : base(readBuffer, encoder, decoder)
    {
    }

    public MyClient()
        : base(
            new BufferSlice(new byte[65535], 0, 65535),
            new MicroMessageEncoder(new DataContractMessageSerializer()),
            new MicroMessageDecoder(new DataContractMessageSerializer()))
    {
    }

    /// <summary>
    /// Add client connect functionality
    /// </summary>
    public void Connect(string remoteAddress, int port)
    {
        var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        socket.Connect(remoteAddress, port);

        //assign the socket to the base class
        Assign(socket);
    }
}

Which can be invoked like.

var myClient = new MyClient();
myClient.MessageReceived = (channel, message) =>
{
    //this is invoked on each message that is pushed from the server
};
myClient.Connect("SomeServer", 7374);
SheppeR commented 8 years ago

This work like a charm

client.Filter = (channel, message) =>
{
    Console.WriteLine("Got a message from the server.");
    return ClientFilterResult.Accept;
};

Thanks for the support and your time on this issue.