[feat] Ctl framework
This commit is contained in:
49
abyssctl/App/App.cs
Normal file
49
abyssctl/App/App.cs
Normal file
@@ -0,0 +1,49 @@
|
||||
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using abyssctl.App.Modules;
|
||||
using abyssctl.Model;
|
||||
using abyssctl.Static;
|
||||
using CommandLine;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace abyssctl.App;
|
||||
|
||||
public class App
|
||||
{
|
||||
private static readonly string SocketPath = "ctl.sock";
|
||||
|
||||
public static async Task<Ctl> CtlWriteRead(Ctl ctl)
|
||||
{
|
||||
var endPoint = new UnixDomainSocketEndPoint(SocketPath);
|
||||
using var socket = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.Unspecified);
|
||||
try
|
||||
{
|
||||
await socket.ConnectAsync(endPoint);
|
||||
await socket.WriteBase64Async(Ctl.MakeBase64(ctl.Head, ctl.Params));
|
||||
var s = Encoding.UTF8.GetString(
|
||||
Convert.FromBase64String(await socket.ReadBase64Async()));
|
||||
return JsonConvert.DeserializeObject<Ctl>(s)!;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return new Ctl
|
||||
{
|
||||
Head = 500,
|
||||
Params = [e.Message]
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<int> RunAsync(string[] args)
|
||||
{
|
||||
return await Task.Run(() =>
|
||||
{
|
||||
return Parser.Default.ParseArguments<HelloOptions, VersionOptions>(args)
|
||||
.MapResult(
|
||||
(HelloOptions opt) => HelloOptions.Run(opt),
|
||||
(VersionOptions opt) => VersionOptions.Run(opt),
|
||||
_ => 1);
|
||||
});
|
||||
}
|
||||
}
|
||||
20
abyssctl/App/Modules/HelloOptions.cs
Normal file
20
abyssctl/App/Modules/HelloOptions.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using abyssctl.Model;
|
||||
using CommandLine;
|
||||
|
||||
namespace abyssctl.App.Modules;
|
||||
|
||||
[Verb("hello", HelpText = "Say hello to abyss server")]
|
||||
public class HelloOptions
|
||||
{
|
||||
public static int Run(HelloOptions opts)
|
||||
{
|
||||
var r = App.CtlWriteRead(new Ctl
|
||||
{
|
||||
Head = 100,
|
||||
Params = []
|
||||
}).GetAwaiter().GetResult();
|
||||
Console.WriteLine($"Response Code: {r.Head}");
|
||||
Console.WriteLine($"Params: {string.Join(",", r.Params)}");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
13
abyssctl/App/Modules/VersionOptions.cs
Normal file
13
abyssctl/App/Modules/VersionOptions.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using CommandLine;
|
||||
|
||||
namespace abyssctl.App.Modules;
|
||||
|
||||
[Verb("ver", HelpText = "Get server version")]
|
||||
public class VersionOptions
|
||||
{
|
||||
public static int Run(VersionOptions opts)
|
||||
{
|
||||
Console.WriteLine("Version");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
19
abyssctl/Model/Ctl.cs
Normal file
19
abyssctl/Model/Ctl.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using System.Text;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace abyssctl.Model;
|
||||
|
||||
public class Ctl
|
||||
{
|
||||
[JsonProperty("head")] public int Head { get; set; }
|
||||
|
||||
[JsonProperty("params")] public string[] Params { get; set; } = [];
|
||||
|
||||
public static string MakeBase64(int head, string[] param)
|
||||
{
|
||||
return Convert.ToBase64String(
|
||||
Encoding.UTF8.GetBytes(
|
||||
JsonConvert.SerializeObject(new Ctl
|
||||
{ Head = head, Params = param })));
|
||||
}
|
||||
}
|
||||
13
abyssctl/Program.cs
Normal file
13
abyssctl/Program.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
|
||||
|
||||
namespace abyssctl;
|
||||
|
||||
|
||||
static class Program
|
||||
{
|
||||
static async Task<int> Main(string[] args)
|
||||
{
|
||||
var app = new App.App();
|
||||
return await app.RunAsync(args);
|
||||
}
|
||||
}
|
||||
50
abyssctl/Static/SocketExtensions.cs
Normal file
50
abyssctl/Static/SocketExtensions.cs
Normal file
@@ -0,0 +1,50 @@
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
|
||||
namespace abyssctl.Static;
|
||||
|
||||
public static class SocketExtensions
|
||||
{
|
||||
public static async Task<string> ReadBase64Async(this Socket socket, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var buffer = new byte[4096];
|
||||
var sb = new StringBuilder();
|
||||
|
||||
while (true)
|
||||
{
|
||||
int bytesRead = await socket.ReceiveAsync(buffer, SocketFlags.None, cancellationToken).ConfigureAwait(false);
|
||||
if (bytesRead == 0)
|
||||
throw new SocketException((int)SocketError.ConnectionReset);
|
||||
|
||||
string chunk = Encoding.UTF8.GetString(buffer, 0, bytesRead);
|
||||
sb.Append(chunk);
|
||||
|
||||
int newlineIndex = sb.ToString().IndexOf('\n');
|
||||
if (newlineIndex >= 0)
|
||||
{
|
||||
string base64 = sb.ToString(0, newlineIndex).Trim();
|
||||
sb.Remove(0, newlineIndex + 1);
|
||||
return base64;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task WriteBase64Async(this Socket socket, string base64, CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(base64))
|
||||
throw new ArgumentException("Base64 string cannot be null or empty.", nameof(base64));
|
||||
|
||||
string message = base64 + "\n";
|
||||
byte[] data = Encoding.UTF8.GetBytes(message);
|
||||
|
||||
int totalSent = 0;
|
||||
while (totalSent < data.Length)
|
||||
{
|
||||
int sent = await socket.SendAsync(data.AsMemory(totalSent), SocketFlags.None, cancellationToken).ConfigureAwait(false);
|
||||
if (sent == 0)
|
||||
throw new SocketException((int)SocketError.ConnectionReset);
|
||||
|
||||
totalSent += sent;
|
||||
}
|
||||
}
|
||||
}
|
||||
24
abyssctl/abyssctl.csproj
Normal file
24
abyssctl/abyssctl.csproj
Normal file
@@ -0,0 +1,24 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<LangVersion>13</LangVersion>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<PublishAot>false</PublishAot>
|
||||
<InvariantGlobalization>true</InvariantGlobalization>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
||||
<OutputPath>../build/</OutputPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CommandLineParser" Version="2.9.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.CommandLine" Version="9.0.9" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
|
||||
<PackageReference Include="System.CommandLine" Version="2.0.0-rc.1.25451.107" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
Reference in New Issue
Block a user