Push handle object into table and use methods to read and write.

Adapted FS lib to use the new read and write handles.
This commit is contained in:
Alessandro Proto 2023-01-13 21:30:37 +01:00
parent 027c13d86e
commit 3150bb6c7f
4 changed files with 109 additions and 361 deletions

View file

@ -9,23 +9,19 @@ using System.Threading.Tasks;
namespace Capy64.LuaRuntime.Handlers; namespace Capy64.LuaRuntime.Handlers;
public class ReadHandle : IDisposable public class ReadHandle
{ {
private readonly MemoryStream _memoryStream; public readonly StreamReader Stream;
private readonly StreamReader _stream; public bool IsClosed = false;
private bool isClosed = false;
public ReadHandle(Stream stream) public ReadHandle(Stream stream)
{ {
_memoryStream = new MemoryStream(capacity: (int)stream.Length); Stream = new StreamReader(stream);
stream.CopyTo(_memoryStream);
_memoryStream.Position = 0;
_stream = new StreamReader(_memoryStream);
} }
public void Push(Lua L) public void Push(Lua L, bool newTable = true)
{ {
if (newTable)
L.NewTable(); L.NewTable();
L.PushString("readAll"); L.PushString("readAll");
L.PushCFunction(L_ReadAll); L.PushCFunction(L_ReadAll);
@ -42,35 +38,49 @@ public class ReadHandle : IDisposable
L.PushString("close"); L.PushString("close");
L.PushCFunction(L_Close); L.PushCFunction(L_Close);
L.SetTable(-3); L.SetTable(-3);
L.PushString("_handle");
L.PushObject(this);
L.SetTable(-3);
} }
private int L_ReadAll(IntPtr state) private static int L_ReadAll(IntPtr state)
{ {
var L = Lua.FromIntPtr(state); var L = Lua.FromIntPtr(state);
if (isClosed) L.CheckType(1, LuaType.Table);
L.PushString("_handle");
L.GetTable(1);
var h = L.ToObject<ReadHandle>(-1, false);
if (h is null || h.IsClosed)
L.Error("handle is closed"); L.Error("handle is closed");
if (_stream.EndOfStream) if (h.Stream.EndOfStream)
{ {
L.PushNil(); L.PushNil();
return 1; return 1;
} }
var content = _stream.ReadToEnd(); var content = h.Stream.ReadToEnd();
L.PushString(content); L.PushString(content);
return 1; return 1;
} }
private int L_ReadLine(IntPtr state) private static int L_ReadLine(IntPtr state)
{ {
var L = Lua.FromIntPtr(state); var L = Lua.FromIntPtr(state);
if (isClosed) L.CheckType(1, LuaType.Table);
L.PushString("_handle");
L.GetTable(1);
var h = L.ToObject<ReadHandle>(-1, false);
if (h is null || h.IsClosed)
L.Error("handle is closed"); L.Error("handle is closed");
var line = _stream.ReadLine(); var line = h.Stream.ReadLine();
if (line is null) if (line is null)
L.PushNil(); L.PushNil();
@ -80,17 +90,24 @@ public class ReadHandle : IDisposable
return 1; return 1;
} }
private int L_Read(IntPtr state) private static int L_Read(IntPtr state)
{ {
var L = Lua.FromIntPtr(state); var L = Lua.FromIntPtr(state);
var count = (int)L.OptNumber(1, 1);
L.ArgumentCheck(count >= 1, 1, "count must be a positive integer"); L.CheckType(1, LuaType.Table);
var count = (int)L.OptNumber(2, 1);
if (isClosed) L.PushString("_handle");
L.GetTable(1);
var h = L.ToObject<ReadHandle>(-1, false);
L.ArgumentCheck(count >= 1, 2, "count must be a positive integer");
if (h is null || h.IsClosed)
L.Error("handle is closed"); L.Error("handle is closed");
if (_stream.EndOfStream) if (h.Stream.EndOfStream)
{ {
L.PushNil(); L.PushNil();
return 1; return 1;
@ -98,29 +115,29 @@ public class ReadHandle : IDisposable
var chunk = new char[count]; var chunk = new char[count];
_stream.Read(chunk, 0, count); h.Stream.Read(chunk, 0, count);
L.PushString(new string(chunk)); L.PushString(new string(chunk));
return 1; return 1;
} }
private int L_Close(IntPtr state) private static int L_Close(IntPtr state)
{ {
var L = Lua.FromIntPtr(state); var L = Lua.FromIntPtr(state);
if (isClosed) L.CheckType(1, LuaType.Table);
L.PushString("_handle");
L.GetTable(1);
var h = L.ToObject<ReadHandle>(-1, true);
if (h is null || h.IsClosed)
return 0; return 0;
_stream.Close(); h.Stream.Close();
isClosed = true; h.IsClosed = true;
return 0; return 0;
} }
public void Dispose()
{
GC.SuppressFinalize(this);
}
} }

View file

@ -10,21 +10,22 @@ namespace Capy64.LuaRuntime.Handlers;
public class WriteHandle public class WriteHandle
{ {
private readonly StreamWriter _stream; public readonly StreamWriter Stream;
private bool isClosed = false; public bool IsClosed = false;
public WriteHandle(Stream stream) public WriteHandle(Stream stream)
{ {
_stream = new StreamWriter(stream); Stream = new StreamWriter(stream);
} }
public WriteHandle(StreamWriter stream) public WriteHandle(StreamWriter stream)
{ {
_stream = stream; Stream = stream;
} }
public void Push(Lua L) public void Push(Lua L, bool newTable = true)
{ {
L.NewTable(); if (newTable)
L.NewTable();
L.PushString("write"); L.PushString("write");
L.PushCFunction(L_Write); L.PushCFunction(L_Write);
@ -33,7 +34,7 @@ public class WriteHandle
L.PushString("writeLine"); L.PushString("writeLine");
L.PushCFunction(L_WriteLine); L.PushCFunction(L_WriteLine);
L.SetTable(-3); L.SetTable(-3);
L.PushString("flush"); L.PushString("flush");
L.PushCFunction(L_Flush); L.PushCFunction(L_Flush);
L.SetTable(-3); L.SetTable(-3);
@ -41,61 +42,84 @@ public class WriteHandle
L.PushString("close"); L.PushString("close");
L.PushCFunction(L_Close); L.PushCFunction(L_Close);
L.SetTable(-3); L.SetTable(-3);
L.PushString("_handle");
L.PushObject(this);
L.SetTable(-3);
} }
private int L_Write(IntPtr state) private static int L_Write(IntPtr state)
{ {
var L = Lua.FromIntPtr(state); var L = Lua.FromIntPtr(state);
if (isClosed) L.CheckType(1, LuaType.Table);
var content = L.CheckString(2);
L.PushString("_handle");
L.GetTable(1);
var h = L.ToObject<WriteHandle>(-1, false);
if (h is null || h.IsClosed)
L.Error("handle is closed"); L.Error("handle is closed");
var content = L.CheckString(1);
_stream.Write(content); h.Stream.Write(content);
return 0; return 0;
} }
private int L_WriteLine(IntPtr state) private static int L_WriteLine(IntPtr state)
{ {
var L = Lua.FromIntPtr(state); var L = Lua.FromIntPtr(state);
if (isClosed) L.CheckType(1, LuaType.Table);
var content = L.CheckString(2);
L.PushString("_handle");
L.GetTable(1);
var h = L.ToObject<WriteHandle>(-1, false);
if (h is null || h.IsClosed)
L.Error("handle is closed"); L.Error("handle is closed");
var content = L.CheckString(1);
_stream.WriteLine(content); h.Stream.WriteLine(content);
return 0; return 0;
} }
private int L_Flush(IntPtr state) private static int L_Flush(IntPtr state)
{ {
var L = Lua.FromIntPtr(state); var L = Lua.FromIntPtr(state);
var count = (int)L.OptNumber(1, 1);
L.ArgumentCheck(count < 1, 1, "count must be a positive integer"); L.CheckType(1, LuaType.Table);
L.PushString("_handle");
L.GetTable(1);
var h = L.ToObject<WriteHandle>(-1, false);
if (isClosed) if (h is null || h.IsClosed)
L.Error("handle is closed"); L.Error("handle is closed");
_stream.Flush(); h.Stream.Flush();
return 0; return 0;
} }
private int L_Close(IntPtr state) private static int L_Close(IntPtr state)
{ {
var L = Lua.FromIntPtr(state); var L = Lua.FromIntPtr(state);
if (isClosed) L.CheckType(1, LuaType.Table);
L.PushString("_handle");
L.GetTable(1);
var h = L.ToObject<WriteHandle>(-1, true);
if (h is null || h.IsClosed)
return 0; return 0;
_stream.Close(); h.Stream.Close();
isClosed = true; h.IsClosed = true;
return 0; return 0;
} }

View file

@ -1,5 +1,6 @@
using Capy64.API; using Capy64.API;
using Capy64.LuaRuntime.Extensions; using Capy64.LuaRuntime.Extensions;
using Capy64.LuaRuntime.Handlers;
using KeraLua; using KeraLua;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@ -512,225 +513,18 @@ public class FileSystem : IPlugin
} }
} }
var handle = File.Open(path, fileMode, fileAccess, FileShare.ReadWrite); var fileStream = File.Open(path, fileMode, fileAccess, FileShare.ReadWrite);
bool isClosed = false;
// todo: add binary mode
var functions = new Dictionary<string, Func<nint, int>>();
if (fileAccess == FileAccess.Read) if (fileAccess == FileAccess.Read)
{ {
var reader = new StreamReader(handle); var handle = new ReadHandle(fileStream);
functions["read"] = (IntPtr state) => handle.Push(L);
{
var L = Lua.FromIntPtr(state);
var count = (int)L.OptNumber(1, 1);
if (isClosed)
{
L.Error("file handle is closed");
return 0;
}
if (reader.EndOfStream)
{
L.PushNil();
return 1;
}
if (binaryMode)
{
var data = new byte[count];
handle.Read(data, 0, count);
L.PushBuffer(data);
}
else
{
var data = new char[count];
reader.ReadBlock(data, 0, count);
L.PushString(new string(data));
}
return 1;
};
functions["readLine"] = (IntPtr state) =>
{
var L = Lua.FromIntPtr(state);
var count = (int)L.OptNumber(1, 1);
if (isClosed)
{
L.Error("file handle is closed");
return 0;
}
if (reader.EndOfStream)
{
L.PushNil();
return 1;
}
if (binaryMode)
{
var line = reader.ReadLine();
L.PushBuffer(Encoding.UTF8.GetBytes(line));
}
else
{
var line = reader.ReadLine();
L.PushString(line);
}
return 1;
};
functions["readAll"] = (IntPtr state) =>
{
var L = Lua.FromIntPtr(state);
var count = (int)L.OptNumber(1, 1);
if (isClosed)
{
L.Error("file handle is closed");
return 0;
}
if (reader.EndOfStream)
{
L.PushNil();
return 1;
}
if (binaryMode)
{
var content = reader.ReadToEnd();
L.PushBuffer(Encoding.UTF8.GetBytes(content));
}
else
{
var content = reader.ReadToEnd();
L.PushString(content);
}
return 1;
};
} }
else else if (fileAccess == FileAccess.Write)
{ {
var writer = new StreamWriter(handle); var handle = new WriteHandle(fileStream);
functions["write"] = (IntPtr state) => handle.Push(L);
{
var L = Lua.FromIntPtr(state);
L.ArgumentCheck(L.IsStringOrNumber(1), 1, "string or number value expected");
if (isClosed)
{
L.Error("file handle is closed");
return 0;
}
if (L.IsString(1))
{
if (binaryMode)
{
handle.Write(L.ToBuffer(1));
}
else
{
writer.Write(L.ToString(1));
}
}
else
{
handle.WriteByte((byte)L.ToInteger(1));
}
return 0;
};
functions["writeLine"] = (IntPtr state) =>
{
var L = Lua.FromIntPtr(state);
L.ArgumentCheck(L.IsStringOrNumber(1), 1, "string or number value expected");
if (isClosed)
{
L.Error("file handle is closed");
return 0;
}
if (L.IsString(1))
{
if (binaryMode)
{
handle.Write(L.ToBuffer(1));
handle.WriteByte((byte)'\n');
}
else
{
writer.WriteLine(L.ToString(1));
}
}
else
{
handle.WriteByte((byte)L.ToInteger(1));
handle.WriteByte((byte)'\n');
}
return 0;
};
functions["flush"] = (IntPtr state) =>
{
var L = Lua.FromIntPtr(state);
if (isClosed)
{
L.Error("file handle is closed");
return 0;
}
handle.Flush();
return 0;
};
}
functions["close"] = (IntPtr state) =>
{
var L = Lua.FromIntPtr(state);
if (isClosed)
{
L.Error("file handle is closed");
return 0;
}
if (fileAccess != FileAccess.Read)
{
handle.Flush();
}
handle.Dispose();
isClosed = true;
return 0;
};
L.NewTable();
foreach (var pair in functions)
{
L.PushString(pair.Key);
L.PushCFunction(new LuaFunction(pair.Value));
L.SetTable(-3);
} }
return 1; return 1;

View file

@ -160,8 +160,8 @@ public class HTTP : IPlugin
else else
content = await response.Content.ReadAsStringAsync();*/ content = await response.Content.ReadAsStringAsync();*/
var _stream = new StreamReader(await response.Content.ReadAsStreamAsync()); var stream = await response.Content.ReadAsStreamAsync();
var isClosed = false; var handler = new ReadHandle(stream);
_game.LuaRuntime.PushEvent("http_response", L => _game.LuaRuntime.PushEvent("http_response", L =>
{ {
@ -195,94 +195,7 @@ public class HTTP : IPlugin
L.SetTable(-3); L.SetTable(-3);
L.PushString("content"); handler.Push(L, false);
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; return 2;
}); });