Improved WS client object

This commit is contained in:
Alessandro Proto 2023-01-27 22:56:57 +01:00
parent bc87363f7c
commit c2aca7a7af
3 changed files with 67 additions and 66 deletions

View file

@ -2,23 +2,6 @@ local http = require("http")
local event = require("event") local event = require("event")
local expect = require("expect").expect local expect = require("expect").expect
local WebSocketHandle = {}
function WebSocketHandle:close()
self:closeAsync()
local _, id
repeat
_, id = event.pull("websocket_close")
until id == self.requestId
end
function WebSocketHandle:receive()
local _, id, par
repeat
_, id, par = event.pull("websocket_message")
until id == self.requestId
return par
end
function http.request(url, body, headers, options) function http.request(url, body, headers, options)
expect(1, url, "string") expect(1, url, "string")
@ -60,12 +43,27 @@ function http.post(url, body, headers, options)
return http.request(url, body, headers, options) return http.request(url, body, headers, options)
end end
local function buildWebsocketHandle(requestId, handle) local WebSocketHandle
handle.requestId = requestId local function buildWebsocketHandle(handle)
local metatable = getmetatable(handle) or {} if not WebSocketHandle then
metatable.__index = WebSocketHandle WebSocketHandle = getmetatable(handle) or { __index = {} }
function WebSocketHandle.__index:close()
self:closeAsync()
local _, id
repeat
_, id = event.pull("websocket_close")
until id == self:getRequestID()
end
setmetatable(handle, metatable) function WebSocketHandle.__index:receive()
local _, id, par
repeat
_, id, par = event.pull("websocket_message")
until id == self:getRequestID()
return par
end
end
return handle return handle
end end
@ -88,5 +86,5 @@ function http.websocket(url, headers)
return nil, par return nil, par
end end
return buildWebsocketHandle(requestId, par) return buildWebsocketHandle(par)
end end

View file

@ -332,7 +332,7 @@ public class HTTP : IPlugin
await task; await task;
var handle = new WebSocketHandle(wsClient, requestId, _game); var handle = new WebSocketHandle(wsClient, requestId);
WebSocketConnections.Add(handle); WebSocketConnections.Add(handle);
_game.LuaRuntime.QueueEvent("websocket_connect", LK => _game.LuaRuntime.QueueEvent("websocket_connect", LK =>
@ -368,10 +368,11 @@ public class HTTP : IPlugin
if (result.EndOfMessage) if (result.EndOfMessage)
{ {
var payload = builder.ToString();
_game.LuaRuntime.QueueEvent("websocket_message", LK => _game.LuaRuntime.QueueEvent("websocket_message", LK =>
{ {
LK.PushInteger(requestId); LK.PushInteger(requestId);
LK.PushString(builder.ToString()); LK.PushString(payload);
return 2; return 2;
}); });

View file

@ -2,78 +2,80 @@
using KeraLua; using KeraLua;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Net.WebSockets; using System.Net.WebSockets;
using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks;
namespace Capy64.Runtime.Objects.Handlers; namespace Capy64.Runtime.Objects.Handlers;
public class WebSocketHandle public class WebSocketHandle
{ {
private ClientWebSocket _client; public const string ObjectType = "WebSocketClient";
private long _requestId; private readonly ClientWebSocket _socket;
private static IGame _game; private readonly long _requestId;
public WebSocketHandle(ClientWebSocket client, long requestId, IGame game) public WebSocketHandle(ClientWebSocket socket, long requestId)
{ {
_client = client; _socket = socket;
_requestId = requestId; _requestId = requestId;
_game = game;
} }
private static readonly Dictionary<string, LuaFunction> functions = new() private static readonly Dictionary<string, LuaFunction> functions = new()
{ {
["getRequestID"] = L_GetRequestId,
["send"] = L_Send, ["send"] = L_Send,
["closeAsync"] = L_CloseAsync, ["closeAsync"] = L_CloseAsync,
}; };
public void Push(Lua L) public void Push(Lua L)
{ {
L.NewTable(); L.PushObject(this);
// metatable if (L.NewMetaTable(ObjectType))
L.NewTable();
L.PushString("__close");
L.PushCFunction(L_CloseAsync);
L.SetTable(-3);
L.PushString("__gc");
L.PushCFunction(L_CloseAsync);
L.SetTable(-3);
L.SetMetaTable(-2);
foreach (var pair in functions)
{ {
L.PushString(pair.Key); L.PushString("__index");
L.PushCFunction(pair.Value); L.NewTable();
foreach (var pair in functions)
{
L.PushString(pair.Key);
L.PushCFunction(pair.Value);
L.SetTable(-3);
}
L.SetTable(-3);
L.PushString("__close");
L.PushCFunction(L_CloseAsync);
L.SetTable(-3);
L.PushString("__gc");
L.PushCFunction(L_CloseAsync);
L.SetTable(-3); L.SetTable(-3);
} }
L.PushString("_handle"); L.SetMetaTable(-2);
L.PushObject(this);
L.SetTable(-3);
} }
private static WebSocketHandle GetHandle(Lua L, bool gc = true) private static int L_GetRequestId(IntPtr state)
{ {
L.CheckType(1, LuaType.Table); var L = Lua.FromIntPtr(state);
L.PushString("_handle");
L.GetTable(1); var client = L.CheckObject<WebSocketHandle>(1, ObjectType, false);
return L.ToObject<WebSocketHandle>(-1, gc);
L.PushInteger(client._requestId);
return 1;
} }
private static int L_Send(IntPtr state) private static int L_Send(IntPtr state)
{ {
var L = Lua.FromIntPtr(state); var L = Lua.FromIntPtr(state);
var client = L.CheckObject<WebSocketHandle>(1, ObjectType, false);
var data = L.CheckBuffer(2); var data = L.CheckBuffer(2);
var h = GetHandle(L, false); if (client is null || client._socket.State == WebSocketState.Closed)
if (h is null || h._client.State == WebSocketState.Closed)
L.Error("connection is closed"); L.Error("connection is closed");
h._client.SendAsync(data, WebSocketMessageType.Text, true, CancellationToken.None); client._socket.SendAsync(data, WebSocketMessageType.Text, true, CancellationToken.None);
return 0; return 0;
} }
@ -82,24 +84,24 @@ public class WebSocketHandle
{ {
var L = Lua.FromIntPtr(state); var L = Lua.FromIntPtr(state);
var h = GetHandle(L, true); var client = L.CheckObject<WebSocketHandle>(1, ObjectType, true);
if (h is null || h._client.State == WebSocketState.Closed) if (client is null || client._socket.State == WebSocketState.Closed)
return 0; return 0;
h._client.CloseAsync(WebSocketCloseStatus.NormalClosure, null, CancellationToken.None) client._socket.CloseAsync(WebSocketCloseStatus.NormalClosure, null, CancellationToken.None)
.ContinueWith(async task => .ContinueWith(async task =>
{ {
await task; await task;
_game.LuaRuntime.QueueEvent("websocket_close", LK => Capy64.Instance.LuaRuntime.QueueEvent("websocket_close", LK =>
{ {
LK.PushInteger(h._requestId); LK.PushInteger(client._requestId);
return 1; return 1;
}); });
}); });
HTTP.WebSocketConnections.Remove(h); HTTP.WebSocketConnections.Remove(client);
return 0; return 0;
} }