123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067 |
- using Microsoft.CodeAnalysis;
- using Microsoft.CodeAnalysis.CSharp;
- using Microsoft.CodeAnalysis.CSharp.Syntax;
- using System;
- using System.Collections.Generic;
- using System.IO;
- using System.Reflection;
- using System.Text;
- using System.Linq;
- using static System.Console;
- using System.Xml.Linq;
- using SoftEther.JsonRpc;
- using Newtonsoft.Json;
- using Newtonsoft.Json.Linq;
- using Newtonsoft.Json.Serialization;
- using Markdig;
- namespace VPNServer_JSONRPC_CodeGen
- {
- public enum TargetLang
- {
- CSharp,
- TypeScript,
- }
- static class CodeGenUtil
- {
- public static string AppExeDir;
- public static string ProjectDir;
- public static string VpnSrcDir;
- public static string OutputDir_Clients;
- public static string OutputDir_HamCore;
- static CodeGenUtil()
- {
- AppExeDir = System.AppContext.BaseDirectory;
- ProjectDir = AppExeDir;
- string tmp = AppExeDir;
- while (true)
- {
- try
- {
- tmp = Path.GetDirectoryName(tmp);
- if (Directory.GetFiles(tmp, "*.csproj").Length >= 1)
- {
- ProjectDir = tmp;
- break;
- }
- }
- catch
- {
- break;
- }
- }
- OutputDir_Clients = Path.Combine(ProjectDir, @"..\vpnserver-jsonrpc-clients");
- string root_dir = Path.Combine(ProjectDir, @"..\..");
- string dirname = null;
- if (Directory.Exists(Path.Combine(root_dir, "Main"))) dirname = "Main";
- if (Directory.Exists(Path.Combine(root_dir, "src"))) dirname = "src";
- if (string.IsNullOrEmpty(dirname)) throw new ApplicationException($"Directory '{root_dir}' is not a root dir.");
- VpnSrcDir = dirname;
- OutputDir_HamCore = Path.Combine(root_dir, dirname, @"bin\hamcore");
- if (Directory.Exists(OutputDir_HamCore) == false) throw new ApplicationException($"Direction '{OutputDir_HamCore}' not found.");
- }
- public static void MakeDir(string path)
- {
- try
- {
- Directory.CreateDirectory(path);
- }
- catch
- {
- }
- }
- }
- class CSharpSourceCode
- {
- public SyntaxTree Tree { get; }
- public CompilationUnitSyntax Root { get; }
- public SemanticModel Model { get; set; }
- public CSharpSourceCode(string filename) : this(File.ReadAllText(filename), filename)
- {
- }
- public CSharpSourceCode(string body, string filename)
- {
- this.Tree = CSharpSyntaxTree.ParseText(body, path: filename);
- this.Root = this.Tree.GetCompilationUnitRoot();
- }
- }
- class CSharpCompiler
- {
- public string AssemblyName { get; }
- public List<MetadataReference> ReferencesList { get; } = new List<MetadataReference>();
- public List<CSharpSourceCode> SourceCodeList { get; } = new List<CSharpSourceCode>();
- CSharpCompilation _compilation = null;
- public CSharpCompilation Compilation
- {
- get
- {
- if (_compilation == null)
- {
- _compilation = CSharpCompilation.Create(this.AssemblyName,
- this.SourceCodeList.Select(s => s.Tree),
- this.ReferencesList,
- options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary, optimizationLevel: OptimizationLevel.Debug,
- assemblyIdentityComparer: DesktopAssemblyIdentityComparer.Default));
- }
- return _compilation;
- }
- }
- public CSharpCompiler(string assembly_name)
- {
- this.AssemblyName = assembly_name;
- }
- public void AddReference(MetadataReference r)
- {
- this.ReferencesList.Add(r);
- }
- public void AddReferenceByPath(string path)
- {
- AddReference(MetadataReference.CreateFromFile(path));
- }
- public void AddReferenceByType(Type type)
- {
- AddReferenceByPath(type.Assembly.Location);
- }
- public void AddReferenceByAssemblyName(string name)
- {
- var a = System.Reflection.Assembly.Load(new System.Reflection.AssemblyName(name));
- AddReferenceByPath(a.Location);
- }
- public void AddReferenceDotNetStandard()
- {
- var a = System.Reflection.Assembly.Load(new System.Reflection.AssemblyName("netstandard"));
- AddReferenceByPath(a.Location);
- string dir = Path.GetDirectoryName(a.Location);
- AddReferenceByPath(Path.Combine(dir, "System.Private.CoreLib.dll"));
-
- foreach (var refa in a.GetReferencedAssemblies())
- {
- string dll_name = Path.Combine(dir, refa.Name) + ".dll";
- if (File.Exists(dll_name))
- {
- AddReferenceByPath(dll_name);
- }
- }
- }
- public void AddSourceCode(CSharpSourceCode cs)
- {
- this.SourceCodeList.Add(cs);
- }
- public bool OkOrPrintErrors()
- {
- MemoryStream ms = new MemoryStream();
- Microsoft.CodeAnalysis.Emit.EmitResult ret = Compilation.Emit(ms);
- if (ret.Success)
- {
- return true;
- }
- IEnumerable<Diagnostic> failures = ret.Diagnostics.Where(diagnostic =>
- diagnostic.IsWarningAsError ||
- diagnostic.Severity == DiagnosticSeverity.Error);
- foreach (Diagnostic diagnostic in failures)
- {
- WriteLine(diagnostic.ToString());
- }
- return false;
- }
- public void Compile(bool test_full_compile = false)
- {
- if (test_full_compile)
- {
- if (OkOrPrintErrors() == false)
- {
- throw new ApplicationException("Compile Error.");
- }
- }
- foreach (CSharpSourceCode cs in this.SourceCodeList)
- {
- cs.Model = this.Compilation.GetSemanticModel(cs.Tree);
- }
- }
- }
- class GeneratedCodePart
- {
- public int Seq = 0;
- public string Text = "";
- }
- class GeneratedCodeSection
- {
- public List<GeneratedCodePart> PartList = new List<GeneratedCodePart>();
- public override string ToString()
- {
- StringWriter w = new StringWriter();
- var a = this.PartList.OrderBy(x => x.Seq);
- foreach (var b in a)
- {
- w.Write(b.Text.ToString());
- }
- return w.ToString();
- }
- public void AddPart(int seq, string text)
- {
- this.PartList.Add(new GeneratedCodePart() { Seq = seq, Text = text });
- }
- }
- class GeneratedCode
- {
- public GeneratedCodeSection Types = new GeneratedCodeSection();
- public GeneratedCodeSection Stubs = new GeneratedCodeSection();
- public GeneratedCodeSection Tests = new GeneratedCodeSection();
- public override string ToString()
- {
- StringWriter w = new StringWriter();
- w.WriteLine("// --- Types ---");
- w.Write(this.Types.ToString());
- w.WriteLine();
- w.WriteLine("// --- Stubs ---");
- w.Write(this.Stubs.ToString());
- w.WriteLine();
- w.WriteLine("// --- Tests ---");
- w.Write(this.Tests.ToString());
- w.WriteLine();
- return w.ToString();
- }
- }
- class GeneratedCodeForLang
- {
- public GeneratedCode TypeScript = new GeneratedCode();
- public string DocsRpc = "";
- }
- static class CodeGenExtensions
- {
- public static string GetDocumentStr(this ISymbol sym)
- {
- if (sym == null) return "";
- string xml = sym.GetDocumentationCommentXml();
- if (string.IsNullOrEmpty(xml)) return "";
- XDocument doc = XDocument.Parse(xml);
- var summary = doc.Descendants("summary").FirstOrDefault();
- string str = summary.Value;
- if (string.IsNullOrEmpty(str)) return "";
- str = str.Replace(" (Async mode)", "", StringComparison.InvariantCultureIgnoreCase);
- str = str.Trim();
- return str;
- }
- }
- class RpcInfo
- {
- public string Name;
- public string TypeName;
- public IMethodSymbol Symbol;
- public HashSet<string> InputParamMembers = new HashSet<string>();
- }
- class RpcTypeParameterInfo
- {
- public string Name;
- public string Type;
- public string Description;
- }
- class RpcTypeInfo
- {
- public string Name;
- public string Description;
- public List<RpcTypeParameterInfo> Params = new List<RpcTypeParameterInfo>();
- public List<string> SubTypes = new List<string>();
- }
- class CodeGen
- {
- CSharpSourceCode cs_types, cs_stubs, cs_tests;
- public Dictionary<string, RpcInfo> rpc_list = new Dictionary<string, RpcInfo>();
- public Dictionary<string, RpcTypeInfo> rpc_type_list = new Dictionary<string, RpcTypeInfo>();
- CSharpCompiler csc;
- public CodeGen()
- {
- csc = new CSharpCompiler("Test");
- csc.AddReferenceDotNetStandard();
- csc.AddReferenceByType(typeof(Newtonsoft.Json.JsonPropertyAttribute));
- cs_types = new CSharpSourceCode(Path.Combine(CodeGenUtil.ProjectDir, @"VpnServerRpc\VPNServerRpcTypes.cs"));
- csc.AddSourceCode(cs_types);
- cs_stubs = new CSharpSourceCode(Path.Combine(CodeGenUtil.ProjectDir, @"VpnServerRpc\VPNServerRpc.cs"));
- csc.AddSourceCode(cs_stubs);
- cs_tests = new CSharpSourceCode(Path.Combine(CodeGenUtil.ProjectDir, @"VpnServerRpcTest\VpnServerRpcTest.cs"));
- csc.AddSourceCode(cs_tests);
- csc.Compile();
- }
- void generate_types(GeneratedCodeForLang ret)
- {
- var model = cs_types.Model;
- var class_list = cs_types.Root.DescendantNodes().OfType<ClassDeclarationSyntax>();
- foreach (ClassDeclarationSyntax c in class_list)
- {
- StringWriter ts = new StringWriter();
- string doc = model.GetDeclaredSymbol(c).GetDocumentStr();
- if (string.IsNullOrEmpty(doc) == false)
- {
- ts.WriteLine($"/** {doc} */");
- }
- RpcTypeInfo info = new RpcTypeInfo()
- {
- Name = c.Identifier.Text,
- Description = doc,
- };
- rpc_type_list[c.Identifier.Text] = info;
- ts.WriteLine($"export class {c.Identifier.Text}");
- ts.WriteLine("{");
- foreach (var member in model.GetDeclaredSymbol(c).GetMembers())
- {
- string json_name = "";
- bool json_name_has_special_char = false;
- var atts = member.GetAttributes();
- var y = atts.Where(x => x.AttributeClass.Name == "JsonPropertyAttribute").FirstOrDefault();
- if (y != null)
- {
- json_name = y.ConstructorArguments.FirstOrDefault().Value.ToString();
- if (json_name.IndexOf(':') != -1 || json_name.IndexOf('.') != -1) json_name_has_special_char = true;
- }
- string default_value = "\"\"";
- string enum_type = "";
- switch (member)
- {
- case IFieldSymbol field:
- string ts_type = "";
- ITypeSymbol type = field.Type;
- switch (type.Kind)
- {
- case SymbolKind.NamedType:
- switch (type.Name)
- {
- case "UInt32":
- case "UInt64":
- ts_type = "number";
- default_value = "0";
- break;
- case "String":
- ts_type = "string";
- break;
- case "Boolean":
- ts_type = "boolean";
- default_value = "false";
- break;
- case "DateTime":
- ts_type = "Date";
- default_value = "new Date()";
- break;
- default:
- if (type.TypeKind == TypeKind.Enum)
- {
- ts_type = type.Name;
- enum_type = type.Name;
- default_value = "0";
- break;
- }
- throw new ApplicationException($"{c.Identifier}.{member.Name}: type.Name = {type.Name}");
- }
- break;
- case SymbolKind.ArrayType:
- ITypeSymbol type2 = ((IArrayTypeSymbol)type).ElementType;
- default_value = "[]";
- switch (type2.Kind)
- {
- case SymbolKind.NamedType:
- switch (type2.Name)
- {
- case "UInt32":
- case "UInt64":
- ts_type = "number[]";
- break;
- case "String":
- ts_type = "string[]";
- break;
- case "Boolean":
- ts_type = "boolean[]";
- break;
- case "Byte":
- ts_type = "Uint8Array";
- default_value = "new Uint8Array([])";
- break;
- default:
- if (type2.ContainingAssembly.Name == csc.AssemblyName)
- {
- ts_type = type2.Name + "[]";
- enum_type = type2.Name;
- break;
- }
- throw new ApplicationException($"{c.Identifier}.{member.Name}: type2.Name = {type2.Name}");
- }
- break;
- default:
- throw new ApplicationException($"{c.Identifier}.{member.Name}: type2.Kind = {type2.Kind}");
- }
- break;
- default:
- throw new ApplicationException($"{c.Identifier}.{member.Name}: type.Kind = {type.Kind}");
- }
- if (string.IsNullOrEmpty(ts_type) == false)
- {
- string field_name = field.Name;
- string doc2 = member.GetDocumentStr();
- if (string.IsNullOrEmpty(json_name) == false) field_name = json_name;
- string info_type = ts_type;
- string info_type2 = "";
- if (field_name.EndsWith("_str")) info_type2 = "ASCII";
- if (field_name.EndsWith("_utf")) info_type2 = "UTF8";
- if (field_name.EndsWith("_ip")) info_type2 = "IP address";
- if (field_name.EndsWith("_u32")) info_type2 = "uint32";
- if (field_name.EndsWith("_u64")) info_type2 = "uint64";
- if (field_name.EndsWith("_bin")) { info_type2 = "Base64 binary"; info_type = "string"; }
- string docs_add = "";
- if (string.IsNullOrEmpty(enum_type) == false)
- {
- Type et = Type.GetType("SoftEther.VPNServerRpc." + enum_type);
- if (et.IsEnum)
- {
- docs_add += "<BR>Values:";
- var ed = cs_types.Root.DescendantNodes().OfType<EnumDeclarationSyntax>()
- .Where(e => e.Identifier.Text == enum_type)
- .Single();
- foreach (var em in model.GetDeclaredSymbol(ed).GetMembers())
- {
- switch (em)
- {
- case IFieldSymbol ef:
- if (ef.IsConst && ef.IsDefinition)
- {
- string doc3 = em.GetDocumentStr();
- docs_add += $"<BR>`{ef.ConstantValue}`: {doc3}";
- }
- break;
- }
- }
- info_type = "number";
- info_type2 = "enum";
- }
- else
- {
- if (info.SubTypes.Contains(enum_type) == false)
- {
- info.SubTypes.Add(enum_type);
- info_type = "Array object";
- }
- }
- }
- info_type = "`" + info_type + "`";
- if (string.IsNullOrEmpty(info_type2) == false) info_type += " (" + info_type2 + ")";
- info.Params.Add(new RpcTypeParameterInfo()
- {
- Name = field_name,
- Type = info_type,
- Description = doc2 + docs_add,
- });
- if (json_name_has_special_char) field_name = $"[\"{json_name}\"]";
- if (string.IsNullOrEmpty(doc2) == false)
- {
- ts.WriteLine($" /** {doc2} */");
- }
- ts.WriteLine($" public {field_name}: {ts_type} = {default_value};");
- ts.WriteLine();
- }
- break;
- case IMethodSymbol method when method.MethodKind == MethodKind.Constructor:
- break;
- default:
- throw new ApplicationException($"{c.Identifier}.{member.Name}: type = {member.GetType()}");
- }
- }
- if (string.IsNullOrEmpty(doc) == false)
- {
- ts.WriteLine($" /** Constructor for the '{c.Identifier.Text}' class: {doc} */");
- }
- ts.WriteLine($" public constructor(init?: Partial<{c.Identifier.Text}>)");
- ts.WriteLine(" {");
- ts.WriteLine(" Object.assign(this, init);");
- ts.WriteLine(" }");
- ts.WriteLine("}");
- ts.WriteLine();
- ret.TypeScript.Types.AddPart(c.SpanStart, ts.ToString());
- }
- var enum_list = cs_types.Root.DescendantNodes().OfType<EnumDeclarationSyntax>();
- foreach (EnumDeclarationSyntax e in enum_list)
- {
- StringWriter ts = new StringWriter();
- string doc = model.GetDeclaredSymbol(e).GetDocumentStr();
- if (string.IsNullOrEmpty(doc) == false)
- {
- ts.WriteLine($"/** {doc} */");
- }
- ts.WriteLine($"export enum {e.Identifier.Text}");
- ts.WriteLine("{");
- foreach (var member in model.GetDeclaredSymbol(e).GetMembers())
- {
- switch (member)
- {
- case IFieldSymbol field:
- if (field.IsConst && field.IsDefinition)
- {
- string doc2 = member.GetDocumentStr();
- if (string.IsNullOrEmpty(doc2) == false)
- {
- ts.WriteLine($" /** {doc2} */");
- }
- ts.WriteLine($" {field.Name} = {field.ConstantValue},");
- ts.WriteLine();
- }
- break;
- }
- }
- ts.WriteLine("}");
- ts.WriteLine();
- ret.TypeScript.Types.AddPart(e.SpanStart, ts.ToString());
- }
- }
- void generate_stubs(GeneratedCodeForLang ret)
- {
- var model = cs_stubs.Model;
- var rpc_class = cs_stubs.Root.DescendantNodes().OfType<ClassDeclarationSyntax>().Where(c => c.Identifier.Text == "VpnServerRpc").First();
- var members = model.GetDeclaredSymbol(rpc_class).GetMembers();
- var methods = members.Where(m => m is IMethodSymbol).Select(m => m as IMethodSymbol).Where(m => m.IsStatic == false)
- .Where(m => m.IsAsync).Where(m => m.Name != "CallAsync");
- foreach (var method in methods)
- {
- string method_name = method.Name;
- if (method_name.EndsWith("Async") == false) throw new ApplicationException($"{method.Name}: method_name = {method_name}");
- method_name = method_name.Substring(0, method_name.Length - 5);
- INamedTypeSymbol ret_type = (INamedTypeSymbol)method.ReturnType;
- if (ret_type.Name != "Task") throw new ApplicationException($"{method.Name}: ret_type.Name = {ret_type.Name}");
- var ret_type_args = ret_type.TypeArguments;
- if (ret_type_args.Length != 1) throw new ApplicationException($"{method.Name}: type_args.Length = {ret_type_args.Length}");
- var ret_type_name = ret_type_args[0].Name;
- if (method.Parameters.Length >= 2) throw new ApplicationException($"{method.Name}: method.Parameters.Length = {method.Parameters.Length}");
- if (method.DeclaringSyntaxReferences.Length != 1) throw new ApplicationException($"{method.Name}: method.DeclaringSyntaxReferences.Length = {method.DeclaringSyntaxReferences.Length}");
- MethodDeclarationSyntax syntax = (MethodDeclarationSyntax)method.DeclaringSyntaxReferences[0].GetSyntax();
- if (syntax.Body != null) throw new ApplicationException($"{method.Name}: syntax.Body != null");
- if (syntax.ExpressionBody == null) throw new ApplicationException($"{method.Name}: syntax.ExpressionBody == null");
- ArrowExpressionClauseSyntax body = syntax.ExpressionBody;
- InvocationExpressionSyntax invoke = body.DescendantNodes().OfType<InvocationExpressionSyntax>().Single();
- if (model.GetSymbolInfo(invoke.Expression).Symbol.Name != "CallAsync") throw new ApplicationException($"{method.Name}: model.GetSymbolInfo(invoke.Expression).Symbol.Name = {model.GetSymbolInfo(invoke.Expression).Symbol.Name}");
- if (invoke.ArgumentList.Arguments.Count != 2) throw new ApplicationException($"{method.Name}: invoke.ArgumentList.Arguments.Count = {invoke.ArgumentList.Arguments.Count}");
- LiteralExpressionSyntax str_syntax = (LiteralExpressionSyntax)invoke.ArgumentList.Arguments[0].Expression;
- string str = str_syntax.Token.Text;
- StringWriter ts = new StringWriter();
- string doc2 = method.GetDocumentStr();
- if (string.IsNullOrEmpty(doc2) == false)
- {
- ts.WriteLine($" /** {doc2} */");
- }
- if (method.Parameters.Length == 0)
- {
- ts.WriteLine($" public {method_name} = (): Promise<{ret_type_name}> =>");
- ts.WriteLine(" {");
- ts.WriteLine($" return this.CallAsync<{ret_type_name}>({str}, new {ret_type_name}());");
- ts.WriteLine(" }");
- ts.WriteLine(" ");
- }
- else
- {
- ts.WriteLine($" public {method_name} = (in_param: {ret_type_name}): Promise<{ret_type_name}> =>");
- ts.WriteLine(" {");
- ts.WriteLine($" return this.CallAsync<{ret_type_name}>({str}, in_param);");
- ts.WriteLine(" }");
- ts.WriteLine(" ");
- }
- rpc_list[method_name] = new RpcInfo()
- {
- Name = method_name,
- TypeName = ret_type_name,
- Symbol = method,
- };
- ret.TypeScript.Stubs.AddPart(method.DeclaringSyntaxReferences[0].Span.Start, ts.ToString());
- }
- }
- class CcWalker : CSharpSyntaxWalker
- {
- StringWriter w = new StringWriter();
- List<string> lines = new List<string>();
- string current_line = "";
- int current_depth = 0;
- const int TabSpace = 4;
- CSharpSourceCode src;
- TargetLang lang;
- public CcWalker(CSharpSourceCode src, TargetLang lang) : base(SyntaxWalkerDepth.StructuredTrivia)
- {
- this.src = src;
- this.lang = lang;
- }
- string convert_type(string src)
- {
- if (lang == TargetLang.TypeScript)
- {
- if (src.StartsWith("Vpn"))
- {
- src = "VPN." + src;
- }
- if (src == "int" || src == "uint" || src == "long" || src == "ulong")
- {
- src = "number";
- }
- if (src == "bool")
- {
- src = "boolean";
- }
- if (src == "DateTime")
- {
- src = "Date";
- }
- }
- return src;
- }
- string convert_function(string src)
- {
- if (lang == TargetLang.TypeScript)
- {
- if (src == "Console.WriteLine" || src == "print_object")
- {
- src = "console.log";
- }
- if (src.StartsWith("api.") || src.StartsWith("Test_"))
- {
- src = "await " + src;
- }
- }
- return src;
- }
- void _emit_internal(string str, bool new_line)
- {
- if (string.IsNullOrEmpty(current_line))
- {
- current_line += new string(' ', current_depth * TabSpace);
- }
- current_line += str;
- if (new_line)
- {
- lines.Add(current_line);
- current_line = "";
- }
- }
- void emit_line(string str = "") => emit(str + "\r\n");
- void emit(string str, bool new_line)
- {
- if (new_line == false)
- {
- emit(str);
- }
- else
- {
- emit_line(str);
- }
- }
- void emit(string str)
- {
- string tmp = "";
- for (int i = 0; i < str.Length; i++)
- {
- char c = str[i];
- if (c == '\r') { }
- else if (c == '\n')
- {
- _emit_internal(tmp, true);
- tmp = "";
- }
- else
- {
- tmp += c;
- }
- }
- if (String.IsNullOrEmpty(tmp) == false)
- {
- _emit_internal(tmp, false);
- }
- }
- public override void VisitMethodDeclaration(MethodDeclarationSyntax node)
- {
- if (node.Identifier.Text == "print_object") return;
- if (lang == TargetLang.TypeScript)
- {
- emit_line();
- var sem = src.Model.GetDeclaredSymbol(node);
- string doc2 = sem.GetDocumentStr();
- if (string.IsNullOrEmpty(doc2) == false)
- {
- emit_line($"/** {doc2} */");
- }
- emit("async function ");
- emit(node.Identifier.Text);
- Visit(node.ParameterList);
- emit(": ");
- emit("Promise<");
- Visit(node.ReturnType);
- emit(">");
- emit_line("");
- Visit(node.Body);
- }
- else
- {
- emit("public");
- emit(" ");
- Visit(node.ReturnType);
- emit(" ");
- emit(node.Identifier.Text);
- Visit(node.ParameterList);
- emit_line("");
- Visit(node.Body);
- }
- }
- public override void VisitParameter(ParameterSyntax node)
- {
- if (lang == TargetLang.TypeScript)
- {
- emit($"{node.Identifier.Text}");
- emit(": ");
- Visit(node.Type);
- }
- else
- {
- Visit(node.Type);
- emit(" ");
- emit($"{node.Identifier.Text}");
- }
- }
- public override void VisitParameterList(ParameterListSyntax node)
- {
- emit("(");
- int num = 0;
- foreach (ParameterSyntax p in node.Parameters)
- {
- if (num >= 1)
- {
- emit(", ");
- }
- Visit(p);
- num++;
- }
- emit(")");
- }
- public override void VisitArgumentList(ArgumentListSyntax node)
- {
- emit("(");
- int num = 0;
- foreach (ArgumentSyntax arg in node.Arguments)
- {
- if (num >= 1)
- {
- emit(", ");
- }
- this.VisitArgument(arg);
- num++;
- }
- emit(")");
- }
- public override void VisitAssignmentExpression(AssignmentExpressionSyntax node)
- {
- if (lang == TargetLang.TypeScript)
- {
- if (node.Parent.Kind() == SyntaxKind.ObjectInitializerExpression)
- {
- Visit(node.Left);
- emit(": ");
- Visit(node.Right);
- }
- else
- {
- Visit(node.Left);
- emit(" = ");
- Visit(node.Right);
- }
- }
- else
- {
- Visit(node.Left);
- emit(" = ");
- Visit(node.Right);
- }
- }
- public override void VisitMemberAccessExpression(MemberAccessExpressionSyntax node)
- {
- Visit(node.Expression);
- emit(node.OperatorToken.Text);
- Visit(node.Name);
- }
- public override void VisitCastExpression(CastExpressionSyntax node)
- {
- if (lang == TargetLang.TypeScript)
- {
- Visit(node.Expression);
- }
- else
- {
- emit("(");
- Visit(node.Type);
- emit(")");
- Visit(node.Expression);
- }
- }
- public override void VisitBreakStatement(BreakStatementSyntax node)
- {
- emit_line("break;");
- }
- public override void VisitReturnStatement(ReturnStatementSyntax node)
- {
- if (node.Expression == null)
- {
- emit_line("return;");
- }
- else
- {
- emit("return");
- emit(" ");
- Visit(node.Expression);
- emit_line(";");
- }
- }
- public override void VisitForEachStatement(ForEachStatementSyntax node)
- {
- if (lang == TargetLang.TypeScript)
- {
- emit("for (let ");
- emit(node.Identifier.Text);
- emit(" of ");
- Visit(node.Expression);
- emit_line(")");
- Visit(node.Statement);
- }
- else
- {
- emit("foreach (");
- Visit(node.Type);
- emit(" ");
- emit(node.Identifier.Text);
- emit(" in ");
- Visit(node.Expression);
- emit_line(")");
- Visit(node.Statement);
- }
- }
- public override void VisitExpressionStatement(ExpressionStatementSyntax node)
- {
- Visit(node.Expression);
- emit_line(";");
- }
- public override void VisitConditionalExpression(ConditionalExpressionSyntax node)
- {
- Visit(node.Condition);
- emit(" ? ");
- Visit(node.WhenTrue);
- emit(" : ");
- Visit(node.WhenFalse);
- }
- public override void VisitIfStatement(IfStatementSyntax node)
- {
- emit("if (");
- Visit(node.Condition);
- emit_line(")");
- Visit(node.Statement);
- if (node.Else != null)
- {
- if (node.Else.Statement is IfStatementSyntax)
- {
- emit("else ");
- }
- else
- {
- emit_line("else");
- }
- Visit(node.Else.Statement);
- }
- }
- public override void VisitInitializerExpression(InitializerExpressionSyntax node)
- {
- if (lang == TargetLang.TypeScript)
- {
- if (node.Kind() == SyntaxKind.ArrayInitializerExpression)
- {
- bool is_byte_array = false;
- if (node.Parent.Kind() == SyntaxKind.ArrayCreationExpression &&
- ((ArrayCreationExpressionSyntax)node.Parent).Type.ElementType.ToString() == "byte")
- {
- is_byte_array = true;
- }
- if (is_byte_array)
- {
- emit("new Uint8Array(");
- }
- emit("[ ");
- current_depth++;
- foreach (var exp in node.Expressions)
- {
- this.Visit(exp);
- emit(", ");
- }
- current_depth--;
- emit(" ]");
- if (is_byte_array)
- {
- emit(")");
- }
- }
- else
- {
- emit_line("{");
- current_depth++;
- foreach (var exp in node.Expressions)
- {
- this.Visit(exp);
- emit_line(",");
- }
- current_depth--;
- emit("}");
- }
- }
- else
- {
- if (node.Kind() == SyntaxKind.ArrayInitializerExpression)
- {
- emit("{ ");
- current_depth++;
- foreach (var exp in node.Expressions)
- {
- this.Visit(exp);
- emit(", ");
- }
- current_depth--;
- emit(" }");
- }
- else
- {
- emit_line("{");
- current_depth++;
- foreach (var exp in node.Expressions)
- {
- this.Visit(exp);
- emit_line(",");
- }
- current_depth--;
- emit("}");
- }
- }
- }
- public override void VisitArrayCreationExpression(ArrayCreationExpressionSyntax node)
- {
- if (lang == TargetLang.TypeScript)
- {
- var type = node.Type;
- if (node.Initializer != null)
- {
- emit(" ");
- Visit(node.Initializer);
- }
- else
- {
- emit("[]");
- }
- }
- else
- {
- var type = node.Type;
- emit("new ");
- Visit(node.Type);
- if (node.Initializer != null)
- {
- emit(" ");
- Visit(node.Initializer);
- }
- }
- }
- public override void VisitObjectCreationExpression(ObjectCreationExpressionSyntax node)
- {
- if (lang == TargetLang.TypeScript)
- {
- var type = (IdentifierNameSyntax)node.Type;
- if (node.Initializer == null)
- {
- emit("new ");
- Visit(node.Type);
- // emit($"new {type.Identifier.Text}");
- Visit(node.ArgumentList);
- }
- else
- {
- emit("new ");
- Visit(node.Type);
- emit_line("(");
- Visit(node.Initializer);
- emit(")");
- }
- }
- else
- {
- var type = (IdentifierNameSyntax)node.Type;
- emit($"new {type.Identifier.Text}");
- Visit(node.ArgumentList);
- if (node.Initializer != null)
- {
- emit_line("");
- Visit(node.Initializer);
- }
- }
- }
- public override void VisitLiteralExpression(LiteralExpressionSyntax node)
- {
- emit(node.Token.Text);
- }
- public override void VisitParenthesizedExpression(ParenthesizedExpressionSyntax node)
- {
- emit("(");
- base.Visit(node.Expression);
- emit(")");
- }
- public override void VisitBinaryExpression(BinaryExpressionSyntax node)
- {
- base.Visit(node.Left);
- emit($" {node.OperatorToken.Text} ");
- base.Visit(node.Right);
- }
- public override void VisitIdentifierName(IdentifierNameSyntax node)
- {
- string name = node.Identifier.Text;
- if (node.Parent.Kind() == SyntaxKind.VariableDeclaration
- || node.Parent.Kind() == SyntaxKind.MethodDeclaration
- || node.Parent.Kind() == SyntaxKind.SimpleMemberAccessExpression
- || node.Parent.Kind() == SyntaxKind.ForEachStatement
- || node.Parent.Kind() == SyntaxKind.Parameter
- || node.Parent.Kind() == SyntaxKind.ObjectCreationExpression)
- {
- name = convert_type(name);
- }
- var sym = src.Model.GetSymbolInfo(node);
- string json_name = "";
- bool json_name_has_special_char = false;
- var atts = sym.Symbol.GetAttributes();
- var y = atts.Where(x => x.AttributeClass.Name == "JsonPropertyAttribute").FirstOrDefault();
- if (y != null)
- {
- json_name = y.ConstructorArguments.FirstOrDefault().Value.ToString();
- if (json_name.IndexOf(':') != -1 || json_name.IndexOf('.') != -1) json_name_has_special_char = true;
- }
- string field_name = name;
- if (lang == TargetLang.TypeScript)
- {
- if (string.IsNullOrEmpty(json_name) == false) field_name = json_name;
- if (json_name_has_special_char) field_name = $"[\"{json_name}\"]";
- }
- emit(field_name);
- }
-
- public override void VisitInvocationExpression(InvocationExpressionSyntax node)
- {
- string func_name = node.Expression.ToString();
- func_name = convert_function(func_name);
- if (lang == TargetLang.TypeScript)
- {
- if (func_name == "rand.Next")
- {
- string a = node.ArgumentList.Arguments[0].ToString();
- string b = node.ArgumentList.Arguments[1].ToString();
- emit($"Math.floor((Math.random() * ({b} - {a})) + {a})");
- return;
- }
- if (func_name == "System.Threading.Thread.Sleep")
- {
- string a = node.ArgumentList.Arguments[0].ToString();
- emit($"await new Promise((r) => setTimeout(r, {a}))");
- return;
- }
- }
- emit(func_name);
- Visit(node.ArgumentList);
- }
- public override void VisitPredefinedType(PredefinedTypeSyntax node)
- {
- string name = node.Keyword.Text;
- name = convert_type(name);
- emit(name);
- }
- public override void VisitArrayRankSpecifier(ArrayRankSpecifierSyntax node)
- {
- emit("[");
- int num = 0;
- foreach (ExpressionSyntax exp in node.Sizes)
- {
- if (num >= 1)
- {
- emit(",");
- }
- Visit(exp);
- num++;
- }
- emit("]");
- }
- public override void VisitConstructorDeclaration(ConstructorDeclarationSyntax node)
- {
- /*foreach (var statement in node.Body.Statements)
- {
- Visit(statement);
- }*/
- }
- public override void VisitArrayType(ArrayTypeSyntax node)
- {
- Visit(node.ElementType);
- foreach (var rank in node.RankSpecifiers)
- {
- Visit(rank);
- }
- }
- public void VisitVariableDeclarator(VariableDeclaratorSyntax node, TypeSyntax type)
- {
- if (lang == TargetLang.TypeScript)
- {
- // if (node.Parent.Parent.Kind() == SyntaxKind.LocalDeclarationStatement)
- {
- emit("let ");
- }
- emit($"{node.Identifier.Text}");
- emit(": ");
- var type_dec = src.Model.GetTypeInfo(type);
- if (type is PredefinedTypeSyntax)
- {
- Visit(type);
- }
- else if (type is ArrayTypeSyntax)
- {
- Visit(type);
- }
- else if (type is IdentifierNameSyntax)
- {
- Visit(type);
- }
- else
- {
- throw new ApplicationException($"VisitVariableDeclarator: {type.GetType().ToString()}");
- }
- if (node.Initializer != null)
- {
- emit(" = ");
- var value = node.Initializer.Value;
- base.Visit(value);
- }
- emit_line(";");
- }
- else
- {
- var type_dec = src.Model.GetTypeInfo(type);
- if (type is PredefinedTypeSyntax)
- {
- Visit(type);
- }
- else if (type is ArrayTypeSyntax)
- {
- Visit(type);
- }
- else if (type is IdentifierNameSyntax)
- {
- Visit(type);
- }
- else
- {
- throw new ApplicationException($"VisitVariableDeclarator: {type.GetType().ToString()}");
- }
- emit($" {node.Identifier.Text}");
- if (node.Initializer != null)
- {
- emit(" = ");
- var value = node.Initializer.Value;
- base.Visit(value);
- }
- emit_line(";");
- }
- }
- public override void VisitVariableDeclaration(VariableDeclarationSyntax node)
- {
- foreach (var v in node.Variables)
- {
- VisitVariableDeclarator(v, node.Type);
- }
- }
- public override void VisitLocalDeclarationStatement(LocalDeclarationStatementSyntax node)
- {
- Visit(node.Declaration);
- }
- public override void VisitFieldDeclaration(FieldDeclarationSyntax node)
- {
- //Visit(node.Declaration);
- }
- public override void VisitBlock(BlockSyntax node)
- {
- emit_line("{");
- current_depth++;
- foreach (var statement in node.Statements)
- {
- Visit(statement);
- }
- current_depth--;
- emit_line("}");
- }
- public override void VisitClassDeclaration(ClassDeclarationSyntax node)
- {
- if (lang == TargetLang.TypeScript)
- {
- base.VisitClassDeclaration(node);
- }
- else
- {
- emit_line($"class {node.Identifier.Text}");
- emit_line("{");
- current_depth++;
- base.VisitClassDeclaration(node);
- current_depth--;
- emit_line("}");
- }
- }
- public override string ToString()
- {
- StringWriter w = new StringWriter();
- this.lines.ForEach(x => w.WriteLine(x));
- if (String.IsNullOrEmpty(this.current_line) == false) w.WriteLine(this.current_line);
- return w.ToString();
- }
- }
- void generate_tests(GeneratedCodeForLang ret)
- {
- var test_class = cs_tests.Root.DescendantNodes().OfType<ClassDeclarationSyntax>().Where(c => c.Identifier.Text == "VPNRPCTest").First();
- CcWalker ts_walker = new CcWalker(cs_tests, TargetLang.TypeScript);
- ts_walker.Visit(test_class);
- ret.TypeScript.Tests.PartList.Add(new GeneratedCodePart() { Seq = 0, Text = ts_walker.ToString() });
- }
- void doc_write_parameters(StringWriter w, RpcTypeInfo type_info)
- {
- List<RpcTypeParameterInfo> plist = new List<RpcTypeParameterInfo>();
- foreach (RpcTypeParameterInfo p in type_info.Params)
- {
- plist.Add(p);
- }
- foreach (string subtype in type_info.SubTypes)
- {
- foreach (RpcTypeParameterInfo p in rpc_type_list[subtype].Params)
- {
- plist.Add(p);
- }
- }
- w.WriteLine("Name | Type | Descrption");
- w.WriteLine("--- | --- | ---");
- foreach (RpcTypeParameterInfo p in plist)
- {
- w.WriteLine($"`{p.Name}` | {p.Type} | {p.Description}");
- }
- }
- void doc_write_function(StringWriter w, RpcInfo rpc)
- {
- string func_summary = rpc.Symbol.GetDocumentStr();
- int index = func_summary.IndexOf(".");
- if (index != -1) func_summary = func_summary.Substring(0, index + 1);
- func_summary = func_summary.TrimEnd('.');
- w.WriteLine($"<a id=\"{rpc.Name.ToLowerInvariant()}\"></a>");
- w.WriteLine($"## \"{rpc.Name}\" RPC API - {func_summary}");
- w.WriteLine("### Description");
- w.WriteLine(rpc.Symbol.GetDocumentStr());
- var model = cs_tests.Model;
- var func = cs_tests.Root.DescendantNodes().OfType<MethodDeclarationSyntax>()
- .Where(f => f.Identifier.Text == "Test_" + rpc.Name)
- .Single();
- var fields = func.DescendantNodes().OfType<InitializerExpressionSyntax>()
- .Where(i => i.Kind() == SyntaxKind.ObjectInitializerExpression)
- .SelectMany(o => o.DescendantNodes().OfType<AssignmentExpressionSyntax>())
- .Where(a => a.Kind() == SyntaxKind.SimpleAssignmentExpression)
- .Select(a => (a.Left as IdentifierNameSyntax));
- foreach (var field in fields)
- {
- string json_name = field.Identifier.Text;
- var sym = model.GetSymbolInfo(field);
- var atts = sym.Symbol.GetAttributes();
- var y = atts.Where(x => x.AttributeClass.Name == "JsonPropertyAttribute").FirstOrDefault();
- if (y != null)
- {
- json_name = y.ConstructorArguments.FirstOrDefault().Value.ToString();
- }
- rpc.InputParamMembers.Add(json_name);
- }
- Type obj_type = Type.GetType("SoftEther.VPNServerRpc." + rpc.TypeName);
- object in_object = Activator.CreateInstance(obj_type);
- object out_object = Activator.CreateInstance(obj_type);
- JsonRpcRequest rpc_in = new JsonRpcRequest() { Method = rpc.Name, Params = in_object, Id = "rpc_call_id", };
- Type rpc_out_type = typeof(JsonRpcResponse<>).MakeGenericType(obj_type);
- var rpc_out = Activator.CreateInstance(rpc_out_type);
- rpc_out_type.GetProperty("Id").SetValue(rpc_out, "rpc_call_id");
- rpc_out_type.GetProperty("Result").SetValue(rpc_out, out_object);
- sample_fill_object(in_object);
- sample_fill_object(out_object);
- JsonSerializerSettings rpc_in_settings = new JsonSerializerSettings()
- {
- MaxDepth = 8,
- NullValueHandling = NullValueHandling.Include,
- ReferenceLoopHandling = ReferenceLoopHandling.Error,
- PreserveReferencesHandling = PreserveReferencesHandling.None,
- ContractResolver = new JSonInputContractResolver(rpc),
- };
- JsonSerializerSettings rpc_out_settings = new JsonSerializerSettings()
- {
- MaxDepth = 8,
- NullValueHandling = NullValueHandling.Include,
- ReferenceLoopHandling = ReferenceLoopHandling.Error,
- PreserveReferencesHandling = PreserveReferencesHandling.None,
- ContractResolver = new JSonOutputContractResolver(rpc),
- };
- string in_str = JsonConvert.SerializeObject(rpc_in, Formatting.Indented, rpc_in_settings);
- string out_str = JsonConvert.SerializeObject(rpc_out, Formatting.Indented, rpc_out_settings);
- w.WriteLine();
- w.WriteLine("### Input JSON-RPC Format");
- w.WriteLine("```json");
- w.WriteLine(in_str);
- w.WriteLine("```");
- w.WriteLine();
- w.WriteLine("### Output JSON-RPC Format");
- w.WriteLine("```json");
- w.WriteLine(out_str);
- w.WriteLine("```");
- w.WriteLine();
- w.WriteLine("### Parameters");
- w.WriteLine();
- doc_write_parameters(w, rpc_type_list[rpc.TypeName]);
- //w.WriteLine("<BR> ");
- w.WriteLine();
- }
- class JSonOutputContractResolver : DefaultContractResolver
- {
- RpcInfo rpc_info;
- public JSonOutputContractResolver(RpcInfo info) : base()
- {
- this.rpc_info = info;
- }
- protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
- {
- if (member.Name == "Error") return null;
- JsonProperty ret = base.CreateProperty(member, memberSerialization);
- return ret;
- }
- }
- class JSonInputConverter : JsonConverter
- {
- RpcInfo rpc_info;
- public JSonInputConverter(RpcInfo info)
- {
- this.rpc_info = info;
- }
- public override bool CanRead => false;
- public override bool CanConvert(Type objectType)
- {
- return true;
- }
- public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
- {
- throw new NotImplementedException();
- }
- public override void WriteJson(JsonWriter w, object value, JsonSerializer serializer)
- {
- JToken t = JToken.FromObject(value);
- List<JProperty> a = new List<JProperty>();
- bool all = false;
- if (rpc_info.Name == "SetHubLog") all = true;
- foreach (var p1 in t.Children<JProperty>())
- {
- foreach (var p2 in p1.Children<JProperty>())
- {
- if (rpc_info.InputParamMembers.Contains(p2.Name) == false) a.Add(p2);
- }
- if (rpc_info.InputParamMembers.Contains(p1.Name) == false) a.Add(p1);
- }
- if (all == false)
- {
- foreach (var p in a)
- {
- try
- {
- p.Remove();
- }
- catch
- {
- }
- }
- }
- t.WriteTo(w);
- }
- }
- class JSonInputContractResolver : DefaultContractResolver
- {
- RpcInfo rpc_info;
- public JSonInputContractResolver(RpcInfo info) : base()
- {
- this.rpc_info = info;
- }
- protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
- {
- JsonProperty ret = base.CreateProperty(member, memberSerialization);
- ret.Converter = new JSonInputConverter(this.rpc_info);
- return ret;
- }
- }
- void sample_fill_object(object o)
- {
- Type t = o.GetType();
- var fields = t.GetFields();
- foreach (var field in fields)
- {
- Type t2 = field.FieldType;
- object v = null;
- if (t2 == typeof(string))
- {
- string tmp = field.Name.ToLowerInvariant();
- if (tmp.EndsWith("_str") || tmp.EndsWith("_utf")) tmp = tmp.Substring(0, tmp.Length - 4);
- if (tmp.EndsWith("_ip"))
- {
- if (tmp.IndexOf("mask", StringComparison.InvariantCultureIgnoreCase) == -1)
- tmp = "192.168.0.1";
- else
- tmp = "255.255.255.255";
- }
- v = tmp;
- }
- else if (t2 == typeof(uint))
- v = (uint)0;
- else if (t2 == typeof(ulong))
- v = (ulong)0;
- else if (t2 == typeof(bool))
- v = (bool)false;
- else if (t2 == typeof(byte[]))
- v = Encoding.UTF8.GetBytes("Hello World");
- else if (t2 == typeof(DateTime))
- v = new DateTime(DateTime.Now.Year + 1, 8, 1, 12, 24, 36, 123);
- else if (t2.IsEnum)
- {
- v = (int)0;
- }
- else if (t2.IsArray)
- {
- if (t2 == typeof(uint[]))
- {
- v = new uint[] { 1, 2, 3 };
- }
- else
- {
- if (t2.GetArrayRank() != 1) throw new ApplicationException("Array rank != 1");
- Type obj_type = t2.GetElementType();
- if (obj_type.IsEnum)
- {
- v = new int[] { 1, 2, 3 };
- }
- else
- {
- int num = 3;
- if (field.Name.IndexOf("single", StringComparison.CurrentCultureIgnoreCase) != -1)
- {
- num = 1;
- }
- object list = Activator.CreateInstance(typeof(List<>).MakeGenericType(obj_type));
- for (int i = 0; i < num; i++)
- {
- object a = Activator.CreateInstance(obj_type);
- sample_fill_object(a);
- list.GetType().GetMethod("Add").Invoke(list, new object[] { a });
- }
- v = list.GetType().GetMethod("ToArray").Invoke(list, new object[] { } );
- }
- }
- }
- else if (t2.Name.StartsWith("Vpn"))
- {
- Type obj_type = Type.GetType("SoftEther.VPNServerRpc." + t2.Name);
- v = Activator.CreateInstance(obj_type);
- sample_fill_object(v);
- }
- else
- {
- throw new ApplicationException($"sample_fill_object: type: {t2.ToString()}");
- }
- field.SetValue(o, v);
- }
- }
- void generate_documents(GeneratedCodeForLang ret)
- {
- StringWriter w = new StringWriter();
- string doc_txt = read_text_resource("doc.txt");
- w.WriteLine(doc_txt);
- w.WriteLine("## Table of contents");
- foreach (RpcInfo rpc in rpc_list.Values)
- {
- string func_summary = rpc.Symbol.GetDocumentStr();
- int index = func_summary.IndexOf(".");
- if (index != -1) func_summary = func_summary.Substring(0, index + 1);
- func_summary = func_summary.TrimEnd('.');
- w.WriteLine($"- [{rpc.Name} - {func_summary}](#{rpc.Name.ToLowerInvariant()})");
- }
- w.WriteLine();
- w.WriteLine("***");
- foreach (RpcInfo rpc in rpc_list.Values)
- {
- if (rpc.Name.IndexOf("Vgs", StringComparison.Ordinal) == -1)
- {
- doc_write_function(w, rpc);
- w.WriteLine("***");
- }
- }
- w.WriteLine($"Automatically generated at {timestamp.ToString("yyyy-MM-dd HH:mm:ss")} by vpnserver-jsonrpc-codegen. ");
- w.WriteLine("Copyright (c) 2014-" + DateTime.Now.Year + " [SoftEther VPN Project](https://www.softether.org/) under the Apache License 2.0. ");
- w.WriteLine();
- ret.DocsRpc = w.ToString();
- }
- public GeneratedCodeForLang GenerateCodes()
- {
- GeneratedCodeForLang ret = new GeneratedCodeForLang();
- generate_stubs(ret);
- generate_tests(ret);
- generate_types(ret);
- generate_documents(ret);
- return ret;
- }
- public void GenerateAndSaveCodes(string output_dir)
- {
- CodeGenUtil.MakeDir(output_dir);
- WriteLine($"GenerateAndSaveCodes(): output_dir = '{output_dir}'");
- WriteLine();
- WriteLine("Generating codes ...");
- GeneratedCodeForLang codes = GenerateCodes();
- WriteLine("Generating codes: done.");
- WriteLine();
- output_docs(codes, output_dir);
- output_csharp(Path.Combine(output_dir, "vpnserver-jsonrpc-client-csharp"));
- output_typescript(codes.TypeScript, Path.Combine(output_dir, "vpnserver-jsonrpc-client-typescript"));
- }
- static Assembly this_assembly = Assembly.GetExecutingAssembly();
- static string read_text_resource(string name)
- {
- var x = this_assembly.GetManifestResourceNames();
- string resourceName = this_assembly.GetManifestResourceNames().Single(str => str.EndsWith(name));
- using (Stream stream = this_assembly.GetManifestResourceStream(resourceName))
- {
- using (StreamReader reader = new StreamReader(stream))
- {
- return reader.ReadToEnd();
- }
- }
- }
- static string read_text_file(string name)
- {
- using (Stream stream = File.OpenRead(name))
- {
- using (StreamReader reader = new StreamReader(stream))
- {
- return reader.ReadToEnd();
- }
- }
- }
- static string replace_strings(string src, params string[] replace_list)
- {
- int i;
- for (i = 0; i < replace_list.Length / 2; i++)
- {
- string s1 = replace_list[i * 2];
- string s2 = replace_list[i * 2 + 1];
- src = src.Replace(s1, s2, StringComparison.InvariantCultureIgnoreCase);
- }
- return src;
- }
- static string normalize_crlf(string src, string crlf)
- {
- StringReader r = new StringReader(src);
- StringWriter w = new StringWriter();
- w.NewLine = crlf;
- while (true)
- {
- string line = r.ReadLine();
- if (line == null) break;
- w.WriteLine(line);
- }
- return w.ToString();
- }
- static void normalize(ref string str, string crlf, params string[] replace_list)
- {
- str = normalize_crlf(replace_strings(str, replace_list), crlf);
- }
- static void save(string path, string body, bool bom)
- {
- string dir_name = Path.GetDirectoryName(path);
- CodeGenUtil.MakeDir(dir_name);
- if (bom)
- File.WriteAllText(path, body, Encoding.UTF8);
- else
- File.WriteAllText(path, body);
- }
- DateTime timestamp = DateTime.Now;
- void output_docs(GeneratedCodeForLang c, string output_dir)
- {
- CodeGenUtil.MakeDir(output_dir);
- save(Path.Combine(output_dir, "README.md"), c.DocsRpc, true);
- var pipeline = new MarkdownPipelineBuilder().UseAdvancedExtensions().Build();
- string md_html_body = Markdown.ToHtml(c.DocsRpc, pipeline);
- string html = read_text_resource("md_html.html");
- string[] replace_list =
- {
- "__BODY__", md_html_body,
- };
- normalize(ref html, "\r\n", replace_list);
- save(Path.Combine(output_dir, "README.html"), html, true);
- save(Path.Combine(CodeGenUtil.OutputDir_HamCore, "vpnserver_api_doc.html"), html, true);
- }
- void output_typescript(GeneratedCode c, string output_dir)
- {
- CodeGenUtil.MakeDir(output_dir);
- string ts_rpc = read_text_resource("ts_rpc.txt");
- string ts_test = read_text_resource("ts_test.txt");
- string[] replace_list =
- {
- "__YEAR__", timestamp.Year.ToString(),
- "__TESTS__", c.Tests.ToString(),
- "__STUBS__", c.Stubs.ToString(),
- "__TYPES__", c.Types.ToString(),
- "__TIMESTAMP__", timestamp.ToString("yyyy-MM-dd HH:mm:ss"),
- };
- normalize(ref ts_rpc, "\n", replace_list);
- normalize(ref ts_test, "\n", replace_list);
- save(Path.Combine(output_dir, "vpnrpc.ts"), ts_rpc, true);
- save(Path.Combine(output_dir, "sample.ts"), ts_test, true);
- save(Path.Combine(output_dir + "/../vpnserver-jsonrpc-client-nodejs-package/src/", "vpnrpc.ts"), ts_rpc, true);
- save(Path.Combine(output_dir + "/../vpnserver-jsonrpc-client-nodejs-package/src/", "sample.ts"), ts_test, true);
- }
- void output_csharp(string output_dir)
- {
- CodeGenUtil.MakeDir(output_dir);
-
- string cs_proj = read_text_resource("cs_proj.txt");
- string cs_sln = read_text_resource("cs_sln.txt");
- string cs_main = read_text_resource("cs_main.txt");
- string cs_code_jsonrpc = read_text_file(Path.Combine(CodeGenUtil.ProjectDir,
- @"VpnServerRpc/JsonRpc.cs"));
- string cs_code_vpnserver_rpc = read_text_file(Path.Combine(CodeGenUtil.ProjectDir,
- @"VpnServerRpc/VPNServerRpc.cs"));
- string cs_code_vpnserver_rpc_types = read_text_file(Path.Combine(CodeGenUtil.ProjectDir,
- @"VpnServerRpc/VPNServerRpcTypes.cs"));
- string cs_code_vpnserver_rpc_test = read_text_file(Path.Combine(CodeGenUtil.ProjectDir,
- @"VpnServerRpcTest/VpnServerRpcTest.cs"));
- string[] replace_list =
- {
- "__YEAR__", timestamp.Year.ToString(),
- "__TIMESTAMP__", timestamp.ToString("yyyy-MM-dd HH:mm:ss"),
- };
- normalize(ref cs_main, "\r\n", replace_list);
- normalize(ref cs_proj, "\r\n", replace_list);
- normalize(ref cs_sln, "\r\n", replace_list);
- normalize(ref cs_code_jsonrpc, "\r\n", replace_list);
- normalize(ref cs_code_vpnserver_rpc, "\r\n", replace_list);
- normalize(ref cs_code_vpnserver_rpc_types, "\r\n", replace_list);
- normalize(ref cs_code_vpnserver_rpc_test, "\r\n", replace_list);
- save(Path.Combine(output_dir, "vpnserver-jsonrpc-client-csharp.csproj"),
- cs_proj, true);
- save(Path.Combine(output_dir, "vpnserver-jsonrpc-client-csharp.sln"),
- cs_sln, true);
- save(Path.Combine(output_dir, @"rpc-stubs\JsonRpc.cs"),
- cs_code_jsonrpc, true);
- save(Path.Combine(output_dir, @"rpc-stubs\VPNServerRpc.cs"),
- cs_code_vpnserver_rpc, true);
- save(Path.Combine(output_dir, @"rpc-stubs\VPNServerRpcTypes.cs"),
- cs_code_vpnserver_rpc_types, true);
- save(Path.Combine(output_dir, @"sample\VpnServerRpcTest.cs"),
- cs_code_vpnserver_rpc_test, true);
- save(Path.Combine(output_dir, @"sample\Main.cs"),
- cs_main, true);
- }
- public void Test()
- {
- GeneratedCodeForLang ret = GenerateCodes();
- Console.WriteLine(ret.TypeScript.ToString());
- return;
- var model = cs_types.Model;
- var type_classes = cs_types.Root.DescendantNodes()
- .OfType<ClassDeclarationSyntax>();
- foreach (ClassDeclarationSyntax v in type_classes)
- {
- WriteLine(v.Identifier.Text);
- var info = model.GetDeclaredSymbol(v);
- var x = info.GetMembers();
- foreach (var y in x)
- {
- WriteLine(y.Name);
- }
- break;
- }
- Console.WriteLine();
- }
- }
- }
|