Merge upstream

This commit is contained in:
Cyberboss
2017-11-05 21:22:04 -05:00
32 changed files with 352 additions and 236 deletions
+18 -20
View File
@@ -35,12 +35,10 @@ namespace TGServerService
const string BDirTest = GameDirB + LiveFile;
const string LiveDirTest = GameDirLive + LiveFile;
const string InterfaceDLLName = "TGServiceInterface.dll";
object CompilerLock = new object();
CompilerStatus compilerCurrentStatus;
string lastCompilerError;
Thread CompilerThread;
bool compilationCancellationRequestation = false;
bool canCancelCompilation = false;
@@ -85,7 +83,7 @@ namespace TGServerService
if (CompilerThread == null || !CompilerThread.IsAlive)
return;
CompilerThread.Abort(); //this will safely kill dm
InitCompiler(); //also cleanup
InitCompiler(); //also cleanup
}
}
@@ -101,7 +99,7 @@ namespace TGServerService
{
return compilerCurrentStatus == CompilerStatus.Uninitialized || compilerCurrentStatus == CompilerStatus.Initialized;
}
/// <inheritdoc />
public bool Initialize()
{
@@ -120,7 +118,7 @@ namespace TGServerService
//what is says on the tin
CompilerStatus IsInitialized()
{
if (File.Exists(RelativePath(Path.Combine(GameDirLive, InterfaceDLLName)))) //its a good tell, jim
if (File.Exists(RelativePath(Path.Combine(GameDirLive, BridgeDLLName)))) //its a good tell, jim
return CompilerStatus.Initialized;
return CompilerStatus.Uninitialized;
}
@@ -128,13 +126,13 @@ namespace TGServerService
//we need to remove symlinks before we can recursively delete
void CleanGameFolder()
{
var GameDirAInterface = RelativePath(Path.Combine(GameDirA, InterfaceDLLName));
if (Directory.Exists(GameDirAInterface))
Directory.Delete(GameDirAInterface);
var GameDirABridge = RelativePath(Path.Combine(GameDirA, BridgeDLLName));
if (Directory.Exists(GameDirABridge))
Directory.Delete(GameDirABridge);
var GameDirBInterface = RelativePath(Path.Combine(GameDirB, InterfaceDLLName));
if (Directory.Exists(GameDirBInterface))
Directory.Delete(GameDirBInterface);
var GameDirBBridge = RelativePath(Path.Combine(GameDirB, BridgeDLLName));
if (Directory.Exists(GameDirBBridge))
Directory.Delete(GameDirBBridge);
var rgdl = RelativePath(GameDirLive);
if (Directory.Exists(rgdl))
@@ -193,9 +191,9 @@ namespace TGServerService
CreateSymlink(RelativePath(Path.Combine(GameDirA, I)), RelativePath(Path.Combine(StaticDirs, I)));
}
var ridlln = RelativePath(InterfaceDLLName);
CreateSymlink(RelativePath(Path.Combine(GameDirA, InterfaceDLLName)), ridlln);
CreateSymlink(RelativePath(Path.Combine(GameDirB, InterfaceDLLName)), ridlln);
var rbdlln = RelativePath(BridgeDLLName);
CreateSymlink(RelativePath(Path.Combine(GameDirA, BridgeDLLName)), rbdlln);
CreateSymlink(RelativePath(Path.Combine(GameDirB, BridgeDLLName)), rbdlln);
CreateSymlink(RelativePath(GameDirLive), RelativePath(GameDirA));
@@ -226,7 +224,7 @@ namespace TGServerService
return;
}
CompileImpl();
}
}
//Returns the A or B dir in which the game is NOT running
string GetStagingDir()
@@ -265,7 +263,7 @@ namespace TGServerService
{
File.Delete(rsclock);
}
catch //held open by byond
catch //held open by byond
{
//This means there is a staged update waiting to be applied, we have to unstage it before we can work
Directory.Delete(RelativePath(GameDirLive));
@@ -348,7 +346,7 @@ namespace TGServerService
resurrectee = GetStagingDir(); //non-relative
var Config = GetCachedRepoConfig();
var deleteExcludeList = new List<string> { InterfaceDLLName };
var deleteExcludeList = new List<string> { BridgeDLLName };
deleteExcludeList.AddRange(Config.StaticDirectoryPaths);
deleteExcludeList.AddRange(Config.DLLPaths);
Program.DeleteDirectory(resurrectee, true, deleteExcludeList);
@@ -369,8 +367,8 @@ namespace TGServerService
CreateSymlink(the_path, RelativePath(Path.Combine(StaticDirs, I)));
}
if (!File.Exists(Path.Combine(resurrectee, InterfaceDLLName)))
CreateSymlink(Path.Combine(resurrectee, InterfaceDLLName), RelativePath(InterfaceDLLName));
if (!File.Exists(Path.Combine(resurrectee, BridgeDLLName)))
CreateSymlink(Path.Combine(resurrectee, BridgeDLLName), RelativePath(BridgeDLLName));
deleteExcludeList.Add(".git");
Program.CopyDirectory(RelativePath(RepoPath), resurrectee, deleteExcludeList);
+42 -20
View File
@@ -151,7 +151,7 @@ namespace TGServerService
//autostart the server
if (Config.Autostart)
//break this off so we don't hold up starting the service
ThreadPool.QueueUserWorkItem( _ => { Start(); });
ThreadPool.QueueUserWorkItem(_ => { Start(); });
}
/// <summary>
@@ -178,7 +178,7 @@ namespace TGServerService
else if (Detach)
Config.ReattachRequired = false;
Stop();
if(pcpu != null)
if (pcpu != null)
pcpu.Dispose();
if (RenameLog)
try
@@ -267,7 +267,7 @@ namespace TGServerService
{
if (DaemonStatus() == DreamDaemonStatus.Offline)
return Start();
lock(restartLock)
lock (restartLock)
{
if (RestartInProgress)
return "Restart already in progress";
@@ -276,8 +276,8 @@ namespace TGServerService
SendMessage("DD: Hard restart triggered", MessageType.WatchdogInfo);
Stop();
var res = Start();
if(res != null)
lock(restartLock)
if (res != null)
lock (restartLock)
{
RestartInProgress = false;
}
@@ -496,7 +496,7 @@ namespace TGServerService
}
return StartImpl(false);
}
/// <summary>
/// Translate the configured <see cref="DreamDaemonSecurity"/> level into a byond command line param
/// </summary>
@@ -519,28 +519,47 @@ namespace TGServerService
}
/// <summary>
/// Copies <see cref="InterfaceDLLName"/> from the program directory to the the <see cref="ServerInstance"/> directory
/// Copies <see cref="BridgeDLLName"/> from the program directory to the the <see cref="ServerInstance"/> directory
/// </summary>
/// <param name="overwrite">If <see langword="true"/>, overwrites the <see cref="ServerInstance"/>'s current interface .dll if it exists</param>
void UpdateInterfaceDll(bool overwrite)
void UpdateBridgeDll(bool overwrite)
{
var ridlln = RelativePath(InterfaceDLLName);
var FileExists = File.Exists(ridlln);
var rbdlln = RelativePath(BridgeDLLName);
var FileExists = File.Exists(rbdlln);
if (FileExists && !overwrite)
return;
//Copy the interface dll to the static dir
var InterfacePath = Assembly.GetAssembly(typeof(DreamDaemonBridge)).Location;
var InterfacePath = Assembly.GetAssembly(typeof(Interface)).Location;
//bridge is installed next to the interface
var BridgePath = Path.Combine(Path.GetDirectoryName(InterfacePath), BridgeDLLName);
#if DEBUG
//We could be debugging from the project directory
if (!File.Exists(BridgePath))
//A little hackish debug mode doctoring never hurt anyone
BridgePath = Path.Combine(Path.GetDirectoryName(Path.GetDirectoryName(Path.GetDirectoryName(Path.GetDirectoryName(InterfacePath)))), "TGDreamDaemonBridge/bin/x86/Debug", BridgeDLLName);
#endif
try
{
//Use reflection to ensure these are the droids we're looking for
Assembly.ReflectionOnlyLoadFrom(BridgePath).GetType(DreamDaemonBridgeType, true);
}
catch (Exception e)
{
WriteError(String.Format("Unable to locate {0}! Error: {1}", BridgeDLLName, e.ToString()), EventID.BridgeDLLUpdateFail);
return;
}
try
{
if (FileExists)
{
var Old = File.ReadAllBytes(ridlln);
var New = File.ReadAllBytes(InterfacePath);
var Old = File.ReadAllBytes(rbdlln);
var New = File.ReadAllBytes(BridgePath);
if (Old.SequenceEqual(New))
return; //no need
}
File.Copy(InterfacePath, ridlln, overwrite);
WriteInfo("Updated interface DLL", EventID.InterfaceDLLUpdated);
File.Copy(BridgePath, rbdlln, overwrite);
}
catch
{
@@ -548,18 +567,20 @@ namespace TGServerService
{
//ok the things being stupid and hasn't released the dll yet, try ONCE more
Thread.Sleep(1000);
File.Copy(InterfacePath, ridlln, overwrite);
File.Copy(InterfacePath, rbdlln, overwrite);
}
catch (Exception e)
{
//intentionally using the fi
WriteError("Failed to update interface DLL! Error: " + e.ToString(), EventID.InterfaceDLLUpdateFail);
WriteError("Failed to update bridge DLL! Error: " + e.ToString(), EventID.BridgeDLLUpdateFail);
return;
}
}
WriteInfo("Updated interface DLL", EventID.BridgeDLLUpdated);
}
/// <summary>
/// Clears the current <see cref="GameAPIVersion"/>, calls <see cref="UpdateInterfaceDll(bool)"/> with a <see langword="true"/> parameter, and attempts to start the DreamDaemon <see cref="Proc"/>
/// Clears the current <see cref="GameAPIVersion"/>, calls <see cref="UpdateBridgeDll(bool)"/> with a <see langword="true"/> parameter, and attempts to start the DreamDaemon <see cref="Proc"/>
/// </summary>
/// <param name="watchdog">If <see langword="false"/>, sets <see cref="DDWatchdog"/> to a new <see cref="Thread"/> pointing to <see cref="Watchdog"/> and starts it</param>
/// <returns><see langword="null"/> on success, error message on failure</returns>
@@ -578,7 +599,7 @@ namespace TGServerService
GenCommsKey();
StartingSecurity = Config.Security;
Proc.StartInfo.Arguments = String.Format("{0} -port {1} {5}-close -verbose -params \"server_service={3}&server_service_version={4}&{6}={7}\" -{2} -public", DMB, Config.Port, SecurityWord(), serviceCommsKey, Version(), Config.Webclient ? "-webclient " : "", SPInstanceName, Config.Name);
UpdateInterfaceDll(true);
UpdateBridgeDll(true);
lock (topicLock)
{
GameAPIVersion = null; //needs updating
@@ -715,7 +736,8 @@ namespace TGServerService
/// <inheritdoc />
public void SetWebclient(bool on)
{
lock (watchdogLock) {
lock (watchdogLock)
{
var diff = on != Config.Webclient;
if (diff)
{
+34 -23
View File
@@ -49,6 +49,19 @@ namespace TGServerService
const string CCPAdminOnly = "admin_only";
const string CCPRequiredParameters = "required_parameters";
/// <summary>
/// The file name of the .dll that contains the <see cref="ITGInterop"/> bridge class
/// </summary>
const string BridgeDLLName = "TGDreamDaemonBridge.dll";
/// <summary>
/// The namespace that contains the <see cref="ITGInterop"/> bridge class. Used for reflection
/// </summary>
const string DreamDaemonBridgeNamespace = "TGDreamDaemonBridge";
/// <summary>
/// The <see cref="ITGInterop"/> bridge class. Used for reflection
/// </summary>
const string DreamDaemonBridgeType = DreamDaemonBridgeNamespace + ".DreamDaemonBridge";
List<Command> ServerChatCommands;
void LoadServerChatCommands()
@@ -172,34 +185,33 @@ namespace TGServerService
lock (topicLock) {
if (!CheckAPIVersionConstraints())
return "Incompatible API!";
StringBuilder stringPacket = new StringBuilder();
stringPacket.Append((char)'\x00', 8);
stringPacket.Append('?' + topicdata);
stringPacket.Append((char)'\x00');
string fullString = stringPacket.ToString();
var packet = Encoding.ASCII.GetBytes(fullString);
packet[1] = 0x83;
var FinalLength = packet.Length - 4;
if (FinalLength > UInt16.MaxValue)
return "Error: Topic too long";
var lengthBytes = BitConverter.GetBytes((ushort)FinalLength);
packet[2] = lengthBytes[1]; //fucking endianess
packet[3] = lengthBytes[0];
var returnedString = "NULL";
var returnedData = new byte[UInt16.MaxValue];
using (var topicSender = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp) { SendTimeout = 5000, ReceiveTimeout = 5000 })
{
try
{
topicSender.Connect(IPAddress.Loopback, port);
StringBuilder stringPacket = new StringBuilder();
stringPacket.Append((char)'\x00', 8);
stringPacket.Append('?' + topicdata);
stringPacket.Append((char)'\x00');
string fullString = stringPacket.ToString();
var packet = Encoding.ASCII.GetBytes(fullString);
packet[1] = 0x83;
var FinalLength = packet.Length - 4;
if (FinalLength > UInt16.MaxValue)
return "Error: Topic too long";
var lengthBytes = BitConverter.GetBytes((ushort)FinalLength);
packet[2] = lengthBytes[1]; //fucking endianess
packet[3] = lengthBytes[0];
topicSender.Send(packet);
string returnedString = "NULL";
try
{
var returnedData = new byte[UInt16.MaxValue];
topicSender.Receive(returnedData);
var raw_string = Encoding.ASCII.GetString(returnedData).TrimEnd(new char[] { (char)0 }).Trim();
if (raw_string.Length > 6)
@@ -213,14 +225,13 @@ namespace TGServerService
{
topicSender.Shutdown(SocketShutdown.Both);
}
return returnedString;
}
catch
{
return "Topic delivery failed!";
}
}
return returnedString;
}
}
+2 -2
View File
@@ -96,7 +96,7 @@ namespace TGServerService
{
Directory.CreateDirectory(RelativePath(RepoKeyDir));
if(Exists())
UpdateInterfaceDll(false);
UpdateBridgeDll(false);
if(LoadRepo() == null)
DisableGarbageCollectionNoLock();
//start the autoupdate timer
@@ -338,7 +338,7 @@ namespace TGServerService
void InitialConfigureRepository()
{
Directory.CreateDirectory(RelativePath(StaticDirs));
UpdateInterfaceDll(false);
UpdateBridgeDll(false);
UpdateTGS3Json();
var Config = GetCachedRepoConfig(); //RepoBusy is set if we're here
foreach(var I in Config.StaticDirectoryPaths)