IOperationHandler and RequestFiber

Options
Sergiy
Sergiy
edited February 2013 in Photon Server
Hi

Please consider following sample code:

[code2=csharp]public class MyPeer: Peer, IOperationHandler
{
protected MyPeer(IRpcProtocol rpcProtocol, IPhotonPeer photonPeer) : base(rpcProtocol, photonPeer)
{
}
.................................................................................
public OperationResponse OnOperationRequest(PeerBase peer, OperationRequest operationRequest, SendParameters sendParameters)
{
switch ((OperationCodes)operationRequest.OperationCode)
{
case OperationCodes.JoinLobby:
SetCurrentOperationHandler(new JoinedOperationHandler());
return new OperationResponse(operationRequest.NoError) { ReturnCode = (short)ErrorCodes.InvalidRequest };
break;
}
return new OperationResponse(operationRequest.OperationCode) { ReturnCode = (short)ErrorCodes.InvalidRequest };
}
}[/code2]

[code2=csharp]class JoinedOperationHandler: IOperationHandler
{
....................................................
public OperationResponse OnOperationRequest(PeerBase peer, OperationRequest operationRequest, SendParameters sendParameters)
{
switch ((OperationCodes)operationRequest.OperationCode)
{
case OperationCodes.SomeOperation:
return new ProcessSomeOperation(operationRequest);
break;
}
return new OperationResponse(operationRequest.OperationCode) { ReturnCode = (short)ErrorCodes.InvalidRequest };
}

private OperationResponse ProcessSomeOperation(OperationRequest operationRequest)
{
return new OperationResponse(operationRequest.OperationCode) { ReturnCode = (short)ErrorCodes.NoError};
}
}[/code2]

Will ProcessSomeOperation() execute in MyClass's RequestFiber or should I create some new dedicated PoolFiber for this? Or perhaps i should create a RequestResponse channel in MyPeer class and do something like:
[code2=csharp]public OperationResponse OnOperationRequest(PeerBase peer, OperationRequest operationRequest, SendParameters sendParameters)
{
switch ((OperationCodes)operationRequest.OperationCode)
{
case OperationCodes.SomeOperation:
OperationResponse operationResponse;
IReply<OperationResponse> reply = peer.SomeChannel.SendRequest(operationRequest);
reply.Receive(1000, out operationResponse);
return operationResponse;
break;
}
return new OperationResponse(operationRequest.OperationCode) { ReturnCode = (short)ErrorCodes.InvalidRequest };
}[/code2]

Please advise :)

Comments

  • ProcessSomeOperation will happen inside the Peer's RequestFiber. Basically this is what photon does it internally when an operation request is received.

    this.RequestFiber.Enque(() => this.CurrentOperationHandler.OnOperationRequest(request, sendParameter));

    Instead of creating a new channel you can use OperationDispatcher class, which makes easier to forward messages to multiple peers.
  • Sergiy
    Options
    Thanks for reply, zeppelinisgod

    If i understand you correctly, in MyPeer class there should be something like this:
    [code2=csharp]public class MyPeer: Peer, IOperationHandler
    {
    protected MyPeer(IRpcProtocol rpcProtocol, IPhotonPeer photonPeer) : base(rpcProtocol, photonPeer)
    {
    }
    .................................................................................
    public OperationResponse OnOperationRequest(PeerBase peer, OperationRequest operationRequest, SendParameters sendParameters)
    {
    switch ((OperationCodes)operationRequest.OperationCode)
    {
    case OperationCodes.JoinLobby:
    SetCurrentOperationHandler(new JoinedOperationHandler());
    return new OperationResponse(operationRequest.OperationCode) { ReturnCode = (short)ErrorCodes.NoError };
    break;
    default: this.RequestFiber.Enque(() => this.CurrentOperationHandler.OnOperationRequest(request, sendParameter));
    }
    }
    }[/code2]

    Is it correct? If it is, then it's unclear, how can i return OperationResponse object? The only way i can see is to create a channel in JoinedOperationHandler and return its response, like this:
    [code2=csharp]public class MyPeer: Peer, IOperationHandler
    {
    protected MyPeer(IRpcProtocol rpcProtocol, IPhotonPeer photonPeer) : base(rpcProtocol, photonPeer)
    {
    }
    .................................................................................
    public OperationResponse OnOperationRequest(PeerBase peer, OperationRequest operationRequest, SendParameters sendParameters)
    {
    switch ((OperationCodes)operationRequest.OperationCode)
    {
    case OperationCodes.JoinLobby:
    SetCurrentOperationHandler(new JoinedOperationHandler());
    return new OperationResponse(operationRequest.OperationCode) { ReturnCode = (short)ErrorCodes.NoError };
    break;
    default:
    OperationResponse operationResponse;
    IReply<OperationResponse> reply = ((JoinedOperationHandler) this.CurrentOperationHandler).SendRequest(operationRequest);
    reply.Receive(1000, out operationResponse);
    return operationResponse;
    }
    }
    }[/code2]
    Looks a bit strange to me..... :?
  • I think you are treating the peer and the operation handler as the same. The peer is what sends the message to the client NOT the OperationHandler, the operation handler acts as a state object.

    So of course you can return an operation response even after setting the current operation handler. And you do not need to call RequestFiber.Enque for default case, just handle it normally, it will be automatically called inside the RequestFiber's ThreadPool. After setting the current operation handler, the default case will be called for the new OperationHandler. Here is an overview of how the Peer class may be designed

    [code2=csharp]public class Peer : PeerBase
    {
    public IOperationHandler CurrentHandler { get { return this.currentHandler; } }

    private IOperationHandler currentHandler;

    public Peer(IRpcProtocol protocol, IPhotonPeer peer) : base(protocol, peer)
    {
    this.SetCurrentOperationHandler(null);
    }

    public SetCurrentOperationHandler(IOperationHandler handler)
    {
    if(handler == null)
    handler = DefaultHandlerGoesHere; // default handler
    this.currentHandler = handler;
    }

    public override void OnOperationRequest(OperationRequest request, SendParameters sendParameters)
    {
    var response = this.currentHandler.OnOperationRequest(this, request, sendParameters);
    if(response != null)
    this.SendOperationResponse(response, new SendParameters()); // sending from peer
    }
    }[/code2]

    so you see here, after returning an operation response, it doesn't matter if you set a different operation handler or not. the response will still be sent to the client :)
  • Sergiy
    Options
    I agree with you - only peer is communicating with client. However, my question was different:

    IOperationHandler has OnOperationRequest(), OnDisconnect() and OnDisconnectByOtherPeer() methods, just as peer.

    Suppose I have a peer class MyPeer and OperationHandler MyOperationHandler.
    Suppose I set MyPeer's OperationHandler to MyOperationHandler.

    Question: Will MyOperationHandler's OnOperationRequest(), OnDisconnect() and OnDisconnectByOtherPeer() methods execute in MyPeer's RequestFiber or I should create a separate fiber?

    P.S. thanks for a great code :)

    UPD: From your code, I have an imagination that MyPeers's OnOperationRequest() will be called first of all, regardless of any OperationHandlers. Then I can pass it to MyOperationHandler's OnOperationRequest(). Same applies to OnDisconnect() and OnDisconnectByOtherPeer() methods.

    Is it correct?
  • exactly, i forgot to write the OnDisconnect and OnDisconnectByOtherPeer but they works the same way as the OperationRequest, they are first called inside the peer then the peer calls the OnDisconnect of the current operation handler. And you DONT have to create a new fiber, every requests from the client automatically executes in the request fiber even OnDisconnect.