diff --git a/Language/en-US/Sync.Tools.DefaultI18n.lang b/Language/en-US/Sync.Tools.DefaultI18n.lang index c4891b1..8118e2b 100644 --- a/Language/en-US/Sync.Tools.DefaultI18n.lang +++ b/Language/en-US/Sync.Tools.DefaultI18n.lang @@ -113,4 +113,4 @@ LANG_NO_PLUGIN_SELECT=Must specify a plugin name LANG_PLUGIN_DISABLED=Disabled LANG_COMMANDS_CLIENTUSERMSG=chatuser send message as username for irc test LANG_COMMANDS_EXIT_DONE=Exit action execution done, please close the window. -LANG_NO_ANY_SOURCE="There is no any source, please check Plugin folder or input 'plugins install DefaultPlugin' to install plugin for default sources." +LANG_NO_ANY_SOURCE="There is no source available, please check Plugin folder or input 'plugins install DefaultPlugin' to install plugin for default sources." diff --git a/OfficalPlugins b/OfficalPlugins index 599aca4..17ed850 160000 --- a/OfficalPlugins +++ b/OfficalPlugins @@ -1 +1 @@ -Subproject commit 599aca4d72eb7c28898355c31cfd7dc8644a984a +Subproject commit 17ed850180f1ef01bc915ca738d71325de19fdc6 diff --git a/Sync/Properties/AssemblyInfo.cs b/Sync/Properties/AssemblyInfo.cs index 34d8489..5aa0eb7 100644 --- a/Sync/Properties/AssemblyInfo.cs +++ b/Sync/Properties/AssemblyInfo.cs @@ -1,55 +1,55 @@ -using System.Reflection; -using System.Resources; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Windows; - -// 有关程序集的一般信息由以下 -// 控制。更改这些特性值可修改 -// 与程序集关联的信息。 -[assembly: AssemblyTitle("Sync!")] -[assembly: AssemblyDescription("Sync Live danmaku and Games!")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("Remilia")] -[assembly: AssemblyProduct("Sync")] -[assembly: AssemblyCopyright("MIT")] -[assembly: AssemblyTrademark("RemiliaScarlet.com")] -[assembly: AssemblyCulture("")] - -//将 ComVisible 设置为 false 将使此程序集中的类型 -//对 COM 组件不可见。 如果需要从 COM 访问此程序集中的类型, -//请将此类型的 ComVisible 特性设置为 true。 -[assembly: ComVisible(false)] - -//若要开始生成可本地化的应用程序,请 -// 中的 .csproj 文件中 -//例如,如果您在源文件中使用的是美国英语, -//使用的是美国英语,请将 设置为 en-US。 然后取消 -//对以下 NeutralResourceLanguage 特性的注释。 更新 -//以下行中的“en-US”以匹配项目文件中的 UICulture 设置。 - -//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] - - -[assembly: ThemeInfo( - ResourceDictionaryLocation.None, //主题特定资源词典所处位置 - //(当资源未在页面 - //或应用程序资源字典中找到时使用) - ResourceDictionaryLocation.SourceAssembly //常规资源词典所处位置 - //(当资源未在页面 - //、应用程序或任何主题专用资源字典中找到时使用) -)] - - -// 程序集的版本信息由下列四个值组成: -// -// 主版本 -// 次版本 -// 生成号 -// 修订号 -// -//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值, -// 方法是按如下所示使用“*”: : -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("2.17.0.0")] -[assembly: AssemblyFileVersion("2.17.0.0")] +using System.Reflection; +using System.Resources; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Windows; + +// 有关程序集的一般信息由以下 +// 控制。更改这些特性值可修改 +// 与程序集关联的信息。 +[assembly: AssemblyTitle("Sync!")] +[assembly: AssemblyDescription("Sync Live danmaku and Games!")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Remilia")] +[assembly: AssemblyProduct("Sync")] +[assembly: AssemblyCopyright("MIT")] +[assembly: AssemblyTrademark("RemiliaScarlet.com")] +[assembly: AssemblyCulture("")] + +//将 ComVisible 设置为 false 将使此程序集中的类型 +//对 COM 组件不可见。 如果需要从 COM 访问此程序集中的类型, +//请将此类型的 ComVisible 特性设置为 true。 +[assembly: ComVisible(false)] + +//若要开始生成可本地化的应用程序,请 +// 中的 .csproj 文件中 +//例如,如果您在源文件中使用的是美国英语, +//使用的是美国英语,请将 设置为 en-US。 然后取消 +//对以下 NeutralResourceLanguage 特性的注释。 更新 +//以下行中的“en-US”以匹配项目文件中的 UICulture 设置。 + +//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] + + +[assembly: ThemeInfo( + ResourceDictionaryLocation.None, //主题特定资源词典所处位置 + //(当资源未在页面 + //或应用程序资源字典中找到时使用) + ResourceDictionaryLocation.SourceAssembly //常规资源词典所处位置 + //(当资源未在页面 + //、应用程序或任何主题专用资源字典中找到时使用) +)] + + +// 程序集的版本信息由下列四个值组成: +// +// 主版本 +// 次版本 +// 生成号 +// 修订号 +// +//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值, +// 方法是按如下所示使用“*”: : +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("2.18.0.0")] +[assembly: AssemblyFileVersion("2.18.0.0")] diff --git a/Sync/Sync.csproj b/Sync/Sync.csproj index 27e5b21..c78c54f 100644 --- a/Sync/Sync.csproj +++ b/Sync/Sync.csproj @@ -1,198 +1,197 @@ - - - - - Debug - AnyCPU - {FBD514C2-2830-479E-B050-D1C383028456} - Exe - Properties - Sync - Sync - v4.5 - 512 - {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - 4 - - false - publish\ - true - Disk - false - Foreground - 7 - Days - false - false - true - 0 - 1.0.0.%2a - false - true - - - x86 - true - full - false - bin\Debug\ - TRACE;DEBUG - prompt - 4 - true - - - x86 - none - true - ..\Release\ - TRACE - prompt - 0 - true - false - true - Off - - - Sync.Program - - - Resources\SyncIcon.ico - - - LocalIntranet - - - false - - - - - - - - - - - - - - - - 4.0 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Code - - - True - True - Resources.resx - - - True - Settings.settings - True - - - ResXFileCodeGenerator - Resources.Designer.cs - - - - SettingsSingleFileGenerator - Settings.Designer.cs - - - - - - - Designer - - - - - - - - False - Microsoft .NET Framework 4.5 %28x86 和 x64%29 - true - - - False - .NET Framework 3.5 SP1 - false - - - - - xcopy $(ProjectDir)\..\Language $(ProjectDir)\$(OutDir)\Language\ /s/e/y - + + + + + Debug + AnyCPU + {FBD514C2-2830-479E-B050-D1C383028456} + Exe + Properties + Sync + Sync + v4.5 + 512 + {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 4 + + false + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + true + + + x86 + true + full + false + bin\Debug\ + TRACE;DEBUG + prompt + 4 + true + + + x86 + none + true + ..\Release\ + TRACE + prompt + 0 + true + false + true + Off + + + Sync.Program + + + Resources\SyncIcon.ico + + + LocalIntranet + + + false + + + + + + + + + + + + + + + + 4.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Code + + + True + True + Resources.resx + + + True + Settings.settings + True + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + + + + + Designer + + + + + + + + False + Microsoft .NET Framework 4.5 %28x86 和 x64%29 + true + + + False + .NET Framework 3.5 SP1 + false + + + + + xcopy $(ProjectDir)\..\Language $(ProjectDir)\$(OutDir)\Language\ /s/e/y + + --> \ No newline at end of file diff --git a/Sync/Tools/Builtin/InternalPlugin.cs b/Sync/Tools/Builtin/InternalPlugin.cs index 476dd4c..e6f09a5 100644 --- a/Sync/Tools/Builtin/InternalPlugin.cs +++ b/Sync/Tools/Builtin/InternalPlugin.cs @@ -1,34 +1,34 @@ -using Sync.Command; -using Sync.Plugins; -using System; - -namespace Sync.Tools.Builtin -{ - public class InternalPlugin : Plugin - { - //private PluginConfigurationManager config; - - private CommonCommand commonCommand = new CommonCommand(); - private PluginCommand pluginCommand = new PluginCommand(); - - public InternalPlugin() : base("InternalPlugin", "OsuSync") - { - } - - public override void OnEnable() - { - //config = new PluginConfigurationManager(this); - - this.EventBus.BindEvent(p => - { - Func addCmd = p.Commands.Dispatch.bind; - addCmd("plugins", pluginCommand.Plugins, "Install & Update Plugins online, type 'plugins' to get help."); - commonCommand.BindCommondCommand(p.Commands.Dispatch); - }); - - Updater.update = this; - } - - internal bool CheckUpdate(string guid) => pluginCommand.CheckUpdate(guid); - } +using Sync.Command; +using Sync.Plugins; +using System; + +namespace Sync.Tools.Builtin +{ + public class InternalPlugin : Plugin + { + //private PluginConfigurationManager config; + + private CommonCommand commonCommand = new CommonCommand(); + private PluginCommand pluginCommand = new PluginCommand(); + + public InternalPlugin() : base("InternalPlugin", "OsuSync") + { + } + + public override void OnEnable() + { + //config = new PluginConfigurationManager(this); + + this.EventBus.BindEvent(p => + { + Func addCmd = p.Commands.Dispatch.bind; + addCmd("plugins", pluginCommand.Plugins, "Install & Update Plugins online, type 'plugins' to get help."); + commonCommand.BindCommondCommand(p.Commands.Dispatch); + }); + + Updater.update = this.pluginCommand; + } + + internal bool CheckUpdate(string guid) => pluginCommand.CheckUpdate(guid); + } } \ No newline at end of file diff --git a/Sync/Tools/Builtin/PluginCommand.cs b/Sync/Tools/Builtin/PluginCommand.cs index a0af7ce..9892f31 100644 --- a/Sync/Tools/Builtin/PluginCommand.cs +++ b/Sync/Tools/Builtin/PluginCommand.cs @@ -1,393 +1,392 @@ -using Sync.Command; -using Sync.Plugins; -using Sync.Tools; -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.IO.Compression; -using System.Linq; -using System.Net; -using System.Reflection; -using System.Runtime.Serialization; -using System.Runtime.Serialization.Json; -using System.Security.Cryptography; -using System.Text; -using static Sync.Tools.DefaultI18n; - -namespace Sync.Tools.Builtin -{ - public sealed class PluginCommand - { - #region Updater Decleare - - [DataContract] - public class UpdateData - { - [DataMember(Order = 0)] - public int id { get; set; } - - [DataMember(Order = 1)] - public string name { get; set; } - - [DataMember(Order = 2)] - public string author { get; set; } - - [DataMember(Order = 3)] - public string latestHash { get; set; } - - [DataMember(Order = 4)] - public string downloadUrl { get; set; } - - [DataMember(Order = 5)] - public string description { get; set; } - - [DataMember(Order = 6)] - public string guid { get; set; } - - [DataMember(Order = 7)] - public string fileName { get; set; } - } - - [DataContract] - public class SyncUpdate - { - [DataMember(Order = 0)] - public string versionHash { get; set; } - - [DataMember(Order = 1)] - public string downloadURL { get; set; } - - [DataMember(Order = 2)] - public string versionId { get; set; } - } - - #endregion Updater Decleare - - public bool Plugins(Arguments arg) - { - if (arg.Count == 0) return Help(); - switch (arg[0]) - { - case "search": - return Search(arg[1]); - - case "update": - return Update(); - - case "install": - return Install(arg[1]); - - case "list": - return List(); - - case "remove": - return Remove(arg[1]); - - case "latest": - return Latest(); - - default: - return Help(); - } - } - - private bool Update() - { - IEnumerable plugins = SyncHost.Instance.EnumPluings(); - foreach (var item in plugins) - { - try - { - IO.CurrentIO.Write($"Fetch update: {item.Name} by {item.Author} [{item.getGuid()}]"); - var result = Serializer($"http://sync.mcbaka.com/api/Update/plugin/{item.getGuid()}"); - var target = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Plugins", result.fileName); - if (MD5HashFile(target).ToLower() != result.latestHash) - { - IO.CurrentIO.Write($"Download: {result.downloadUrl}..."); - if (!DownloadSingleFile(result.downloadUrl, target, result.fileName)) - { - IO.CurrentIO.WriteColor("Download Failed!", ConsoleColor.Red); - } - } - else - { - IO.CurrentIO.Write(string.Format(LANG_VERSION_LATEST, result.name)); - } - } - catch (Exception e) - { - IO.CurrentIO.Write(string.Format(LANG_UPDATE_ERROR, e.TargetSite.Name, e.Message)); - continue; - } - } - - RequireRestart(LANG_UPDATE_DONE); - return true; - } - - private bool Search(string keyword) - { - try - { - var result = Serializer($"http://sync.mcbaka.com/api/Update/search/{keyword}"); - - foreach (var item in result) - { - IO.CurrentIO.WriteColor("Name", ConsoleColor.Cyan, false, false); - IO.CurrentIO.WriteColor(item.name.PadRight(15), ConsoleColor.White, false, false); - IO.CurrentIO.WriteColor("Author", ConsoleColor.DarkCyan, false, false); - IO.CurrentIO.WriteColor(item.author.PadRight(15), ConsoleColor.White, false, false); - IO.CurrentIO.WriteColor("Description", ConsoleColor.DarkCyan, false, false); - IO.CurrentIO.WriteColor(item.description, ConsoleColor.White, true, false); - IO.CurrentIO.WriteColor("GUID ", ConsoleColor.DarkCyan, false, false); - IO.CurrentIO.WriteColor(item.guid.PadRight(32), ConsoleColor.White, true, false); - IO.CurrentIO.WriteColor("===============", ConsoleColor.White, true, false); - } - return true; - } - catch (Exception e) - { - IO.CurrentIO.Write($"Error while {e.TargetSite.Name} : {e.Message}"); - } - return false; - } - - private bool Install(string guid) - { - if (CheckUpdate(guid)) - { - RequireRestart(LANG_INSTALL_DONE); - return true; - } - else - { - if (Serializer($"http://sync.mcbaka.com/api/Update/search/{guid}") is UpdateData[] datas) - { - if (datas.Length == 0 || CheckUpdate(datas[0].guid)) - { - RequireRestart(LANG_INSTALL_DONE); - return true; - } - else return false; - } - return false; - } - } - - private bool Remove(string name) - { - var type = SyncHost.Instance.EnumPluings().FirstOrDefault(p => p.Name.ToLower().Contains(name.ToLower())); - if (type == null) - { - IO.CurrentIO.WriteColor(string.Format(LANG_PLUGIN_NOT_FOUND, name), ConsoleColor.Red); - return false; - } - else - { - var result = Serializer($"http://sync.mcbaka.com/api/Update/search/{name}")?[0]; - var target = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Plugins", Path.GetFileName(result.fileName)); - if (File.Exists(target)) File.Delete(target); - - RequireRestart(LANG_REMOVE_DONE); - return true; - } - } - - private bool List() - { - var list = SyncHost.Instance.EnumPluings(); - foreach (var item in list) - { - IO.CurrentIO.WriteColor("Name", ConsoleColor.Cyan, false, false); - IO.CurrentIO.WriteColor(item.Name.PadRight(25), ConsoleColor.White, false, false); - IO.CurrentIO.WriteColor("Author", ConsoleColor.DarkCyan, false, false); - IO.CurrentIO.WriteColor(item.Author.PadRight(20), ConsoleColor.White, false, false); - var info = item.GetType().GetCustomAttribute(); - IO.CurrentIO.WriteColor("Support Update:", ConsoleColor.DarkCyan, false, false); - if (info != null) - { - IO.CurrentIO.WriteColor("Yes".PadRight(15), ConsoleColor.White, false, false); - IO.CurrentIO.WriteColor("Ver:", ConsoleColor.DarkCyan, false, false); - IO.CurrentIO.WriteColor(info.Version.PadRight(15), ConsoleColor.White, true, false); - } - else - { - IO.CurrentIO.WriteColor("No", ConsoleColor.White, true, false); - } - } - return true; - } - - internal bool Latest() - { - IO.CurrentIO.WriteColor("Fetch Sync update..", ConsoleColor.Cyan); - var result = Serializer($"http://sync.mcbaka.com/api/Update/latest"); - if (!File.Exists(Updater.CurrentFullSourceEXEPath) || MD5HashFile(Updater.CurrentFullSourceEXEPath) != result.versionHash) - { - IO.CurrentIO.Write($"Download: {result.downloadURL}..."); - DownloadSingleFile(result.downloadURL, Updater.CurrentFullUpdateEXEPath, "Sync"); - RequireRestart("Update downloaded. Restart to apply effect"); - } - return true; - } - - private bool Help() - { - IO.CurrentIO.Write("Help for 'plugins' command:"); - IO.CurrentIO.WriteHelp("install", "install [guid/name] Install plugin"); - IO.CurrentIO.WriteHelp("remove", "remove [name] Remove plugin by name"); - IO.CurrentIO.WriteHelp("search", "search [keyword] Search plugins"); - IO.CurrentIO.WriteHelp("update", "Check update for Sync and Plugins"); - IO.CurrentIO.WriteHelp("list", "List current installed plugins"); - IO.CurrentIO.WriteHelp("latest", "Check latest Sync update"); - return true; - } - - private void RequireRestart(string msg) - { - IO.CurrentIO.WriteColor($"{msg}? (Y/N):", ConsoleColor.Green, false); - var result = IO.CurrentIO.ReadCommand(); - if (result.ToLower().StartsWith("y")) SyncHost.Instance.RestartSync(); - } - - internal bool CheckUpdate(string guid) - { - try - { - IO.CurrentIO.Write($"Fetch update: {guid}"); - var result = Serializer($"http://sync.mcbaka.com/api/Update/plugin/{guid}"); - var target = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Plugins", result.fileName); - if (!File.Exists(target) || MD5HashFile(target) != result.latestHash) - { - IO.CurrentIO.Write($"Download: {result.downloadUrl}..."); - return DownloadSingleFile(result.downloadUrl, target, result.fileName); - } - else - { - IO.CurrentIO.Write(string.Format(LANG_VERSION_LATEST, result.name)); - return false; - } - } - catch (Exception e) - { - IO.CurrentIO.Write(string.Format(LANG_UPDATE_CHECK_ERROR, guid, e.TargetSite.Name, e.Message)); - return false; - } - } - - private T Serializer(string url) - { - WebClient web; - web = new WebClient(); - Random rd = new Random(); - Stream data = web.OpenRead(url + "?rd=" + rd.Next()); - DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(T)); - return (T)serializer.ReadObject(data); - } - - private string MD5HashFile(string filePath) - { - FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read); - MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider(); - md5.ComputeHash(fs); - byte[] b = md5.Hash; - - fs.Dispose(); - md5.Clear(); - - StringBuilder sb = new StringBuilder(32); - for (int i = 0; i < b.Length; i++) - sb.Append(b[i].ToString("X2")); - return sb.ToString(); - } - - private bool DownloadSingleFile(string dlUrl, string path, string name) - { - try - { - //打开HTTP连接,获得文件长度 - IO.CurrentIO.WriteColor($"Download {name} from {dlUrl}", ConsoleColor.Magenta); - ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Ssl3; - HttpWebRequest Myrq = (HttpWebRequest)WebRequest.Create(dlUrl); - HttpWebResponse myrp = (HttpWebResponse)Myrq.GetResponse(); - long totalBytes = myrp.ContentLength; - IO.CurrentIO.WriteHelp(name, totalBytes.ToString()); - //判断是否存在已经下载的文件,如果存在,且长度相等,则直接解压 - - if (File.Exists(path + "_")) File.Delete(path + "_"); //如果存在目标缓存文件,就删掉它 - - Stream st = myrp.GetResponseStream(); //获得http流 - Stream so = new FileStream(path + "_", FileMode.Create); //创建文件流 - - long totalDownloadedByte = 0; //已经下载的字节数量 - long updateDownloadByte = 0; //已经计算下载速度的字节位置 - long downloadspeed = 0; //当前下载速度 byte - Stopwatch time = new Stopwatch(); //下载速度计时器 - time.Reset(); - time.Start(); - byte[] buffer = new byte[1024]; //缓冲区 - int osize = st.Read(buffer, 0, buffer.Length); //向缓冲区填入数据 - - while (osize > 0) //判断还剩没剩数据 - { - so.Write(buffer, 0, osize); //写入文件流 - - totalDownloadedByte += osize; //更新当前下载进度 - osize = st.Read(buffer, 0, buffer.Length); //获得下一个缓冲区 - - if (time.ElapsedMilliseconds > 1000) //数据统计大于1000ms,则更新下载速度 - { - downloadspeed = totalDownloadedByte - updateDownloadByte; //这段时间已经下载的数据量 - time.Restart(); //计时器重新开始计时 - updateDownloadByte = totalDownloadedByte; //更新已经计算速度的数据位置 - IO.CurrentIO.WriteHelp($"{downloadspeed.ToString()}Byte/s", $"{totalDownloadedByte.ToString()}Byte OK");//UI更新 - } - } - - IO.CurrentIO.WriteHelp($"{downloadspeed.ToString()}Byte/s", $"{totalDownloadedByte.ToString()}Byte OK");//UI更新 - - so.Close(); - st.Close(); - - if (File.Exists(path)) - { - File.Delete(path); - } - - File.Copy(path + "_", path); - File.Delete(path + "_"); - - if (dlUrl.EndsWith("zip")) - { - var zip = Path.Combine(Path.GetDirectoryName(path), Path.GetFileNameWithoutExtension(path) + ".zip"); - if (File.Exists(zip)) File.Delete(zip); - File.Move(path, zip); - using (var archive = ZipFile.Open(zip, ZipArchiveMode.Update)) - { - foreach (ZipArchiveEntry entry in archive.Entries) - { - if (entry.Length == 0) continue; - IO.CurrentIO.WriteHelp(entry.FullName, entry.Length.ToString()); - try - { - entry.ExtractToFile(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, entry.FullName), true); - } - catch { } - } - } - - File.Delete(zip); - } - - IO.CurrentIO.Write($"[{name}] Done."); - return true; - } - catch (Exception e) - { - IO.CurrentIO.Write($"Error while {e.TargetSite.Name} : {e.Message}"); - return false; - } - } - } +using Sync.Command; +using Sync.Plugins; +using Sync.Tools; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.IO.Compression; +using System.Linq; +using System.Net; +using System.Reflection; +using System.Runtime.Serialization; +using System.Runtime.Serialization.Json; +using System.Security.Cryptography; +using System.Text; +using static Sync.Tools.DefaultI18n; + +namespace Sync.Tools.Builtin +{ + internal sealed class PluginCommand + { + #region Updater Decleare + + [DataContract] + public class UpdateData + { + [DataMember(Order = 0)] + public int id { get; set; } + + [DataMember(Order = 1)] + public string name { get; set; } + + [DataMember(Order = 2)] + public string author { get; set; } + + [DataMember(Order = 3)] + public string latestHash { get; set; } + + [DataMember(Order = 4)] + public string downloadUrl { get; set; } + + [DataMember(Order = 5)] + public string description { get; set; } + + [DataMember(Order = 6)] + public string guid { get; set; } + + [DataMember(Order = 7)] + public string fileName { get; set; } + } + + [DataContract] + public class SyncUpdate + { + [DataMember(Order = 0)] + public string versionHash { get; set; } + + [DataMember(Order = 1)] + public string downloadURL { get; set; } + + [DataMember(Order = 2)] + public string versionId { get; set; } + } + + #endregion Updater Decleare + + public bool Plugins(Arguments arg) + { + if (arg.Count == 0) return Help(); + switch (arg[0]) + { + case "search": + return Search(arg[1]); + + case "update": + return Update(); + + case "install": + return Install(arg[1]); + + case "list": + return List(); + + case "remove": + return Remove(arg[1]); + + case "latest": + return Latest(); + + default: + return Help(); + } + } + + private bool Update() + { + IEnumerable plugins = SyncHost.Instance.EnumPluings(); + foreach (var item in plugins) + { + try + { + IO.CurrentIO.Write($"Fetch update: {item.Name} by {item.Author} [{item.getGuid()}]"); + var result = Serializer($"http://sync.mcbaka.com/api/Update/plugin/{item.getGuid()}"); + var target = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Plugins", result.fileName); + if (MD5HashFile(target).ToLower() != result.latestHash) + { + IO.CurrentIO.Write($"Download: {result.downloadUrl}..."); + if (!DownloadSingleFile(result.downloadUrl, target, result.fileName)) + { + IO.CurrentIO.WriteColor("Download Failed!", ConsoleColor.Red); + } + } + else + { + IO.CurrentIO.Write(string.Format(LANG_VERSION_LATEST, result.name)); + } + } + catch (Exception e) + { + IO.CurrentIO.Write(string.Format(LANG_UPDATE_ERROR, e.TargetSite.Name, e.Message)); + continue; + } + } + + RequireRestart(LANG_UPDATE_DONE); + return true; + } + + private bool Search(string keyword) + { + try + { + var result = Serializer($"http://sync.mcbaka.com/api/Update/search/{keyword}"); + + foreach (var item in result) + { + IO.CurrentIO.WriteColor("Name", ConsoleColor.Cyan, false, false); + IO.CurrentIO.WriteColor(item.name.PadRight(15), ConsoleColor.White, false, false); + IO.CurrentIO.WriteColor("Author", ConsoleColor.DarkCyan, false, false); + IO.CurrentIO.WriteColor(item.author.PadRight(15), ConsoleColor.White, false, false); + IO.CurrentIO.WriteColor("Description", ConsoleColor.DarkCyan, false, false); + IO.CurrentIO.WriteColor(item.description, ConsoleColor.White, true, false); + IO.CurrentIO.WriteColor("GUID ", ConsoleColor.DarkCyan, false, false); + IO.CurrentIO.WriteColor(item.guid.PadRight(32), ConsoleColor.White, true, false); + IO.CurrentIO.WriteColor("===============", ConsoleColor.White, true, false); + } + return true; + } + catch (Exception e) + { + IO.CurrentIO.Write($"Error while {e.TargetSite.Name} : {e.Message}"); + } + return false; + } + + private bool Install(string guid) + { + if (CheckUpdate(guid)) + { + RequireRestart(LANG_INSTALL_DONE); + return true; + } + else + { + if (Serializer($"http://sync.mcbaka.com/api/Update/search/{guid}") is UpdateData[] datas) + { + if (datas.Length == 0 || CheckUpdate(datas[0].guid)) + { + RequireRestart(LANG_INSTALL_DONE); + return true; + } + else return false; + } + return false; + } + } + + private bool Remove(string name) + { + var type = SyncHost.Instance.EnumPluings().FirstOrDefault(p => p.Name.ToLower().Contains(name.ToLower())); + if (type == null) + { + IO.CurrentIO.WriteColor(string.Format(LANG_PLUGIN_NOT_FOUND, name), ConsoleColor.Red); + return false; + } + else + { + var result = Serializer($"http://sync.mcbaka.com/api/Update/search/{name}")?[0]; + var target = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Plugins", Path.GetFileName(result.fileName)); + if (File.Exists(target)) File.Delete(target); + + RequireRestart(LANG_REMOVE_DONE); + return true; + } + } + + private bool List() + { + var list = SyncHost.Instance.EnumPluings(); + foreach (var item in list) + { + IO.CurrentIO.WriteColor("Name", ConsoleColor.Cyan, false, false); + IO.CurrentIO.WriteColor(item.Name.PadRight(25), ConsoleColor.White, false, false); + IO.CurrentIO.WriteColor("Author", ConsoleColor.DarkCyan, false, false); + IO.CurrentIO.WriteColor(item.Author.PadRight(20), ConsoleColor.White, false, false); + var info = item.GetType().GetCustomAttribute(); + IO.CurrentIO.WriteColor("Support Update:", ConsoleColor.DarkCyan, false, false); + if (info != null) + { + IO.CurrentIO.WriteColor("Yes".PadRight(15), ConsoleColor.White, false, false); + IO.CurrentIO.WriteColor("Ver:", ConsoleColor.DarkCyan, false, false); + IO.CurrentIO.WriteColor(info.Version.PadRight(15), ConsoleColor.White, true, false); + } + else + { + IO.CurrentIO.WriteColor("No", ConsoleColor.White, true, false); + } + } + return true; + } + + internal bool Latest() + { + IO.CurrentIO.WriteColor("Fetch Sync update..", ConsoleColor.Cyan); + var result = Serializer($"http://sync.mcbaka.com/api/Update/latest"); + if (!File.Exists(Updater.CurrentFullSourceEXEPath) || MD5HashFile(Updater.CurrentFullSourceEXEPath) != result.versionHash) + { + IO.CurrentIO.Write($"Download: {result.downloadURL}..."); + DownloadSingleFile(result.downloadURL, Updater.CurrentFullUpdateEXEPath, "Sync"); + RequireRestart("Update downloaded. Restart to apply effect"); + } + return true; + } + + private bool Help() + { + IO.CurrentIO.Write("Help for 'plugins' command:"); + IO.CurrentIO.WriteHelp("install", "install [guid/name] Install plugin"); + IO.CurrentIO.WriteHelp("remove", "remove [name] Remove plugin by name"); + IO.CurrentIO.WriteHelp("search", "search [keyword] Search plugins"); + IO.CurrentIO.WriteHelp("update", "Check update for Sync and Plugins"); + IO.CurrentIO.WriteHelp("list", "List current installed plugins"); + IO.CurrentIO.WriteHelp("latest", "Check latest Sync update"); + return true; + } + + private void RequireRestart(string msg) + { + IO.CurrentIO.WriteColor($"{msg}? (Y/N):", ConsoleColor.Green, false); + var result = IO.CurrentIO.ReadCommand(); + if (result.ToLower().StartsWith("y")) SyncHost.Instance.RestartSync(); + } + + internal bool CheckUpdate(string guid) + { + try + { + IO.CurrentIO.Write($"Fetch update: {guid}"); + var result = Serializer($"http://sync.mcbaka.com/api/Update/plugin/{guid}"); + var target = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Plugins", result.fileName); + if (!File.Exists(target) || MD5HashFile(target) != result.latestHash) + { + IO.CurrentIO.Write($"Download: {result.downloadUrl}..."); + return DownloadSingleFile(result.downloadUrl, target, result.fileName); + } + else + { + IO.CurrentIO.Write(string.Format(LANG_VERSION_LATEST, result.name)); + return false; + } + } + catch (Exception e) + { + IO.CurrentIO.Write(string.Format(LANG_UPDATE_CHECK_ERROR, guid, e.TargetSite.Name, e.Message)); + return false; + } + } + + private T Serializer(string url) + { + WebClient web; + web = new WebClient(); + Random rd = new Random(); + Stream data = web.OpenRead(url + "?rd=" + rd.Next()); + DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(T)); + return (T)serializer.ReadObject(data); + } + + private string MD5HashFile(string filePath) + { + FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read); + MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider(); + md5.ComputeHash(fs); + byte[] b = md5.Hash; + + fs.Dispose(); + md5.Clear(); + + StringBuilder sb = new StringBuilder(32); + for (int i = 0; i < b.Length; i++) + sb.Append(b[i].ToString("X2")); + return sb.ToString(); + } + + private bool DownloadSingleFile(string dlUrl, string path, string name) + { + try + { + //打开HTTP连接,获得文件长度 + IO.CurrentIO.WriteColor($"Download {name} from {dlUrl}", ConsoleColor.Magenta); + ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Ssl3; + HttpWebRequest Myrq = (HttpWebRequest)WebRequest.Create(dlUrl); + HttpWebResponse myrp = (HttpWebResponse)Myrq.GetResponse(); + long totalBytes = myrp.ContentLength; + string convertdTotal = (totalBytes / 1024).ToString("0.00"); + IO.CurrentIO.WriteHelp(name, $"Total: {convertdTotal} KB"); + //判断是否存在已经下载的文件,如果存在,且长度相等,则直接解压 + + if (File.Exists(path + "_")) File.Delete(path + "_"); //如果存在目标缓存文件,就删掉它 + + Stream st = myrp.GetResponseStream(); //获得http流 + Stream so = new FileStream(path + "_", FileMode.Create); //创建文件流 + + long totalDownloadedByte = 0; //已经下载的字节数量 + long updateDownloadByte = 0; //已经计算下载速度的字节位置 + long downloadspeed = 0; //当前下载速度 byte + Stopwatch time = new Stopwatch(); //下载速度计时器 + time.Reset(); + time.Start(); + byte[] buffer = new byte[1024]; //缓冲区 + int osize = st.Read(buffer, 0, buffer.Length); //向缓冲区填入数据 + + while (osize > 0) //判断还剩没剩数据 + { + so.Write(buffer, 0, osize); //写入文件流 + + totalDownloadedByte += osize; //更新当前下载进度 + osize = st.Read(buffer, 0, buffer.Length); //获得下一个缓冲区 + + if (time.ElapsedMilliseconds > 1000) //数据统计大于1000ms,则更新下载速度 + { + downloadspeed = totalDownloadedByte - updateDownloadByte; //这段时间已经下载的数据量 + time.Restart(); //计时器重新开始计时 + updateDownloadByte = totalDownloadedByte; //更新已经计算速度的数据位置 + IO.CurrentIO.WriteHelp($"{(downloadspeed / 1024).ToString("0.0")}KB/s", $"{(totalDownloadedByte / 1024).ToString("0.0")}/{convertdTotal} KB");//UI更新 + } + } + + so.Close(); + st.Close(); + + if (File.Exists(path)) + { + File.Delete(path); + } + + File.Copy(path + "_", path); + File.Delete(path + "_"); + + if (dlUrl.EndsWith("zip")) + { + var zip = Path.Combine(Path.GetDirectoryName(path), Path.GetFileNameWithoutExtension(path) + ".zip"); + if (File.Exists(zip)) File.Delete(zip); + File.Move(path, zip); + using (var archive = ZipFile.Open(zip, ZipArchiveMode.Update)) + { + foreach (ZipArchiveEntry entry in archive.Entries) + { + if (entry.Length == 0) continue; + IO.CurrentIO.WriteHelp(entry.FullName, entry.Length.ToString()); + try + { + entry.ExtractToFile(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, entry.FullName), true); + } + catch { } + } + } + + File.Delete(zip); + } + + IO.CurrentIO.Write($"[{name}] Done."); + return true; + } + catch (Exception e) + { + IO.CurrentIO.Write($"Error while {e.TargetSite.Name} : {e.Message}"); + return false; + } + } + } } \ No newline at end of file diff --git a/Sync/Tools/CommandParser.cs b/Sync/Tools/CommandParser.cs index 2ce1b75..6b4d875 100644 --- a/Sync/Tools/CommandParser.cs +++ b/Sync/Tools/CommandParser.cs @@ -12,17 +12,13 @@ internal class CommandParser string[] args; List> parsedArgumentActions = new List>(); List> parsedExecuteActions = new List>(); - Dictionary>> parseArgumentBinder; - Dictionary>> parseActionBinder; + Dictionary>> parseArgumentBinder; + Dictionary>> parseActionBinder; int parseSharedIndex = 0; - internal CommandParser(string[] args) + internal CommandParser(string[] args) : this(args, new Dictionary>>(), new Dictionary>>()) { - this.args = args; - this.parseArgumentBinder = new Dictionary>>(); - this.parseActionBinder = new Dictionary>>(); - ParseCommands(); } - internal CommandParser(string[] args, Dictionary>> arguments, Dictionary>> actions) + internal CommandParser(string[] args, Dictionary>> arguments, Dictionary>> actions) { this.args = args; this.parseArgumentBinder = arguments; @@ -39,14 +35,18 @@ public void ParseCommands() ParseStringBlock($"{item} "); } } - catch (System.Exception) + catch (Exception) { - System.Console.WriteLine("Wrong argument"); + Console.WriteLine("Wrong argument"); } } private void ParseStringBlock(string value) { - if (value.StartsWith("-")) + if (value.StartsWith("--")) + { + ParseArgumentFullArgs(value.Substring(2)); + } + else if (value.StartsWith("-")) { ParseArgumentArgs(value.Substring(1)); } @@ -55,11 +55,15 @@ private void ParseStringBlock(string value) ParseExecuteArgs(value); } } + private void ParseArgumentFullArgs(string value) + { + parsedArgumentActions.Add(parseArgumentBinder[value](value)); + } private void ParseArgumentArgs(string value) { for (parseSharedIndex = 0; parseSharedIndex < value.Length - 1; parseSharedIndex++) { - parsedArgumentActions.Add(parseArgumentBinder[value[parseSharedIndex]](value)); + parsedArgumentActions.Add(parseArgumentBinder[value.Substring(parseSharedIndex, 1)](value)); } } @@ -67,7 +71,7 @@ private void ParseExecuteArgs(string value) { if (value.Length > 0) { - parsedExecuteActions.Add(parseActionBinder[value[0]](value)); + parsedExecuteActions.Add(parseActionBinder[value.Substring(0, 1)](value)); } } #region ParseTools diff --git a/Sync/Tools/Configuration.cs b/Sync/Tools/Configuration.cs index 7fc198f..58e796b 100644 --- a/Sync/Tools/Configuration.cs +++ b/Sync/Tools/Configuration.cs @@ -27,6 +27,9 @@ public class DefaultConfiguration : IConfigurable [Bool] public ConfigurationElement EnableGiftChangedNotify { get; set; } = "False"; + [Bool] + public ConfigurationElement CheckUpdateOnStartup { get; set; } = "True"; + [List(ValueList = new[] { "Auto", "ForceAll", "OnlySendCommand", "DisableAll" }, IgnoreCase = true)] public ConfigurationElement MessageManagerDefaultOption { get; set; } = "Auto"; @@ -43,13 +46,13 @@ public void onConfigurationReload() public void onConfigurationSave() { MessageManagerDefaultOption = MessageManager.Option.ToString(); - } - + } + public static readonly DefaultConfiguration Instance = new DefaultConfiguration(); private static readonly PluginConfigurationManager config = new PluginConfigurationManager("Sync"); - static DefaultConfiguration() - { - config.AddItem(Instance); + static DefaultConfiguration() + { + config.AddItem(Instance); } } diff --git a/Sync/Tools/StartupArgument.cs b/Sync/Tools/StartupArgument.cs index 70ed35d..c0be063 100644 --- a/Sync/Tools/StartupArgument.cs +++ b/Sync/Tools/StartupArgument.cs @@ -8,13 +8,17 @@ namespace Sync.Tools { internal static class StartupArgument { - internal static Dictionary>> Arguments = new Dictionary>>() - { - { 'f', (string arg) => (_) => StartupHelper.ForceStart = true }, - { 'u', (string arg) => (_) => StartupHelper.NeedUpdateSync = true }, + private static Action ForceStartArg(string arg) => (_) => StartupHelper.ForceStart = true; + private static Action NeedUpdateSyncArg(string arg) => (_) => StartupHelper.NeedUpdateSync = true; + internal static Dictionary>> Arguments = new Dictionary>>() + { + { "f", ForceStartArg }, + { "--force-start", ForceStartArg }, + { "u", NeedUpdateSyncArg }, + { "--update", NeedUpdateSyncArg } }; - internal static Dictionary>> Actions = new Dictionary>>(); + internal static Dictionary>> Actions = new Dictionary>>(); } } diff --git a/Sync/Tools/StartupHelper.cs b/Sync/Tools/StartupHelper.cs index 7247164..3b5ec10 100644 --- a/Sync/Tools/StartupHelper.cs +++ b/Sync/Tools/StartupHelper.cs @@ -37,39 +37,39 @@ private void SyncInstanceLocker(MemoryMappedFile syncMappedFile, bool forceExit) using (var reader = new BinaryReader(syncViewStream)) { pid = reader.ReadInt32(); - } - if (pid != 0) - { - var oldSync = Process.GetProcesses().FirstOrDefault((proc) => proc.Id == pid); - if (oldSync != null) + if (pid != 0) { - if (forceExit) - { - oldSync.Kill(); - } - else + var oldSync = Process.GetProcesses().FirstOrDefault((proc) => proc.Id == pid); + if (oldSync != null) { - CurrentIO.WriteColor(DefaultI18n.LANG_Instance_Exist, ConsoleColor.Red); - int limit = 50, current = 0; - while (oldSync.WaitForExit(100)) + if (forceExit) { - current++; - if (current > limit) break; + oldSync.Kill(); } - - if (!oldSync.WaitForExit(100)) + else { - oldSync.Kill(); + CurrentIO.WriteColor(DefaultI18n.LANG_Instance_Exist, ConsoleColor.Red); + int limit = 50, current = 0; + while (oldSync.WaitForExit(100)) + { + current++; + if (current > limit) break; + } + + if (!oldSync.WaitForExit(100)) + { + oldSync.Kill(); + } } } } - } - using (var writer = new BinaryWriter(syncViewStream)) - { - writer.Seek(0, SeekOrigin.Begin); - writer.Write(Process.GetCurrentProcess().Id); + using (var writer = new BinaryWriter(syncViewStream)) + { + writer.Seek(0, SeekOrigin.Begin); + writer.Write(Process.GetCurrentProcess().Id); + } } } } @@ -84,9 +84,10 @@ private void PerLuanchChecker(bool forceStart) static void InitSync() { - //Update check + + //Apply update if (Updater.ApplyUpdate(NeedUpdateSync)) - return; + Environment.Exit(0); //Initialize I18n I18n.Instance.ApplyLanguage(new DefaultI18n()); @@ -98,11 +99,16 @@ static void InitSync() SyncHost.Instance = new SyncHost(); SyncHost.Instance.Load(); + //Sync ready message to all plugins SyncHost.Instance.Plugins.ReadySync(); + //Check update + if (DefaultConfiguration.Instance.CheckUpdateOnStartup.ToBool()) + Updater.update.Latest(); + //Sync program update check if (Updater.IsUpdated) - IO.CurrentIO.WriteColor("Sync is already up to date!", ConsoleColor.Green); + CurrentIO.WriteColor("Sync is already up to date!", ConsoleColor.Green); } diff --git a/Sync/Tools/SyncIO/NConsoleWriter.cs b/Sync/Tools/SyncIO/NConsoleWriter.cs index a59885d..2082eac 100644 --- a/Sync/Tools/SyncIO/NConsoleWriter.cs +++ b/Sync/Tools/SyncIO/NConsoleWriter.cs @@ -1,116 +1,116 @@ -using System; -using static Sync.Tools.DefaultI18n; - -namespace Sync.Tools -{ - public class NConsoleWriter : ISyncConsoleWriter, ISyncOutput, ISyncInput - { - private bool wait = false; - - /// - /// Read Line - /// - /// Input chars - public string ReadCommand() - { - WriteColor("", ConsoleColor.Green, false, false); - wait = true; - return Console.ReadLine(); - } - - /// - /// Write a message to console - /// - /// Message - /// Display in new line - public void Write(string msg, bool newline = true, bool time = true) - { - if (wait) - { - wait = false; - Console.SetCursorPosition(0, Console.CursorTop); - } - - string ms = System.Text.RegularExpressions.Regex.Replace(msg, @"\\t|\\n", m => - { - switch (m.ToString()) - { - case @"\t": return "\t"; - case @"\n": return "\n"; - } - return m.ToString(); - }); - - Console.Write((time ? "[" + DateTime.Now.ToLongTimeString() + "] " : "") - + ms - + (newline ? "\n" : "")); - } - - /// - /// Write a message with color - /// - /// Message - /// Color - /// Display in new line - public void WriteColor(string text, ConsoleColor color, bool newline = true, bool time = true) - { - Console.ForegroundColor = color; - Write(text, newline, time); - Console.ResetColor(); - } - - /// - /// Write a formated help message - /// - /// 命令 - /// 命令描述 - public void WriteHelp(string cmd, string desc) - { - WriteColor(cmd.PadRight(10), ConsoleColor.Cyan, false, false); - WriteColor(desc, ConsoleColor.White, true, false); - } - - /// - /// Write current work status - /// - public void WriteStatus() - { - WriteColor("Source:" + SyncHost.Instance.SourceWrapper.Source?.Status.ToString(), ConsoleColor.Magenta); - WriteColor("Client:" + SyncHost.Instance.ClientWrapper.Client?.CurrentStatus.ToString(), ConsoleColor.Magenta); - } - - /// - /// Write welcolme message - /// - public void WriteWelcome() - { - Write(string.Format(LANG_Welcome, - System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString())); - - Write(LANG_Help); - } - - /// - /// Write all commands - /// - public void WriteHelp() - { - WriteHelp(LANG_Command, LANG_Command_Description); - WriteHelp("======", "======"); - foreach (var item in SyncHost.Instance.Commands.Dispatch.getCommandsHelp()) - { - WriteHelp(item.Key, item.Value); - } - WriteHelp("======", "======"); - Write("", true, false); - } - - /// - /// Clear screen - /// - public void Clear() - { - Console.Clear(); - } - } +using System; +using static Sync.Tools.DefaultI18n; + +namespace Sync.Tools +{ + public class NConsoleWriter : ISyncConsoleWriter, ISyncOutput, ISyncInput + { + private bool wait = false; + + /// + /// Read Line + /// + /// Input chars + public string ReadCommand() + { + WriteColor(">", ConsoleColor.Green, false, false); + wait = true; + return Console.ReadLine(); + } + + /// + /// Write a message to console + /// + /// Message + /// Display in new line + public void Write(string msg, bool newline = true, bool time = true) + { + if (wait) + { + wait = false; + Console.SetCursorPosition(0, Console.CursorTop); + } + + string ms = System.Text.RegularExpressions.Regex.Replace(msg, @"\\t|\\n", m => + { + switch (m.ToString()) + { + case @"\t": return "\t"; + case @"\n": return "\n"; + } + return m.ToString(); + }); + + Console.Write((time ? "[" + DateTime.Now.ToLongTimeString() + "] " : "") + + ms + + (newline ? "\n" : "")); + } + + /// + /// Write a message with color + /// + /// Message + /// Color + /// Display in new line + public void WriteColor(string text, ConsoleColor color, bool newline = true, bool time = true) + { + Console.ForegroundColor = color; + Write(text, newline, time); + Console.ResetColor(); + } + + /// + /// Write a formated help message + /// + /// 命令 + /// 命令描述 + public void WriteHelp(string cmd, string desc) + { + WriteColor(cmd.PadRight(10), ConsoleColor.Cyan, false, false); + WriteColor(desc, ConsoleColor.White, true, false); + } + + /// + /// Write current work status + /// + public void WriteStatus() + { + WriteColor("Source:" + SyncHost.Instance.SourceWrapper.Source?.Status.ToString(), ConsoleColor.Magenta); + WriteColor("Client:" + SyncHost.Instance.ClientWrapper.Client?.CurrentStatus.ToString(), ConsoleColor.Magenta); + } + + /// + /// Write welcolme message + /// + public void WriteWelcome() + { + Write(string.Format(LANG_Welcome, + System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString())); + + Write(LANG_Help); + } + + /// + /// Write all commands + /// + public void WriteHelp() + { + WriteHelp(LANG_Command, LANG_Command_Description); + WriteHelp("======", "======"); + foreach (var item in SyncHost.Instance.Commands.Dispatch.getCommandsHelp()) + { + WriteHelp(item.Key, item.Value); + } + WriteHelp("======", "======"); + Write("", true, false); + } + + /// + /// Clear screen + /// + public void Clear() + { + Console.Clear(); + } + } } \ No newline at end of file diff --git a/Sync/Tools/Updater.cs b/Sync/Tools/Updater.cs index 8a7a0df..ffc86bf 100644 --- a/Sync/Tools/Updater.cs +++ b/Sync/Tools/Updater.cs @@ -14,14 +14,14 @@ static class Updater { public const string SourceEXEName = "Sync.exe"; public const string UpdateEXEName = "Sync_update.exe"; - public const string UpdateArg = "-u"; + public const string UpdateArg = "--update"; public static readonly string CurrentEXEName = Path.GetFileName(Process.GetCurrentProcess().Modules[0].FileName); public static readonly string CurrentPath = AppDomain.CurrentDomain.BaseDirectory; public static readonly string CurrentFullEXEPath = Path.Combine(CurrentPath, CurrentEXEName); public static readonly string CurrentFullSourceEXEPath = Path.Combine(CurrentPath, SourceEXEName); public static readonly string CurrentFullUpdateEXEPath = Path.Combine(CurrentPath, UpdateEXEName); public static bool IsUpdated = false; - internal static InternalPlugin update; + internal static PluginCommand update; public static bool ApplyUpdate(bool needUpdate) {