Skip to content

Instantly share code, notes, and snippets.

@notcake
Created June 10, 2015 22:03
Show Gist options
  • Save notcake/d7618e007bb1c8680918 to your computer and use it in GitHub Desktop.
Save notcake/d7618e007bb1c8680918 to your computer and use it in GitHub Desktop.
RPC
local self = {}
XC.RPC.Connection = XC.MakeConstructor (self)
--[[
Events:
Closed ()
Fired when the connection has been closed.
DispatchPacket (packetData)
Fired when a packet needs to be sent.
HandlePacket (packetData)
]]
function self:ctor (id)
self.Id = id
self.SentPacketCount = 0
self.ReadHandlerQueue = {}
self.ReadDataQueue = {}
XC.EventProvider (self)
end
function self:GetId ()
return self.Id
end
function self:GetSentPacketCount ()
return self.SentPacketCount
end
function self:Close ()
self:DispatchEvent ("Closed")
end
function self:Read ()
if #self.ReadDataQueue == 0 then
self.ReadHandlerQueue [#self.ReadHandlerQueue + 1] = coroutine.running ()
coroutine.yield ()
end
local packet = self.ReadDataQueue [1]
table.remove (self.ReadDataQueue, 1)
return XC.StringInBuffer (packet)
end
function self:Write (packetData)
if type (packetData) == "table" then
packetData = packetData:GetString ()
end
self:DispatchEvent ("DispatchPacket", packetData)
self.SentPacketCount = self.SentPacketCount + 1
end
function self:HandlePacket (packetData)
self:DispatchEvent ("HandlePacket", packetData)
self.ReadDataQueue [#self.ReadDataQueue + 1] = packetData
if #self.ReadHandlerQueue > 1 then
local handlerCoroutine = self.ReadHandlerQueue [1]
table.remove (self.ReadHandlerQueue, 1)
coroutine.resume (handlerCoroutine)
end
end
local self = {}
XC.RPC.Service = XC.MakeConstructor (self)
function self:ctor (channelName)
self.ChannelName = channelName or self.ChannelName
self.Connections = XC.WeakKeyTable ()
if SERVER then
util.AddNetworkString (self.ChannelName)
end
net.Receive (self.ChannelName,
function (len, remoteId)
if CLIENT then remoteId = "Server" end
local messageType = net.ReadUInt (8)
local connectionId = net.ReadUInt (32)
local dataLength = net.ReadUInt (32)
local data = net.ReadData (dataLength)
if messageType == 0 then
-- New connection
local connection = self:CreateConnection (connectionId, remoteId)
connection:HandlePacket (data)
self:HandleQuery (connection, remoteId)
elseif messageType == 1 then
-- Existing connection
local connection = self.Connections [remoteId] [connectionId]
connection:HandlePacket (data)
end
end
)
end
function self:dtor ()
end
function self:GetChannelName ()
return self.ChannelName
end
function self:HandleQuery (connection, remoteId)
XC.Error ("Service:HandleQuery : Not implemented.")
end
function self:Query (data, remoteId)
if CLIENT then remoteId = "Server" end
local connection = self:AllocateConnection (remoteId)
connection:AddEventListener ("DispatchPacket",
function (_, packetData)
net.Start (self.ChannelName)
net.WriteUInt (connection:GetSentPacketCount () == 0 and 0 or 1, 8)
net.WriteUInt (connection:GetId (), 32)
net.WriteUInt (#packetData, 32)
net.WriteData (packetData, #packetData)
if CLIENT then
net.SendToServer ()
else
net.Send (remoteId)
end
end
)
connection:Write (data)
return connection
end
-- Internal, do not call
function self:AllocateConnection (remoteId)
if CLIENT then remoteId = "Server" end
self.Connections [remoteId] = self.Connections [remoteId] or {}
local connectionId = #self.Connections [remoteId] + 1
return self:CreateConnection (connectionId, remoteId)
end
function self:CreateConnection (connectionId, remoteId)
if CLIENT then remoteId = "Server" end
self.Connections [remoteId] = self.Connections [remoteId] or {}
local connection = XC.RPC.Connection (connectionId)
self.Connections [remoteId] [connection:GetId ()] = connection
connection:AddEventListener ("Closed",
function (_)
self.Connections [remoteId] [connection:GetId ()] = nil
end
)
return connection
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment