From 027c13d86eea32070686e867c45e3546f7523ea4 Mon Sep 17 00:00:00 2001 From: Alessandro Proto Date: Fri, 13 Jan 2023 20:39:54 +0100 Subject: [PATCH] Attempting to return streams as response content. Fails horribly after reaching the end and attempting to access the methods --- .../LuaRuntime/Handlers/BinaryReadHandle.cs | 128 ++++++++++++++++++ .../LuaRuntime/Handlers/BinaryWriteHandle.cs | 127 +++++++++++++++++ Capy64/LuaRuntime/Handlers/ReadHandle.cs | 126 +++++++++++++++++ Capy64/LuaRuntime/Handlers/WriteHandle.cs | 102 ++++++++++++++ Capy64/LuaRuntime/Libraries/HTTP.cs | 107 +++++++++++++-- 5 files changed, 580 insertions(+), 10 deletions(-) create mode 100644 Capy64/LuaRuntime/Handlers/BinaryReadHandle.cs create mode 100644 Capy64/LuaRuntime/Handlers/BinaryWriteHandle.cs create mode 100644 Capy64/LuaRuntime/Handlers/ReadHandle.cs create mode 100644 Capy64/LuaRuntime/Handlers/WriteHandle.cs diff --git a/Capy64/LuaRuntime/Handlers/BinaryReadHandle.cs b/Capy64/LuaRuntime/Handlers/BinaryReadHandle.cs new file mode 100644 index 0000000..f87f5ce --- /dev/null +++ b/Capy64/LuaRuntime/Handlers/BinaryReadHandle.cs @@ -0,0 +1,128 @@ +using KeraLua; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Capy64.LuaRuntime.Handlers; + +[Obsolete("Work in progress")] +public class BinaryReadHandle +{ + private readonly BinaryReader _stream; + private bool isClosed = false; + private bool ended => _stream.BaseStream.Position == _stream.BaseStream.Length; + public BinaryReadHandle(Stream stream) + { + _stream = new BinaryReader(stream); + } + + public BinaryReadHandle(BinaryReader stream) + { + _stream = stream; + } + + /*public void Push(Lua L) + { + L.NewTable(); + + L.PushString("readAll"); + L.PushCFunction(L_ReadAll); + L.SetTable(-3); + + L.PushString("readLine"); + L.PushCFunction(L_ReadLine); + L.SetTable(-3); + + L.PushString("read"); + L.PushCFunction(L_Read); + L.SetTable(-3); + + L.PushString("close"); + L.PushCFunction(L_Close); + L.SetTable(-3); + } + + private int L_ReadAll(IntPtr state) + { + var L = Lua.FromIntPtr(state); + + if (isClosed) + L.Error("handle is closed"); + + if (ended) + { + L.PushNil(); + return 1; + } + + //var content = _stream.read; + L.PushString(content); + + return 1; + } + + private int L_ReadLine(IntPtr state) + { + var L = Lua.FromIntPtr(state); + + if (isClosed) + L.Error("handle is closed"); + + if (ended) + { + L.PushNil(); + return 1; + } + + var line = _stream.ReadLine(); + + if (line is null) + L.PushNil(); + else + L.PushString(line); + + return 1; + } + + private int L_Read(IntPtr state) + { + var L = Lua.FromIntPtr(state); + var count = (int)L.OptNumber(1, 1); + + L.ArgumentCheck(count < 1, 1, "count must be a positive integer"); + + if (ended) + L.Error("handle is closed"); + + if (_stream.EndOfStream) + { + L.PushNil(); + return 1; + } + + var chunk = new char[count]; + + _stream.Read(chunk, 0, count); + + L.PushString(new string(chunk)); + + return 1; + } + + private int L_Close(IntPtr state) + { + var L = Lua.FromIntPtr(state); + + if (isClosed) + return 0; + + _stream.Close(); + + isClosed = true; + + return 0; + }*/ +} diff --git a/Capy64/LuaRuntime/Handlers/BinaryWriteHandle.cs b/Capy64/LuaRuntime/Handlers/BinaryWriteHandle.cs new file mode 100644 index 0000000..6a6e032 --- /dev/null +++ b/Capy64/LuaRuntime/Handlers/BinaryWriteHandle.cs @@ -0,0 +1,127 @@ +using KeraLua; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Capy64.LuaRuntime.Handlers; + +[Obsolete("Work in progress")] +public class BinaryWriteHandle +{ + private readonly BinaryWriter _stream; + private bool isClosed = false; + public BinaryWriteHandle(Stream stream) + { + _stream = new BinaryWriter(stream); + } + + public BinaryWriteHandle(BinaryWriter stream) + { + _stream = stream; + } + + /*public void Push(Lua L) + { + L.NewTable(); + + L.PushString("readAll"); + L.PushCFunction(L_ReadAll); + L.SetTable(-3); + + L.PushString("readLine"); + L.PushCFunction(L_ReadLine); + L.SetTable(-3); + + L.PushString("read"); + L.PushCFunction(L_Read); + L.SetTable(-3); + + L.PushString("close"); + L.PushCFunction(L_Close); + L.SetTable(-3); + } + + private int L_ReadAll(IntPtr state) + { + var L = Lua.FromIntPtr(state); + + if (isClosed) + L.Error("handle is closed"); + + if (ended) + { + L.PushNil(); + return 1; + } + + //var content = _stream.read; + L.PushString(content); + + return 1; + } + + private int L_ReadLine(IntPtr state) + { + var L = Lua.FromIntPtr(state); + + if (isClosed) + L.Error("handle is closed"); + + if (ended) + { + L.PushNil(); + return 1; + } + + var line = _stream.ReadLine(); + + if (line is null) + L.PushNil(); + else + L.PushString(line); + + return 1; + } + + private int L_Read(IntPtr state) + { + var L = Lua.FromIntPtr(state); + var count = (int)L.OptNumber(1, 1); + + L.ArgumentCheck(count < 1, 1, "count must be a positive integer"); + + if (ended) + L.Error("handle is closed"); + + if (_stream.EndOfStream) + { + L.PushNil(); + return 1; + } + + var chunk = new char[count]; + + _stream.Read(chunk, 0, count); + + L.PushString(new string(chunk)); + + return 1; + } + + private int L_Close(IntPtr state) + { + var L = Lua.FromIntPtr(state); + + if (isClosed) + return 0; + + _stream.Close(); + + isClosed = true; + + return 0; + }*/ +} diff --git a/Capy64/LuaRuntime/Handlers/ReadHandle.cs b/Capy64/LuaRuntime/Handlers/ReadHandle.cs new file mode 100644 index 0000000..6005c58 --- /dev/null +++ b/Capy64/LuaRuntime/Handlers/ReadHandle.cs @@ -0,0 +1,126 @@ +using KeraLua; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net.Http; +using System.Text; +using System.Threading.Tasks; + +namespace Capy64.LuaRuntime.Handlers; + +public class ReadHandle : IDisposable +{ + private readonly MemoryStream _memoryStream; + private readonly StreamReader _stream; + private bool isClosed = false; + public ReadHandle(Stream stream) + { + _memoryStream = new MemoryStream(capacity: (int)stream.Length); + stream.CopyTo(_memoryStream); + _memoryStream.Position = 0; + _stream = new StreamReader(_memoryStream); + } + + public void Push(Lua L) + { + + L.NewTable(); + + L.PushString("readAll"); + L.PushCFunction(L_ReadAll); + L.SetTable(-3); + + L.PushString("readLine"); + L.PushCFunction(L_ReadLine); + L.SetTable(-3); + + L.PushString("read"); + L.PushCFunction(L_Read); + L.SetTable(-3); + + L.PushString("close"); + L.PushCFunction(L_Close); + L.SetTable(-3); + } + + private int L_ReadAll(IntPtr state) + { + var L = Lua.FromIntPtr(state); + + if (isClosed) + L.Error("handle is closed"); + + if (_stream.EndOfStream) + { + L.PushNil(); + return 1; + } + + var content = _stream.ReadToEnd(); + L.PushString(content); + + return 1; + } + + private int L_ReadLine(IntPtr state) + { + var L = Lua.FromIntPtr(state); + + if (isClosed) + L.Error("handle is closed"); + + var line = _stream.ReadLine(); + + if (line is null) + L.PushNil(); + else + L.PushString(line); + + return 1; + } + + private int L_Read(IntPtr state) + { + var L = Lua.FromIntPtr(state); + var count = (int)L.OptNumber(1, 1); + + L.ArgumentCheck(count >= 1, 1, "count must be a positive integer"); + + if (isClosed) + L.Error("handle is closed"); + + if (_stream.EndOfStream) + { + L.PushNil(); + return 1; + } + + var chunk = new char[count]; + + _stream.Read(chunk, 0, count); + + L.PushString(new string(chunk)); + + return 1; + } + + private int L_Close(IntPtr state) + { + var L = Lua.FromIntPtr(state); + + if (isClosed) + return 0; + + _stream.Close(); + + isClosed = true; + + return 0; + } + + public void Dispose() + { + GC.SuppressFinalize(this); + } +} diff --git a/Capy64/LuaRuntime/Handlers/WriteHandle.cs b/Capy64/LuaRuntime/Handlers/WriteHandle.cs new file mode 100644 index 0000000..d33d9ae --- /dev/null +++ b/Capy64/LuaRuntime/Handlers/WriteHandle.cs @@ -0,0 +1,102 @@ +using KeraLua; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Capy64.LuaRuntime.Handlers; + +public class WriteHandle +{ + private readonly StreamWriter _stream; + private bool isClosed = false; + public WriteHandle(Stream stream) + { + _stream = new StreamWriter(stream); + } + + public WriteHandle(StreamWriter stream) + { + _stream = stream; + } + + public void Push(Lua L) + { + L.NewTable(); + + L.PushString("write"); + L.PushCFunction(L_Write); + L.SetTable(-3); + + L.PushString("writeLine"); + L.PushCFunction(L_WriteLine); + L.SetTable(-3); + + L.PushString("flush"); + L.PushCFunction(L_Flush); + L.SetTable(-3); + + L.PushString("close"); + L.PushCFunction(L_Close); + L.SetTable(-3); + } + + private int L_Write(IntPtr state) + { + var L = Lua.FromIntPtr(state); + + if (isClosed) + L.Error("handle is closed"); + + var content = L.CheckString(1); + + _stream.Write(content); + + return 0; + } + + private int L_WriteLine(IntPtr state) + { + var L = Lua.FromIntPtr(state); + + if (isClosed) + L.Error("handle is closed"); + + var content = L.CheckString(1); + + _stream.WriteLine(content); + + return 0; + } + + private int L_Flush(IntPtr state) + { + var L = Lua.FromIntPtr(state); + var count = (int)L.OptNumber(1, 1); + + L.ArgumentCheck(count < 1, 1, "count must be a positive integer"); + + if (isClosed) + L.Error("handle is closed"); + + _stream.Flush(); + + return 0; + } + + private int L_Close(IntPtr state) + { + var L = Lua.FromIntPtr(state); + + if (isClosed) + return 0; + + _stream.Close(); + + isClosed = true; + + return 0; + } +} diff --git a/Capy64/LuaRuntime/Libraries/HTTP.cs b/Capy64/LuaRuntime/Libraries/HTTP.cs index efb6e19..cacb779 100644 --- a/Capy64/LuaRuntime/Libraries/HTTP.cs +++ b/Capy64/LuaRuntime/Libraries/HTTP.cs @@ -1,8 +1,10 @@ using Capy64.API; using Capy64.LuaRuntime.Extensions; +using Capy64.LuaRuntime.Handlers; using KeraLua; using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Net.Http; @@ -13,6 +15,7 @@ public class HTTP : IPlugin private static IGame _game; private static HttpClient _client; private static long RequestId; + private static List ReadHandles = new(); private readonly LuaRegister[] HttpLib = new LuaRegister[] { @@ -151,12 +154,14 @@ public class HTTP : IPlugin reqTask.ContinueWith(async (task) => { var response = await task; - object content; + /*object content; if ((bool)options["binary"]) content = await response.Content.ReadAsByteArrayAsync(); else - content = await response.Content.ReadAsStringAsync(); + content = await response.Content.ReadAsStringAsync();*/ + var _stream = new StreamReader(await response.Content.ReadAsStreamAsync()); + var isClosed = false; _game.LuaRuntime.PushEvent("http_response", L => { @@ -178,23 +183,105 @@ public class HTTP : IPlugin L.PushString(response.ReasonPhrase); L.SetTable(-3); - L.PushString("content"); - if ((bool)options["binary"]) - L.PushBuffer((byte[])content); - else - L.PushString((string)content); - L.SetTable(-3); - L.PushString("headers"); L.NewTable(); - foreach(var header in response.Headers) + foreach (var header in response.Headers) { L.PushString(header.Key); L.PushArray(header.Value.ToArray()); L.SetTable(-3); } + L.SetTable(-3); + + L.PushString("content"); + L.NewTable(); + + L.PushString("readAll"); + L.PushCFunction((IntPtr state) => + { + var L = Lua.FromIntPtr(state); + + if (isClosed) + L.Error("handle is closed"); + + if (_stream.EndOfStream) + { + L.PushNil(); + return 1; + } + + var content = _stream.ReadToEnd(); + L.PushString(content); + + return 1; + }); + L.SetTable(-3); + + L.PushString("readLine"); + L.PushCFunction((IntPtr state) => + { + var L = Lua.FromIntPtr(state); + + if (isClosed) + L.Error("handle is closed"); + + var line = _stream.ReadLine(); + + if (line is null) + L.PushNil(); + else + L.PushString(line); + + return 1; + }); + L.SetTable(-3); + + L.PushString("read"); + L.PushCFunction((IntPtr state) => + { + var L = Lua.FromIntPtr(state); + var count = (int)L.OptNumber(1, 1); + + L.ArgumentCheck(count >= 1, 1, "count must be a positive integer"); + + if (isClosed) + L.Error("handle is closed"); + + if (_stream.EndOfStream) + { + L.PushNil(); + return 1; + } + + var chunk = new char[count]; + + _stream.Read(chunk, 0, count); + + L.PushString(new string(chunk)); + + return 1; + }); + L.SetTable(-3); + + L.PushString("close"); + L.PushCFunction((IntPtr state) => + { + var L = Lua.FromIntPtr(state); + + if (isClosed) + return 0; + + _stream.Close(); + + isClosed = true; + + return 0; + }); + L.SetTable(-3); + + L.SetTable(-3); return 2;