public NetPackage ProcessRequest(Stream stream, Action <object> handleResult)
        {
            Func <IMessage, NetPackage> Prepared = (message) => { return(this.Pack(message)); };

            IMessage income = null;

            try
            {
                income = ProtobufMessageParser.GetMessage(stream); // throws server-side exceptions
                if (income != null)
                {
                    Debug.WriteLine($"{this.Identifier} {this.Id}: '{income.GetType().Name}' received");
                }
            }
            catch (Exception ex) {
                handleResult(ex);
            }

            try
            {
                if (income == null)
                {
                    return(null);
                }
                else if (income is ConnectRequestMsg)
                {
                    return(Prepared(new ConnectResponseMsg {
                        Type = RemotingCommands.ConnectionResponse, Message = "+ok"
                    }));
                }
                if (income is ConnectResponseMsg)
                {
                    handleResult(((ConnectResponseMsg)income).Message);
                }
                else if (income is QueryInterfaceMsg)
                {
                    QueryInterfaceMsg response = (QueryInterfaceMsg)income;

                    string serviceGuid = _broker.CreateService(response.InterfaceName, new IPEndPoint(IPAddress.Parse(response.CallbackAddress), (int)response.CallbackPort));
                    return(Prepared(new QueryInterfaceResponseMsg {
                        Type = RemotingCommands.QueryInterfaceResponse, InterfaceGuid = serviceGuid
                    }));
                }
                else if (income is QueryInterfaceResponseMsg)
                {
                    string serviceGuid = ((QueryInterfaceResponseMsg)income).InterfaceGuid;
                    handleResult(serviceGuid);
                }
                else if (income is InvokeMethodMsg)
                {
                    InvokeMethodMsg message = (InvokeMethodMsg)income;

                    #region Deserialize parameters
                    List <MethodParameter> deserializedParameters = new List <MethodParameter>();

                    MethodParameterMsg[] serializedParameters = message.Parameters.ToArray();
                    foreach (var p in serializedParameters)
                    {
                        using (var ms = new MemoryStream(p.Value.ToByteArray()))
                        {
                            Type            parType  = Type.GetType(p.Type);
                            object          variable = Serializer.Deserialize(parType, ms);
                            MethodParameter prm      = new MethodParameter(p.Name, parType, variable);
                            deserializedParameters.Add(prm);
                        }
                    }
                    #endregion

                    object result = _broker.InvokeMethod(message.InterfaceGuid, message.Method, deserializedParameters) ?? "";

                    using (var ms = new MemoryStream())
                    {
                        Serializer.Serialize(ms, result);
                        return(Prepared(new InvokeMethodResponseMsg {
                            Type = RemotingCommands.InvokeMethodResponse, Result = ByteString.CopyFrom(ms.ToArray()), ResultType = result.GetType().AssemblyQualifiedName
                        }));
                    }
                }
                else if (income is InvokeMethodResponseMsg)
                {
                    InvokeMethodResponseMsg response = (InvokeMethodResponseMsg)income;

                    using (var ms = new MemoryStream(response.Result.ToByteArray()))
                    {
                        object result = Serializer.Deserialize(Type.GetType(response.ResultType), ms);
                        handleResult(result);
                    }
                }
                else if (income is TriggerEventMsg)
                {
                    TriggerEventMsg incomeEvent = (TriggerEventMsg)income;

                    using (var ms = new MemoryStream(incomeEvent.Value.ToByteArray()))
                    {
                        object       result = Serializer.Deserialize(Type.GetType(incomeEvent.EventType), ms);
                        ServiceEvent ev     = new ServiceEvent {
                            ServiceUid = incomeEvent.ServiceUid, Data = result
                        };
                        handleResult(ev);
                    }
                }
                else if (income is ReleaseInterfaceMsg)
                {
                    ReleaseInterfaceMsg releaseInterfaceMessage = (ReleaseInterfaceMsg)income;

                    _broker.ReleaseService(releaseInterfaceMessage.InterfaceUid);
                    return(Prepared(new ReleaseInterfaceResponseMsg {
                        Type = RemotingCommands.ReleaseInterfaceResponse
                    }));
                }
                else if (income is ReleaseInterfaceResponseMsg)
                {
                    ReleaseInterfaceResponseMsg releaseInterfaceResponseMessage = (ReleaseInterfaceResponseMsg)income;

                    handleResult("");
                }

                return(null);
            }
            catch (Exception ex)
            {
                return(Prepared(new RemotingExceptionMsg
                {
                    Message = ex.Message,
                    Type = RemotingCommands.Exception
                }));
            }
        }