public static unsafe Task <T> Rpc <T>(string serverId, Route route, object msg)
        {
            return(_rpcTaskFactory.StartNew(() =>
            {
                MemoryBuffer *memBufPtr = null;
                var retError = new Error();
                var ok = false;
                Stopwatch sw = null;
                try
                {
                    var data = SerializerUtils.SerializeOrRaw(msg, _serializer);
                    sw = Stopwatch.StartNew();
                    fixed(byte *p = data)
                    {
                        ok = RPCInternal(serverId, route.ToString(), (IntPtr)p, data.Length, &memBufPtr, ref retError);
                    }

                    sw.Stop();

                    if (!ok) // error
                    {
                        if (retError.code == "PIT-504")
                        {
                            throw new PitayaTimeoutException($"Timeout on RPC call: ({retError.code}: {retError.msg})");
                        }
                        if (retError.code == "PIT-404")
                        {
                            throw new PitayaRouteNotFoundException($"Route not found on RPC call: ({retError.code}: {retError.msg})");
                        }
                        throw new PitayaException($"RPC call failed: ({retError.code}: {retError.msg})");
                    }

                    var protoRet = GetProtoMessageFromMemoryBuffer <T>(*memBufPtr);
                    return protoRet;
                }
                finally
                {
                    if (sw != null)
                    {
                        if (ok)
                        {
                            MetricsReporters.ReportTimer(Metrics.Constants.Status.success.ToString(), route.ToString(),
                                                         "rpc", "", sw);
                        }
                        else
                        {
                            MetricsReporters.ReportTimer(Metrics.Constants.Status.fail.ToString(), route.ToString(),
                                                         "rpc", $"{retError.code}", sw);
                        }
                    }

                    if (memBufPtr != null)
                    {
                        FreeMemoryBufferInternal(memBufPtr);
                    }
                }
            }));
        }
        public static unsafe Task <bool> SendPushToUser(string frontendId, string serverType, string route, string uid,
                                                        object pushMsg)
        {
            return(_rpcTaskFactory.StartNew(() =>
            {
                bool ok = false;
                MemoryBuffer inMemBuf = new MemoryBuffer();
                MemoryBuffer *outMemBufPtr = null;
                var retError = new Error();

                var push = new Push
                {
                    Route = route,
                    Uid = uid,
                    Data = ByteString.CopyFrom(SerializerUtils.SerializeOrRaw(pushMsg, _serializer))
                };

                try
                {
                    var data = push.ToByteArray();
                    fixed(byte *p = data)
                    {
                        inMemBuf.data = (IntPtr)p;
                        inMemBuf.size = data.Length;
                        IntPtr inMemBufPtr = new StructWrapper(inMemBuf);

                        ok = PushInternal(frontendId, serverType, inMemBufPtr, &outMemBufPtr, ref retError);
                        if (!ok) // error
                        {
                            Logger.Error($"Push failed: ({retError.code}: {retError.msg})");
                            return false;
                        }

                        return true;
                    }
                }
                finally
                {
                    if (outMemBufPtr != null)
                    {
                        FreeMemoryBufferInternal(outMemBufPtr);
                    }
                }
            }));
        }
        public static unsafe Task <bool> SendKickToUser(string frontendId, string serverType, KickMsg kick)
        {
            return(_rpcTaskFactory.StartNew(() =>
            {
                bool ok = false;
                MemoryBuffer inMemBuf = new MemoryBuffer();
                MemoryBuffer *outMemBufPtr = null;
                var retError = new Error();

                try
                {
                    var data = kick.ToByteArray();
                    fixed(byte *p = data)
                    {
                        inMemBuf.data = (IntPtr)p;
                        inMemBuf.size = data.Length;
                        IntPtr inMemBufPtr = new StructWrapper(inMemBuf);
                        ok = KickInternal(frontendId, serverType, inMemBufPtr, &outMemBufPtr, ref retError);
                        if (!ok) // error
                        {
                            Logger.Error($"Push failed: ({retError.code}: {retError.msg})");
                            return false;
                        }

                        var kickAns = new KickAnswer();
                        kickAns.MergeFrom(new CodedInputStream(outMemBufPtr->GetData()));

                        return kickAns.Kicked;
                    }
                }
                finally
                {
                    if (outMemBufPtr != null)
                    {
                        FreeMemoryBufferInternal(outMemBufPtr);
                    }
                }
            }));
        }
 private static extern unsafe void FreeMemoryBufferInternal(MemoryBuffer *ptr);