mirror of
https://github.com/tgstation/tgstation-server.git
synced 2026-08-26 22:48:20 +01:00
Adds player counting
This commit is contained in:
@@ -5,3 +5,4 @@
|
||||
#define SERVER_TOOLS_WORLD_ANNOUNCE(message) world << ##message
|
||||
#define SERVER_TOOLS_LOG(message) world.log << ##message
|
||||
#define SERVER_TOOLS_NOTIFY_ADMINS(event) message_admins(event)
|
||||
#define SERVER_TOOLS_CLIENT_COUNT clients.len
|
||||
+126
-123
@@ -1,123 +1,126 @@
|
||||
// /tg/station 13 server tools API v3.1
|
||||
|
||||
//CONFIGURATION
|
||||
//use this define if you want to do configuration outside of this file
|
||||
#ifndef SERVER_TOOLS_EXTERNAL_CONFIGURATION
|
||||
//Comment this out once you've filled in the below
|
||||
#error /tg/station server tools interface unconfigured
|
||||
|
||||
//Required interfaces (fill in with your codebase equivalent):
|
||||
|
||||
//create a global variable named `Name` and set it to `Value`
|
||||
//These globals must not be modifiable from anywhere outside of the server tools
|
||||
#define SERVER_TOOLS_DEFINE_AND_SET_GLOBAL(Name, Value)
|
||||
//Read the value in the global variable `Name`
|
||||
#define SERVER_TOOLS_READ_GLOBAL(Name)
|
||||
//Set the value in the global variable `Name` to `Value`
|
||||
#define SERVER_TOOLS_WRITE_GLOBAL(Name, Value)
|
||||
//display an announcement `message` from the server to all players
|
||||
#define SERVER_TOOLS_WORLD_ANNOUNCE(message)
|
||||
//Write a string `message` to a server log
|
||||
#define SERVER_TOOLS_LOG(message)
|
||||
//Notify current in-game administrators of a string `event`
|
||||
#define SERVER_TOOLS_NOTIFY_ADMINS(event)
|
||||
#endif
|
||||
|
||||
//Required hooks:
|
||||
|
||||
//Put this somewhere in /world/New() that is always run
|
||||
#define SERVER_TOOLS_ON_NEW ServiceInit()
|
||||
//Put this somewhere in /world/Topic(T, Addr, Master, Keys) that is always run before T is modified
|
||||
#define SERVER_TOOLS_ON_TOPIC var/service_topic_return = ServiceCommand(params2list(T)); if(service_topic_return) return service_topic_return
|
||||
//Put at the beginning of world/Reboot(reason)
|
||||
#define SERVER_TOOLS_ON_REBOOT ServiceReboot()
|
||||
|
||||
//Optional callable functions:
|
||||
|
||||
//Returns the string version of the API
|
||||
#define SERVER_TOOLS_API_VERSION ServiceAPIVersion()
|
||||
//Returns TRUE if the world was launched under the server tools and the API matches, FALSE otherwise
|
||||
//No function below this succeed if this is FALSE
|
||||
#define SERVER_TOOLS_PRESENT RunningService()
|
||||
//Gets the current version of the service running the server
|
||||
#define SERVER_TOOLS_VERSION ServiceVersion()
|
||||
//Forces a hard reboot of BYOND by ending the process
|
||||
//unlike del(world) clients will try to reconnect
|
||||
//If the service has not requested a shutdown, the world will reboot shortly after
|
||||
#define SERVER_TOOLS_REBOOT_BYOND world.ServiceEndProcess()
|
||||
/*
|
||||
Gets the list of any testmerged github pull requests
|
||||
|
||||
"[PR Number]" => list(
|
||||
"title" -> PR title
|
||||
"commit" -> Full hash of commit merged
|
||||
"author" -> Github username of the author of the PR
|
||||
)
|
||||
*/
|
||||
#define SERVER_TOOLS_PR_LIST GetTestMerges()
|
||||
//Sends a message to connected game chats
|
||||
#define SERVER_TOOLS_CHAT_BROADCAST(message) world.ChatBroadcast(message)
|
||||
//Sends a message to connected admin chats
|
||||
#define SERVER_TOOLS_RELAY_BROADCAST(message) world.AdminBroadcast(message)
|
||||
|
||||
//IMPLEMENTATION
|
||||
|
||||
#define SERVICE_API_VERSION_STRING "3.1.0.0"
|
||||
|
||||
#define REBOOT_MODE_NORMAL 0
|
||||
#define REBOOT_MODE_HARD 1
|
||||
#define REBOOT_MODE_SHUTDOWN 2
|
||||
|
||||
#define SERVICE_WORLD_PARAM "server_service"
|
||||
#define SERVICE_VERSION_PARAM "server_service_version"
|
||||
#define SERVICE_PR_TEST_JSON "prtestjob.json"
|
||||
#define SERVICE_INTERFACE_DLL "TGServiceInterface.dll"
|
||||
#define SERVICE_INTERFACE_FUNCTION "DDEntryPoint"
|
||||
|
||||
#define SERVICE_CMD_HARD_REBOOT "hard_reboot"
|
||||
#define SERVICE_CMD_GRACEFUL_SHUTDOWN "graceful_shutdown"
|
||||
#define SERVICE_CMD_WORLD_ANNOUNCE "world_announce"
|
||||
#define SERVICE_CMD_LIST_CUSTOM "list_custom_commands"
|
||||
|
||||
#define SERVICE_CMD_PARAM_KEY "serviceCommsKey"
|
||||
#define SERVICE_CMD_PARAM_COMMAND "command"
|
||||
#define SERVICE_CMD_PARAM_SENDER "sender"
|
||||
#define SERVICE_CMD_PARAM_CUSTOM "custom"
|
||||
#define SERVICE_CMD_API_COMPATIBLE "api_compat"
|
||||
|
||||
#define SERVICE_JSON_PARAM_HELPTEXT "help_text"
|
||||
#define SERVICE_JSON_PARAM_ADMINONLY "admin_only"
|
||||
#define SERVICE_JSON_PARAM_REQUIREDPARAMETERS "required_parameters"
|
||||
|
||||
#define SERVICE_REQUEST_KILL_PROCESS "killme"
|
||||
#define SERVICE_REQUEST_IRC_BROADCAST "irc"
|
||||
#define SERVICE_REQUEST_IRC_ADMIN_CHANNEL_MESSAGE "send2irc"
|
||||
#define SERVICE_REQUEST_WORLD_REBOOT "worldreboot"
|
||||
#define SERVICE_REQUEST_API_VERSION "api_ver"
|
||||
|
||||
/*
|
||||
The MIT License
|
||||
|
||||
Copyright (c) 2011 Dominic Tarr
|
||||
|
||||
Permission is hereby granted, free of charge,
|
||||
to any person obtaining a copy of this software and
|
||||
associated documentation files (the "Software"), to
|
||||
deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify,
|
||||
merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom
|
||||
the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice
|
||||
shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
// /tg/station 13 server tools API v3.1.0.1
|
||||
|
||||
//CONFIGURATION
|
||||
//use this define if you want to do configuration outside of this file
|
||||
#ifndef SERVER_TOOLS_EXTERNAL_CONFIGURATION
|
||||
//Comment this out once you've filled in the below
|
||||
#error /tg/station server tools interface unconfigured
|
||||
|
||||
//Required interfaces (fill in with your codebase equivalent):
|
||||
|
||||
//create a global variable named `Name` and set it to `Value`
|
||||
//These globals must not be modifiable from anywhere outside of the server tools
|
||||
#define SERVER_TOOLS_DEFINE_AND_SET_GLOBAL(Name, Value)
|
||||
//Read the value in the global variable `Name`
|
||||
#define SERVER_TOOLS_READ_GLOBAL(Name)
|
||||
//Set the value in the global variable `Name` to `Value`
|
||||
#define SERVER_TOOLS_WRITE_GLOBAL(Name, Value)
|
||||
//display an announcement `message` from the server to all players
|
||||
#define SERVER_TOOLS_WORLD_ANNOUNCE(message)
|
||||
//Write a string `message` to a server log
|
||||
#define SERVER_TOOLS_LOG(message)
|
||||
//Notify current in-game administrators of a string `event`
|
||||
#define SERVER_TOOLS_NOTIFY_ADMINS(event)
|
||||
//The current amount of connected clients
|
||||
#define SERVER_TOOLS_CLIENT_COUNT
|
||||
#endif
|
||||
|
||||
//Required hooks:
|
||||
|
||||
//Put this somewhere in /world/New() that is always run
|
||||
#define SERVER_TOOLS_ON_NEW ServiceInit()
|
||||
//Put this somewhere in /world/Topic(T, Addr, Master, Keys) that is always run before T is modified
|
||||
#define SERVER_TOOLS_ON_TOPIC var/service_topic_return = ServiceCommand(params2list(T)); if(service_topic_return) return service_topic_return
|
||||
//Put at the beginning of world/Reboot(reason)
|
||||
#define SERVER_TOOLS_ON_REBOOT ServiceReboot()
|
||||
|
||||
//Optional callable functions:
|
||||
|
||||
//Returns the string version of the API
|
||||
#define SERVER_TOOLS_API_VERSION ServiceAPIVersion()
|
||||
//Returns TRUE if the world was launched under the server tools and the API matches, FALSE otherwise
|
||||
//No function below this succeed if this is FALSE
|
||||
#define SERVER_TOOLS_PRESENT RunningService()
|
||||
//Gets the current version of the service running the server
|
||||
#define SERVER_TOOLS_VERSION ServiceVersion()
|
||||
//Forces a hard reboot of BYOND by ending the process
|
||||
//unlike del(world) clients will try to reconnect
|
||||
//If the service has not requested a shutdown, the world will reboot shortly after
|
||||
#define SERVER_TOOLS_REBOOT_BYOND world.ServiceEndProcess()
|
||||
/*
|
||||
Gets the list of any testmerged github pull requests
|
||||
|
||||
"[PR Number]" => list(
|
||||
"title" -> PR title
|
||||
"commit" -> Full hash of commit merged
|
||||
"author" -> Github username of the author of the PR
|
||||
)
|
||||
*/
|
||||
#define SERVER_TOOLS_PR_LIST GetTestMerges()
|
||||
//Sends a message to connected game chats
|
||||
#define SERVER_TOOLS_CHAT_BROADCAST(message) world.ChatBroadcast(message)
|
||||
//Sends a message to connected admin chats
|
||||
#define SERVER_TOOLS_RELAY_BROADCAST(message) world.AdminBroadcast(message)
|
||||
|
||||
//IMPLEMENTATION
|
||||
|
||||
#define SERVICE_API_VERSION_STRING "3.1.0.1"
|
||||
|
||||
#define REBOOT_MODE_NORMAL 0
|
||||
#define REBOOT_MODE_HARD 1
|
||||
#define REBOOT_MODE_SHUTDOWN 2
|
||||
|
||||
#define SERVICE_WORLD_PARAM "server_service"
|
||||
#define SERVICE_VERSION_PARAM "server_service_version"
|
||||
#define SERVICE_PR_TEST_JSON "prtestjob.json"
|
||||
#define SERVICE_INTERFACE_DLL "TGServiceInterface.dll"
|
||||
#define SERVICE_INTERFACE_FUNCTION "DDEntryPoint"
|
||||
|
||||
#define SERVICE_CMD_HARD_REBOOT "hard_reboot"
|
||||
#define SERVICE_CMD_GRACEFUL_SHUTDOWN "graceful_shutdown"
|
||||
#define SERVICE_CMD_WORLD_ANNOUNCE "world_announce"
|
||||
#define SERVICE_CMD_LIST_CUSTOM "list_custom_commands"
|
||||
#define SERVICE_CMD_API_COMPATIBLE "api_compat"
|
||||
#define SERVICE_CMD_PLAYER_COUNT "client_count"
|
||||
|
||||
#define SERVICE_CMD_PARAM_KEY "serviceCommsKey"
|
||||
#define SERVICE_CMD_PARAM_COMMAND "command"
|
||||
#define SERVICE_CMD_PARAM_SENDER "sender"
|
||||
#define SERVICE_CMD_PARAM_CUSTOM "custom"
|
||||
|
||||
#define SERVICE_JSON_PARAM_HELPTEXT "help_text"
|
||||
#define SERVICE_JSON_PARAM_ADMINONLY "admin_only"
|
||||
#define SERVICE_JSON_PARAM_REQUIREDPARAMETERS "required_parameters"
|
||||
|
||||
#define SERVICE_REQUEST_KILL_PROCESS "killme"
|
||||
#define SERVICE_REQUEST_IRC_BROADCAST "irc"
|
||||
#define SERVICE_REQUEST_IRC_ADMIN_CHANNEL_MESSAGE "send2irc"
|
||||
#define SERVICE_REQUEST_WORLD_REBOOT "worldreboot"
|
||||
#define SERVICE_REQUEST_API_VERSION "api_ver"
|
||||
|
||||
/*
|
||||
The MIT License
|
||||
|
||||
Copyright (c) 2011 Dominic Tarr
|
||||
|
||||
Permission is hereby granted, free of charge,
|
||||
to any person obtaining a copy of this software and
|
||||
associated documentation files (the "Software"), to
|
||||
deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify,
|
||||
merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom
|
||||
the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice
|
||||
shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
@@ -89,6 +89,8 @@ SERVER_TOOLS_DEFINE_AND_SET_GLOBAL(server_tools_api_compatible, FALSE)
|
||||
return "No message set!"
|
||||
SERVER_TOOLS_WORLD_ANNOUNCE(msg)
|
||||
return "SUCCESS"
|
||||
if(SERVICE_CMD_PLAYER_COUNT)
|
||||
return "[SERVER_TOOLS_CLIENT_COUNT]"
|
||||
if(SERVICE_CMD_LIST_CUSTOM)
|
||||
return json_encode(ListServiceCustomCommands(FALSE))
|
||||
else
|
||||
|
||||
+314
-311
@@ -1,311 +1,314 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using TGServiceInterface;
|
||||
|
||||
namespace TGCommandLine
|
||||
{
|
||||
class DDCommand : RootCommand
|
||||
{
|
||||
public DDCommand()
|
||||
{
|
||||
Keyword = "dd";
|
||||
Children = new Command[] { new DDStartCommand(), new DDStopCommand(), new DDRestartCommand(), new DDStatusCommand(), new DDAutostartCommand(), new DDPortCommand(), new DDSecurityCommand(), new DDWorldAnnounceCommand(), new DDWebclientCommand() };
|
||||
}
|
||||
public override string GetHelpText()
|
||||
{
|
||||
return "Manage DreamDaemon";
|
||||
}
|
||||
}
|
||||
|
||||
class DDWorldAnnounceCommand : Command
|
||||
{
|
||||
public DDWorldAnnounceCommand()
|
||||
{
|
||||
Keyword = "announce";
|
||||
RequiredParameters = 1;
|
||||
}
|
||||
|
||||
public override string GetHelpText()
|
||||
{
|
||||
return "Sends a message all players on the server";
|
||||
}
|
||||
|
||||
public override string GetArgumentString()
|
||||
{
|
||||
return "<message>";
|
||||
}
|
||||
|
||||
protected override ExitCode Run(IList<string> parameters)
|
||||
{
|
||||
var res = Server.GetComponent<ITGDreamDaemon>().WorldAnnounce(String.Join(" ", parameters));
|
||||
OutputProc(res ?? "Success!");
|
||||
return res == null ? ExitCode.Normal : ExitCode.ServerError;
|
||||
}
|
||||
}
|
||||
|
||||
class DDStartCommand : Command
|
||||
{
|
||||
public DDStartCommand()
|
||||
{
|
||||
Keyword = "start";
|
||||
}
|
||||
|
||||
public override string GetHelpText()
|
||||
{
|
||||
return "Starts the server and watchdog";
|
||||
}
|
||||
|
||||
protected override ExitCode Run(IList<string> parameters)
|
||||
{
|
||||
var res = Server.GetComponent<ITGDreamDaemon>().Start();
|
||||
OutputProc(res ?? "Success!");
|
||||
return res == null ? ExitCode.Normal : ExitCode.ServerError;
|
||||
}
|
||||
}
|
||||
|
||||
class DDStopCommand : Command
|
||||
{
|
||||
public DDStopCommand()
|
||||
{
|
||||
Keyword = "stop";
|
||||
}
|
||||
public override string GetArgumentString()
|
||||
{
|
||||
return "[--graceful]";
|
||||
}
|
||||
|
||||
public override string GetHelpText()
|
||||
{
|
||||
return "Stops the server and watchdog optionally waiting for the current round to end";
|
||||
}
|
||||
|
||||
protected override ExitCode Run(IList<string> parameters)
|
||||
{
|
||||
var DD = Server.GetComponent<ITGDreamDaemon>();
|
||||
if (parameters.Count > 0 && parameters[0].ToLower() == "--graceful")
|
||||
{
|
||||
if (DD.DaemonStatus() != TGDreamDaemonStatus.Online)
|
||||
{
|
||||
OutputProc("Error: The game is not currently running!");
|
||||
return ExitCode.ServerError;
|
||||
}
|
||||
DD.RequestStop();
|
||||
return ExitCode.Normal;
|
||||
}
|
||||
var res = DD.Stop();
|
||||
OutputProc(res ?? "Success!");
|
||||
return res == null ? ExitCode.Normal : ExitCode.ServerError;
|
||||
}
|
||||
}
|
||||
class DDRestartCommand : Command
|
||||
{
|
||||
public DDRestartCommand()
|
||||
{
|
||||
Keyword = "restart";
|
||||
}
|
||||
|
||||
public override string GetArgumentString()
|
||||
{
|
||||
return "[--graceful]";
|
||||
}
|
||||
protected override ExitCode Run(IList<string> parameters)
|
||||
{
|
||||
var DD = Server.GetComponent<ITGDreamDaemon>();
|
||||
if (parameters.Count > 0 && parameters[0].ToLower() == "--graceful")
|
||||
{
|
||||
if (DD.DaemonStatus() != TGDreamDaemonStatus.Online)
|
||||
{
|
||||
OutputProc("Error: The game is not currently running!");
|
||||
return ExitCode.ServerError;
|
||||
}
|
||||
DD.RequestRestart();
|
||||
return ExitCode.Normal;
|
||||
}
|
||||
var res = DD.Restart();
|
||||
OutputProc(res ?? "Success!");
|
||||
return res == null ? ExitCode.Normal : ExitCode.ServerError;
|
||||
}
|
||||
|
||||
public override string GetHelpText()
|
||||
{
|
||||
return "Restarts the server and watchdog optionally waiting for the current round to end";
|
||||
}
|
||||
}
|
||||
class DDStatusCommand : Command
|
||||
{
|
||||
public DDStatusCommand()
|
||||
{
|
||||
Keyword = "status";
|
||||
}
|
||||
|
||||
public override string GetHelpText()
|
||||
{
|
||||
return "Gets the current status of the watchdog and server";
|
||||
}
|
||||
|
||||
protected override ExitCode Run(IList<string> parameters)
|
||||
{
|
||||
var DD = Server.GetComponent<ITGDreamDaemon>();
|
||||
OutputProc(DD.StatusString(true));
|
||||
if (DD.ShutdownInProgress())
|
||||
OutputProc("The server will shutdown once the current round completes.");
|
||||
return ExitCode.Normal;
|
||||
}
|
||||
}
|
||||
|
||||
class DDAutostartCommand : Command
|
||||
{
|
||||
public DDAutostartCommand()
|
||||
{
|
||||
Keyword = "autostart";
|
||||
RequiredParameters = 1;
|
||||
}
|
||||
|
||||
protected override ExitCode Run(IList<string> parameters)
|
||||
{
|
||||
var DD = Server.GetComponent<ITGDreamDaemon>();
|
||||
switch (parameters[0].ToLower())
|
||||
{
|
||||
case "on":
|
||||
DD.SetAutostart(true);
|
||||
break;
|
||||
case "off":
|
||||
DD.SetAutostart(false);
|
||||
break;
|
||||
case "check":
|
||||
OutputProc("Autostart is: " + (DD.Autostart() ? "On" : "Off"));
|
||||
break;
|
||||
default:
|
||||
OutputProc("Invalid parameter: " + parameters[0]);
|
||||
return ExitCode.BadCommand;
|
||||
}
|
||||
return ExitCode.Normal;
|
||||
}
|
||||
|
||||
public override string GetArgumentString()
|
||||
{
|
||||
return "<on|off|check>";
|
||||
}
|
||||
public override string GetHelpText()
|
||||
{
|
||||
return "Change or check autostarting of the game server with the service";
|
||||
}
|
||||
}
|
||||
class DDWebclientCommand : Command
|
||||
{
|
||||
public DDWebclientCommand()
|
||||
{
|
||||
Keyword = "webclient";
|
||||
RequiredParameters = 1;
|
||||
}
|
||||
|
||||
protected override ExitCode Run(IList<string> parameters)
|
||||
{
|
||||
var DD = Server.GetComponent<ITGDreamDaemon>();
|
||||
switch (parameters[0].ToLower())
|
||||
{
|
||||
case "on":
|
||||
DD.SetWebclient(true);
|
||||
break;
|
||||
case "off":
|
||||
DD.SetWebclient(false);
|
||||
break;
|
||||
case "check":
|
||||
OutputProc("Webclient is: " + (DD.Webclient() ? "Enabled" : "Disabled"));
|
||||
break;
|
||||
default:
|
||||
OutputProc("Invalid parameter: " + parameters[0]);
|
||||
return ExitCode.BadCommand;
|
||||
}
|
||||
return ExitCode.Normal;
|
||||
}
|
||||
|
||||
public override string GetArgumentString()
|
||||
{
|
||||
return "<on|off|check>";
|
||||
}
|
||||
public override string GetHelpText()
|
||||
{
|
||||
return "Change or check if the BYOND webclient is enabled for the game server";
|
||||
}
|
||||
}
|
||||
|
||||
class DDPortCommand : Command
|
||||
{
|
||||
public DDPortCommand()
|
||||
{
|
||||
Keyword = "set-port";
|
||||
RequiredParameters = 1;
|
||||
}
|
||||
|
||||
protected override ExitCode Run(IList<string> parameters)
|
||||
{
|
||||
ushort port;
|
||||
try
|
||||
{
|
||||
port = Convert.ToUInt16(parameters[0]);
|
||||
}
|
||||
catch
|
||||
{
|
||||
OutputProc("Invalid port number!");
|
||||
return ExitCode.BadCommand;
|
||||
}
|
||||
|
||||
Server.GetComponent<ITGDreamDaemon>().SetPort(port);
|
||||
return ExitCode.Normal;
|
||||
}
|
||||
|
||||
public override string GetArgumentString()
|
||||
{
|
||||
return "<number>";
|
||||
}
|
||||
|
||||
public override string GetHelpText()
|
||||
{
|
||||
return "Sets the port DreamDaemon will open the server on. Requires a server restart to apply and queues a graceful one up";
|
||||
}
|
||||
}
|
||||
|
||||
class DDSecurityCommand : Command
|
||||
{
|
||||
public DDSecurityCommand()
|
||||
{
|
||||
Keyword = "set-security";
|
||||
RequiredParameters = 1;
|
||||
}
|
||||
|
||||
protected override ExitCode Run(IList<string> parameters)
|
||||
{
|
||||
TGDreamDaemonSecurity sec;
|
||||
switch (parameters[0].ToLower())
|
||||
{
|
||||
case "safe":
|
||||
sec = TGDreamDaemonSecurity.Safe;
|
||||
break;
|
||||
case "ultra":
|
||||
case "ultrasafe":
|
||||
sec = TGDreamDaemonSecurity.Ultrasafe;
|
||||
break;
|
||||
case "trust":
|
||||
case "trusted":
|
||||
sec = TGDreamDaemonSecurity.Trusted;
|
||||
break;
|
||||
default:
|
||||
OutputProc("Invalid security word!");
|
||||
return ExitCode.BadCommand;
|
||||
}
|
||||
Server.GetComponent<ITGDreamDaemon>().SetSecurityLevel(sec);
|
||||
return ExitCode.Normal;
|
||||
}
|
||||
|
||||
public override string GetArgumentString()
|
||||
{
|
||||
return "<safe|ultrasafe|trusted>";
|
||||
}
|
||||
|
||||
public override string GetHelpText()
|
||||
{
|
||||
return "Sets the visibility option for the DreamDaemon world";
|
||||
}
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using TGServiceInterface;
|
||||
|
||||
namespace TGCommandLine
|
||||
{
|
||||
class DDCommand : RootCommand
|
||||
{
|
||||
public DDCommand()
|
||||
{
|
||||
Keyword = "dd";
|
||||
Children = new Command[] { new DDStartCommand(), new DDStopCommand(), new DDRestartCommand(), new DDStatusCommand(), new DDAutostartCommand(), new DDPortCommand(), new DDSecurityCommand(), new DDWorldAnnounceCommand(), new DDWebclientCommand() };
|
||||
}
|
||||
public override string GetHelpText()
|
||||
{
|
||||
return "Manage DreamDaemon";
|
||||
}
|
||||
}
|
||||
|
||||
class DDWorldAnnounceCommand : Command
|
||||
{
|
||||
public DDWorldAnnounceCommand()
|
||||
{
|
||||
Keyword = "announce";
|
||||
RequiredParameters = 1;
|
||||
}
|
||||
|
||||
public override string GetHelpText()
|
||||
{
|
||||
return "Sends a message all players on the server";
|
||||
}
|
||||
|
||||
public override string GetArgumentString()
|
||||
{
|
||||
return "<message>";
|
||||
}
|
||||
|
||||
protected override ExitCode Run(IList<string> parameters)
|
||||
{
|
||||
var res = Server.GetComponent<ITGDreamDaemon>().WorldAnnounce(String.Join(" ", parameters));
|
||||
OutputProc(res ?? "Success!");
|
||||
return res == null ? ExitCode.Normal : ExitCode.ServerError;
|
||||
}
|
||||
}
|
||||
|
||||
class DDStartCommand : Command
|
||||
{
|
||||
public DDStartCommand()
|
||||
{
|
||||
Keyword = "start";
|
||||
}
|
||||
|
||||
public override string GetHelpText()
|
||||
{
|
||||
return "Starts the server and watchdog";
|
||||
}
|
||||
|
||||
protected override ExitCode Run(IList<string> parameters)
|
||||
{
|
||||
var res = Server.GetComponent<ITGDreamDaemon>().Start();
|
||||
OutputProc(res ?? "Success!");
|
||||
return res == null ? ExitCode.Normal : ExitCode.ServerError;
|
||||
}
|
||||
}
|
||||
|
||||
class DDStopCommand : Command
|
||||
{
|
||||
public DDStopCommand()
|
||||
{
|
||||
Keyword = "stop";
|
||||
}
|
||||
public override string GetArgumentString()
|
||||
{
|
||||
return "[--graceful]";
|
||||
}
|
||||
|
||||
public override string GetHelpText()
|
||||
{
|
||||
return "Stops the server and watchdog optionally waiting for the current round to end";
|
||||
}
|
||||
|
||||
protected override ExitCode Run(IList<string> parameters)
|
||||
{
|
||||
var DD = Server.GetComponent<ITGDreamDaemon>();
|
||||
if (parameters.Count > 0 && parameters[0].ToLower() == "--graceful")
|
||||
{
|
||||
if (DD.DaemonStatus() != TGDreamDaemonStatus.Online)
|
||||
{
|
||||
OutputProc("Error: The game is not currently running!");
|
||||
return ExitCode.ServerError;
|
||||
}
|
||||
DD.RequestStop();
|
||||
return ExitCode.Normal;
|
||||
}
|
||||
var res = DD.Stop();
|
||||
OutputProc(res ?? "Success!");
|
||||
return res == null ? ExitCode.Normal : ExitCode.ServerError;
|
||||
}
|
||||
}
|
||||
class DDRestartCommand : Command
|
||||
{
|
||||
public DDRestartCommand()
|
||||
{
|
||||
Keyword = "restart";
|
||||
}
|
||||
|
||||
public override string GetArgumentString()
|
||||
{
|
||||
return "[--graceful]";
|
||||
}
|
||||
protected override ExitCode Run(IList<string> parameters)
|
||||
{
|
||||
var DD = Server.GetComponent<ITGDreamDaemon>();
|
||||
if (parameters.Count > 0 && parameters[0].ToLower() == "--graceful")
|
||||
{
|
||||
if (DD.DaemonStatus() != TGDreamDaemonStatus.Online)
|
||||
{
|
||||
OutputProc("Error: The game is not currently running!");
|
||||
return ExitCode.ServerError;
|
||||
}
|
||||
DD.RequestRestart();
|
||||
return ExitCode.Normal;
|
||||
}
|
||||
var res = DD.Restart();
|
||||
OutputProc(res ?? "Success!");
|
||||
return res == null ? ExitCode.Normal : ExitCode.ServerError;
|
||||
}
|
||||
|
||||
public override string GetHelpText()
|
||||
{
|
||||
return "Restarts the server and watchdog optionally waiting for the current round to end";
|
||||
}
|
||||
}
|
||||
class DDStatusCommand : Command
|
||||
{
|
||||
public DDStatusCommand()
|
||||
{
|
||||
Keyword = "status";
|
||||
}
|
||||
|
||||
public override string GetHelpText()
|
||||
{
|
||||
return "Gets the current status of the watchdog and server";
|
||||
}
|
||||
|
||||
protected override ExitCode Run(IList<string> parameters)
|
||||
{
|
||||
var DD = Server.GetComponent<ITGDreamDaemon>();
|
||||
OutputProc(DD.StatusString(true));
|
||||
if (DD.ShutdownInProgress())
|
||||
OutputProc("The server will shutdown once the current round completes.");
|
||||
var pc = DD.PlayerCount();
|
||||
if (pc != -1)
|
||||
OutputProc(pc + " connected clients");
|
||||
return ExitCode.Normal;
|
||||
}
|
||||
}
|
||||
|
||||
class DDAutostartCommand : Command
|
||||
{
|
||||
public DDAutostartCommand()
|
||||
{
|
||||
Keyword = "autostart";
|
||||
RequiredParameters = 1;
|
||||
}
|
||||
|
||||
protected override ExitCode Run(IList<string> parameters)
|
||||
{
|
||||
var DD = Server.GetComponent<ITGDreamDaemon>();
|
||||
switch (parameters[0].ToLower())
|
||||
{
|
||||
case "on":
|
||||
DD.SetAutostart(true);
|
||||
break;
|
||||
case "off":
|
||||
DD.SetAutostart(false);
|
||||
break;
|
||||
case "check":
|
||||
OutputProc("Autostart is: " + (DD.Autostart() ? "On" : "Off"));
|
||||
break;
|
||||
default:
|
||||
OutputProc("Invalid parameter: " + parameters[0]);
|
||||
return ExitCode.BadCommand;
|
||||
}
|
||||
return ExitCode.Normal;
|
||||
}
|
||||
|
||||
public override string GetArgumentString()
|
||||
{
|
||||
return "<on|off|check>";
|
||||
}
|
||||
public override string GetHelpText()
|
||||
{
|
||||
return "Change or check autostarting of the game server with the service";
|
||||
}
|
||||
}
|
||||
class DDWebclientCommand : Command
|
||||
{
|
||||
public DDWebclientCommand()
|
||||
{
|
||||
Keyword = "webclient";
|
||||
RequiredParameters = 1;
|
||||
}
|
||||
|
||||
protected override ExitCode Run(IList<string> parameters)
|
||||
{
|
||||
var DD = Server.GetComponent<ITGDreamDaemon>();
|
||||
switch (parameters[0].ToLower())
|
||||
{
|
||||
case "on":
|
||||
DD.SetWebclient(true);
|
||||
break;
|
||||
case "off":
|
||||
DD.SetWebclient(false);
|
||||
break;
|
||||
case "check":
|
||||
OutputProc("Webclient is: " + (DD.Webclient() ? "Enabled" : "Disabled"));
|
||||
break;
|
||||
default:
|
||||
OutputProc("Invalid parameter: " + parameters[0]);
|
||||
return ExitCode.BadCommand;
|
||||
}
|
||||
return ExitCode.Normal;
|
||||
}
|
||||
|
||||
public override string GetArgumentString()
|
||||
{
|
||||
return "<on|off|check>";
|
||||
}
|
||||
public override string GetHelpText()
|
||||
{
|
||||
return "Change or check if the BYOND webclient is enabled for the game server";
|
||||
}
|
||||
}
|
||||
|
||||
class DDPortCommand : Command
|
||||
{
|
||||
public DDPortCommand()
|
||||
{
|
||||
Keyword = "set-port";
|
||||
RequiredParameters = 1;
|
||||
}
|
||||
|
||||
protected override ExitCode Run(IList<string> parameters)
|
||||
{
|
||||
ushort port;
|
||||
try
|
||||
{
|
||||
port = Convert.ToUInt16(parameters[0]);
|
||||
}
|
||||
catch
|
||||
{
|
||||
OutputProc("Invalid port number!");
|
||||
return ExitCode.BadCommand;
|
||||
}
|
||||
|
||||
Server.GetComponent<ITGDreamDaemon>().SetPort(port);
|
||||
return ExitCode.Normal;
|
||||
}
|
||||
|
||||
public override string GetArgumentString()
|
||||
{
|
||||
return "<number>";
|
||||
}
|
||||
|
||||
public override string GetHelpText()
|
||||
{
|
||||
return "Sets the port DreamDaemon will open the server on. Requires a server restart to apply and queues a graceful one up";
|
||||
}
|
||||
}
|
||||
|
||||
class DDSecurityCommand : Command
|
||||
{
|
||||
public DDSecurityCommand()
|
||||
{
|
||||
Keyword = "set-security";
|
||||
RequiredParameters = 1;
|
||||
}
|
||||
|
||||
protected override ExitCode Run(IList<string> parameters)
|
||||
{
|
||||
TGDreamDaemonSecurity sec;
|
||||
switch (parameters[0].ToLower())
|
||||
{
|
||||
case "safe":
|
||||
sec = TGDreamDaemonSecurity.Safe;
|
||||
break;
|
||||
case "ultra":
|
||||
case "ultrasafe":
|
||||
sec = TGDreamDaemonSecurity.Ultrasafe;
|
||||
break;
|
||||
case "trust":
|
||||
case "trusted":
|
||||
sec = TGDreamDaemonSecurity.Trusted;
|
||||
break;
|
||||
default:
|
||||
OutputProc("Invalid security word!");
|
||||
return ExitCode.BadCommand;
|
||||
}
|
||||
Server.GetComponent<ITGDreamDaemon>().SetSecurityLevel(sec);
|
||||
return ExitCode.Normal;
|
||||
}
|
||||
|
||||
public override string GetArgumentString()
|
||||
{
|
||||
return "<safe|ultrasafe|trusted>";
|
||||
}
|
||||
|
||||
public override string GetHelpText()
|
||||
{
|
||||
return "Sets the visibility option for the DreamDaemon world";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+220
-220
@@ -1,220 +1,220 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using TGServiceInterface;
|
||||
|
||||
namespace TGCommandLine
|
||||
{
|
||||
|
||||
class Program
|
||||
{
|
||||
static ExitCode RunCommandLine(IList<string> argsAsList)
|
||||
{
|
||||
//first lookup the connection string
|
||||
bool badConnectionString = false;
|
||||
for (var I = 0; I < argsAsList.Count - 1; ++I) {
|
||||
var lowerarg = argsAsList[I].ToLower();
|
||||
if (lowerarg == "-c" || lowerarg == "--connect")
|
||||
{
|
||||
var connectionString = argsAsList[I + 1];
|
||||
var splits = connectionString.Split('@');
|
||||
var userpass = splits[0].Split(':');
|
||||
if (splits.Length != 2 || userpass.Length != 2)
|
||||
{
|
||||
badConnectionString = true;
|
||||
break;
|
||||
}
|
||||
var addrport = splits[1].Split(':');
|
||||
if (addrport.Length != 2)
|
||||
{
|
||||
badConnectionString = true;
|
||||
break;
|
||||
}
|
||||
var username = userpass[0];
|
||||
var password = userpass[1];
|
||||
var address = addrport[0];
|
||||
ushort port;
|
||||
try
|
||||
{
|
||||
port = Convert.ToUInt16(addrport[1]);
|
||||
}
|
||||
catch
|
||||
{
|
||||
badConnectionString = true;
|
||||
break;
|
||||
}
|
||||
if(String.IsNullOrWhiteSpace(username) || String.IsNullOrWhiteSpace(password) || String.IsNullOrWhiteSpace(address))
|
||||
{
|
||||
badConnectionString = true;
|
||||
break;
|
||||
}
|
||||
argsAsList.RemoveAt(I);
|
||||
argsAsList.RemoveAt(I);
|
||||
Server.SetRemoteLoginInformation(address, port, username, password);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (badConnectionString)
|
||||
{
|
||||
Console.WriteLine("Remote connection usage: <-c/--connect> username:password@address:port");
|
||||
return ExitCode.BadCommand;
|
||||
}
|
||||
|
||||
var res = Server.VerifyConnection();
|
||||
if (res != null)
|
||||
{
|
||||
Console.WriteLine("Unable to connect to service: " + res);
|
||||
Console.WriteLine("Remote connection usage: <-c/--connect> username:password@address:port");
|
||||
return ExitCode.ConnectionError;
|
||||
}
|
||||
|
||||
if (!Server.Authenticate())
|
||||
{
|
||||
Console.WriteLine("Authentication error: Username/password/windows identity is not authorized!");
|
||||
return ExitCode.ConnectionError;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return new CLICommand().DoRun(argsAsList);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine("Error: " + e.ToString());
|
||||
return ExitCode.ConnectionError;
|
||||
};
|
||||
}
|
||||
public static string ReadLineSecure()
|
||||
{
|
||||
string result = "";
|
||||
while (true)
|
||||
{
|
||||
ConsoleKeyInfo i = Console.ReadKey(true);
|
||||
if (i.Key == ConsoleKey.Enter)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if (i.Key == ConsoleKey.Backspace)
|
||||
{
|
||||
if (result.Length > 0)
|
||||
{
|
||||
result = result.Substring(0, result.Length - 1);
|
||||
Console.Write("\b \b");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result += i.KeyChar;
|
||||
Console.Write("*");
|
||||
}
|
||||
}
|
||||
Console.WriteLine();
|
||||
return result;
|
||||
}
|
||||
|
||||
static string AcceptedBadCert;
|
||||
static bool BadCertificateInteractive(string message)
|
||||
{
|
||||
if (AcceptedBadCert == message)
|
||||
return true;
|
||||
Console.WriteLine(message);
|
||||
Console.Write("Do you wish to continue? NOT RECCOMENDED! (y/N): ");
|
||||
var result = Console.ReadLine().Trim().ToLower();
|
||||
if (result == "y" || result == "yes")
|
||||
{
|
||||
AcceptedBadCert = message;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static int Main(string[] args)
|
||||
{
|
||||
Command.OutputProcVar.Value = Console.WriteLine;
|
||||
if (args.Length != 0)
|
||||
{
|
||||
Server.SetBadCertificateHandler((message) => {
|
||||
foreach (var I in args)
|
||||
if (I.ToLower() == "--disable-ssl-verification") //im just not even going to document this because i hate it so much
|
||||
return true;
|
||||
return false;
|
||||
});
|
||||
//allow self signed certs in debug mode
|
||||
return (int)RunCommandLine(new List<string>(args));
|
||||
}
|
||||
|
||||
Server.SetBadCertificateHandler(BadCertificateInteractive);
|
||||
|
||||
Console.WriteLine("Type 'remote' to connect to a remote service");
|
||||
//interactive mode
|
||||
while (true)
|
||||
{
|
||||
Console.Write("Enter command: ");
|
||||
var NextCommand = Console.ReadLine();
|
||||
switch (NextCommand.ToLower())
|
||||
{
|
||||
case "remote":
|
||||
Console.Write("Enter server address: ");
|
||||
var address = Console.ReadLine();
|
||||
Console.Write("Enter server port: ");
|
||||
ushort port;
|
||||
try{
|
||||
port = Convert.ToUInt16(Console.ReadLine());
|
||||
}
|
||||
catch
|
||||
{
|
||||
Console.WriteLine("Error: Bad port!");
|
||||
break;
|
||||
}
|
||||
Console.Write("Enter username: ");
|
||||
var username = Console.ReadLine();
|
||||
Console.Write("Enter password: ");
|
||||
var password = ReadLineSecure();
|
||||
Server.SetRemoteLoginInformation(address, port, username, password);
|
||||
var res = Server.VerifyConnection();
|
||||
if (res != null)
|
||||
{
|
||||
Console.WriteLine("Unable to connect: " + res);
|
||||
Server.MakeLocalConnection();
|
||||
}
|
||||
else if (!Server.Authenticate())
|
||||
{
|
||||
Console.WriteLine("Authentication error: Username/password/windows identity is not authorized! Returning to local mode...");
|
||||
Server.MakeLocalConnection();
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Connected remotely");
|
||||
Console.WriteLine("Type 'disconnect' to return to local mode");
|
||||
}
|
||||
break;
|
||||
case "disconnect":
|
||||
Server.MakeLocalConnection();
|
||||
Console.WriteLine("Switch to local mode");
|
||||
break;
|
||||
case "quit":
|
||||
case "exit":
|
||||
return (int)ExitCode.Normal;
|
||||
#if DEBUG
|
||||
case "debug-upgrade":
|
||||
Server.GetComponent<ITGSService>().PrepareForUpdate();
|
||||
return (int)ExitCode.Normal;
|
||||
#endif
|
||||
default:
|
||||
//linq voodoo to get quoted strings
|
||||
var formattedCommand = NextCommand.Split('"')
|
||||
.Select((element, index) => index % 2 == 0 // If even index
|
||||
? element.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries) // Split the item
|
||||
: new string[] { element }) // Keep the entire item
|
||||
.SelectMany(element => element).ToList();
|
||||
|
||||
formattedCommand = formattedCommand.Select(x => x.Trim()).ToList();
|
||||
formattedCommand.Remove("");
|
||||
RunCommandLine(formattedCommand);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using TGServiceInterface;
|
||||
|
||||
namespace TGCommandLine
|
||||
{
|
||||
|
||||
class Program
|
||||
{
|
||||
static ExitCode RunCommandLine(IList<string> argsAsList)
|
||||
{
|
||||
//first lookup the connection string
|
||||
bool badConnectionString = false;
|
||||
for (var I = 0; I < argsAsList.Count - 1; ++I) {
|
||||
var lowerarg = argsAsList[I].ToLower();
|
||||
if (lowerarg == "-c" || lowerarg == "--connect")
|
||||
{
|
||||
var connectionString = argsAsList[I + 1];
|
||||
var splits = connectionString.Split('@');
|
||||
var userpass = splits[0].Split(':');
|
||||
if (splits.Length != 2 || userpass.Length != 2)
|
||||
{
|
||||
badConnectionString = true;
|
||||
break;
|
||||
}
|
||||
var addrport = splits[1].Split(':');
|
||||
if (addrport.Length != 2)
|
||||
{
|
||||
badConnectionString = true;
|
||||
break;
|
||||
}
|
||||
var username = userpass[0];
|
||||
var password = userpass[1];
|
||||
var address = addrport[0];
|
||||
ushort port;
|
||||
try
|
||||
{
|
||||
port = Convert.ToUInt16(addrport[1]);
|
||||
}
|
||||
catch
|
||||
{
|
||||
badConnectionString = true;
|
||||
break;
|
||||
}
|
||||
if(String.IsNullOrWhiteSpace(username) || String.IsNullOrWhiteSpace(password) || String.IsNullOrWhiteSpace(address))
|
||||
{
|
||||
badConnectionString = true;
|
||||
break;
|
||||
}
|
||||
argsAsList.RemoveAt(I);
|
||||
argsAsList.RemoveAt(I);
|
||||
Server.SetRemoteLoginInformation(address, port, username, password);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (badConnectionString)
|
||||
{
|
||||
Console.WriteLine("Remote connection usage: <-c/--connect> username:password@address:port");
|
||||
return ExitCode.BadCommand;
|
||||
}
|
||||
|
||||
var res = Server.VerifyConnection();
|
||||
if (res != null)
|
||||
{
|
||||
Console.WriteLine("Unable to connect to service: " + res);
|
||||
Console.WriteLine("Remote connection usage: <-c/--connect> username:password@address:port");
|
||||
return ExitCode.ConnectionError;
|
||||
}
|
||||
|
||||
if (!Server.Authenticate())
|
||||
{
|
||||
Console.WriteLine("Authentication error: Username/password/windows identity is not authorized!");
|
||||
return ExitCode.ConnectionError;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return new CLICommand().DoRun(argsAsList);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine("Error: " + e.ToString());
|
||||
return ExitCode.ConnectionError;
|
||||
};
|
||||
}
|
||||
public static string ReadLineSecure()
|
||||
{
|
||||
string result = "";
|
||||
while (true)
|
||||
{
|
||||
ConsoleKeyInfo i = Console.ReadKey(true);
|
||||
if (i.Key == ConsoleKey.Enter)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if (i.Key == ConsoleKey.Backspace)
|
||||
{
|
||||
if (result.Length > 0)
|
||||
{
|
||||
result = result.Substring(0, result.Length - 1);
|
||||
Console.Write("\b \b");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result += i.KeyChar;
|
||||
Console.Write("*");
|
||||
}
|
||||
}
|
||||
Console.WriteLine();
|
||||
return result;
|
||||
}
|
||||
|
||||
static string AcceptedBadCert;
|
||||
static bool BadCertificateInteractive(string message)
|
||||
{
|
||||
if (AcceptedBadCert == message)
|
||||
return true;
|
||||
Console.WriteLine(message);
|
||||
Console.Write("Do you wish to continue? NOT RECCOMENDED! (y/N): ");
|
||||
var result = Console.ReadLine().Trim().ToLower();
|
||||
if (result == "y" || result == "yes")
|
||||
{
|
||||
AcceptedBadCert = message;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static int Main(string[] args)
|
||||
{
|
||||
Command.OutputProcVar.Value = Console.WriteLine;
|
||||
if (args.Length != 0)
|
||||
{
|
||||
Server.SetBadCertificateHandler((message) => {
|
||||
foreach (var I in args)
|
||||
if (I.ToLower() == "--disable-ssl-verification") //im just not even going to document this because i hate it so much
|
||||
return true;
|
||||
return false;
|
||||
});
|
||||
//allow self signed certs in debug mode
|
||||
return (int)RunCommandLine(new List<string>(args));
|
||||
}
|
||||
|
||||
Server.SetBadCertificateHandler(BadCertificateInteractive);
|
||||
|
||||
Console.WriteLine("Type 'remote' to connect to a remote service");
|
||||
//interactive mode
|
||||
while (true)
|
||||
{
|
||||
Console.Write("Enter command: ");
|
||||
var NextCommand = Console.ReadLine();
|
||||
switch (NextCommand.ToLower())
|
||||
{
|
||||
case "remote":
|
||||
Console.Write("Enter server address: ");
|
||||
var address = Console.ReadLine();
|
||||
Console.Write("Enter server port: ");
|
||||
ushort port;
|
||||
try{
|
||||
port = Convert.ToUInt16(Console.ReadLine());
|
||||
}
|
||||
catch
|
||||
{
|
||||
Console.WriteLine("Error: Bad port!");
|
||||
break;
|
||||
}
|
||||
Console.Write("Enter username: ");
|
||||
var username = Console.ReadLine();
|
||||
Console.Write("Enter password: ");
|
||||
var password = ReadLineSecure();
|
||||
Server.SetRemoteLoginInformation(address, port, username, password);
|
||||
var res = Server.VerifyConnection();
|
||||
if (res != null)
|
||||
{
|
||||
Console.WriteLine("Unable to connect: " + res);
|
||||
Server.MakeLocalConnection();
|
||||
}
|
||||
else if (!Server.Authenticate())
|
||||
{
|
||||
Console.WriteLine("Authentication error: Username/password/windows identity is not authorized! Returning to local mode...");
|
||||
Server.MakeLocalConnection();
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Connected remotely");
|
||||
Console.WriteLine("Type 'disconnect' to return to local mode");
|
||||
}
|
||||
break;
|
||||
case "disconnect":
|
||||
Server.MakeLocalConnection();
|
||||
Console.WriteLine("Switch to local mode");
|
||||
break;
|
||||
case "quit":
|
||||
case "exit":
|
||||
return (int)ExitCode.Normal;
|
||||
#if DEBUG
|
||||
case "debug-upgrade":
|
||||
Server.GetComponent<ITGSService>().PrepareForUpdate();
|
||||
return (int)ExitCode.Normal;
|
||||
#endif
|
||||
default:
|
||||
//linq voodoo to get quoted strings
|
||||
var formattedCommand = NextCommand.Split('"')
|
||||
.Select((element, index) => index % 2 == 0 // If even index
|
||||
? element.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries) // Split the item
|
||||
: new string[] { element }) // Keep the entire item
|
||||
.SelectMany(element => element).ToList();
|
||||
|
||||
formattedCommand = formattedCommand.Select(x => x.Trim()).ToList();
|
||||
formattedCommand.Remove("");
|
||||
RunCommandLine(formattedCommand);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+45
-45
@@ -1,45 +1,45 @@
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace TGControlPanel
|
||||
{
|
||||
public partial class Main : Form
|
||||
{
|
||||
public Main()
|
||||
{
|
||||
InitializeComponent();
|
||||
Panels.SelectedIndexChanged += Panels_SelectedIndexChanged;
|
||||
Panels.SelectedIndex += Math.Min(Properties.Settings.Default.LastPageIndex, Panels.TabCount - 1);
|
||||
InitRepoPage();
|
||||
InitBYONDPage();
|
||||
InitServerPage();
|
||||
LoadChatPage();
|
||||
InitStaticPage();
|
||||
}
|
||||
|
||||
private void Main_Resize(object sender, EventArgs e)
|
||||
{
|
||||
Panels.Location = new Point(10, 10);
|
||||
Panels.Width = ClientSize.Width - 20;
|
||||
Panels.Height = ClientSize.Height - 20;
|
||||
}
|
||||
|
||||
private void Panels_SelectedIndexChanged(object sender, EventArgs e)
|
||||
{
|
||||
switch (Panels.SelectedIndex)
|
||||
{
|
||||
case 1: //byond
|
||||
UpdateBYONDButtons();
|
||||
break;
|
||||
case 2: //scp
|
||||
LoadServerPage();
|
||||
break;
|
||||
case 3: //chat
|
||||
LoadChatPage();
|
||||
break;
|
||||
}
|
||||
Properties.Settings.Default.LastPageIndex = Panels.SelectedIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace TGControlPanel
|
||||
{
|
||||
public partial class Main : Form
|
||||
{
|
||||
public Main()
|
||||
{
|
||||
InitializeComponent();
|
||||
Panels.SelectedIndexChanged += Panels_SelectedIndexChanged;
|
||||
Panels.SelectedIndex += Math.Min(Properties.Settings.Default.LastPageIndex, Panels.TabCount - 1);
|
||||
InitRepoPage();
|
||||
InitBYONDPage();
|
||||
InitServerPage();
|
||||
LoadChatPage();
|
||||
InitStaticPage();
|
||||
}
|
||||
|
||||
private void Main_Resize(object sender, EventArgs e)
|
||||
{
|
||||
Panels.Location = new Point(10, 10);
|
||||
Panels.Width = ClientSize.Width - 20;
|
||||
Panels.Height = ClientSize.Height - 20;
|
||||
}
|
||||
|
||||
private void Panels_SelectedIndexChanged(object sender, EventArgs e)
|
||||
{
|
||||
switch (Panels.SelectedIndex)
|
||||
{
|
||||
case 1: //byond
|
||||
UpdateBYONDButtons();
|
||||
break;
|
||||
case 2: //scp
|
||||
LoadServerPage();
|
||||
break;
|
||||
case 3: //chat
|
||||
LoadChatPage();
|
||||
break;
|
||||
}
|
||||
Properties.Settings.Default.LastPageIndex = Panels.SelectedIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+477
-474
@@ -1,474 +1,477 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Windows.Forms;
|
||||
using TGServiceInterface;
|
||||
|
||||
namespace TGControlPanel
|
||||
{
|
||||
partial class Main
|
||||
{
|
||||
enum FullUpdateAction
|
||||
{
|
||||
UpdateHard,
|
||||
UpdateMerge,
|
||||
UpdateHardTestmerge,
|
||||
Reset,
|
||||
Testmerge,
|
||||
}
|
||||
|
||||
FullUpdateAction fuAction;
|
||||
ushort testmergePR;
|
||||
string updateError;
|
||||
bool updatingFields = false;
|
||||
|
||||
void InitServerPage()
|
||||
{
|
||||
LoadServerPage();
|
||||
if (!Server.AuthenticateAdmin())
|
||||
{
|
||||
ServerPathTextbox.Enabled = false;
|
||||
ServerPathTextbox.ReadOnly = true;
|
||||
}
|
||||
FullUpdateWorker.RunWorkerCompleted += FullUpdateWorker_RunWorkerCompleted;
|
||||
ServerPathTextbox.LostFocus += ServerPathTextbox_LostFocus;
|
||||
ServerPathTextbox.KeyDown += ServerPathTextbox_KeyDown;
|
||||
projectNameText.LostFocus += ProjectNameText_LostFocus;
|
||||
projectNameText.KeyDown += ProjectNameText_KeyDown;
|
||||
ServerStartBGW.RunWorkerCompleted += ServerStartBGW_RunWorkerCompleted;
|
||||
}
|
||||
|
||||
private void ServerStartBGW_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
|
||||
{
|
||||
if (e.Result != null)
|
||||
MessageBox.Show((string)e.Result);
|
||||
LoadServerPage();
|
||||
}
|
||||
|
||||
private void ProjectNameText_KeyDown(object sender, KeyEventArgs e)
|
||||
{
|
||||
if (e.KeyCode == Keys.Enter)
|
||||
UpdateProjectName();
|
||||
}
|
||||
|
||||
private void ServerPathTextbox_KeyDown(object sender, KeyEventArgs e)
|
||||
{
|
||||
if (e.KeyCode == Keys.Enter)
|
||||
UpdateServerPath();
|
||||
}
|
||||
|
||||
private void FullUpdateWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
|
||||
{
|
||||
if (updateError != null)
|
||||
MessageBox.Show(updateError);
|
||||
UpdateHardButton.Enabled = true;
|
||||
UpdateMergeButton.Enabled = true;
|
||||
TestmergeButton.Enabled = true;
|
||||
UpdateTestmergeButton.Enabled = true;
|
||||
LoadServerPage();
|
||||
}
|
||||
|
||||
private void CompileCancelButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
var res = Server.GetComponent<ITGCompiler>().Cancel();
|
||||
if (res != null)
|
||||
MessageBox.Show(res);
|
||||
LoadServerPage();
|
||||
}
|
||||
|
||||
private void ServerPathTextbox_LostFocus(object sender, EventArgs e)
|
||||
{
|
||||
UpdateServerPath();
|
||||
}
|
||||
|
||||
void UpdateServerPath()
|
||||
{
|
||||
if (!Program.CheckAdminWithWarning())
|
||||
{
|
||||
ServerPathTextbox.Enabled = false;
|
||||
ServerPathTextbox.ReadOnly = true;
|
||||
return;
|
||||
}
|
||||
if (updatingFields || ServerPathTextbox.Text.Trim() == Server.GetComponent<ITGConfig>().ServerDirectory())
|
||||
return;
|
||||
var DialogResult = MessageBox.Show("This will move the entire server installation.", "Confim", MessageBoxButtons.YesNo);
|
||||
if (DialogResult != DialogResult.Yes)
|
||||
return;
|
||||
|
||||
if (!Program.CheckAdminWithWarning())
|
||||
{
|
||||
ServerPathTextbox.Enabled = false;
|
||||
ServerPathTextbox.ReadOnly = true;
|
||||
return;
|
||||
}
|
||||
MessageBox.Show(Server.GetComponent<ITGAdministration>().MoveServer(ServerPathTextbox.Text) ?? "Success!");
|
||||
}
|
||||
|
||||
void LoadServerPage()
|
||||
{
|
||||
var RepoExists = Server.GetComponent<ITGRepository>().Exists();
|
||||
compileButton.Visible = RepoExists;
|
||||
initializeButton.Visible = RepoExists;
|
||||
AutostartCheckbox.Visible = RepoExists;
|
||||
WebclientCheckBox.Visible = RepoExists;
|
||||
PortSelector.Visible = RepoExists;
|
||||
projectNameText.Visible = RepoExists;
|
||||
CompilerStatusLabel.Visible = RepoExists;
|
||||
CompileCancelButton.Visible = RepoExists;
|
||||
CompilerLabel.Visible = RepoExists;
|
||||
ProjectPathLabel.Visible = RepoExists;
|
||||
ServerPRLabel.Visible = RepoExists;
|
||||
ServerGStopButton.Visible = RepoExists;
|
||||
ServerStartButton.Visible = RepoExists;
|
||||
ServerGRestartButton.Visible = RepoExists;
|
||||
ServerRestartButton.Visible = RepoExists;
|
||||
PortLabel.Visible = RepoExists;
|
||||
ServerStopButton.Visible = RepoExists;
|
||||
TestmergeButton.Visible = RepoExists;
|
||||
ServerTestmergeInput.Visible = RepoExists;
|
||||
UpdateHardButton.Visible = RepoExists;
|
||||
UpdateMergeButton.Visible = RepoExists;
|
||||
UpdateTestmergeButton.Visible = RepoExists;
|
||||
ResetTestmerge.Visible = RepoExists;
|
||||
WorldAnnounceField.Visible = RepoExists;
|
||||
WorldAnnounceButton.Visible = RepoExists;
|
||||
WorldAnnounceLabel.Visible = RepoExists;
|
||||
|
||||
var DM = Server.GetComponent<ITGCompiler>();
|
||||
var DD = Server.GetComponent<ITGDreamDaemon>();
|
||||
var Config = Server.GetComponent<ITGConfig>();
|
||||
|
||||
if (updatingFields)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
updatingFields = true;
|
||||
|
||||
if (!ServerPathTextbox.Focused)
|
||||
ServerPathTextbox.Text = Config.ServerDirectory();
|
||||
|
||||
SecuritySelector.SelectedIndex = (int)DD.SecurityLevel();
|
||||
|
||||
if (!RepoExists)
|
||||
return;
|
||||
|
||||
var DaeStat = DD.DaemonStatus();
|
||||
var Online = DaeStat == TGDreamDaemonStatus.Online;
|
||||
ServerStartButton.Enabled = !Online;
|
||||
ServerGStopButton.Enabled = Online;
|
||||
ServerGRestartButton.Enabled = Online;
|
||||
ServerStopButton.Enabled = Online;
|
||||
ServerRestartButton.Enabled = Online;
|
||||
|
||||
switch (DaeStat)
|
||||
{
|
||||
case TGDreamDaemonStatus.HardRebooting:
|
||||
ServerStatusLabel.Text = "REBOOTING";
|
||||
break;
|
||||
case TGDreamDaemonStatus.Offline:
|
||||
ServerStatusLabel.Text = "OFFLINE";
|
||||
break;
|
||||
case TGDreamDaemonStatus.Online:
|
||||
ServerStatusLabel.Text = "ONLINE";
|
||||
break;
|
||||
}
|
||||
|
||||
ServerGStopButton.Checked = DD.ShutdownInProgress();
|
||||
|
||||
AutostartCheckbox.Checked = DD.Autostart();
|
||||
WebclientCheckBox.Checked = DD.Webclient();
|
||||
if (!PortSelector.Focused)
|
||||
PortSelector.Value = DD.Port();
|
||||
if (!projectNameText.Focused)
|
||||
projectNameText.Text = DM.ProjectName();
|
||||
|
||||
switch (DM.GetStatus())
|
||||
{
|
||||
case TGCompilerStatus.Compiling:
|
||||
CompilerStatusLabel.Text = "Compiling...";
|
||||
compileButton.Enabled = false;
|
||||
initializeButton.Enabled = false;
|
||||
CompileCancelButton.Enabled = true;
|
||||
break;
|
||||
case TGCompilerStatus.Initializing:
|
||||
CompilerStatusLabel.Text = "Initializing...";
|
||||
compileButton.Enabled = false;
|
||||
initializeButton.Enabled = false;
|
||||
CompileCancelButton.Enabled = false;
|
||||
break;
|
||||
case TGCompilerStatus.Initialized:
|
||||
CompilerStatusLabel.Text = "Idle";
|
||||
initializeButton.Enabled = true;
|
||||
compileButton.Enabled = true;
|
||||
CompileCancelButton.Enabled = false;
|
||||
break;
|
||||
case TGCompilerStatus.Uninitialized:
|
||||
CompilerStatusLabel.Text = "Uninitialized";
|
||||
compileButton.Enabled = false;
|
||||
initializeButton.Enabled = true;
|
||||
CompileCancelButton.Enabled = false;
|
||||
break;
|
||||
default:
|
||||
CompilerStatusLabel.Text = "Unknown!";
|
||||
initializeButton.Enabled = true;
|
||||
compileButton.Enabled = true;
|
||||
CompileCancelButton.Enabled = true;
|
||||
break;
|
||||
}
|
||||
var error = DM.CompileError();
|
||||
if (error != null)
|
||||
MessageBox.Show("Error: " + error);
|
||||
}
|
||||
finally
|
||||
{
|
||||
updatingFields = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void ProjectNameText_LostFocus(object sender, EventArgs e)
|
||||
{
|
||||
UpdateProjectName();
|
||||
}
|
||||
|
||||
void UpdateProjectName()
|
||||
{
|
||||
if (!updatingFields)
|
||||
Server.GetComponent<ITGCompiler>().SetProjectName(projectNameText.Text);
|
||||
}
|
||||
|
||||
private void PortSelector_ValueChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (!updatingFields)
|
||||
Server.GetComponent<ITGDreamDaemon>().SetPort((ushort)PortSelector.Value);
|
||||
}
|
||||
|
||||
private void RunServerUpdate(FullUpdateAction fua, ushort tm = 0)
|
||||
{
|
||||
if (FullUpdateWorker.IsBusy)
|
||||
return;
|
||||
testmergePR = tm;
|
||||
fuAction = fua;
|
||||
initializeButton.Enabled = false;
|
||||
compileButton.Enabled = false;
|
||||
UpdateHardButton.Enabled = false;
|
||||
UpdateMergeButton.Enabled = false;
|
||||
TestmergeButton.Enabled = false;
|
||||
UpdateTestmergeButton.Enabled = false;
|
||||
switch (fuAction)
|
||||
{
|
||||
case FullUpdateAction.Testmerge:
|
||||
CompilerStatusLabel.Text = String.Format("Testmerging pull request #{0}...", testmergePR);
|
||||
break;
|
||||
case FullUpdateAction.UpdateHard:
|
||||
CompilerStatusLabel.Text = String.Format("Updating Server (RESET)...");
|
||||
break;
|
||||
case FullUpdateAction.UpdateMerge:
|
||||
CompilerStatusLabel.Text = String.Format("Updating Server (MERGE)...");
|
||||
break;
|
||||
case FullUpdateAction.UpdateHardTestmerge:
|
||||
CompilerStatusLabel.Text = String.Format("Updating and testmerging pull request #{0}...", testmergePR);
|
||||
break;
|
||||
}
|
||||
FullUpdateWorker.RunWorkerAsync();
|
||||
}
|
||||
|
||||
private void ServerPageRefreshButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
LoadServerPage();
|
||||
}
|
||||
|
||||
private void InitializeButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (!Server.GetComponent<ITGCompiler>().Initialize())
|
||||
MessageBox.Show("Unable to start initialization!");
|
||||
LoadServerPage();
|
||||
}
|
||||
private void CompileButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (!Server.GetComponent<ITGCompiler>().Compile())
|
||||
MessageBox.Show("Unable to start compilation!");
|
||||
LoadServerPage();
|
||||
}
|
||||
|
||||
private void AutostartCheckbox_CheckedChanged(object sender, System.EventArgs e)
|
||||
{
|
||||
if (!updatingFields)
|
||||
Server.GetComponent<ITGDreamDaemon>().SetAutostart(AutostartCheckbox.Checked);
|
||||
}
|
||||
private void ServerStartButton_Click(object sender, System.EventArgs e)
|
||||
{
|
||||
if (!ServerStartBGW.IsBusy)
|
||||
ServerStartBGW.RunWorkerAsync();
|
||||
}
|
||||
|
||||
private void ServerStartBGW_DoWork(object sender, DoWorkEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
e.Result = Server.GetComponent<ITGDreamDaemon>().Start();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
e.Result = ex.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
private void ServerStopButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
var DialogResult = MessageBox.Show("This will immediately shut down the server. Continue?", "Confim", MessageBoxButtons.YesNo);
|
||||
if (DialogResult == DialogResult.No)
|
||||
return;
|
||||
var res = Server.GetComponent<ITGDreamDaemon>().Stop();
|
||||
if (res != null)
|
||||
MessageBox.Show(res);
|
||||
}
|
||||
|
||||
private void ServerRestartButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
var DialogResult = MessageBox.Show("This will immediately restart the server. Continue?", "Confim", MessageBoxButtons.YesNo);
|
||||
if (DialogResult == DialogResult.No)
|
||||
return;
|
||||
var res = Server.GetComponent<ITGDreamDaemon>().Restart();
|
||||
if (res != null)
|
||||
MessageBox.Show(res);
|
||||
}
|
||||
|
||||
private void ServerGStopButton_Checked(object sender, EventArgs e)
|
||||
{
|
||||
if (updatingFields)
|
||||
return;
|
||||
var DialogResult = MessageBox.Show("This will shut down the server when the current round ends. Continue?", "Confim", MessageBoxButtons.YesNo);
|
||||
if (DialogResult == DialogResult.No)
|
||||
return;
|
||||
Server.GetComponent<ITGDreamDaemon>().RequestStop();
|
||||
LoadServerPage();
|
||||
}
|
||||
|
||||
private void ServerGRestartButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
var DialogResult = MessageBox.Show("This will restart the server when the current round ends. Continue?", "Confim", MessageBoxButtons.YesNo);
|
||||
if (DialogResult == DialogResult.No)
|
||||
return;
|
||||
Server.GetComponent<ITGDreamDaemon>().RequestRestart();
|
||||
}
|
||||
|
||||
|
||||
private void FullUpdateWorker_DoWork(object sender, DoWorkEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
var Repo = Server.GetComponent<ITGRepository>();
|
||||
var DM = Server.GetComponent<ITGCompiler>();
|
||||
switch (fuAction)
|
||||
{
|
||||
case FullUpdateAction.Testmerge:
|
||||
updateError = Repo.MergePullRequest(testmergePR);
|
||||
if (updateError == null)
|
||||
{
|
||||
Repo.GenerateChangelog(out updateError);
|
||||
updateError = DM.Compile(true) ? updateError : "Compilation failed!";
|
||||
}
|
||||
break;
|
||||
case FullUpdateAction.UpdateHard:
|
||||
updateError = Repo.Update(true);
|
||||
if (updateError == null)
|
||||
{
|
||||
Repo.GenerateChangelog(out updateError);
|
||||
if (updateError == null)
|
||||
updateError = Repo.PushChangelog();
|
||||
updateError = DM.Compile(true) ? updateError : "Compilation failed!";
|
||||
}
|
||||
break;
|
||||
case FullUpdateAction.UpdateHardTestmerge:
|
||||
updateError = Repo.Update(true);
|
||||
if (updateError == null)
|
||||
{
|
||||
Repo.GenerateChangelog(out updateError);
|
||||
if (updateError == null)
|
||||
updateError = Repo.PushChangelog();
|
||||
updateError = Repo.MergePullRequest(testmergePR);
|
||||
if (updateError == null)
|
||||
{
|
||||
Repo.GenerateChangelog(out updateError);
|
||||
updateError = DM.Compile(true) ? updateError : "Compilation failed!";
|
||||
}
|
||||
}
|
||||
break;
|
||||
case FullUpdateAction.UpdateMerge:
|
||||
updateError = Repo.Update(false);
|
||||
if (updateError == null)
|
||||
{
|
||||
Repo.GenerateChangelog(out updateError);
|
||||
if (updateError == null)
|
||||
Repo.PushChangelog(); //not an error 99% of the time if this fails, just a dirty tree
|
||||
updateError = DM.Compile(true) ? updateError : "Compilation failed!";
|
||||
}
|
||||
break;
|
||||
case FullUpdateAction.Reset:
|
||||
updateError = Repo.Reset(true);
|
||||
if (updateError == null)
|
||||
{
|
||||
Repo.GenerateChangelog(out updateError);
|
||||
updateError = DM.Compile(true) ? updateError : "Compilation failed!";
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Program.ServiceDisconnectException(ex);
|
||||
}
|
||||
}
|
||||
private void ResetTestmerge_Click(object sender, EventArgs e)
|
||||
{
|
||||
RunServerUpdate(FullUpdateAction.Reset);
|
||||
}
|
||||
|
||||
private void UpdateHardButton_Click(object sender, System.EventArgs e)
|
||||
{
|
||||
RunServerUpdate(FullUpdateAction.UpdateHard);
|
||||
}
|
||||
|
||||
private void UpdateTestmergeButton_Click(object sender, System.EventArgs e)
|
||||
{
|
||||
RunServerUpdate(FullUpdateAction.UpdateHardTestmerge, (ushort)ServerTestmergeInput.Value);
|
||||
}
|
||||
|
||||
private void UpdateMergeButton_Click(object sender, System.EventArgs e)
|
||||
{
|
||||
RunServerUpdate(FullUpdateAction.UpdateMerge);
|
||||
}
|
||||
private void TestmergeButton_Click(object sender, System.EventArgs e)
|
||||
{
|
||||
RunServerUpdate(FullUpdateAction.Testmerge, (ushort)ServerTestmergeInput.Value);
|
||||
}
|
||||
|
||||
private void SecuritySelector_SelectedIndexChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (!updatingFields)
|
||||
if (!Server.GetComponent<ITGDreamDaemon>().SetSecurityLevel((TGDreamDaemonSecurity)SecuritySelector.SelectedIndex))
|
||||
MessageBox.Show("Security change will be applied after next server reboot.");
|
||||
}
|
||||
|
||||
private void WorldAnnounceButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
var msg = WorldAnnounceField.Text;
|
||||
if (!String.IsNullOrWhiteSpace(msg))
|
||||
{
|
||||
var res = Server.GetComponent<ITGDreamDaemon>().WorldAnnounce(msg);
|
||||
if (res != null)
|
||||
{
|
||||
MessageBox.Show(res);
|
||||
return;
|
||||
}
|
||||
}
|
||||
WorldAnnounceField.Text = "";
|
||||
}
|
||||
|
||||
private void WebclientCheckBox_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (!updatingFields)
|
||||
Server.GetComponent<ITGDreamDaemon>().SetWebclient(WebclientCheckBox.Checked);
|
||||
}
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Windows.Forms;
|
||||
using TGServiceInterface;
|
||||
|
||||
namespace TGControlPanel
|
||||
{
|
||||
partial class Main
|
||||
{
|
||||
enum FullUpdateAction
|
||||
{
|
||||
UpdateHard,
|
||||
UpdateMerge,
|
||||
UpdateHardTestmerge,
|
||||
Reset,
|
||||
Testmerge,
|
||||
}
|
||||
|
||||
FullUpdateAction fuAction;
|
||||
ushort testmergePR;
|
||||
string updateError;
|
||||
bool updatingFields = false;
|
||||
|
||||
void InitServerPage()
|
||||
{
|
||||
LoadServerPage();
|
||||
if (!Server.AuthenticateAdmin())
|
||||
{
|
||||
ServerPathTextbox.Enabled = false;
|
||||
ServerPathTextbox.ReadOnly = true;
|
||||
}
|
||||
FullUpdateWorker.RunWorkerCompleted += FullUpdateWorker_RunWorkerCompleted;
|
||||
ServerPathTextbox.LostFocus += ServerPathTextbox_LostFocus;
|
||||
ServerPathTextbox.KeyDown += ServerPathTextbox_KeyDown;
|
||||
projectNameText.LostFocus += ProjectNameText_LostFocus;
|
||||
projectNameText.KeyDown += ProjectNameText_KeyDown;
|
||||
ServerStartBGW.RunWorkerCompleted += ServerStartBGW_RunWorkerCompleted;
|
||||
}
|
||||
|
||||
private void ServerStartBGW_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
|
||||
{
|
||||
if (e.Result != null)
|
||||
MessageBox.Show((string)e.Result);
|
||||
LoadServerPage();
|
||||
}
|
||||
|
||||
private void ProjectNameText_KeyDown(object sender, KeyEventArgs e)
|
||||
{
|
||||
if (e.KeyCode == Keys.Enter)
|
||||
UpdateProjectName();
|
||||
}
|
||||
|
||||
private void ServerPathTextbox_KeyDown(object sender, KeyEventArgs e)
|
||||
{
|
||||
if (e.KeyCode == Keys.Enter)
|
||||
UpdateServerPath();
|
||||
}
|
||||
|
||||
private void FullUpdateWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
|
||||
{
|
||||
if (updateError != null)
|
||||
MessageBox.Show(updateError);
|
||||
UpdateHardButton.Enabled = true;
|
||||
UpdateMergeButton.Enabled = true;
|
||||
TestmergeButton.Enabled = true;
|
||||
UpdateTestmergeButton.Enabled = true;
|
||||
LoadServerPage();
|
||||
}
|
||||
|
||||
private void CompileCancelButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
var res = Server.GetComponent<ITGCompiler>().Cancel();
|
||||
if (res != null)
|
||||
MessageBox.Show(res);
|
||||
LoadServerPage();
|
||||
}
|
||||
|
||||
private void ServerPathTextbox_LostFocus(object sender, EventArgs e)
|
||||
{
|
||||
UpdateServerPath();
|
||||
}
|
||||
|
||||
void UpdateServerPath()
|
||||
{
|
||||
if (!Program.CheckAdminWithWarning())
|
||||
{
|
||||
ServerPathTextbox.Enabled = false;
|
||||
ServerPathTextbox.ReadOnly = true;
|
||||
return;
|
||||
}
|
||||
if (updatingFields || ServerPathTextbox.Text.Trim() == Server.GetComponent<ITGConfig>().ServerDirectory())
|
||||
return;
|
||||
var DialogResult = MessageBox.Show("This will move the entire server installation.", "Confim", MessageBoxButtons.YesNo);
|
||||
if (DialogResult != DialogResult.Yes)
|
||||
return;
|
||||
|
||||
if (!Program.CheckAdminWithWarning())
|
||||
{
|
||||
ServerPathTextbox.Enabled = false;
|
||||
ServerPathTextbox.ReadOnly = true;
|
||||
return;
|
||||
}
|
||||
MessageBox.Show(Server.GetComponent<ITGAdministration>().MoveServer(ServerPathTextbox.Text) ?? "Success!");
|
||||
}
|
||||
|
||||
void LoadServerPage()
|
||||
{
|
||||
var RepoExists = Server.GetComponent<ITGRepository>().Exists();
|
||||
compileButton.Visible = RepoExists;
|
||||
initializeButton.Visible = RepoExists;
|
||||
AutostartCheckbox.Visible = RepoExists;
|
||||
WebclientCheckBox.Visible = RepoExists;
|
||||
PortSelector.Visible = RepoExists;
|
||||
projectNameText.Visible = RepoExists;
|
||||
CompilerStatusLabel.Visible = RepoExists;
|
||||
CompileCancelButton.Visible = RepoExists;
|
||||
CompilerLabel.Visible = RepoExists;
|
||||
ProjectPathLabel.Visible = RepoExists;
|
||||
ServerPRLabel.Visible = RepoExists;
|
||||
ServerGStopButton.Visible = RepoExists;
|
||||
ServerStartButton.Visible = RepoExists;
|
||||
ServerGRestartButton.Visible = RepoExists;
|
||||
ServerRestartButton.Visible = RepoExists;
|
||||
PortLabel.Visible = RepoExists;
|
||||
ServerStopButton.Visible = RepoExists;
|
||||
TestmergeButton.Visible = RepoExists;
|
||||
ServerTestmergeInput.Visible = RepoExists;
|
||||
UpdateHardButton.Visible = RepoExists;
|
||||
UpdateMergeButton.Visible = RepoExists;
|
||||
UpdateTestmergeButton.Visible = RepoExists;
|
||||
ResetTestmerge.Visible = RepoExists;
|
||||
WorldAnnounceField.Visible = RepoExists;
|
||||
WorldAnnounceButton.Visible = RepoExists;
|
||||
WorldAnnounceLabel.Visible = RepoExists;
|
||||
|
||||
var DM = Server.GetComponent<ITGCompiler>();
|
||||
var DD = Server.GetComponent<ITGDreamDaemon>();
|
||||
var Config = Server.GetComponent<ITGConfig>();
|
||||
|
||||
if (updatingFields)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
updatingFields = true;
|
||||
|
||||
if (!ServerPathTextbox.Focused)
|
||||
ServerPathTextbox.Text = Config.ServerDirectory();
|
||||
|
||||
SecuritySelector.SelectedIndex = (int)DD.SecurityLevel();
|
||||
|
||||
if (!RepoExists)
|
||||
return;
|
||||
|
||||
var DaeStat = DD.DaemonStatus();
|
||||
var Online = DaeStat == TGDreamDaemonStatus.Online;
|
||||
ServerStartButton.Enabled = !Online;
|
||||
ServerGStopButton.Enabled = Online;
|
||||
ServerGRestartButton.Enabled = Online;
|
||||
ServerStopButton.Enabled = Online;
|
||||
ServerRestartButton.Enabled = Online;
|
||||
|
||||
switch (DaeStat)
|
||||
{
|
||||
case TGDreamDaemonStatus.HardRebooting:
|
||||
ServerStatusLabel.Text = "REBOOTING";
|
||||
break;
|
||||
case TGDreamDaemonStatus.Offline:
|
||||
ServerStatusLabel.Text = "OFFLINE";
|
||||
break;
|
||||
case TGDreamDaemonStatus.Online:
|
||||
ServerStatusLabel.Text = "ONLINE";
|
||||
var pc = DD.PlayerCount();
|
||||
if (pc != -1)
|
||||
ServerStatusLabel.Text += " (" + pc + " players)";
|
||||
break;
|
||||
}
|
||||
|
||||
ServerGStopButton.Checked = DD.ShutdownInProgress();
|
||||
|
||||
AutostartCheckbox.Checked = DD.Autostart();
|
||||
WebclientCheckBox.Checked = DD.Webclient();
|
||||
if (!PortSelector.Focused)
|
||||
PortSelector.Value = DD.Port();
|
||||
if (!projectNameText.Focused)
|
||||
projectNameText.Text = DM.ProjectName();
|
||||
|
||||
switch (DM.GetStatus())
|
||||
{
|
||||
case TGCompilerStatus.Compiling:
|
||||
CompilerStatusLabel.Text = "Compiling...";
|
||||
compileButton.Enabled = false;
|
||||
initializeButton.Enabled = false;
|
||||
CompileCancelButton.Enabled = true;
|
||||
break;
|
||||
case TGCompilerStatus.Initializing:
|
||||
CompilerStatusLabel.Text = "Initializing...";
|
||||
compileButton.Enabled = false;
|
||||
initializeButton.Enabled = false;
|
||||
CompileCancelButton.Enabled = false;
|
||||
break;
|
||||
case TGCompilerStatus.Initialized:
|
||||
CompilerStatusLabel.Text = "Idle";
|
||||
initializeButton.Enabled = true;
|
||||
compileButton.Enabled = true;
|
||||
CompileCancelButton.Enabled = false;
|
||||
break;
|
||||
case TGCompilerStatus.Uninitialized:
|
||||
CompilerStatusLabel.Text = "Uninitialized";
|
||||
compileButton.Enabled = false;
|
||||
initializeButton.Enabled = true;
|
||||
CompileCancelButton.Enabled = false;
|
||||
break;
|
||||
default:
|
||||
CompilerStatusLabel.Text = "Unknown!";
|
||||
initializeButton.Enabled = true;
|
||||
compileButton.Enabled = true;
|
||||
CompileCancelButton.Enabled = true;
|
||||
break;
|
||||
}
|
||||
var error = DM.CompileError();
|
||||
if (error != null)
|
||||
MessageBox.Show("Error: " + error);
|
||||
}
|
||||
finally
|
||||
{
|
||||
updatingFields = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void ProjectNameText_LostFocus(object sender, EventArgs e)
|
||||
{
|
||||
UpdateProjectName();
|
||||
}
|
||||
|
||||
void UpdateProjectName()
|
||||
{
|
||||
if (!updatingFields)
|
||||
Server.GetComponent<ITGCompiler>().SetProjectName(projectNameText.Text);
|
||||
}
|
||||
|
||||
private void PortSelector_ValueChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (!updatingFields)
|
||||
Server.GetComponent<ITGDreamDaemon>().SetPort((ushort)PortSelector.Value);
|
||||
}
|
||||
|
||||
private void RunServerUpdate(FullUpdateAction fua, ushort tm = 0)
|
||||
{
|
||||
if (FullUpdateWorker.IsBusy)
|
||||
return;
|
||||
testmergePR = tm;
|
||||
fuAction = fua;
|
||||
initializeButton.Enabled = false;
|
||||
compileButton.Enabled = false;
|
||||
UpdateHardButton.Enabled = false;
|
||||
UpdateMergeButton.Enabled = false;
|
||||
TestmergeButton.Enabled = false;
|
||||
UpdateTestmergeButton.Enabled = false;
|
||||
switch (fuAction)
|
||||
{
|
||||
case FullUpdateAction.Testmerge:
|
||||
CompilerStatusLabel.Text = String.Format("Testmerging pull request #{0}...", testmergePR);
|
||||
break;
|
||||
case FullUpdateAction.UpdateHard:
|
||||
CompilerStatusLabel.Text = String.Format("Updating Server (RESET)...");
|
||||
break;
|
||||
case FullUpdateAction.UpdateMerge:
|
||||
CompilerStatusLabel.Text = String.Format("Updating Server (MERGE)...");
|
||||
break;
|
||||
case FullUpdateAction.UpdateHardTestmerge:
|
||||
CompilerStatusLabel.Text = String.Format("Updating and testmerging pull request #{0}...", testmergePR);
|
||||
break;
|
||||
}
|
||||
FullUpdateWorker.RunWorkerAsync();
|
||||
}
|
||||
|
||||
private void ServerPageRefreshButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
LoadServerPage();
|
||||
}
|
||||
|
||||
private void InitializeButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (!Server.GetComponent<ITGCompiler>().Initialize())
|
||||
MessageBox.Show("Unable to start initialization!");
|
||||
LoadServerPage();
|
||||
}
|
||||
private void CompileButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (!Server.GetComponent<ITGCompiler>().Compile())
|
||||
MessageBox.Show("Unable to start compilation!");
|
||||
LoadServerPage();
|
||||
}
|
||||
|
||||
private void AutostartCheckbox_CheckedChanged(object sender, System.EventArgs e)
|
||||
{
|
||||
if (!updatingFields)
|
||||
Server.GetComponent<ITGDreamDaemon>().SetAutostart(AutostartCheckbox.Checked);
|
||||
}
|
||||
private void ServerStartButton_Click(object sender, System.EventArgs e)
|
||||
{
|
||||
if (!ServerStartBGW.IsBusy)
|
||||
ServerStartBGW.RunWorkerAsync();
|
||||
}
|
||||
|
||||
private void ServerStartBGW_DoWork(object sender, DoWorkEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
e.Result = Server.GetComponent<ITGDreamDaemon>().Start();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
e.Result = ex.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
private void ServerStopButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
var DialogResult = MessageBox.Show("This will immediately shut down the server. Continue?", "Confim", MessageBoxButtons.YesNo);
|
||||
if (DialogResult == DialogResult.No)
|
||||
return;
|
||||
var res = Server.GetComponent<ITGDreamDaemon>().Stop();
|
||||
if (res != null)
|
||||
MessageBox.Show(res);
|
||||
}
|
||||
|
||||
private void ServerRestartButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
var DialogResult = MessageBox.Show("This will immediately restart the server. Continue?", "Confim", MessageBoxButtons.YesNo);
|
||||
if (DialogResult == DialogResult.No)
|
||||
return;
|
||||
var res = Server.GetComponent<ITGDreamDaemon>().Restart();
|
||||
if (res != null)
|
||||
MessageBox.Show(res);
|
||||
}
|
||||
|
||||
private void ServerGStopButton_Checked(object sender, EventArgs e)
|
||||
{
|
||||
if (updatingFields)
|
||||
return;
|
||||
var DialogResult = MessageBox.Show("This will shut down the server when the current round ends. Continue?", "Confim", MessageBoxButtons.YesNo);
|
||||
if (DialogResult == DialogResult.No)
|
||||
return;
|
||||
Server.GetComponent<ITGDreamDaemon>().RequestStop();
|
||||
LoadServerPage();
|
||||
}
|
||||
|
||||
private void ServerGRestartButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
var DialogResult = MessageBox.Show("This will restart the server when the current round ends. Continue?", "Confim", MessageBoxButtons.YesNo);
|
||||
if (DialogResult == DialogResult.No)
|
||||
return;
|
||||
Server.GetComponent<ITGDreamDaemon>().RequestRestart();
|
||||
}
|
||||
|
||||
|
||||
private void FullUpdateWorker_DoWork(object sender, DoWorkEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
var Repo = Server.GetComponent<ITGRepository>();
|
||||
var DM = Server.GetComponent<ITGCompiler>();
|
||||
switch (fuAction)
|
||||
{
|
||||
case FullUpdateAction.Testmerge:
|
||||
updateError = Repo.MergePullRequest(testmergePR);
|
||||
if (updateError == null)
|
||||
{
|
||||
Repo.GenerateChangelog(out updateError);
|
||||
updateError = DM.Compile(true) ? updateError : "Compilation failed!";
|
||||
}
|
||||
break;
|
||||
case FullUpdateAction.UpdateHard:
|
||||
updateError = Repo.Update(true);
|
||||
if (updateError == null)
|
||||
{
|
||||
Repo.GenerateChangelog(out updateError);
|
||||
if (updateError == null)
|
||||
updateError = Repo.PushChangelog();
|
||||
updateError = DM.Compile(true) ? updateError : "Compilation failed!";
|
||||
}
|
||||
break;
|
||||
case FullUpdateAction.UpdateHardTestmerge:
|
||||
updateError = Repo.Update(true);
|
||||
if (updateError == null)
|
||||
{
|
||||
Repo.GenerateChangelog(out updateError);
|
||||
if (updateError == null)
|
||||
updateError = Repo.PushChangelog();
|
||||
updateError = Repo.MergePullRequest(testmergePR);
|
||||
if (updateError == null)
|
||||
{
|
||||
Repo.GenerateChangelog(out updateError);
|
||||
updateError = DM.Compile(true) ? updateError : "Compilation failed!";
|
||||
}
|
||||
}
|
||||
break;
|
||||
case FullUpdateAction.UpdateMerge:
|
||||
updateError = Repo.Update(false);
|
||||
if (updateError == null)
|
||||
{
|
||||
Repo.GenerateChangelog(out updateError);
|
||||
if (updateError == null)
|
||||
Repo.PushChangelog(); //not an error 99% of the time if this fails, just a dirty tree
|
||||
updateError = DM.Compile(true) ? updateError : "Compilation failed!";
|
||||
}
|
||||
break;
|
||||
case FullUpdateAction.Reset:
|
||||
updateError = Repo.Reset(true);
|
||||
if (updateError == null)
|
||||
{
|
||||
Repo.GenerateChangelog(out updateError);
|
||||
updateError = DM.Compile(true) ? updateError : "Compilation failed!";
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Program.ServiceDisconnectException(ex);
|
||||
}
|
||||
}
|
||||
private void ResetTestmerge_Click(object sender, EventArgs e)
|
||||
{
|
||||
RunServerUpdate(FullUpdateAction.Reset);
|
||||
}
|
||||
|
||||
private void UpdateHardButton_Click(object sender, System.EventArgs e)
|
||||
{
|
||||
RunServerUpdate(FullUpdateAction.UpdateHard);
|
||||
}
|
||||
|
||||
private void UpdateTestmergeButton_Click(object sender, System.EventArgs e)
|
||||
{
|
||||
RunServerUpdate(FullUpdateAction.UpdateHardTestmerge, (ushort)ServerTestmergeInput.Value);
|
||||
}
|
||||
|
||||
private void UpdateMergeButton_Click(object sender, System.EventArgs e)
|
||||
{
|
||||
RunServerUpdate(FullUpdateAction.UpdateMerge);
|
||||
}
|
||||
private void TestmergeButton_Click(object sender, System.EventArgs e)
|
||||
{
|
||||
RunServerUpdate(FullUpdateAction.Testmerge, (ushort)ServerTestmergeInput.Value);
|
||||
}
|
||||
|
||||
private void SecuritySelector_SelectedIndexChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (!updatingFields)
|
||||
if (!Server.GetComponent<ITGDreamDaemon>().SetSecurityLevel((TGDreamDaemonSecurity)SecuritySelector.SelectedIndex))
|
||||
MessageBox.Show("Security change will be applied after next server reboot.");
|
||||
}
|
||||
|
||||
private void WorldAnnounceButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
var msg = WorldAnnounceField.Text;
|
||||
if (!String.IsNullOrWhiteSpace(msg))
|
||||
{
|
||||
var res = Server.GetComponent<ITGDreamDaemon>().WorldAnnounce(msg);
|
||||
if (res != null)
|
||||
{
|
||||
MessageBox.Show(res);
|
||||
return;
|
||||
}
|
||||
}
|
||||
WorldAnnounceField.Text = "";
|
||||
}
|
||||
|
||||
private void WebclientCheckBox_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (!updatingFields)
|
||||
Server.GetComponent<ITGDreamDaemon>().SetWebclient(WebclientCheckBox.Checked);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+246
-233
@@ -1,233 +1,246 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Web.Script.Serialization;
|
||||
using System.Web.Security;
|
||||
using TGServiceInterface;
|
||||
|
||||
namespace TGServerService
|
||||
{
|
||||
//handles talking between the world and us
|
||||
partial class TGStationServer : ITGInterop
|
||||
{
|
||||
|
||||
object topicLock = new object();
|
||||
const int CommsKeyLen = 64;
|
||||
string serviceCommsKey; //regenerated every DD restart
|
||||
|
||||
//range of supported api versions
|
||||
readonly Version MinAPIVersion = new Version("3.1.0.0");
|
||||
readonly Version MaxAPIVersion = new Version("3.1.0.99");
|
||||
Version GameAPIVersion;
|
||||
|
||||
//See code/modules/server_tools/server_tools.dm for command switch
|
||||
const string SCHardReboot = "hard_reboot"; //requests that dreamdaemon restarts when the round ends
|
||||
const string SCGracefulShutdown = "graceful_shutdown"; //requests that dreamdaemon stops when the round ends
|
||||
const string SCWorldAnnounce = "world_announce"; //sends param 'message' to the world
|
||||
const string SCListCustomCommands = "list_custom_commands"; //Get a list of commands supported by the server
|
||||
const string SCAPICompat = "api_compat"; //Tells the server we understand each other
|
||||
|
||||
const string SRKillProcess = "killme";
|
||||
const string SRIRCBroadcast = "irc";
|
||||
const string SRIRCAdminChannelMessage = "send2irc";
|
||||
const string SRWorldReboot = "worldreboot";
|
||||
const string SRAPIVersion = "api_ver";
|
||||
|
||||
const string CCPHelpText = "help_text";
|
||||
const string CCPAdminOnly = "admin_only";
|
||||
const string CCPRequiredParameters = "required_parameters";
|
||||
|
||||
List<Command> ServerChatCommands;
|
||||
|
||||
void LoadServerChatCommands()
|
||||
{
|
||||
if (DaemonStatus() != TGDreamDaemonStatus.Online)
|
||||
return;
|
||||
var json = SendCommand(SCListCustomCommands);
|
||||
if (String.IsNullOrWhiteSpace(json))
|
||||
return;
|
||||
List<Command> tmp = new List<Command>();
|
||||
try
|
||||
{
|
||||
foreach(var I in new JavaScriptSerializer().Deserialize<IDictionary<string, IDictionary<string, object>>>(json))
|
||||
tmp.Add(new ServerChatCommand(I.Key, (string)I.Value[CCPHelpText], ((int)I.Value[CCPAdminOnly]) == 1, (int)I.Value[CCPRequiredParameters]));
|
||||
ServerChatCommands = tmp;
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
//raw command string sent here via world.ExportService
|
||||
void HandleCommand(string cmd)
|
||||
{
|
||||
var splits = new List<string>(cmd.Split(' '));
|
||||
cmd = splits[0];
|
||||
splits.RemoveAt(0);
|
||||
|
||||
bool APIValid;
|
||||
lock (topicLock)
|
||||
{
|
||||
APIValid = CheckAPIVersionConstraints();
|
||||
}
|
||||
|
||||
if (!APIValid && cmd != SRAPIVersion)
|
||||
return; //SPEAK THE LANGUAGE!!!
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
case SRIRCBroadcast:
|
||||
SendMessage("GAME: " + String.Join(" ", splits), ChatMessageType.GameInfo);
|
||||
break;
|
||||
case SRKillProcess:
|
||||
KillMe();
|
||||
break;
|
||||
case SRIRCAdminChannelMessage:
|
||||
SendMessage("RELAY: " + String.Join(" ", splits), ChatMessageType.AdminInfo);
|
||||
break;
|
||||
case SRWorldReboot:
|
||||
TGServerService.WriteInfo("World Rebooted", TGServerService.EventID.WorldReboot);
|
||||
ServerChatCommands = null;
|
||||
ChatConnectivityCheck();
|
||||
lock (CompilerLock)
|
||||
{
|
||||
if (UpdateStaged)
|
||||
{
|
||||
UpdateStaged = false;
|
||||
lock (topicLock)
|
||||
{
|
||||
GameAPIVersion = null; //needs updating
|
||||
}
|
||||
TGServerService.WriteInfo("Staged update applied", TGServerService.EventID.ServerUpdateApplied);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SRAPIVersion:
|
||||
lock (topicLock)
|
||||
{
|
||||
try
|
||||
{
|
||||
GameAPIVersion = new Version(splits[0]);
|
||||
if (!CheckAPIVersionConstraints())
|
||||
throw new Exception();
|
||||
}
|
||||
catch
|
||||
{
|
||||
TGServerService.WriteWarning(String.Format("API version of the game ({0}) is incompatible with the current supported API versions (Min: {1}. Max: {2}). Interop disabled.", splits.Count > 1 ? splits[1] : "NULL", MinAPIVersion, MaxAPIVersion), TGServerService.EventID.APIVersionMismatch);
|
||||
GameAPIVersion = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
//This needs to be done asyncronously otherwise DD won't be able to process it, because it's waiting for THIS THREAD to return
|
||||
ThreadPool.QueueUserWorkItem(_ => SendCommand(SCAPICompat));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public string SendCommand(string cmd)
|
||||
{
|
||||
lock (watchdogLock)
|
||||
{
|
||||
if (currentStatus != TGDreamDaemonStatus.Online)
|
||||
return "Error: Server Offline!";
|
||||
return SendTopic(String.Format("serviceCommsKey={0};command={1}", serviceCommsKey, cmd), currentPort);
|
||||
}
|
||||
}
|
||||
|
||||
//requires topiclock
|
||||
bool CheckAPIVersionConstraints()
|
||||
{
|
||||
return !(GameAPIVersion == null || GameAPIVersion < MinAPIVersion || GameAPIVersion > MaxAPIVersion);
|
||||
}
|
||||
|
||||
//Fuckery to diddle byond with the right packet to accept our girth
|
||||
string SendTopic(string topicdata, ushort port)
|
||||
{
|
||||
lock (topicLock) {
|
||||
if (!CheckAPIVersionConstraints())
|
||||
return "Incompatible API!";
|
||||
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)
|
||||
returnedString = raw_string.Substring(5, raw_string.Length - 5).Trim();
|
||||
}
|
||||
catch
|
||||
{
|
||||
returnedString = "Topic recieve error!";
|
||||
}
|
||||
finally
|
||||
{
|
||||
topicSender.Shutdown(SocketShutdown.Both);
|
||||
}
|
||||
|
||||
return returnedString;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return "Topic delivery failed!";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Every time we make a new DD process we generate a new comms key for security
|
||||
//It's in world.params['server_service']
|
||||
void GenCommsKey()
|
||||
{
|
||||
var charsToRemove = new string[] { "!", "@", "#", "$", "%", "^", "&", "*", "(", ")", "_", "-", "+", "=", "[", "{", "]", "}", ";", ":", "<", ">", "|", ".", "/", "?" };
|
||||
serviceCommsKey = String.Empty;
|
||||
do {
|
||||
var tmp = Membership.GeneratePassword(CommsKeyLen, 0);
|
||||
foreach (var c in charsToRemove)
|
||||
tmp = tmp.Replace(c, String.Empty);
|
||||
serviceCommsKey += tmp;
|
||||
} while (serviceCommsKey.Length < CommsKeyLen);
|
||||
serviceCommsKey = serviceCommsKey.Substring(0, CommsKeyLen);
|
||||
TGServerService.WriteInfo("Service Comms Key set to: " + serviceCommsKey, TGServerService.EventID.CommsKeySet);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool InteropMessage(string command)
|
||||
{
|
||||
try
|
||||
{
|
||||
HandleCommand(command);
|
||||
return true;
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
TGServerService.WriteWarning(String.Format("Handle command for \"{0}\" failed: {1}", command, e.ToString()), TGServerService.EventID.InteropCallException);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Web.Script.Serialization;
|
||||
using System.Web.Security;
|
||||
using TGServiceInterface;
|
||||
|
||||
namespace TGServerService
|
||||
{
|
||||
//handles talking between the world and us
|
||||
partial class TGStationServer : ITGInterop
|
||||
{
|
||||
|
||||
object topicLock = new object();
|
||||
const int CommsKeyLen = 64;
|
||||
string serviceCommsKey; //regenerated every DD restart
|
||||
|
||||
//range of supported api versions
|
||||
readonly Version MinAPIVersion = new Version("3.1.0.0");
|
||||
readonly Version MaxAPIVersion = new Version("3.1.0.99");
|
||||
Version GameAPIVersion;
|
||||
|
||||
//See code/modules/server_tools/server_tools.dm for command switch
|
||||
const string SCHardReboot = "hard_reboot"; //requests that dreamdaemon restarts when the round ends
|
||||
const string SCGracefulShutdown = "graceful_shutdown"; //requests that dreamdaemon stops when the round ends
|
||||
const string SCWorldAnnounce = "world_announce"; //sends param 'message' to the world
|
||||
const string SCListCustomCommands = "list_custom_commands"; //Get a list of commands supported by the server
|
||||
const string SCAPICompat = "api_compat"; //Tells the server we understand each other
|
||||
const string SCPlayerCount = "client_count"; //Gets the number of connected clients
|
||||
|
||||
const string SRKillProcess = "killme";
|
||||
const string SRIRCBroadcast = "irc";
|
||||
const string SRIRCAdminChannelMessage = "send2irc";
|
||||
const string SRWorldReboot = "worldreboot";
|
||||
const string SRAPIVersion = "api_ver";
|
||||
|
||||
const string CCPHelpText = "help_text";
|
||||
const string CCPAdminOnly = "admin_only";
|
||||
const string CCPRequiredParameters = "required_parameters";
|
||||
|
||||
List<Command> ServerChatCommands;
|
||||
|
||||
void LoadServerChatCommands()
|
||||
{
|
||||
if (DaemonStatus() != TGDreamDaemonStatus.Online)
|
||||
return;
|
||||
var json = SendCommand(SCListCustomCommands);
|
||||
if (String.IsNullOrWhiteSpace(json))
|
||||
return;
|
||||
List<Command> tmp = new List<Command>();
|
||||
try
|
||||
{
|
||||
foreach(var I in new JavaScriptSerializer().Deserialize<IDictionary<string, IDictionary<string, object>>>(json))
|
||||
tmp.Add(new ServerChatCommand(I.Key, (string)I.Value[CCPHelpText], ((int)I.Value[CCPAdminOnly]) == 1, (int)I.Value[CCPRequiredParameters]));
|
||||
ServerChatCommands = tmp;
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
//raw command string sent here via world.ExportService
|
||||
void HandleCommand(string cmd)
|
||||
{
|
||||
var splits = new List<string>(cmd.Split(' '));
|
||||
cmd = splits[0];
|
||||
splits.RemoveAt(0);
|
||||
|
||||
bool APIValid;
|
||||
lock (topicLock)
|
||||
{
|
||||
APIValid = CheckAPIVersionConstraints();
|
||||
}
|
||||
|
||||
if (!APIValid && cmd != SRAPIVersion)
|
||||
return; //SPEAK THE LANGUAGE!!!
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
case SRIRCBroadcast:
|
||||
SendMessage("GAME: " + String.Join(" ", splits), ChatMessageType.GameInfo);
|
||||
break;
|
||||
case SRKillProcess:
|
||||
KillMe();
|
||||
break;
|
||||
case SRIRCAdminChannelMessage:
|
||||
SendMessage("RELAY: " + String.Join(" ", splits), ChatMessageType.AdminInfo);
|
||||
break;
|
||||
case SRWorldReboot:
|
||||
TGServerService.WriteInfo("World Rebooted", TGServerService.EventID.WorldReboot);
|
||||
ServerChatCommands = null;
|
||||
ChatConnectivityCheck();
|
||||
lock (CompilerLock)
|
||||
{
|
||||
if (UpdateStaged)
|
||||
{
|
||||
UpdateStaged = false;
|
||||
lock (topicLock)
|
||||
{
|
||||
GameAPIVersion = null; //needs updating
|
||||
}
|
||||
TGServerService.WriteInfo("Staged update applied", TGServerService.EventID.ServerUpdateApplied);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SRAPIVersion:
|
||||
lock (topicLock)
|
||||
{
|
||||
try
|
||||
{
|
||||
GameAPIVersion = new Version(splits[0]);
|
||||
if (!CheckAPIVersionConstraints())
|
||||
throw new Exception();
|
||||
}
|
||||
catch
|
||||
{
|
||||
TGServerService.WriteWarning(String.Format("API version of the game ({0}) is incompatible with the current supported API versions (Min: {1}. Max: {2}). Interop disabled.", splits.Count > 1 ? splits[1] : "NULL", MinAPIVersion, MaxAPIVersion), TGServerService.EventID.APIVersionMismatch);
|
||||
GameAPIVersion = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
//This needs to be done asyncronously otherwise DD won't be able to process it, because it's waiting for THIS THREAD to return
|
||||
ThreadPool.QueueUserWorkItem(_ => SendCommand(SCAPICompat));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public string SendCommand(string cmd)
|
||||
{
|
||||
lock (watchdogLock)
|
||||
{
|
||||
if (currentStatus != TGDreamDaemonStatus.Online)
|
||||
return "Error: Server Offline!";
|
||||
return SendTopic(String.Format("serviceCommsKey={0};command={1}", serviceCommsKey, cmd), currentPort);
|
||||
}
|
||||
}
|
||||
|
||||
public int PlayerCount()
|
||||
{
|
||||
try
|
||||
{
|
||||
return Convert.ToInt32(SendCommand(SCPlayerCount));
|
||||
}
|
||||
catch
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
//requires topiclock
|
||||
bool CheckAPIVersionConstraints()
|
||||
{
|
||||
return !(GameAPIVersion == null || GameAPIVersion < MinAPIVersion || GameAPIVersion > MaxAPIVersion);
|
||||
}
|
||||
|
||||
//Fuckery to diddle byond with the right packet to accept our girth
|
||||
string SendTopic(string topicdata, ushort port)
|
||||
{
|
||||
lock (topicLock) {
|
||||
if (!CheckAPIVersionConstraints())
|
||||
return "Incompatible API!";
|
||||
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)
|
||||
returnedString = raw_string.Substring(5, raw_string.Length - 5).Trim();
|
||||
}
|
||||
catch
|
||||
{
|
||||
returnedString = "Topic recieve error!";
|
||||
}
|
||||
finally
|
||||
{
|
||||
topicSender.Shutdown(SocketShutdown.Both);
|
||||
}
|
||||
|
||||
return returnedString;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return "Topic delivery failed!";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Every time we make a new DD process we generate a new comms key for security
|
||||
//It's in world.params['server_service']
|
||||
void GenCommsKey()
|
||||
{
|
||||
var charsToRemove = new string[] { "!", "@", "#", "$", "%", "^", "&", "*", "(", ")", "_", "-", "+", "=", "[", "{", "]", "}", ";", ":", "<", ">", "|", ".", "/", "?" };
|
||||
serviceCommsKey = String.Empty;
|
||||
do {
|
||||
var tmp = Membership.GeneratePassword(CommsKeyLen, 0);
|
||||
foreach (var c in charsToRemove)
|
||||
tmp = tmp.Replace(c, String.Empty);
|
||||
serviceCommsKey += tmp;
|
||||
} while (serviceCommsKey.Length < CommsKeyLen);
|
||||
serviceCommsKey = serviceCommsKey.Substring(0, CommsKeyLen);
|
||||
TGServerService.WriteInfo("Service Comms Key set to: " + serviceCommsKey, TGServerService.EventID.CommsKeySet);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool InteropMessage(string command)
|
||||
{
|
||||
try
|
||||
{
|
||||
HandleCommand(command);
|
||||
return true;
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
TGServerService.WriteWarning(String.Format("Handle command for \"{0}\" failed: {1}", command, e.ToString()), TGServerService.EventID.InteropCallException);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+189
-182
@@ -1,182 +1,189 @@
|
||||
using System.ServiceModel;
|
||||
|
||||
namespace TGServiceInterface
|
||||
{
|
||||
/// <summary>
|
||||
/// The status of the DD instance
|
||||
/// </summary>
|
||||
public enum TGDreamDaemonStatus
|
||||
{
|
||||
/// <summary>
|
||||
/// Server is not running
|
||||
/// </summary>
|
||||
Offline,
|
||||
/// <summary>
|
||||
/// Server is being rebooted
|
||||
/// </summary>
|
||||
HardRebooting,
|
||||
/// <summary>
|
||||
/// Server is running
|
||||
/// </summary>
|
||||
Online,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// DreamDaemon's security level
|
||||
/// </summary>
|
||||
public enum TGDreamDaemonSecurity
|
||||
{
|
||||
/// <summary>
|
||||
/// Server is unrestricted in terms of file access and shell commands
|
||||
/// </summary>
|
||||
Trusted = 0,
|
||||
/// <summary>
|
||||
/// Server will not be able to run shell commands or access files outside it's working directory
|
||||
/// </summary>
|
||||
Safe,
|
||||
/// <summary>
|
||||
/// Server will not be able to run shell commands or access anything but temporary files
|
||||
/// </summary>
|
||||
Ultrasafe
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Interface for managing the actual BYOND game server
|
||||
/// </summary>
|
||||
[ServiceContract]
|
||||
public interface ITGDreamDaemon
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the status of DreamDaemon
|
||||
/// </summary>
|
||||
/// <returns>The appropriate TGDreamDaemonStatus</returns>
|
||||
[OperationContract]
|
||||
TGDreamDaemonStatus DaemonStatus();
|
||||
|
||||
/// <summary>
|
||||
/// Returns a human readable string of the current server status
|
||||
/// </summary>
|
||||
/// <param name="includeMetaInfo">If true, the status will include the server's current visibility and security levels</param>
|
||||
/// <returns>A human readable string of the current server status</returns>
|
||||
[OperationContract]
|
||||
string StatusString(bool includeMetaInfo);
|
||||
|
||||
/// <summary>
|
||||
/// Check if a call to Start will fail
|
||||
/// Of course, be aware of race conditions with other control panels
|
||||
/// </summary>
|
||||
/// <returns>returns the error that would occur, null otherwise</returns>
|
||||
[OperationContract]
|
||||
string CanStart();
|
||||
|
||||
/// <summary>
|
||||
/// Starts the server if it isn't running
|
||||
/// </summary>
|
||||
/// <returns>null on success or error message on failure</returns>
|
||||
[OperationContract]
|
||||
string Start();
|
||||
|
||||
/// <summary>
|
||||
/// Immediately kills the server
|
||||
/// </summary>
|
||||
/// <returns>null on success or error message on failure</returns>
|
||||
[OperationContract]
|
||||
string Stop();
|
||||
|
||||
/// <summary>
|
||||
/// Immediately kills and restarts the server
|
||||
/// </summary>
|
||||
/// <returns>null on success or error message on failure</returns>
|
||||
[OperationContract]
|
||||
string Restart();
|
||||
|
||||
/// <summary>
|
||||
/// Restart the server after the currently running round ends
|
||||
/// Has no effect if the server isn't running
|
||||
/// </summary>
|
||||
[OperationContract]
|
||||
void RequestRestart();
|
||||
|
||||
/// <summary>
|
||||
/// Stop the server after the currently running round ends
|
||||
/// Has no effect if the server isn't running
|
||||
/// </summary>
|
||||
[OperationContract]
|
||||
void RequestStop();
|
||||
|
||||
/// <summary>
|
||||
/// Get the configured (not running) security level
|
||||
/// </summary>
|
||||
/// <returns>The configured (not running) security level</returns>
|
||||
[OperationContract]
|
||||
TGDreamDaemonSecurity SecurityLevel();
|
||||
|
||||
/// <summary>
|
||||
/// Sets the security level of the server. Requires reboot to apply
|
||||
/// Implies a call to RequestRestart()
|
||||
/// note that anything higher than Trusted will disable interop from DD
|
||||
/// </summary>
|
||||
/// <param name="level">The new security level</param>
|
||||
/// <returns>True if the change was immediately applied, false if a graceful restart was queued</returns>
|
||||
[OperationContract]
|
||||
bool SetSecurityLevel(TGDreamDaemonSecurity level);
|
||||
|
||||
/// <summary>
|
||||
/// Get the configured port. Not necessarily the running port if it has since changed
|
||||
/// </summary>
|
||||
/// <returns>The configured port</returns>
|
||||
[OperationContract]
|
||||
ushort Port();
|
||||
|
||||
/// <summary>
|
||||
/// Set the port to host DD on. Requires reboot to apply
|
||||
/// Implies a call to RequestRestart()
|
||||
/// </summary>
|
||||
/// <param name="new_port">The new port</param>
|
||||
[OperationContract]
|
||||
void SetPort(ushort new_port);
|
||||
|
||||
/// <summary>
|
||||
/// Check if the watchdog will start when the service starts
|
||||
/// </summary>
|
||||
/// <returns>true if autostart is enabled, false otherwise</returns>
|
||||
[OperationContract]
|
||||
bool Autostart();
|
||||
|
||||
/// <summary>
|
||||
/// Set the autostart config
|
||||
/// </summary>
|
||||
/// <param name="on">true to start the watchdog with the service, false otherwise</param>
|
||||
[OperationContract]
|
||||
void SetAutostart(bool on);
|
||||
|
||||
/// <summary>
|
||||
/// Check if the byond webclient is currently enabled for the server
|
||||
/// </summary>
|
||||
/// <returns>true if the webclient is enabled, false otherwise</returns>
|
||||
[OperationContract]
|
||||
bool Webclient();
|
||||
|
||||
/// <summary>
|
||||
/// Set the webclient config. Calls <see cref="RequestRestart"/>
|
||||
/// </summary>
|
||||
/// <param name="on">true to enable the byond webclient for the server, false otherwise</param>
|
||||
[OperationContract]
|
||||
void SetWebclient(bool on);
|
||||
|
||||
/// <summary>
|
||||
/// Checks if a server stop has bee requested
|
||||
/// </summary>
|
||||
/// <returns>true if RequestStop has been called since the last server start, false otherwise</returns>
|
||||
[OperationContract]
|
||||
bool ShutdownInProgress();
|
||||
|
||||
/// <summary>
|
||||
/// Sends a message to everyone on the server
|
||||
/// </summary>
|
||||
/// <param name="msg">The message to send</param>
|
||||
/// <returns>null on success, error message on failure</returns>
|
||||
[OperationContract]
|
||||
string WorldAnnounce(string msg);
|
||||
}
|
||||
}
|
||||
using System.ServiceModel;
|
||||
|
||||
namespace TGServiceInterface
|
||||
{
|
||||
/// <summary>
|
||||
/// The status of the DD instance
|
||||
/// </summary>
|
||||
public enum TGDreamDaemonStatus
|
||||
{
|
||||
/// <summary>
|
||||
/// Server is not running
|
||||
/// </summary>
|
||||
Offline,
|
||||
/// <summary>
|
||||
/// Server is being rebooted
|
||||
/// </summary>
|
||||
HardRebooting,
|
||||
/// <summary>
|
||||
/// Server is running
|
||||
/// </summary>
|
||||
Online,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// DreamDaemon's security level
|
||||
/// </summary>
|
||||
public enum TGDreamDaemonSecurity
|
||||
{
|
||||
/// <summary>
|
||||
/// Server is unrestricted in terms of file access and shell commands
|
||||
/// </summary>
|
||||
Trusted = 0,
|
||||
/// <summary>
|
||||
/// Server will not be able to run shell commands or access files outside it's working directory
|
||||
/// </summary>
|
||||
Safe,
|
||||
/// <summary>
|
||||
/// Server will not be able to run shell commands or access anything but temporary files
|
||||
/// </summary>
|
||||
Ultrasafe
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Interface for managing the actual BYOND game server
|
||||
/// </summary>
|
||||
[ServiceContract]
|
||||
public interface ITGDreamDaemon
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the status of DreamDaemon
|
||||
/// </summary>
|
||||
/// <returns>The appropriate TGDreamDaemonStatus</returns>
|
||||
[OperationContract]
|
||||
TGDreamDaemonStatus DaemonStatus();
|
||||
|
||||
/// <summary>
|
||||
/// Returns a human readable string of the current server status
|
||||
/// </summary>
|
||||
/// <param name="includeMetaInfo">If true, the status will include the server's current visibility and security levels</param>
|
||||
/// <returns>A human readable string of the current server status</returns>
|
||||
[OperationContract]
|
||||
string StatusString(bool includeMetaInfo);
|
||||
|
||||
/// <summary>
|
||||
/// Check if a call to Start will fail
|
||||
/// Of course, be aware of race conditions with other control panels
|
||||
/// </summary>
|
||||
/// <returns>returns the error that would occur, null otherwise</returns>
|
||||
[OperationContract]
|
||||
string CanStart();
|
||||
|
||||
/// <summary>
|
||||
/// Starts the server if it isn't running
|
||||
/// </summary>
|
||||
/// <returns>null on success or error message on failure</returns>
|
||||
[OperationContract]
|
||||
string Start();
|
||||
|
||||
/// <summary>
|
||||
/// Immediately kills the server
|
||||
/// </summary>
|
||||
/// <returns>null on success or error message on failure</returns>
|
||||
[OperationContract]
|
||||
string Stop();
|
||||
|
||||
/// <summary>
|
||||
/// Immediately kills and restarts the server
|
||||
/// </summary>
|
||||
/// <returns>null on success or error message on failure</returns>
|
||||
[OperationContract]
|
||||
string Restart();
|
||||
|
||||
/// <summary>
|
||||
/// Restart the server after the currently running round ends
|
||||
/// Has no effect if the server isn't running
|
||||
/// </summary>
|
||||
[OperationContract]
|
||||
void RequestRestart();
|
||||
|
||||
/// <summary>
|
||||
/// Stop the server after the currently running round ends
|
||||
/// Has no effect if the server isn't running
|
||||
/// </summary>
|
||||
[OperationContract]
|
||||
void RequestStop();
|
||||
|
||||
/// <summary>
|
||||
/// Get the configured (not running) security level
|
||||
/// </summary>
|
||||
/// <returns>The configured (not running) security level</returns>
|
||||
[OperationContract]
|
||||
TGDreamDaemonSecurity SecurityLevel();
|
||||
|
||||
/// <summary>
|
||||
/// Sets the security level of the server. Requires reboot to apply
|
||||
/// Implies a call to RequestRestart()
|
||||
/// note that anything higher than Trusted will disable interop from DD
|
||||
/// </summary>
|
||||
/// <param name="level">The new security level</param>
|
||||
/// <returns>True if the change was immediately applied, false if a graceful restart was queued</returns>
|
||||
[OperationContract]
|
||||
bool SetSecurityLevel(TGDreamDaemonSecurity level);
|
||||
|
||||
/// <summary>
|
||||
/// Get the configured port. Not necessarily the running port if it has since changed
|
||||
/// </summary>
|
||||
/// <returns>The configured port</returns>
|
||||
[OperationContract]
|
||||
ushort Port();
|
||||
|
||||
/// <summary>
|
||||
/// Set the port to host DD on. Requires reboot to apply
|
||||
/// Implies a call to RequestRestart()
|
||||
/// </summary>
|
||||
/// <param name="new_port">The new port</param>
|
||||
[OperationContract]
|
||||
void SetPort(ushort new_port);
|
||||
|
||||
/// <summary>
|
||||
/// Check if the watchdog will start when the service starts
|
||||
/// </summary>
|
||||
/// <returns>true if autostart is enabled, false otherwise</returns>
|
||||
[OperationContract]
|
||||
bool Autostart();
|
||||
|
||||
/// <summary>
|
||||
/// Set the autostart config
|
||||
/// </summary>
|
||||
/// <param name="on">true to start the watchdog with the service, false otherwise</param>
|
||||
[OperationContract]
|
||||
void SetAutostart(bool on);
|
||||
|
||||
/// <summary>
|
||||
/// Check if the byond webclient is currently enabled for the server
|
||||
/// </summary>
|
||||
/// <returns>true if the webclient is enabled, false otherwise</returns>
|
||||
[OperationContract]
|
||||
bool Webclient();
|
||||
|
||||
/// <summary>
|
||||
/// Set the webclient config. Calls <see cref="RequestRestart"/>
|
||||
/// </summary>
|
||||
/// <param name="on">true to enable the byond webclient for the server, false otherwise</param>
|
||||
[OperationContract]
|
||||
void SetWebclient(bool on);
|
||||
|
||||
/// <summary>
|
||||
/// Checks if a server stop has bee requested
|
||||
/// </summary>
|
||||
/// <returns>true if RequestStop has been called since the last server start, false otherwise</returns>
|
||||
[OperationContract]
|
||||
bool ShutdownInProgress();
|
||||
|
||||
/// <summary>
|
||||
/// Sends a message to everyone on the server
|
||||
/// </summary>
|
||||
/// <param name="msg">The message to send</param>
|
||||
/// <returns>null on success, error message on failure</returns>
|
||||
[OperationContract]
|
||||
string WorldAnnounce(string msg);
|
||||
|
||||
/// <summary>
|
||||
/// Returns the number of connected players. Requires game to use API version >= 3.1.0.1
|
||||
/// </summary>
|
||||
/// <returns>The number of connected players or -1 on error</returns>
|
||||
[OperationContract]
|
||||
int PlayerCount();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user