diff --git a/src/Luban.Client/Source/Utils/MultiFileWatcher.cs b/src/Luban.Client/Source/Utils/MultiFileWatcher.cs index ea66139..90dd5b2 100644 --- a/src/Luban.Client/Source/Utils/MultiFileWatcher.cs +++ b/src/Luban.Client/Source/Utils/MultiFileWatcher.cs @@ -7,7 +7,7 @@ using System.Threading.Tasks; namespace Luban.Client.Utils { - class MultiFileWatcher + public class MultiFileWatcher { private static readonly NLog.Logger s_logger = NLog.LogManager.GetCurrentClassLogger(); diff --git a/src/Luban.ClientServer/Luban.ClientServer.csproj b/src/Luban.ClientServer/Luban.ClientServer.csproj new file mode 100644 index 0000000..fa5d3cc --- /dev/null +++ b/src/Luban.ClientServer/Luban.ClientServer.csproj @@ -0,0 +1,13 @@ + + + + Exe + net5.0 + + + + + + + + diff --git a/src/Luban.ClientServer/Program.cs b/src/Luban.ClientServer/Program.cs new file mode 100644 index 0000000..d4a041f --- /dev/null +++ b/src/Luban.ClientServer/Program.cs @@ -0,0 +1,294 @@ +using CommandLine; +using Luban.Client.Common.Net; +using Luban.Client.Common.Utils; +using Luban.Client.Utils; +using Luban.Common.Protos; +using Luban.Common.Utils; +using Luban.Server; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +namespace Luban.ClientServer +{ + class Program + { + public class AllCommandLineOptions + { + public string StringTemplateDir { get; set; } = "Templates"; + + public int Port { get; set; } = 8899; + + public string JobType { get; set; } + + public List JobArguments { get; set; } = new List(); + + public bool Verbose { get; set; } + + public string LogLevel { get; set; } = "INFO"; + + public string CacheMetaInfoFile { get; set; } = ".cache.meta"; + + public string[] WatchDir { get; set; } + } + + private static void PrintUsage(string err) + { + Console.WriteLine("ERRORS:"); + Console.WriteLine("\t" + err); + Console.WriteLine(@" +Luban.Client ... [-- [job options]] +e.g. + Luban.ClientServer -j cfg -- --name abc + +Options: + -p --port port. default 8899 + -j --job Required. job type. avaliable value: cfg + -v --verbose verbose print + -l --loglevel log level. default INFO. avaliable value: TRACE,DEBUG,INFO,WARN,ERROR,FATAL,OFF + -c --cachemetafile cache meta file name. default is '.cache.meta' + -w --watch watch data change and regenerate. + -t --templatedirectory string templates directory. default is 'Templates' + -h --help show usage +"); + } + + private static (object, AllCommandLineOptions) ParseArgs(string[] args) + { + var ops = new AllCommandLineOptions(); + + for (int i = 0; i < args.Length; i++) + { + var arg = args[i]; + try + { + switch (arg) + { + case "-p": + case "--port": + { + ops.Port = int.Parse(args[++i]); + break; + } + case "-j": + case "--job": + { + ops.JobType = args[++i]; + break; + } + case "-v": + case "--verbose": + { + ops.Verbose = true; + break; + } + case "-l": + case "--loglevel": + { + ops.LogLevel = args[++i]; + break; + } + case "-c": + case "--cachemetafile": + { + ops.CacheMetaInfoFile = args[++i]; + break; + } + case "-w": + case "--watch": + { + ops.WatchDir = args[++i].Split(';', ','); + break; + } + case "-t": + case "--templatedirectory": + { + ops.StringTemplateDir = args[++i]; + break; + } + case "--": + { + ++i; + ops.JobArguments = args.ToList().GetRange(i, args.Length - i); + return (null, ops); + } + default: + { + return ($"unknown argument:{arg}", null); + } + } + } + catch (Exception) + { + return ($"argument:{arg} err", null); + } + } + if (ops.JobType == null) + { + return ("--job missing", null); + } + + return (null, ops); + } + + private static void StartServer(AllCommandLineOptions options) + { + Job.Common.Utils.StringTemplateUtil.TemplateDir = options.StringTemplateDir; + + GenServer.Ins.Start(options.Port, ProtocolStub.Factories); + + GenServer.Ins.RegisterJob("cfg", new Luban.Job.Cfg.JobController()); + GenServer.Ins.RegisterJob("proto", new Luban.Job.Proto.JobController()); + GenServer.Ins.RegisterJob("db", new Luban.Job.Db.JobController()); + + int processorCount = System.Environment.ProcessorCount; + ThreadPool.SetMinThreads(Math.Max(4, processorCount), 5); + ThreadPool.SetMaxThreads(Math.Max(16, processorCount * 4), 10); + } + + private static void StartClient(AllCommandLineOptions options, ProfileTimer profile) + { + + if (options.WatchDir == null || options.WatchDir.Length == 0) + { + int exitCode = GenOnce(options, profile); + Environment.Exit(exitCode); + } + else + { + GenOnce(options, profile); + + new MultiFileWatcher(options.WatchDir, () => GenOnce(options, profile)); + } + } + + private static NLog.Logger s_logger; + + static void Main(string[] args) + { + ConsoleWindow.EnableQuickEditMode(false); + Console.OutputEncoding = System.Text.Encoding.UTF8; + System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance); + + var parseResult = ParseArgs(args); + if (parseResult.Item1 != null) + { + PrintUsage((string)parseResult.Item1); + Environment.Exit(1); + return; + } + var options = parseResult.Item2; + + var profile = new ProfileTimer(); + profile.StartPhase("all"); + + LogUtil.InitSimpleNLogConfigure(NLog.LogLevel.FromString(options.LogLevel)); + s_logger = NLog.LogManager.GetCurrentClassLogger(); + + StartServer(options); + + StartClient(options, profile); + } + + private static int GenOnce(AllCommandLineOptions options, ProfileTimer profile) + { + int exitCode; + try + { + profile.StartPhase("generation"); + profile.StartPhase("connect server"); + var conn = GenClient.Start("127.0.0.1", options.Port, ProtocolStub.Factories); + + profile.StartPhase("load cache meta file"); + CacheMetaManager.Ins.Load(options.CacheMetaInfoFile); + profile.EndPhaseAndLog(); + + conn.Wait(); + profile.EndPhaseAndLog(); + + if (GenClient.Ins.Session.Channel.IsOpen) + { + profile.StartPhase("gen job"); + exitCode = SubmitGenJob(options); + profile.EndPhaseAndLog(); + } + else + { + s_logger.Error("connect fail"); + exitCode = 2; + } + + profile.EndPhaseAndLog(); + } + catch (Exception e) + { + exitCode = 1; + s_logger.Error(e); + } + finally + { + GenClient.Stop(); + } + + CacheMetaManager.Ins.Save(); + CacheMetaManager.Ins.Reset(); + if (exitCode == 0) + { + s_logger.Info("== succ =="); + } + else + { + s_logger.Error("== fail =="); + } + return exitCode; + } + + const int GEN_JOB_TIMEOUT = 120; + + private static int SubmitGenJob(AllCommandLineOptions options) + { + var res = GenClient.Ins.Session.CallRpcAsync(new GenJobArg() + { + JobType = options.JobType, + JobArguments = options.JobArguments, + Verbose = options.Verbose, + }, GEN_JOB_TIMEOUT).Result; + + if (res.ErrCode != 0) + { + if (res.ErrCode == Luban.Common.EErrorCode.JOB_ARGUMENT_ERROR) + { + s_logger.Error("job argument error"); + Console.WriteLine(res.ErrMsg); + } + else + { + s_logger.Error("GenJob fail. err:{err} msg:{msg}", res.ErrCode, res.ErrMsg); + if (!string.IsNullOrEmpty(res.StackTrace)) + { + s_logger.Debug("StackTrace: {}", res.StackTrace); + } + } + + return 1; + } + + var tasks = new List(); + + foreach (var fg in res.FileGroups) + { + tasks.Add(DownloadFileUtil.DownloadGeneratedFiles(fg.Dir, fg.Files)); + } + + foreach (var f in res.ScatteredFiles) + { + tasks.Add(DownloadFileUtil.DownloadGeneratedFile(f)); + } + + Task.WaitAll(tasks.ToArray()); + return 0; + } + } +} diff --git a/src/Luban.sln b/src/Luban.sln index 2afa966..31f6197 100644 --- a/src/Luban.sln +++ b/src/Luban.sln @@ -19,7 +19,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Luban.Job.Proto", "Luban.Jo EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Luban.Job.Db", "Luban.Job.Db\Luban.Job.Db.csproj", "{7467AC15-C61F-4C56-942F-18EAEA902C58}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Excel2TextDiff", "Excel2TextDiff\Excel2TextDiff.csproj", "{9477226F-469E-458F-A3AD-9115D777A65A}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Excel2TextDiff", "Excel2TextDiff\Excel2TextDiff.csproj", "{9477226F-469E-458F-A3AD-9115D777A65A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Luban.ClientServer", "Luban.ClientServer\Luban.ClientServer.csproj", "{457C22FF-46A5-4E1D-8017-7AE5923868F8}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -63,6 +65,10 @@ Global {9477226F-469E-458F-A3AD-9115D777A65A}.Debug|Any CPU.Build.0 = Debug|Any CPU {9477226F-469E-458F-A3AD-9115D777A65A}.Release|Any CPU.ActiveCfg = Release|Any CPU {9477226F-469E-458F-A3AD-9115D777A65A}.Release|Any CPU.Build.0 = Release|Any CPU + {457C22FF-46A5-4E1D-8017-7AE5923868F8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {457C22FF-46A5-4E1D-8017-7AE5923868F8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {457C22FF-46A5-4E1D-8017-7AE5923868F8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {457C22FF-46A5-4E1D-8017-7AE5923868F8}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE