diff --git a/TGCommandLine/RootCommands.cs b/TGCommandLine/RootCommands.cs index 884f1c0744..9fba17ca44 100644 --- a/TGCommandLine/RootCommands.cs +++ b/TGCommandLine/RootCommands.cs @@ -8,7 +8,7 @@ namespace TGCommandLine { public CLICommand() { - var tmp = new List { new UpdateCommand(), new TestmergeCommand(), new RepoCommand(), new BYONDCommand(), new DMCommand(), new DDCommand(), new ConfigCommand(), new IRCCommand(), new DiscordCommand() }; + var tmp = new List { new UpdateCommand(), new TestmergeCommand(), new RepoCommand(), new BYONDCommand(), new DMCommand(), new DDCommand(), new ConfigCommand(), new IRCCommand(), new DiscordCommand(), new AutoUpdateCommand(), new SetAutoUpdateCommand() }; if (Server.VerifyConnection() == null && Server.Authenticate() && Server.AuthenticateAdmin()) tmp.Add(new AdminCommand()); Children = tmp.ToArray(); @@ -20,6 +20,64 @@ namespace TGCommandLine base.PrintHelp(); } } + class AutoUpdateCommand : Command + { + public AutoUpdateCommand() + { + Keyword = "auto-update"; + } + + public override string GetHelpText() + { + return "Get the interval in minutes that the server automatically updates"; + } + + protected override ExitCode Run(IList parameters) + { + var res = Server.GetComponent().AutoUpdateInterval(); + OutputProc(res == 0 ? "OFF" : String.Format("Auto updating every {0} minutes", res)); + return ExitCode.Normal; + } + } + class SetAutoUpdateCommand : Command + { + public SetAutoUpdateCommand() + { + Keyword = "set-auto-update"; + RequiredParameters = 1; + } + + public override string GetArgumentString() + { + return ""; + } + + public override string GetHelpText() + { + return "Set the interval in minutes that the server automatically updates"; + } + + protected override ExitCode Run(IList parameters) + { + ulong NewInterval; + if (parameters[0].ToLower() == "off") + NewInterval = 0; + else + try + { + NewInterval = Convert.ToUInt64(parameters[0]); + } + catch + { + OutputProc("Invalid interval specified!"); + return ExitCode.BadCommand; + } + + Server.GetComponent().SetAutoUpdateInterval(NewInterval); + return ExitCode.Normal; + } + + } class UpdateCommand : Command { public UpdateCommand() diff --git a/TGControlPanel/Main.Designer.cs b/TGControlPanel/Main.Designer.cs index a58a04b3dc..3f787f03be 100644 --- a/TGControlPanel/Main.Designer.cs +++ b/TGControlPanel/Main.Designer.cs @@ -70,6 +70,9 @@ this.AdminModeSpecial = new System.Windows.Forms.RadioButton(); this.AdminModeNormal = new System.Windows.Forms.RadioButton(); this.ServerPanel = new System.Windows.Forms.TabPage(); + this.AutoUpdateMLabel = new System.Windows.Forms.Label(); + this.AutoUpdateInterval = new System.Windows.Forms.NumericUpDown(); + this.AutoUpdateCheckbox = new System.Windows.Forms.CheckBox(); this.ServerPageRefreshButton = new System.Windows.Forms.Button(); this.AutostartCheckbox = new System.Windows.Forms.CheckBox(); this.WebclientCheckBox = new System.Windows.Forms.CheckBox(); @@ -160,6 +163,7 @@ this.ChatProviderSelectorPanel.SuspendLayout(); this.panel1.SuspendLayout(); this.ServerPanel.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.AutoUpdateInterval)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.PortSelector)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.ServerTestmergeInput)).BeginInit(); this.BYONDPanel.SuspendLayout(); @@ -631,6 +635,9 @@ // ServerPanel // this.ServerPanel.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(39)))), ((int)(((byte)(40)))), ((int)(((byte)(34))))); + this.ServerPanel.Controls.Add(this.AutoUpdateMLabel); + this.ServerPanel.Controls.Add(this.AutoUpdateInterval); + this.ServerPanel.Controls.Add(this.AutoUpdateCheckbox); this.ServerPanel.Controls.Add(this.ServerPageRefreshButton); this.ServerPanel.Controls.Add(this.AutostartCheckbox); this.ServerPanel.Controls.Add(this.WebclientCheckBox); @@ -671,6 +678,60 @@ this.ServerPanel.TabIndex = 2; this.ServerPanel.Text = "Server"; // + // AutoUpdateMLabel + // + this.AutoUpdateMLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.AutoUpdateMLabel.AutoSize = true; + this.AutoUpdateMLabel.Font = new System.Drawing.Font("Verdana", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.AutoUpdateMLabel.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(248)))), ((int)(((byte)(248)))), ((int)(((byte)(242))))); + this.AutoUpdateMLabel.Location = new System.Drawing.Point(433, 136); + this.AutoUpdateMLabel.Name = "AutoUpdateMLabel"; + this.AutoUpdateMLabel.Size = new System.Drawing.Size(21, 18); + this.AutoUpdateMLabel.TabIndex = 47; + this.AutoUpdateMLabel.Text = "M"; + this.AutoUpdateMLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + this.AutoUpdateMLabel.Visible = false; + // + // AutoUpdateInterval + // + this.AutoUpdateInterval.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.AutoUpdateInterval.Location = new System.Drawing.Point(365, 135); + this.AutoUpdateInterval.Maximum = new decimal(new int[] { + 276447231, + 23283, + 0, + 0}); + this.AutoUpdateInterval.Minimum = new decimal(new int[] { + 1, + 0, + 0, + 0}); + this.AutoUpdateInterval.Name = "AutoUpdateInterval"; + this.AutoUpdateInterval.Size = new System.Drawing.Size(62, 20); + this.AutoUpdateInterval.TabIndex = 46; + this.AutoUpdateInterval.Value = new decimal(new int[] { + 1, + 0, + 0, + 0}); + this.AutoUpdateInterval.Visible = false; + this.AutoUpdateInterval.ValueChanged += new System.EventHandler(this.AutoUpdateInterval_ValueChanged); + // + // AutoUpdateCheckbox + // + this.AutoUpdateCheckbox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.AutoUpdateCheckbox.AutoSize = true; + this.AutoUpdateCheckbox.Font = new System.Drawing.Font("Verdana", 12F); + this.AutoUpdateCheckbox.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(248)))), ((int)(((byte)(248)))), ((int)(((byte)(242))))); + this.AutoUpdateCheckbox.Location = new System.Drawing.Point(228, 134); + this.AutoUpdateCheckbox.Name = "AutoUpdateCheckbox"; + this.AutoUpdateCheckbox.Size = new System.Drawing.Size(131, 22); + this.AutoUpdateCheckbox.TabIndex = 45; + this.AutoUpdateCheckbox.Text = "Auto-Update"; + this.AutoUpdateCheckbox.UseVisualStyleBackColor = true; + this.AutoUpdateCheckbox.Visible = false; + this.AutoUpdateCheckbox.CheckedChanged += new System.EventHandler(this.AutoUpdateCheckbox_CheckedChanged); + // // ServerPageRefreshButton // this.ServerPageRefreshButton.Anchor = System.Windows.Forms.AnchorStyles.Top; @@ -713,7 +774,7 @@ // WorldAnnounceButton // this.WorldAnnounceButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.WorldAnnounceButton.Location = new System.Drawing.Point(785, 136); + this.WorldAnnounceButton.Location = new System.Drawing.Point(785, 133); this.WorldAnnounceButton.Name = "WorldAnnounceButton"; this.WorldAnnounceButton.Size = new System.Drawing.Size(77, 20); this.WorldAnnounceButton.TabIndex = 41; @@ -724,7 +785,7 @@ // WorldAnnounceField // this.WorldAnnounceField.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.WorldAnnounceField.Location = new System.Drawing.Point(566, 136); + this.WorldAnnounceField.Location = new System.Drawing.Point(566, 134); this.WorldAnnounceField.Name = "WorldAnnounceField"; this.WorldAnnounceField.Size = new System.Drawing.Size(213, 20); this.WorldAnnounceField.TabIndex = 40; @@ -751,7 +812,7 @@ this.WorldAnnounceLabel.AutoSize = true; this.WorldAnnounceLabel.Font = new System.Drawing.Font("Verdana", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.WorldAnnounceLabel.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(248)))), ((int)(((byte)(248)))), ((int)(((byte)(242))))); - this.WorldAnnounceLabel.Location = new System.Drawing.Point(466, 139); + this.WorldAnnounceLabel.Location = new System.Drawing.Point(466, 135); this.WorldAnnounceLabel.Name = "WorldAnnounceLabel"; this.WorldAnnounceLabel.Size = new System.Drawing.Size(94, 18); this.WorldAnnounceLabel.TabIndex = 39; @@ -766,7 +827,7 @@ "Trusted", "Safe", "Ultrasafe"}); - this.SecuritySelector.Location = new System.Drawing.Point(136, 136); + this.SecuritySelector.Location = new System.Drawing.Point(101, 134); this.SecuritySelector.Name = "SecuritySelector"; this.SecuritySelector.Size = new System.Drawing.Size(121, 21); this.SecuritySelector.TabIndex = 38; @@ -777,7 +838,7 @@ this.SecurityTitle.AutoSize = true; this.SecurityTitle.Font = new System.Drawing.Font("Verdana", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.SecurityTitle.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(248)))), ((int)(((byte)(248)))), ((int)(((byte)(242))))); - this.SecurityTitle.Location = new System.Drawing.Point(44, 139); + this.SecurityTitle.Location = new System.Drawing.Point(15, 139); this.SecurityTitle.Name = "SecurityTitle"; this.SecurityTitle.Size = new System.Drawing.Size(80, 18); this.SecurityTitle.TabIndex = 37; @@ -1758,6 +1819,7 @@ this.panel1.PerformLayout(); this.ServerPanel.ResumeLayout(false); this.ServerPanel.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.AutoUpdateInterval)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.PortSelector)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.ServerTestmergeInput)).EndInit(); this.BYONDPanel.ResumeLayout(false); @@ -1901,5 +1963,8 @@ private System.Windows.Forms.Button BYONDRefreshButton; private System.Windows.Forms.Button ServerPageRefreshButton; private System.Windows.Forms.Button RecreateStaticButton; + private System.Windows.Forms.NumericUpDown AutoUpdateInterval; + private System.Windows.Forms.CheckBox AutoUpdateCheckbox; + private System.Windows.Forms.Label AutoUpdateMLabel; } } diff --git a/TGControlPanel/Main.cs b/TGControlPanel/Main.cs index 584e8b1f75..969e926771 100644 --- a/TGControlPanel/Main.cs +++ b/TGControlPanel/Main.cs @@ -35,6 +35,9 @@ namespace TGControlPanel { switch (Panels.SelectedIndex) { + case 0: //repo + PopulateRepoFields(); + break; case 1: //byond UpdateBYONDButtons(); break; diff --git a/TGControlPanel/ServerPage.cs b/TGControlPanel/ServerPage.cs index 69b868a547..0f001d3abc 100644 --- a/TGControlPanel/ServerPage.cs +++ b/TGControlPanel/ServerPage.cs @@ -107,6 +107,7 @@ namespace TGControlPanel { var RepoExists = Server.GetComponent().Exists(); compileButton.Visible = RepoExists; + AutoUpdateCheckbox.Visible = RepoExists; initializeButton.Visible = RepoExists; AutostartCheckbox.Visible = RepoExists; WebclientCheckBox.Visible = RepoExists; @@ -133,12 +134,13 @@ namespace TGControlPanel WorldAnnounceButton.Visible = RepoExists; WorldAnnounceLabel.Visible = RepoExists; + if (updatingFields) + return; + var DM = Server.GetComponent(); var DD = Server.GetComponent(); var Config = Server.GetComponent(); - - if (updatingFields) - return; + var Repo = Server.GetComponent(); try { @@ -152,6 +154,14 @@ namespace TGControlPanel if (!RepoExists) return; + var interval = Repo.AutoUpdateInterval(); + var interval_not_zero = interval != 0; + AutoUpdateCheckbox.Checked = interval_not_zero; + AutoUpdateInterval.Visible = interval_not_zero; + AutoUpdateMLabel.Visible = interval_not_zero; + if (interval_not_zero) + AutoUpdateInterval.Value = interval; + var DaeStat = DD.DaemonStatus(); var Online = DaeStat == TGDreamDaemonStatus.Online; ServerStartButton.Enabled = !Online; @@ -473,5 +483,24 @@ namespace TGControlPanel if (!updatingFields) Server.GetComponent().SetWebclient(WebclientCheckBox.Checked); } + + private void AutoUpdateInterval_ValueChanged(object sender, EventArgs e) + { + if (!updatingFields) + Server.GetComponent().SetAutoUpdateInterval((ulong)AutoUpdateInterval.Value); + } + + private void AutoUpdateCheckbox_CheckedChanged(object sender, EventArgs e) + { + if (updatingFields) + return; + var on = AutoUpdateCheckbox.Visible && AutoUpdateCheckbox.Checked; + AutoUpdateInterval.Visible = on; + AutoUpdateMLabel.Visible = on; + if (!on) + Server.GetComponent().SetAutoUpdateInterval(0); + else + Server.GetComponent().SetAutoUpdateInterval((ulong)AutoUpdateInterval.Value); + } } } diff --git a/TGInstallerWrapper/FodyWeavers.xml b/TGInstallerWrapper/FodyWeavers.xml new file mode 100644 index 0000000000..c6e1b7c8af --- /dev/null +++ b/TGInstallerWrapper/FodyWeavers.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/TGInstallerWrapper/Main.Designer.cs b/TGInstallerWrapper/Main.Designer.cs index 42842a7c05..88b82a06a3 100644 --- a/TGInstallerWrapper/Main.Designer.cs +++ b/TGInstallerWrapper/Main.Designer.cs @@ -1,4 +1,8 @@ -namespace TGInstallerWrapper +using System; +using System.Diagnostics; +using System.Reflection; + +namespace TGInstallerWrapper { partial class Main { @@ -127,7 +131,7 @@ this.VersionLabel.Name = "VersionLabel"; this.VersionLabel.Size = new System.Drawing.Size(228, 18); this.VersionLabel.TabIndex = 8; - this.VersionLabel.Text = "None (No Service Running)"; + this.VersionLabel.Text = "Unknown (No service running)"; // // InstallButton // @@ -160,7 +164,7 @@ this.TargetVersionLabel.Name = "TargetVersionLabel"; this.TargetVersionLabel.Size = new System.Drawing.Size(132, 18); this.TargetVersionLabel.TabIndex = 11; - this.TargetVersionLabel.Text = "Target Version:"; + this.TargetVersionLabel.Text = "Target Version: v" + FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location).FileVersion; // // InstallCancelButton // @@ -179,6 +183,7 @@ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(39)))), ((int)(((byte)(40)))), ((int)(((byte)(34))))); this.ClientSize = new System.Drawing.Size(537, 153); + this.FormClosing += Main_FormClosing; this.Controls.Add(this.InstallCancelButton); this.Controls.Add(this.TargetVersionLabel); this.Controls.Add(this.ShowLogCheckbox); diff --git a/TGInstallerWrapper/Main.cs b/TGInstallerWrapper/Main.cs index 43045bb0cc..e8fbd719d2 100644 --- a/TGInstallerWrapper/Main.cs +++ b/TGInstallerWrapper/Main.cs @@ -3,36 +3,122 @@ using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; -using System.Linq; +using System.Reflection; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; -using TGServiceInterface; namespace TGInstallerWrapper { public partial class Main : Form { - const string InstallDir = "TG Station Server"; //keep this in sync with the msi installer + const string DefaultInstallDir = "TG Station Server"; //keep this in sync with the msi installer + + //reflection shit, make sure it matches + const string InterfaceDLL = "TGServiceInterface.dll"; + const string InterfaceNamespace = "TGServiceInterface"; + const string InterfaceClass = InterfaceNamespace + ".Server"; + const string InterfaceServiceInterface = InterfaceNamespace + ".ITGSService"; //fuck this typo + const string InterfaceClassVerifyConnection = "VerifyConnection"; + const string InterfaceClassGetComponent = "GetComponent"; + const string InterfaceServiceInterfaceVersion = "Version"; + const string InterfaceServiceInterfacePrepareForUpdate = "PrepareForUpdate"; + + Assembly InterfaceAssembly; + Type Server, ITGSService; + MethodInfo VerifyConnection, GetComponentITGSService, Version, PrepareForUpdate; + + string tempDir; bool installing = false; bool cancelled = false; bool pathIsDefault = true; + public Main() { InitializeComponent(); - FormClosing += Main_FormClosing; - PathTextBox.Text = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86) + Path.DirectorySeparatorChar + InstallDir; - var verifiedConnection = Server.VerifyConnection() == null; + SetupTempDir(); + LoadInterfaceFromReflection(); + CheckForExistingVersion(); + PathTextBox.Text = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), DefaultInstallDir); + } + + void SetupTempDir() + { + tempDir = Path.Combine(Path.GetTempPath(), "TGS3InstallerTempDir"); try { - VersionLabel.Text = Server.GetComponent().Version(); + if (File.Exists(tempDir)) + File.Delete(tempDir); + else if (Directory.Exists(tempDir)) + Directory.Delete(tempDir); + } + catch { } + if (File.Exists(tempDir) || Directory.Exists(tempDir)) + { + tempDir = Path.GetTempFileName(); + File.Delete(tempDir); //we want a dir not a file + } + Directory.CreateDirectory(tempDir); + } + + void LoadInterfaceFromReflection() + { + //so this is where we expect to find the interface dll + try + { + var tmppath = Path.Combine(tempDir, InterfaceDLL); + File.WriteAllBytes(tmppath, Properties.Resources.TGServiceInterface); + InterfaceAssembly = Assembly.LoadFrom(tmppath); //we can't link to it, or load the bytes directly because the thing will complain about mixing the DLLExport code and IL code + Server = InterfaceAssembly.GetType(InterfaceClass); + ITGSService = InterfaceAssembly.GetType(InterfaceServiceInterface); + VerifyConnection = Server.GetMethod(InterfaceClassVerifyConnection); + GetComponentITGSService = Server.GetMethod(InterfaceClassGetComponent).MakeGenericMethod(ITGSService); + Version = ITGSService.GetMethod(InterfaceServiceInterfaceVersion); + PrepareForUpdate = ITGSService.GetMethod(InterfaceServiceInterfacePrepareForUpdate); } catch { - if(verifiedConnection) + InterfaceAssembly = null; + VersionLabel.Text = "Error: (Could not load interface dll)"; + return; + } + } + + void CheckForExistingVersion() { + if (InterfaceAssembly == null) + return; + var verifiedConnection = VerifyConnection.Invoke(null, null) == null; + try + { + VersionLabel.Text = (string)Version.Invoke(GetComponentITGSService.Invoke(null, null), null); + } + catch + { + if (verifiedConnection) VersionLabel.Text = "< v3.0.85.0 (Missing ITGService.Version())"; } - TargetVersionLabel.Text += " v" + FileVersionInfo.GetVersionInfo(System.Reflection.Assembly.GetExecutingAssembly().Location).FileVersion; + } + + bool ConfirmDangerousUpgrade() + { + return MessageBox.Show("Unable connect to service! Existing DreamDaemon instances will be terminated. Continue?", "Warning", MessageBoxButtons.YesNo) == DialogResult.Yes; + } + + bool TellServiceWereComingForThem() + { + if (InterfaceAssembly == null) + return ConfirmDangerousUpgrade(); + var connectionVerified = VerifyConnection.Invoke(null, null) == null; + try + { + PrepareForUpdate.Invoke(GetComponentITGSService.Invoke(null, null), null); + Thread.Sleep(3000); //chat messages + return true; + } + catch + { + return ConfirmDangerousUpgrade(); + } } private void Main_FormClosing(object sender, FormClosingEventArgs e) @@ -71,7 +157,6 @@ namespace TGInstallerWrapper async void DoInstall() { - string path = null; string logfile = null; try { @@ -90,6 +175,9 @@ namespace TGInstallerWrapper break; } + if (!TellServiceWereComingForThem()) + return; + var args = new List(); if (!pathIsDefault) args.Add(String.Format("INSTALLFOLDER=\"{0}\"", PathTextBox.Text)); @@ -108,32 +196,16 @@ namespace TGInstallerWrapper ShowLogCheckbox.Enabled = false; InstallButton.Text = "Installing..."; - path = Path.GetTempFileName(); - File.Delete(path); //we want a dir not a file - Directory.CreateDirectory(path); - var msipath = path + Path.DirectorySeparatorChar + "TGServiceInstaller.msi"; + var msipath = Path.Combine(tempDir, "TGServiceInstaller.msi"); File.WriteAllBytes(msipath, Properties.Resources.TGServiceInstaller); - File.WriteAllBytes(path + Path.DirectorySeparatorChar + "cab1.cab", Properties.Resources.cab1); + File.WriteAllBytes(Path.Combine(tempDir, "cab1.cab"), Properties.Resources.cab1); ProgressBar.Style = ProgressBarStyle.Marquee; - - var connectionVerified = Server.VerifyConnection() == null; - try - { - Server.GetComponent().PrepareForUpdate(); - Thread.Sleep(3000); //chat messages - } - catch - { - if (connectionVerified && MessageBox.Show("ITGSService.PrepareForUpdate() threw an exception! Existing DreamDaemon instances will be terminated. Continue?", "Warning", MessageBoxButtons.YesNo) != DialogResult.Yes) - return; - } - InstallCancelButton.Enabled = true; if (ShowLogCheckbox.Checked) { - logfile = path + Path.DirectorySeparatorChar + "tgsinstall.log"; + logfile = Path.Combine(tempDir, "tgsinstall.log"); Installer.EnableLog(InstallLogModes.Verbose | InstallLogModes.PropertyDump, logfile); } var cl = String.Join(" ", args); @@ -172,12 +244,6 @@ namespace TGInstallerWrapper Process.Start(logfile).WaitForInputIdle(); } catch { } - if (path != null) - try - { - Directory.Delete(path, true); - } - catch { } } MessageBox.Show("Success!"); Application.Exit(); @@ -208,7 +274,7 @@ namespace TGInstallerWrapper if (fbd.ShowDialog() != DialogResult.OK) return; pathIsDefault = false; - PathTextBox.Text = fbd.SelectedPath + Path.DirectorySeparatorChar + InstallDir; + PathTextBox.Text = fbd.SelectedPath + Path.DirectorySeparatorChar + DefaultInstallDir; } private void CancelButton_Click(object sender, EventArgs e) diff --git a/TGInstallerWrapper/Program.cs b/TGInstallerWrapper/Program.cs index c9669327d9..96dc421f86 100644 --- a/TGInstallerWrapper/Program.cs +++ b/TGInstallerWrapper/Program.cs @@ -1,7 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; using System.Windows.Forms; namespace TGInstallerWrapper diff --git a/TGInstallerWrapper/Properties/Resources.Designer.cs b/TGInstallerWrapper/Properties/Resources.Designer.cs index 9365443396..e3858daec9 100644 --- a/TGInstallerWrapper/Properties/Resources.Designer.cs +++ b/TGInstallerWrapper/Properties/Resources.Designer.cs @@ -19,7 +19,7 @@ namespace TGInstallerWrapper.Properties { // class via a tool like ResGen or Visual Studio. // To add or remove a member, edit your .ResX file then rerun ResGen // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] internal class Resources { @@ -79,5 +79,15 @@ namespace TGInstallerWrapper.Properties { return ((byte[])(obj)); } } + + /// + /// Looks up a localized resource of type System.Byte[]. + /// + internal static byte[] TGServiceInterface { + get { + object obj = ResourceManager.GetObject("TGServiceInterface", resourceCulture); + return ((byte[])(obj)); + } + } } } diff --git a/TGInstallerWrapper/Properties/Resources.resx b/TGInstallerWrapper/Properties/Resources.resx index b29efcb08f..daa2b3cb0c 100644 --- a/TGInstallerWrapper/Properties/Resources.resx +++ b/TGInstallerWrapper/Properties/Resources.resx @@ -122,6 +122,9 @@ ..\..\TGServiceInstaller\bin\Release\cab1.cab;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - ...\..\TGServiceInstaller\bin\Release\TGServiceInstaller.msi;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + ..\..\TGServiceInstaller\bin\Release\TGServiceInstaller.msi;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + ..\..\TGServiceInterface\bin\x86\Release\TGServiceInterface.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 \ No newline at end of file diff --git a/TGInstallerWrapper/TGInstallerWrapper.csproj b/TGInstallerWrapper/TGInstallerWrapper.csproj index e94ed50a6c..7e1bf4045e 100644 --- a/TGInstallerWrapper/TGInstallerWrapper.csproj +++ b/TGInstallerWrapper/TGInstallerWrapper.csproj @@ -11,6 +11,8 @@ v4.5.2 512 true + + AnyCPU @@ -38,6 +40,10 @@ tgs.ico + + ..\packages\Costura.Fody.1.6.2\lib\dotnet\Costura.dll + False + @@ -70,15 +76,21 @@ + - - {ac4e7e8b-f83a-481c-a8b0-8fa4e8ae59ab} - TGServiceInterface - - - + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + \ No newline at end of file diff --git a/TGInstallerWrapper/packages.config b/TGInstallerWrapper/packages.config new file mode 100644 index 0000000000..b4d46b584a --- /dev/null +++ b/TGInstallerWrapper/packages.config @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/TGS3Release.ps1 b/TGS3Release.ps1 index 0749e410db..ea5884c247 100644 --- a/TGS3Release.ps1 +++ b/TGS3Release.ps1 @@ -2,19 +2,12 @@ $bf = $Env:APPVEYOR_BUILD_FOLDER $src = "$bf\TGInstallerWrapper\bin\Release" $version = [System.Diagnostics.FileVersionInfo]::GetVersionInfo("$src\TG Station Server Installer.exe").FileVersion -Remove-Item "$src\Microsoft.Deployment.WindowsInstaller.xml" -Remove-Item "$src\TG Station Server Installer.exe.config" -Remove-Item "$src\TG Station Server Installer.pdb" -Rename-Item -Path "$src\TG Station Server Installer.exe" -NewName "$src\TG Station Server Installer v$version.exe" +$destination = "$bf\TGS3-Server-v$version.exe" -$destination = "$bf\TGS3-Server-v$version.zip" - -If(Test-path $destination) {Remove-item $destination} +Move-Item -Path "$src\TG Station Server Installer.exe" -Destination "$destination" Add-Type -assembly "system.io.compression.filesystem" -[io.compression.zipfile]::CreateFromDirectory($src, $destination) - $destination_md5sha = $Env:APPVEYOR_BUILD_FOLDER + "\MD5-SHA1-Server-v$version.txt" $src2 = $Env:APPVEYOR_BUILD_FOLDER + "\ClientApps" diff --git a/TGServerService/App.config b/TGServerService/App.config index b0894c51a4..f17feaf7ae 100644 --- a/TGServerService/App.config +++ b/TGServerService/App.config @@ -56,7 +56,7 @@ 0 - 4 + 5 @@ -73,6 +73,9 @@ + + 0 + False diff --git a/TGServerService/ChatCommands.cs b/TGServerService/ChatCommands.cs index a3ecf0d5cd..0f6db947b7 100644 --- a/TGServerService/ChatCommands.cs +++ b/TGServerService/ChatCommands.cs @@ -82,8 +82,13 @@ namespace TGServerService } protected override ExitCode Run(IList parameters) { - OutputProc(String.Format("^{0}", Instance.GetHead(true, out string error)) ?? error); - return error == null ? ExitCode.Normal : ExitCode.ServerError; + var res = Instance.LiveSha(); + if (res == "UNKNOWN") { + OutputProc(res); + return ExitCode.ServerError; + } + OutputProc(String.Format("^{0}", res)); + return ExitCode.Normal; } public override string GetHelpText() diff --git a/TGServerService/Compiler.cs b/TGServerService/Compiler.cs index 1ec5dbd916..71c78187c4 100644 --- a/TGServerService/Compiler.cs +++ b/TGServerService/Compiler.cs @@ -337,6 +337,7 @@ namespace TGServerService return; } } + string CurrentSha; try { bool silent; @@ -378,6 +379,7 @@ namespace TGServerService deleteExcludeList.Add(".git"); Program.CopyDirectory(RepoPath, resurrectee, deleteExcludeList); + CurrentSha = GetHead(false, out string error); //just the tip const string GitLogsDir = "/.git/logs"; Program.CopyDirectory(RepoPath + GitLogsDir, resurrectee + GitLogsDir); @@ -524,6 +526,7 @@ namespace TGServerService TGServerService.WriteWarning("Postcompile hook failed!", TGServerService.EventID.DMCompileError); return; } + UpdateLiveSha(CurrentSha); var msg = String.Format("Compile complete!{0}", !staged ? "" : " Server will update next round."); SendMessage("DM: " + msg, ChatMessageType.DeveloperInfo); TGServerService.WriteInfo(msg, TGServerService.EventID.DMCompileSuccess); diff --git a/TGServerService/DreamDaemon.cs b/TGServerService/DreamDaemon.cs index 0d822de64e..d7d5226721 100644 --- a/TGServerService/DreamDaemon.cs +++ b/TGServerService/DreamDaemon.cs @@ -3,6 +3,7 @@ using System.Diagnostics; using System.IO; using System.Reflection; using System.Threading; +using System.Timers; using TGServiceInterface; namespace TGServerService @@ -18,14 +19,18 @@ namespace TGServerService Pinged, } + const string DiagnosticsDir = "Diagnostics"; + const string ResourceDiagnosticsDir = DiagnosticsDir + "/Resources"; const int DDHangStartTime = 60; const int DDBadStartTime = 10; Process Proc; + PerformanceCounter pcpu; object watchdogLock = new object(); Thread DDWatchdog; TGDreamDaemonStatus currentStatus; + string CurrentDDLog; ushort currentPort = 0; object restartLock = new object(); @@ -38,6 +43,8 @@ namespace TGServerService //Only need 1 proc instance void InitDreamDaemon() { + Directory.CreateDirectory(DiagnosticsDir); + Directory.CreateDirectory(ResourceDiagnosticsDir); var Reattach = Properties.Settings.Default.ReattachToDD; if (Reattach) try @@ -94,6 +101,7 @@ namespace TGServerService void DisposeDreamDaemon() { var Detach = Properties.Settings.Default.ReattachToDD; + bool RenameLog = false; if (DaemonStatus() == TGDreamDaemonStatus.Online) { if (!Detach) @@ -102,13 +110,23 @@ namespace TGServerService Thread.Sleep(1000); } else + { + RenameLog = CurrentDDLog != null; SendMessage("DD: Detaching watch dog for update!", ChatMessageType.WatchdogInfo); + WriteCurrentDDLog("Service updating! Splitting diagnostics..."); + } } else if (Detach) - { Properties.Settings.Default.ReattachToDD = false; - } Stop(); + if(pcpu != null) + pcpu.Dispose(); + if (RenameLog) + try + { + File.Move(Path.Combine(ResourceDiagnosticsDir, CurrentDDLog), Path.Combine(ResourceDiagnosticsDir, "SU-" + CurrentDDLog)); + } + catch { } } //public api @@ -189,20 +207,30 @@ namespace TGServerService { if (DaemonStatus() == TGDreamDaemonStatus.Offline) return Start(); - if (!Monitor.TryEnter(restartLock)) - return "Restart already in progress"; - try + lock(restartLock) { - SendMessage("DD: Hard restart triggered", ChatMessageType.WatchdogInfo); + if (RestartInProgress) + return "Restart already in progress"; RestartInProgress = true; - Stop(); - var res = Start(); - return res; } - finally + SendMessage("DD: Hard restart triggered", ChatMessageType.WatchdogInfo); + Stop(); + var res = Start(); + if(res != null) + lock(restartLock) + { + RestartInProgress = false; + } + return res; + } + + void WriteCurrentDDLog(string message) + { + lock (watchdogLock) { - RestartInProgress = false; - Monitor.Exit(restartLock); + if (currentStatus != TGDreamDaemonStatus.Online || CurrentDDLog == null) + return; + File.AppendAllText(Path.Combine(ResourceDiagnosticsDir, CurrentDDLog), String.Format("[{0}]: {1}\n", DateTime.Now.ToLongTimeString(), message)); } } @@ -225,6 +253,13 @@ namespace TGServerService } } var retries = 0; + + var MemTrackTimer = new System.Timers.Timer + { + AutoReset = true, + Interval = 5000 //every 5 seconds + }; + MemTrackTimer.Elapsed += MemTrackTimer_Elapsed; while (true) { var starttime = DateTime.Now; @@ -235,8 +270,23 @@ namespace TGServerService SendCommand(SCGracefulShutdown); } + //all good to go, let's start monitoring + var Now = DateTime.Now; + lock (watchdogLock) + { + CurrentDDLog = String.Format("{0} {1} Diagnostics.txt", Now.ToLongDateString(), Now.ToLongTimeString()).Replace(':', '-'); + WriteCurrentDDLog("Starting monitoring..."); + pcpu = new PerformanceCounter("Process", "% Processor Time", Proc.ProcessName, true); + } + MemTrackTimer.Start(); Proc.WaitForExit(); + lock (watchdogLock) //synchronize + { + MemTrackTimer.Stop(); + pcpu.Dispose(); + } + bool BadStart; lock (watchdogLock) { currentStatus = TGDreamDaemonStatus.HardRebooting; @@ -245,8 +295,8 @@ namespace TGServerService if (AwaitingShutdown == ShutdownRequestPhase.Pinged) return; - - if ((DateTime.Now - starttime).TotalSeconds < DDBadStartTime) + BadStart = (DateTime.Now - starttime).TotalSeconds < DDBadStartTime; + if (BadStart) { ++retries; var sleep_time = (int)Math.Min(Math.Pow(2, retries), 3600); //max of one hour @@ -261,6 +311,8 @@ namespace TGServerService TGServerService.WriteWarning(msg, TGServerService.EventID.DDWatchdogRebootingServer); } } + if (BadStart) + WriteCurrentDDLog("Crash detected!"); var res = StartImpl(true); if (res != null) @@ -313,6 +365,20 @@ namespace TGServerService } } + private void MemTrackTimer_Elapsed(object sender, ElapsedEventArgs e) + { + ulong megamem; + float cputime; + lock (watchdogLock) + { + cputime = pcpu.NextValue(); + using (var pcm = new PerformanceCounter("Process", "Working Set - Private", Proc.ProcessName, true)) + megamem = Convert.ToUInt64(pcm.NextValue()) / 1024; + } + var PercentCpuTime = (int)Math.Round((Decimal)cputime); + WriteCurrentDDLog(String.Format("CPU: {1}% Memory: {0}MB", megamem, PercentCpuTime.ToString("D3"))); + } + //public api public string CanStart() { @@ -396,7 +462,7 @@ namespace TGServerService GenCommsKey(); StartingSecurity = (TGDreamDaemonSecurity)Config.ServerSecurity; - Proc.StartInfo.Arguments = String.Format("{0} -port {1} {5}-close -verbose -params \"server_service={3}&server_service_version={4}\" -{2} -public", DMB, Config.ServerPort, SecurityWord(), serviceCommsKey, Version(), Config.Webclient ? "-webclient" : ""); + Proc.StartInfo.Arguments = String.Format("{0} -port {1} {5}-close -verbose -params \"server_service={3}&server_service_version={4}\" -{2} -public", DMB, Config.ServerPort, SecurityWord(), serviceCommsKey, Version(), Config.Webclient ? "-webclient " : ""); UpdateInterfaceDll(true); lock (topicLock) { diff --git a/TGServerService/IRC.cs b/TGServerService/IRC.cs index 7194be267c..a04dfc2d36 100644 --- a/TGServerService/IRC.cs +++ b/TGServerService/IRC.cs @@ -88,6 +88,8 @@ namespace TGServerService { if (IRCConfig.AdminsAreSpecial) { + if (e.Channel == null) + return false; var user = (NonRfcChannelUser)irc.GetChannelUser(e.Channel, e.Nick); if (user != null) switch (IRCConfig.AuthLevel) diff --git a/TGServerService/Interop.cs b/TGServerService/Interop.cs index 5c8040162c..42ea994f50 100644 --- a/TGServerService/Interop.cs +++ b/TGServerService/Interop.cs @@ -89,6 +89,7 @@ namespace TGServerService break; case SRWorldReboot: TGServerService.WriteInfo("World Rebooted", TGServerService.EventID.WorldReboot); + WriteCurrentDDLog("World rebooted"); ServerChatCommands = null; ChatConnectivityCheck(); lock (CompilerLock) diff --git a/TGServerService/Program.cs b/TGServerService/Program.cs index d4822ea533..ef6ab4bfc1 100644 --- a/TGServerService/Program.cs +++ b/TGServerService/Program.cs @@ -57,6 +57,7 @@ namespace TGServerService if (excludeRoot != null && excludeRoot.Contains(file.Name.ToLower())) continue; file.Attributes = FileAttributes.Normal; + file.Delete(); } } diff --git a/TGServerService/Properties/Settings.Designer.cs b/TGServerService/Properties/Settings.Designer.cs index 630f47980d..2ff095f958 100644 --- a/TGServerService/Properties/Settings.Designer.cs +++ b/TGServerService/Properties/Settings.Designer.cs @@ -205,7 +205,7 @@ namespace TGServerService.Properties { [global::System.Configuration.UserScopedSettingAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("4")] + [global::System.Configuration.DefaultSettingValueAttribute("5")] public int SettingsVersion { get { return ((int)(this["SettingsVersion"])); @@ -275,6 +275,18 @@ namespace TGServerService.Properties { } } + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("0")] + public ulong AutoUpdateInterval { + get { + return ((ulong)(this["AutoUpdateInterval"])); + } + set { + this["AutoUpdateInterval"] = value; + } + } + [global::System.Configuration.UserScopedSettingAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Configuration.DefaultSettingValueAttribute("False")] diff --git a/TGServerService/Properties/Settings.settings b/TGServerService/Properties/Settings.settings index c8afebdedd..6cae9c7ba7 100644 --- a/TGServerService/Properties/Settings.settings +++ b/TGServerService/Properties/Settings.settings @@ -48,7 +48,7 @@ 0 - 4 + 5 @@ -65,6 +65,9 @@ + + 0 + False diff --git a/TGServerService/Repository.cs b/TGServerService/Repository.cs index 68dfba3809..4ca73f7fcb 100644 --- a/TGServerService/Repository.cs +++ b/TGServerService/Repository.cs @@ -19,9 +19,11 @@ namespace TGServerService const string CachedTGS3SettingsPath = "TGS3.json"; const string RepoErrorUpToDate = "Already up to date!"; const string SSHPushRemote = "ssh_push_target"; - const string PrivateKeyPath = "RepoKey/private_key.txt"; - const string PublicKeyPath = "RepoKey/public_key.txt"; + const string RepoKeyDir = "RepoKey/"; + const string PrivateKeyPath = RepoKeyDir + "private_key.txt"; + const string PublicKeyPath = RepoKeyDir + "public_key.txt"; const string PRJobFile = "prtestjob.json"; + const string LiveTrackingBranch = "___TGSLiveCommitTrackingBranch"; const string CommitMessage = "Automatic changelog compile, [ci skip]"; object RepoLock = new object(); @@ -31,6 +33,11 @@ namespace TGServerService Repository Repo; int currentProgress = -1; + System.Timers.Timer autoUpdateTimer = new System.Timers.Timer() + { + AutoReset = true + }; + /// /// Repo specific information about the installation /// Requires RepoLock and !RepoBusy to be instantiated @@ -41,7 +48,7 @@ namespace TGServerService public readonly string PathToChangelogPy; public readonly string ChangelogPyArguments; public readonly IList PipDependancies = new List(); - public readonly IList ChangelogPathsToStage = new List(); + public readonly IList PathsToStage = new List(); public readonly IList StaticDirectoryPaths = new List(); public readonly IList DLLPaths = new List(); @@ -64,16 +71,16 @@ namespace TGServerService PipDependancies = LoadArray(details["pip_dependancies"]); } catch { } - try - { - ChangelogPathsToStage = LoadArray(details["synchronize_paths"]); - } - catch { } } catch { ChangelogSupport = false; } try + { + PathsToStage = LoadArray(json["synchronize_paths"]); + } + catch { } + try { StaticDirectoryPaths = LoadArray(json["static_directories"]); } @@ -109,7 +116,7 @@ namespace TGServerService && PathToChangelogPy == other.PathToChangelogPy && ChangelogPyArguments == other.ChangelogPyArguments && ListEquals(PipDependancies, other.PipDependancies) - && ListEquals(ChangelogPathsToStage, other.ChangelogPathsToStage) + && ListEquals(PathsToStage, other.PathsToStage) && ListEquals(StaticDirectoryPaths, other.StaticDirectoryPaths) && ListEquals(DLLPaths, other.DLLPaths); } @@ -121,7 +128,7 @@ namespace TGServerService hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(PathToChangelogPy); hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(ChangelogPyArguments); hashCode = hashCode * -1521134295 + EqualityComparer>.Default.GetHashCode(PipDependancies); - hashCode = hashCode * -1521134295 + EqualityComparer>.Default.GetHashCode(ChangelogPathsToStage); + hashCode = hashCode * -1521134295 + EqualityComparer>.Default.GetHashCode(PathsToStage); hashCode = hashCode * -1521134295 + EqualityComparer>.Default.GetHashCode(StaticDirectoryPaths); hashCode = hashCode * -1521134295 + EqualityComparer>.Default.GetHashCode(DLLPaths); return hashCode; @@ -140,10 +147,14 @@ namespace TGServerService void InitRepo() { + Directory.CreateDirectory(RepoKeyDir); if(Exists()) UpdateInterfaceDll(false); if(LoadRepo() == null) DisableGarbageCollectionNoLock(); + //start the autoupdate timer + autoUpdateTimer.Elapsed += AutoUpdateTimer_Elapsed; + SetAutoUpdateInterval(Properties.Settings.Default.AutoUpdateInterval); } bool RepoConfigsMatch() @@ -491,6 +502,8 @@ namespace TGServerService //public api public string Checkout(string sha) { + if (sha == LiveTrackingBranch) + return "I'm sorry Dave, I'm afraid I can't do that..."; lock (RepoLock) { var result = LoadRepo(); @@ -583,13 +596,17 @@ namespace TGServerService //public api public string Update(bool reset) + { + return UpdateImpl(reset, true); + } + + string UpdateImpl(bool reset, bool successOnUpToDate) { lock (RepoLock) { var result = LoadRepo(); if (result != null) return result; - SendMessage(String.Format("REPO: Updating origin branch...({0})", reset ? "Hard Reset" : "Merge"), ChatMessageType.DeveloperInfo); try { if (Repo.Head == null || !Repo.Head.IsTracking) @@ -600,6 +617,11 @@ namespace TGServerService return res; var originBranch = Repo.Head.TrackedBranch; + if (!successOnUpToDate && Repo.Head.Tip.Sha == originBranch.Tip.Sha) + return RepoErrorUpToDate; + + SendMessage(String.Format("REPO: Updating origin branch...({0})", reset ? "Hard Reset" : "Merge"), ChatMessageType.DeveloperInfo); + if (reset) { var error = ResetNoLock(Repo.Head.TrackedBranch); @@ -1016,7 +1038,7 @@ namespace TGServerService try { // Stage the file - foreach(var I in Config.ChangelogPathsToStage) + foreach(var I in Config.PathsToStage) Commands.Stage(Repo, I); if (Repo.RetrieveStatus().Staged.Count() == 0) //nothing to commit @@ -1205,6 +1227,33 @@ namespace TGServerService } } + /// + public void SetAutoUpdateInterval(ulong newInterval) + { + lock (autoUpdateTimer) + { + autoUpdateTimer.Stop(); + if (newInterval > 0) { + autoUpdateTimer.Interval = newInterval * 60 * 1000; //convert from minutes to ms + autoUpdateTimer.Start(); + } + } + Properties.Settings.Default.AutoUpdateInterval = newInterval; + } + + public ulong AutoUpdateInterval() + { + return Properties.Settings.Default.AutoUpdateInterval; + } + + private void AutoUpdateTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) + { + if (UpdateImpl(true, false) == null) + { + Compile(true); + } + } + //public api public bool SetPythonPath(string path) { @@ -1219,6 +1268,22 @@ namespace TGServerService return Properties.Settings.Default.PythonPath; } + void UpdateLiveSha(string newSha) + { + if (LoadRepo() != null) + return; + var B = Repo.Branches[LiveTrackingBranch]; + if (B != null) + Repo.Branches.Remove(B); + Repo.CreateBranch(LiveTrackingBranch, newSha); + } + + public string LiveSha() + { + var B = Repo.Branches[LiveTrackingBranch]; + return B != null ? B.Tip.Sha : "UNKNOWN"; + } + /// public bool PushTestmergeCommits() { diff --git a/TGServiceInterface/Repository.cs b/TGServiceInterface/Repository.cs index bb0f1afff1..2821e4bae5 100644 --- a/TGServiceInterface/Repository.cs +++ b/TGServiceInterface/Repository.cs @@ -226,6 +226,20 @@ namespace TGServiceInterface [OperationContract] string UpdateTGS3Json(); + /// + /// (De)Activate and set the interval for the automatic server updater + /// + /// Interval to check for updates in minutes, disables if zero + [OperationContract] + void SetAutoUpdateInterval(ulong newInterval); + + /// + /// Get the current autoupdate interval + /// + /// The current auto update interval or zero if it's disabled + [OperationContract] + ulong AutoUpdateInterval(); + /// /// Check if we push a temporary branch to the remote when we make testmerge commits /// diff --git a/Version.cs b/Version.cs index 29d52bda09..966f876961 100644 --- a/Version.cs +++ b/Version.cs @@ -12,6 +12,6 @@ using System.Reflection; // [assembly: AssemblyVersion("1.0.*")] //It's impossible to make these a define, don't say I didn't warn you -[assembly: AssemblyVersion("3.1.2.2")] -[assembly: AssemblyFileVersion("3.1.2.2")] -[assembly: AssemblyInformationalVersion("3.1.2.2")] +[assembly: AssemblyVersion("3.1.4.1")] +[assembly: AssemblyFileVersion("3.1.4.1")] +[assembly: AssemblyInformationalVersion("3.1.4.1")] diff --git a/appveyor.yml b/appveyor.yml index cd29c86075..0bbbd54080 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -5,7 +5,7 @@ image: Visual Studio 2017 configuration: Release shallow_clone: true artifacts: -- path: TGS3-Server-v*.zip +- path: TGS3-Server-v*.exe name: TGS3Server - path: MD5-SHA1-Server-v*.txt name: MD5SHA1Server