Refactor SS,SSR Controller Generate Argument

This commit is contained in:
ChsBuffer
2021-07-19 06:35:57 +08:00
parent 773bad4845
commit 5647a6c7ea
4 changed files with 76 additions and 211 deletions

49
Netch/Models/Arguments.cs Normal file
View File

@@ -0,0 +1,49 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Netch.Utils;
namespace Netch.Models
{
public static class Arguments
{
public static string Format(IEnumerable<object?> a)
{
var arguments = a.ToList();
if (arguments.Count % 2 != 0)
throw new FormatException("missing last argument value");
var tokens = new List<string>();
for (var i = 0; i < arguments.Count; i += 2)
{
var keyObj = arguments[i];
var valueObj = arguments[i + 1];
if (keyObj is not string key)
throw new FormatException($"argument key at array index {i} is not string");
switch (valueObj)
{
case SpecialArgument.Flag:
tokens.Add(key);
break;
case null:
case string value when value.IsNullOrWhiteSpace():
continue;
default:
tokens.Add(key);
tokens.Add(valueObj.ToString()!);
break;
}
}
return string.Join(' ', tokens);
}
}
public enum SpecialArgument
{
Flag
}
}

View File

@@ -1,120 +0,0 @@
using System;
using System.Linq;
using System.Reflection;
namespace Netch.Models
{
public abstract class ParameterBase
{
// null value par
private readonly bool _full;
protected readonly string ParametersSeparate = " ";
protected readonly string Separate = " ";
protected readonly string VerbPrefix = "-";
protected readonly string FullPrefix = "--";
protected ParameterBase()
{
_full = !GetType().IsDefined(typeof(VerbAttribute));
}
public override string ToString()
{
var parameters = GetType().GetProperties().Select(PropToParameter).Where(s => s != null).Cast<string>();
return string.Join(ParametersSeparate, parameters).Trim();
}
private string? PropToParameter(PropertyInfo p)
{
// prefix
bool full;
if (p.IsDefined(typeof(VerbAttribute)))
full = false;
else if (p.IsDefined(typeof(FullAttribute)))
full = true;
else
full = _full;
var prefix = full ? FullPrefix : VerbPrefix;
// key
var key = p.GetCustomAttribute<RealNameAttribute>()?.Name ?? p.Name;
// build
var value = p.GetValue(this);
switch (value)
{
case bool b:
return b ? $"{prefix}{key}" : null;
default:
if (string.IsNullOrWhiteSpace(value?.ToString()))
return p.IsDefined(typeof(OptionalAttribute)) ? null : throw new RequiredArgumentValueInvalidException(p.Name, this, null);
if (p.IsDefined(typeof(QuoteAttribute)))
value = $"\"{value}\"";
return $"{prefix}{key}{Separate}{value}";
}
}
}
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Class)]
public class VerbAttribute : Attribute
{
// Don't use verb and full both on one class or property
// if you did, will take verb
}
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Class)]
public class FullAttribute : Attribute
{
}
[AttributeUsage(AttributeTargets.Property)]
public class OptionalAttribute : Attribute
{
}
[AttributeUsage(AttributeTargets.Property)]
public class QuoteAttribute : Attribute
{
}
[AttributeUsage(AttributeTargets.Property)]
public class RealNameAttribute : Attribute
{
public string Name { get; }
public RealNameAttribute(string name)
{
Name = name;
}
}
[Serializable]
public class RequiredArgumentValueInvalidException : Exception
{
public string? ArgumentName { get; }
public object? ArgumentObject { get; }
private readonly string? _message;
private const string DefaultMessage = "{0}'s Argument \"{1}\" value invalid. A required argument's value can't be null or empty.";
public override string Message => _message ?? string.Format(DefaultMessage, ArgumentObject!.GetType(), ArgumentName);
public RequiredArgumentValueInvalidException()
{
_message = "Some Argument value invalid. A required argument value's can't be null or empty.";
}
public RequiredArgumentValueInvalidException(string argumentName, object argumentObject, string? message)
{
ArgumentName = argumentName;
ArgumentObject = argumentObject;
_message = message;
}
}
}

View File

@@ -27,48 +27,21 @@ namespace Netch.Servers.Shadowsocks
{
var server = (Shadowsocks)s;
var command = new SSParameter
var arguments = new object?[]
{
s = await server.AutoResolveHostnameAsync(),
p = server.Port,
b = this.LocalAddress(),
l = this.Socks5LocalPort(),
m = server.EncryptMethod,
k = server.Password,
u = true,
plugin = server.Plugin,
plugin_opts = server.PluginOption
"-s", await server.AutoResolveHostnameAsync(),
"-p", server.Port,
"-b", this.LocalAddress(),
"-l", this.Socks5LocalPort(),
"-m", server.EncryptMethod,
"-k", server.Password,
"-u", SpecialArgument.Flag,
"--plugin", server.Plugin,
"--plugin-opts", server.PluginOption
};
await StartGuardAsync(command.ToString());
await StartGuardAsync(Arguments.Format(arguments));
return new Socks5Bridge(IPAddress.Loopback.ToString(), this.Socks5LocalPort(), server.Hostname);
}
[Verb]
private class SSParameter : ParameterBase
{
public string? s { get; set; }
public ushort? p { get; set; }
public string? b { get; set; }
public ushort? l { get; set; }
public string? m { get; set; }
public string? k { get; set; }
public bool u { get; set; }
[Full] [Optional] public string? plugin { get; set; }
[Full]
[Optional]
[RealName("plugin-opts")]
public string? plugin_opts { get; set; }
[Full] [Quote] [Optional] public string? acl { get; set; }
}
}
}

View File

@@ -1,3 +1,4 @@
using System;
using System.Collections.Generic;
using System.Net;
using System.Threading.Tasks;
@@ -27,62 +28,24 @@ namespace Netch.Servers.ShadowsocksR
{
var server = (ShadowsocksR)s;
var command = new SSRParameter
var arguments = new object?[]
{
s = await server.AutoResolveHostnameAsync(),
p = server.Port,
k = server.Password,
m = server.EncryptMethod,
t = "120",
O = server.Protocol,
G = server.ProtocolParam,
o = server.OBFS,
g = server.OBFSParam,
b = this.LocalAddress(),
l = this.Socks5LocalPort(),
u = true
"-s", await server.AutoResolveHostnameAsync(),
"-p", server.Port,
"-k", server.Password,
"-m", server.EncryptMethod,
"-t", 120,
"-O", server.Protocol,
"-G", server.ProtocolParam,
"-o", server.OBFS,
"-g", server.OBFSParam,
"-b", this.LocalAddress(),
"-l", this.Socks5LocalPort(),
"-u", SpecialArgument.Flag
};
await StartGuardAsync(command.ToString());
return new Socks5Bridge(IPAddress.Loopback.ToString(), this.Socks5LocalPort(),server.Hostname);
}
[Verb]
class SSRParameter : ParameterBase
{
public string? s { get; set; }
public ushort? p { get; set; }
[Quote]
public string? k { get; set; }
public string? m { get; set; }
public string? t { get; set; }
[Optional]
public string? O { get; set; }
[Optional]
public string? G { get; set; }
[Optional]
public string? o { get; set; }
[Optional]
public string? g { get; set; }
public string? b { get; set; }
public ushort? l { get; set; }
public bool u { get; set; }
[Full]
[Quote]
[Optional]
public string? acl { get; set; }
await StartGuardAsync(Arguments.Format(arguments));
return new Socks5Bridge(IPAddress.Loopback.ToString(), this.Socks5LocalPort(), server.Hostname);
}
}
}