From 7bf848dad95c2fd582dd64e649de52e29ad16175 Mon Sep 17 00:00:00 2001 From: Jordan Brown Date: Wed, 22 Apr 2020 01:07:40 -0400 Subject: [PATCH] Finish DMAPI v5 --- src/DMAPI/tgs/core/core.dm | 6 +- src/DMAPI/tgs/core/datum.dm | 2 +- src/DMAPI/tgs/includes.dm | 31 ++ src/DMAPI/tgs/v5/_defines.dm | 46 ++- src/DMAPI/tgs/v5/api.dm | 295 ++++++++---------- src/DMAPI/tgs/v5/commands.dm | 34 +- src/DMAPI/tgs/v5/undef.dm | 114 +++++++ .../Interop/Bridge/BridgeResponse.cs | 2 +- .../Components/Interop/DMApiConstants.cs | 2 +- tests/DMAPI/Test.dm | 7 + 10 files changed, 348 insertions(+), 191 deletions(-) create mode 100644 src/DMAPI/tgs/v5/undef.dm diff --git a/src/DMAPI/tgs/core/core.dm b/src/DMAPI/tgs/core/core.dm index 674af2bf77..64226796d7 100644 --- a/src/DMAPI/tgs/core/core.dm +++ b/src/DMAPI/tgs/core/core.dm @@ -30,6 +30,8 @@ switch(version.minor) if(0) api_datum = /datum/tgs_api/v4 + if(5) + api_datum = /datum/tgs_api/v5 var/datum/tgs_version/max_api_version = TgsMaximumAPIVersion(); if(version.suite != null && version.minor != null && version.patch != null && version.deprecated_patch != null && version.deprefixed_parameter > max_api_version.deprefixed_parameter) @@ -51,10 +53,10 @@ TGS_ERROR_LOG("Failed to activate API!") /world/TgsMaximumAPIVersion() - return new /datum/tgs_version("4.0.x.x") + return new /datum/tgs_version("5.x.x") /world/TgsMinimumAPIVersion() - return new /datum/tgs_version("3.2.0.0") + return new /datum/tgs_version("3.2.x") /world/TgsInitializationComplete() var/datum/tgs_api/api = TGS_READ_GLOBAL(tgs) diff --git a/src/DMAPI/tgs/core/datum.dm b/src/DMAPI/tgs/core/datum.dm index fb2508059a..3adecbb556 100644 --- a/src/DMAPI/tgs/core/datum.dm +++ b/src/DMAPI/tgs/core/datum.dm @@ -8,7 +8,7 @@ TGS_DEFINE_AND_SET_GLOBAL(tgs, null) src.version = version /datum/tgs_api/latest - parent_type = /datum/tgs_api/v4 + parent_type = /datum/tgs_api/v5 TGS_PROTECT_DATUM(/datum/tgs_api) diff --git a/src/DMAPI/tgs/includes.dm b/src/DMAPI/tgs/includes.dm index 23fe376bf6..7723d9c2c8 100644 --- a/src/DMAPI/tgs/includes.dm +++ b/src/DMAPI/tgs/includes.dm @@ -2,11 +2,42 @@ #include "core\core.dm" #include "core\datum.dm" #include "core\tgs_version.dm" + #ifdef TGS_V3_API #include "v3210\api.dm" #include "v3210\commands.dm" #endif + #include "v4\api.dm" #include "v4\commands.dm" + #include "v5\api.dm" #include "v5\commands.dm" +#include "v5\undef.dm" + +/* +The MIT License + +Copyright (c) 2017 Jordan Brown + +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. +*/ diff --git a/src/DMAPI/tgs/v5/_defines.dm b/src/DMAPI/tgs/v5/_defines.dm index 2f060b3a76..f08e78c091 100644 --- a/src/DMAPI/tgs/v5/_defines.dm +++ b/src/DMAPI/tgs/v5/_defines.dm @@ -1,5 +1,6 @@ #define DMAPI5_PARAM_RUNTIME_INFORMATION_FILE "tgs_json" -#define DMAPI5_TOPIC_DATA "data" +#define DMAPI5_BRIDGE_DATA "data" +#define DMAPI5_TOPIC_DATA "tgs_data" #define DMAPI5_BRIDGE_COMMAND_PORT_UPDATE 0 #define DMAPI5_BRIDGE_COMMAND_VALIDATE 1 @@ -9,6 +10,7 @@ #define DMAPI5_BRIDGE_COMMAND_CHAT_SEND 5 #define DMAPI5_PARAMETER_ACCESS_IDENTIFIER "accessIdentifier" +#define DMAPI5_RESPONSE_ERROR_MESSAGE "errorMessage" #define DMAPI5_BRIDGE_PARAMETER_COMMAND_TYPE "commandType" #define DMAPI5_BRIDGE_PARAMETER_CURRENT_PORT "currentPort" @@ -16,8 +18,7 @@ #define DMAPI5_BRIDGE_PARAMETER_CHAT_MESSAGE "chatMessage" #define DMAPI5_BRIDGE_PARAMETER_MINIMUM_SECURITY_LEVEL "minimumSecurityLevel" -#define DMAPI5_BRIDGE_RESPONSE_ERROR_MESSAGE "errorMessage" -#define DMAPI5_BRIDGE_RESPONSE_ERROR_NEW_PORT "newPort" +#define DMAPI5_BRIDGE_RESPONSE_NEW_PORT "newPort" #define DMAPI5_CHAT_MESSAGE_TEXT "text" #define DMAPI5_CHAT_MESSAGE_CHANNEL_IDS "channelIds" @@ -29,6 +30,9 @@ #define DMAPI5_RUNTIME_INFORMATION_INSTANCE_NAME "instanceName" #define DMAPI5_RUNTIME_INFORMATION_REVISION "revision" #define DMAPI5_RUNTIME_INFORMATION_TEST_MERGES "testMerges" +#define DMAPI5_RUNTIME_INFORMATION_SECURITY_LEVEL "securityLevel" +#define DMAPI5_RUNTIME_INFORMATION_CHAT_COMMANDS_JSON "chatCommandsJson" +#define DMAPI5_RUNTIME_INFORMATION_CHAT_CHANNELS_JSON "chatChannelsJson" #define DMAPI5_TEST_MERGE_TIME_MERGED "timeMerged" #define DMAPI5_TEST_MERGE_REVISION "revision" @@ -36,6 +40,9 @@ #define DMAPI5_TEST_MERGE_BODY_AT_MERGE "bodyAtMerge" #define DMAPI5_TEST_MERGE_URL "url" #define DMAPI5_TEST_MERGE_AUTHOR "author" +#define DMAPI5_TEST_MERGE_NUMBER "number" +#define DMAPI5_TEST_MERGE_PULL_REQUEST_REVISION "pullRequestRevision" +#define DMAPI5_TEST_MERGE_COMMENT "comment" #define DMAPI5_CHAT_COMMAND_NAME "name" #define DMAPI5_CHAT_COMMAND_PARAMS "params" @@ -57,7 +64,6 @@ #define DMAPI5_TOPIC_PARAMETER_NEW_REBOOT_STATE "newRebootState" #define DMAPI5_TOPIC_PARAMETER_NEW_INSTANCE_NAME "newInstanceName" -#define DMAPI5_TOPIC_RESPONSE_ERROR_MESSAGE "errorMessage" #define DMAPI5_TOPIC_RESPONSE_COMMAND_RESPONSE_MESSAGE "commandResponseMessage" #define DMAPI5_TOPIC_RESPONSE_CHAT_RESPONSES "chatResponses" @@ -74,5 +80,35 @@ #define DMAPI5_CHAT_CHANNEL_CONNECTION_NAME "connectionName" #define DMAPI5_CHAT_CHANNEL_IS_ADMIN_CHANNEL "isAdminChannel" #define DMAPI5_CHAT_CHANNEL_IS_PRIVATE_CHANNEL "isPrivateChannel" -#define DMAPI5_CHAT_CHANNEL_IS_WATCHDOG_CHANNEL "isWatchdogChannel" #define DMAPI5_CHAT_CHANNEL_TAG "tag" + +#define DMAPI5_CUSTOM_CHAT_COMMAND_NAME "name" +#define DMAPI5_CUSTOM_CHAT_COMMAND_HELP_TEXT "helpText" +#define DMAPI5_CUSTOM_CHAT_COMMAND_ADMIN_ONLY "adminOnly" + +/* +The MIT License + +Copyright (c) 2020 Jordan Brown + +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. +*/ diff --git a/src/DMAPI/tgs/v5/api.dm b/src/DMAPI/tgs/v5/api.dm index 96a037644a..9f8fb3abb8 100644 --- a/src/DMAPI/tgs/v5/api.dm +++ b/src/DMAPI/tgs/v5/api.dm @@ -1,30 +1,3 @@ -#define TGS4_PARAM_DEPLOYMENT_INFORMATION_FILE "tgs_json" -#define TGS4_TOPIC_DATA "data" - -#define TGS4_INTEROP_ACCESS_IDENTIFIER "tgs_tok" - -#define TGS4_RESPONSE_SUCCESS "tgs_succ" - -#define TGS4_TOPIC_CHANGE_PORT "tgs_port" -#define TGS4_TOPIC_CHANGE_REBOOT_MODE "tgs_rmode" -#define TGS4_TOPIC_CHAT_COMMAND "tgs_chat_comm" -#define TGS4_TOPIC_EVENT "tgs_event" -#define TGS4_TOPIC_INTEROP_RESPONSE "tgs_interop" - -#define TGS4_COMM_NEW_PORT "tgs_new_port" -#define TGS4_COMM_VALIDATE "tgs_validate" -#define TGS4_COMM_SERVER_PRIMED "tgs_prime" -#define TGS4_COMM_WORLD_REBOOT "tgs_reboot" -#define TGS4_COMM_END_PROCESS "tgs_kill" -#define TGS4_COMM_CHAT "tgs_chat_send" - -#define TGS4_PARAMETER_COMMAND "tgs_com" -#define TGS4_PARAMETER_DATA "tgs_data" - -#define TGS4_PORT_CRITFAIL_MESSAGE " Must exit to let watchdog reboot..." - -#define EXPORT_TIMEOUT_DS 200 - /datum/tgs_api/v5 var/access_identifier var/instance_name @@ -33,8 +6,7 @@ var/chat_commands_json_path var/reboot_mode = TGS_REBOOT_MODE_NORMAL var/security_level - - var/requesting_new_port = FALSE + var/server_port var/list/intercepted_message_queue @@ -47,13 +19,13 @@ var/export_lock = FALSE -/datum/tgs_api/v4/ApiVersion() +/datum/tgs_api/v5/ApiVersion() return "5.0.0" -/datum/tgs_api/v4/OnWorldNew(datum/tgs_event_handler/event_handler, minimum_required_security_level) - json_path = world.params[TGS4_PARAM_INFO_JSON] +/datum/tgs_api/v5/OnWorldNew(datum/tgs_event_handler/event_handler, minimum_required_security_level) + json_path = world.params[DMAPI5_PARAM_RUNTIME_INFORMATION_FILE] if(!json_path) - TGS_ERROR_LOG("Missing [TGS4_PARAM_INFO_JSON] world parameter!") + TGS_ERROR_LOG("Missing [DMAPI5_PARAM_RUNTIME_INFORMATION_FILE] world parameter!") return var/json_file = file2text(json_path) if(!json_file) @@ -64,181 +36,176 @@ TGS_ERROR_LOG("Failed to decode info json: [json_file]") return - access_identifier = cached_json["accessIdentifier"] - server_commands_json_path = cached_json["serverCommandsJson"] + access_identifier = cached_json[DMAPI5_RUNTIME_INFORMATION_ACCESS_IDENTIFIER] + server_port = cached_json[DMAPI5_RUNTIME_INFORMATION_SERVER_PORT] - if(cached_json["apiValidateOnly"]) - TGS_INFO_LOG("Validating API and exiting...") - Export(TGS4_COMM_VALIDATE, list(TGS4_PARAMETER_DATA = "[minimum_required_security_level]")) + if(cached_json[DMAPI5_RUNTIME_INFORMATION_API_VALIDATE_ONLY]) + TGS_INFO_LOG("Validating DMAPI and exiting...") + Bridge(DMAPI5_BRIDGE_COMMAND_VALIDATE, list(DMAPI5_BRIDGE_PARAMETER_MINIMUM_SECURITY_LEVEL = minimum_required_security_level, DMAPI5_BRIDGE_PARAMETER_VERSION = Version())) del(world) - security_level = cached_json["securityLevel"] - chat_channels_json_path = cached_json["chatChannelsJson"] - chat_commands_json_path = cached_json["chatCommandsJson"] + security_level = cached_json[DMAPI5_RUNTIME_INFORMATION_SECURITY_LEVEL] + chat_channels_json_path = cached_json[DMAPI5_RUNTIME_INFORMATION_CHAT_CHANNELS_JSON] + chat_commands_json_path = cached_json[DMAPI5_RUNTIME_INFORMATION_CHAT_COMMANDS_JSON] src.event_handler = event_handler - instance_name = cached_json["instanceName"] + instance_name = cached_json[DMAPI5_RUNTIME_INFORMATION_INSTANCE_NAME] ListCustomCommands() - var/list/revisionData = cached_json["revision"] + var/list/revisionData = cached_json[DMAPI5_RUNTIME_INFORMATION_REVISION] if(revisionData) cached_revision = new - cached_revision.commit = revisionData["commitSha"] - cached_revision.origin_commit = revisionData["originCommitSha"] + cached_revision.commit = revisionData[DMAPI5_REVISION_INFORMATION_COMMIT_SHA] + cached_revision.origin_commit = revisionData[DMAPI5_REVISION_INFORMATION_ORIGIN_COMMIT_SHA] cached_test_merges = list() - var/list/json = cached_json["testMerges"] + var/list/json = cached_json[DMAPI5_RUNTIME_INFORMATION_TEST_MERGES] for(var/entry in json) var/datum/tgs_revision_information/test_merge/tm = new - tm.time_merged = text2num(entry["timeMerged"]) + tm.time_merged = text2num(entry[DMAPI5_TEST_MERGE_TIME_MERGED]) - var/list/revInfo = entry["revision"] + var/list/revInfo = entry[DMAPI5_TEST_MERGE_REVISION] if(revInfo) - tm.commit = revInfo["commitSha"] - tm.origin_commit = revInfo["originCommitSha"] + tm.commit = revisionData[DMAPI5_REVISION_INFORMATION_COMMIT_SHA] + tm.origin_commit = revisionData[DMAPI5_REVISION_INFORMATION_ORIGIN_COMMIT_SHA] - tm.title = entry["titleAtMerge"] - tm.body = entry["bodyAtMerge"] - tm.url = entry["url"] - tm.author = entry["author"] - tm.number = entry["number"] - tm.pull_request_commit = entry["pullRequestRevision"] - tm.comment = entry["comment"] + tm.title = entry[DMAPI5_TEST_MERGE_TITLE_AT_MERGE] + tm.body = entry[DMAPI5_TEST_MERGE_BODY_AT_MERGE] + tm.url = entry[DMAPI5_TEST_MERGE_URL] + tm.author = entry[DMAPI5_TEST_MERGE_AUTHOR] + tm.number = entry[DMAPI5_TEST_MERGE_NUMBER] + tm.pull_request_commit = entry[DMAPI5_TEST_MERGE_PULL_REQUEST_REVISION] + tm.comment = entry[DMAPI5_TEST_MERGE_COMMENT] cached_test_merges += tm return TRUE -/datum/tgs_api/v4/OnInitializationComplete() - Export(TGS4_COMM_SERVER_PRIMED) +/datum/tgs_api/v5/OnInitializationComplete() + Bridge(TGS4_COMM_SERVER_PRIMED) - var/tgs4_secret_sleep_offline_sauce = 24051994 + var/tgs4_secret_sleep_offline_sauce = 29051994 var/old_sleep_offline = world.sleep_offline world.sleep_offline = tgs4_secret_sleep_offline_sauce sleep(1) if(world.sleep_offline == tgs4_secret_sleep_offline_sauce) //if not someone changed it world.sleep_offline = old_sleep_offline -/datum/tgs_api/v4/OnTopic(T) +/datum/tgs_api/v5/TopicError(message) + return json_encode(list(DMAPI5_RESPONSE_ERROR_MESSAGE = message)) + +/datum/tgs_api/v5/OnTopic(T) var/list/params = params2list(T) - var/their_sCK = params[TGS4_INTEROP_ACCESS_IDENTIFIER] - if(!their_sCK) + var/json = params[DMAPI5_TOPIC_DATA] + if(!json) return FALSE //continue world/Topic + var/list/topic_parameters = json_decode(json) + if(!topic_parameters) + return TopicError("Invalid topic parameters json!"); + + var/their_sCK = topic_parameters[DMAPI5_PARAMETER_ACCESS_IDENTIFIER] if(their_sCK != access_identifier) - return "Invalid comms key!"; + return TopicError("Invalid access identifier!"); - var/command = params[TGS4_PARAMETER_COMMAND] - if(!command) - return "No command!" - - . = TGS4_RESPONSE_SUCCESS + var/command = topic_parameters[DMAPI5_TOPIC_PARAMETER_COMMAND_TYPE] + if(command == null) + return TopicError("No command type!") switch(command) - if(TGS4_TOPIC_CHAT_COMMAND) - var/result = HandleCustomCommand(params[TGS4_PARAMETER_DATA]) - if(result == null) - result = "Error running chat command!" + if(DMAPI5_TOPIC_COMMAND_CHAT_COMMAND) + var/result = HandleCustomCommand(topic_parameters[DMAPI5_TOPIC_PARAMETER_CHAT_COMMAND]) + if(!result) + result = TopicError("Error running chat command!") return result - if(TGS4_TOPIC_EVENT) + if(DMAPI5_TOPIC_COMMAND_EVENT_NOTIFICATION) intercepted_message_queue = list() - var/list/event_notification = json_decode(params[TGS4_PARAMETER_DATA]) - var/list/event_parameters = event_notification["Parameters"] - - var/list/event_call = list(event_notification["Type"]) + var/list/event_notification = topic_parameters[DMAPI5_TOPIC_PARAMETER_EVENT_NOTIFICATION] + var/list/event_parameters = event_notification[DMAPI5_EVENT_NOTIFICATION_PARAMETERS] + var/list/event_call = list(event_notification[DMAPI5_EVENT_NOTIFICATION_TYPE]) if(event_parameters) event_call += event_parameters if(event_handler != null) event_handler.HandleEvent(arglist(event_call)) - . = json_encode(intercepted_message_queue) + var/list/response = list() + if(intercepted_message_queue.len) + response[DMAPI5_TOPIC_RESPONSE_CHAT_RESPONSES] = intercepted_message_queue intercepted_message_queue = null - return - if(TGS4_TOPIC_INTEROP_RESPONSE) - last_interop_response = json_decode(params[TGS4_PARAMETER_DATA]) - return - if(TGS4_TOPIC_CHANGE_PORT) - var/new_port = text2num(params[TGS4_PARAMETER_DATA]) + return json_encode(response) + if(DMAPI5_TOPIC_COMMAND_CHANGE_PORT) + var/new_port = text2num(topic_parameters[DMAPI5_TOPIC_PARAMETER_NEW_PORT]) if (!(new_port > 0)) - return "Invalid port: [new_port]" + return TopicError("Invalid port: [new_port]") //the topic still completes, miraculously //I honestly didn't believe byond could do it if(event_handler != null) event_handler.HandleEvent(TGS_EVENT_PORT_SWAP, new_port) if(!world.OpenPort(new_port)) - return "Port change failed!" - return - if(TGS4_TOPIC_CHANGE_REBOOT_MODE) - var/new_reboot_mode = text2num(params[TGS4_PARAMETER_DATA]) + return TopicError("Port change failed!") + return json_encode(list()) + if(DMAPI5_TOPIC_COMMAND_CHANGE_REBOOT_STATE) + var/new_reboot_mode = text2num(topic_parameters[DMAPI5_TOPIC_PARAMETER_NEW_REBOOT_STATE]) if(event_handler != null) event_handler.HandleEvent(TGS_EVENT_REBOOT_MODE_CHANGE, reboot_mode, new_reboot_mode) reboot_mode = new_reboot_mode - return + return json_encode(list()) + if(DMAPI5_TOPIC_COMMAND_INSTANCE_RENAMED) + var/new_instance_name = topic_parameters[DMAPI5_TOPIC_PARAMETER_NEW_INSTANCE_NAME] + if(!new_instance_name) + return TopicError("Missing new instance name!") + instance_name = new_instance_name + return json_encode(list()) - return "Unknown command: [command]" + return TopicError("Unknown command: [command]") + +/datum/tgs_api/v5/proc/Bridge(command, list/data) + if(command == null) + TGS_ERROR_LOG("Attempted to bridge with no command!") + return -/datum/tgs_api/v4/proc/Export(command, list/data, override_requesting_new_port = FALSE) if(!data) data = list() - data[TGS4_PARAMETER_COMMAND] = command + + data[DMAPI5_BRIDGE_PARAMETER_COMMAND_TYPE] = command + data[DMAPI5_PARAMETER_ACCESS_IDENTIFIER] = access_identifier + var/json = json_encode(data) + var/encoded_json = url_encode(json) + + // This is an infinite sleep until we get a response + var/export_response = world.Export("http://127.0.0.1:[server_port]/Bridge?[DMAPI5_BRIDGE_DATA]=[encoded_json]") + if(!export_response) + TGS_ERROR_LOG("Failed export request: [json]") + return + + var/response_json = file2text(export_result["CONTENT"]) + if(!response_json) + TGS_ERROR_LOG("Failed export request, missing content!") + return + + var/list/bridge_response = json_decode(response_json) + if(!bridge_response) + TGS_ERROR_LOG("Failed export request, bad json: [response_json]") + return - while(requesting_new_port && !override_requesting_new_port) - sleep(1) + var/error = bridge_response[DMAPI5_RESPONSE_ERROR_MESSAGE] + if(error) + TGS_ERROR_LOG("Failed export request, bad request: [error]") + return + + return bridge_response - //we need some port open at this point to facilitate return communication - if(!world.port) - requesting_new_port = TRUE - if(!world.OpenPort(0)) //open any port - TGS_ERROR_LOG("Unable to open random port to retrieve new port![TGS4_PORT_CRITFAIL_MESSAGE]") - del(world) - - //request a new port - export_lock = FALSE - var/list/new_port_json = Export(TGS4_COMM_NEW_PORT, list(TGS4_PARAMETER_DATA = "[world.port]"), TRUE) //stringify this on purpose - - if(!new_port_json) - TGS_ERROR_LOG("No new port response from server![TGS4_PORT_CRITFAIL_MESSAGE]") - del(world) - - var/new_port = new_port_json[TGS4_PARAMETER_DATA] - if(!isnum(new_port) || new_port <= 0) - TGS_ERROR_LOG("Malformed new port json ([json_encode(new_port_json)])![TGS4_PORT_CRITFAIL_MESSAGE]") - del(world) - - if(new_port != world.port && !world.OpenPort(new_port)) - TGS_ERROR_LOG("Unable to open port [new_port]![TGS4_PORT_CRITFAIL_MESSAGE]") - del(world) - requesting_new_port = FALSE - - while(export_lock) - sleep(1) - export_lock = TRUE - - last_interop_response = null - fdel(server_commands_json_path) - text2file(json, server_commands_json_path) - - for(var/I = 0; I < EXPORT_TIMEOUT_DS && !last_interop_response; ++I) - sleep(1) - - if(!last_interop_response) - TGS_ERROR_LOG("Failed to get export result for: [json]") - else - . = last_interop_response - - export_lock = FALSE - -/datum/tgs_api/v4/OnReboot() - var/list/result = Export(TGS4_COMM_WORLD_REBOOT) +/datum/tgs_api/v5/OnReboot() + var/list/result = Bridge(DMAPI5_BRIDGE_COMMAND_REBOOT) if(!result) return //okay so the standard TGS4 proceedure is: right before rebooting change the port to whatever was sent to us in the above json's data parameter - var/port = result[TGS4_PARAMETER_DATA] + var/port = result[DMAPI5_BRIDGE_RESPONSE_NEW_PORT] if(!isnum(port)) return //this is valid, server may just want use to reboot @@ -249,74 +216,74 @@ if(!world.OpenPort(port)) TGS_ERROR_LOG("Unable to set port to [port]!") -/datum/tgs_api/v4/InstanceName() +/datum/tgs_api/v5/InstanceName() return instance_name -/datum/tgs_api/v4/TestMerges() +/datum/tgs_api/v5/TestMerges() return cached_test_merges -/datum/tgs_api/v4/EndProcess() - Export(TGS4_COMM_END_PROCESS) +/datum/tgs_api/v5/EndProcess() + Bridge(DMAPI5_BRIDGE_COMMAND_KILL) -/datum/tgs_api/v4/Revision() +/datum/tgs_api/v5/Revision() return cached_revision -/datum/tgs_api/v4/ChatBroadcast(message, list/channels) +/datum/tgs_api/v5/ChatBroadcast(message, list/channels) var/list/ids if(length(channels)) ids = list() for(var/I in channels) var/datum/tgs_chat_channel/channel = I ids += channel.id - message = list("message" = message, "channelIds" = ids) + message = list(DMAPI5_CHAT_MESSAGE_TEXT = message, DMAPI5_CHAT_MESSAGE_CHANNEL_IDS = ids) if(intercepted_message_queue) intercepted_message_queue += list(message) else - Export(TGS4_COMM_CHAT, message) + Bridge(DMAPI5_BRIDGE_PARAMETER_CHAT_MESSAGE, message) -/datum/tgs_api/v4/ChatTargetedBroadcast(message, admin_only) +/datum/tgs_api/v5/ChatTargetedBroadcast(message, admin_only) var/list/channels = list() for(var/I in ChatChannelInfo()) var/datum/tgs_chat_channel/channel = I if (!channel.is_private_channel && ((channel.is_admin_channel && admin_only) || (!channel.is_admin_channel && !admin_only))) channels += channel.id - message = list("message" = message, "channelIds" = channels) + message = list(DMAPI5_CHAT_MESSAGE_TEXT = message, DMAPI5_CHAT_MESSAGE_CHANNEL_IDS = channels) if(intercepted_message_queue) intercepted_message_queue += list(message) else Export(TGS4_COMM_CHAT, message) -/datum/tgs_api/v4/ChatPrivateMessage(message, datum/tgs_chat_user/user) - message = list("message" = message, "channelIds" = list(user.channel.id)) +/datum/tgs_api/v5/ChatPrivateMessage(message, datum/tgs_chat_user/user) + message = list(DMAPI5_CHAT_MESSAGE_TEXT = message, DMAPI5_CHAT_MESSAGE_CHANNEL_IDS = list(user.channel.id)) if(intercepted_message_queue) intercepted_message_queue += list(message) else Export(TGS4_COMM_CHAT, message) -/datum/tgs_api/v4/ChatChannelInfo() +/datum/tgs_api/v5/ChatChannelInfo() . = list() //no caching cause tgs may change this var/list/json = json_decode(file2text(chat_channels_json_path)) for(var/I in json) . += DecodeChannel(I) -/datum/tgs_api/v4/proc/DecodeChannel(channel_json) +/datum/tgs_api/v5/proc/DecodeChannel(channel_json) var/datum/tgs_chat_channel/channel = new - channel.id = channel_json["id"] - channel.friendly_name = channel_json["friendlyName"] - channel.connection_name = channel_json["connectionName"] - channel.is_admin_channel = channel_json["isAdminChannel"] - channel.is_private_channel = channel_json["isPrivateChannel"] - channel.custom_tag = channel_json["tag"] + channel.id = channel_json[DMAPI5_CHAT_CHANNEL_ID] + channel.friendly_name = channel_json[DMAPI5_CHAT_CHANNEL_FRIENDLY_NAME] + channel.connection_name = channel_json[DMAPI5_CHAT_CHANNEL_CONNECTION_NAME] + channel.is_admin_channel = channel_json[DMAPI5_CHAT_CHANNEL_IS_ADMIN_CHANNEL] + channel.is_private_channel = channel_json[DMAPI5_CHAT_CHANNEL_IS_PRIVATE_CHANNEL] + channel.custom_tag = channel_json[DMAPI5_CHAT_CHANNEL_TAG] return channel -/datum/tgs_api/v4/SecurityLevel() +/datum/tgs_api/v5/SecurityLevel() return security_level /* The MIT License -Copyright (c) 2017 Jordan Brown +Copyright (c) 2020 Jordan Brown Permission is hereby granted, free of charge, to any person obtaining a copy of this software and diff --git a/src/DMAPI/tgs/v5/commands.dm b/src/DMAPI/tgs/v5/commands.dm index 1d9951bc04..a3f27f99af 100644 --- a/src/DMAPI/tgs/v5/commands.dm +++ b/src/DMAPI/tgs/v5/commands.dm @@ -1,4 +1,4 @@ -/datum/tgs_api/v4/proc/ListCustomCommands() +/datum/tgs_api/v5/proc/ListCustomCommands() var/results = list() custom_commands = list() for(var/I in typesof(/datum/tgs_chat_command) - /datum/tgs_chat_command) @@ -12,7 +12,7 @@ var/datum/other = custom_commands[command_name] TGS_ERROR_LOG("Custom commands [other.type] and [I] have the same name (\"[command_name]\"), only [other.type] will be available!") continue - results += list(list("name" = command_name, "help_text" = stc.help_text, "admin_only" = stc.admin_only)) + results += list(list(DMAPI5_CUSTOM_CHAT_COMMAND_NAME = command_name, DMAPI5_CUSTOM_CHAT_COMMAND_HELP_TEXT = stc.help_text, DMAPI5_CUSTOM_CHAT_COMMAND_ADMIN_ONLY = stc.admin_only)) custom_commands[command_name] = stc var/commands_file = chat_commands_json_path @@ -20,31 +20,31 @@ return text2file(json_encode(results), commands_file) -/datum/tgs_api/v4/proc/HandleCustomCommand(command_json) - var/list/data = json_decode(command_json) - var/command = data["command"] - var/user = data["user"] - var/params = data["params"] +/datum/tgs_api/v5/proc/HandleCustomCommand(list/command_json) + var/command = data[DMAPI5_CHAT_COMMAND_NAME] + var/user = data[DMAPI5_CHAT_COMMAND_USER] + var/params = data[DMAPI5_CHAT_COMMAND_PARAMS] var/datum/tgs_chat_user/u = new - u.id = user["id"] - u.friendly_name = user["friendlyName"] - u.mention = user["mention"] - u.channel = DecodeChannel(user["channel"]) + u.id = user[DMAPI5_CHAT_USER_ID] + u.friendly_name = user[DMAPI5_CHAT_USER_FRIENDLY_NAME] + u.mention = user[DMAPI5_CHAT_USER_MENTION] + u.channel = DecodeChannel(user[DMAPI5_CHAT_USER_CHANNEL]) var/datum/tgs_chat_command/sc = custom_commands[command] if(sc) - var/result = sc.Run(u, params) - if(result == null) - result = "" - return result - return "Unknown command: [command]!" + var/textResponse = sc.Run(u, params) + var/list/topic_response = list() + if(textResponse != null) + topic_response(DMAPI5_TOPIC_RESPONSE_COMMAND_RESPONSE_MESSAGE = textResponse) + return topic_response + return TopicError("Unknown custom chat command: [command]!") /* The MIT License -Copyright (c) 2017 Jordan Brown +Copyright (c) 2020 Jordan Brown Permission is hereby granted, free of charge, to any person obtaining a copy of this software and diff --git a/src/DMAPI/tgs/v5/undef.dm b/src/DMAPI/tgs/v5/undef.dm new file mode 100644 index 0000000000..a16ad00e38 --- /dev/null +++ b/src/DMAPI/tgs/v5/undef.dm @@ -0,0 +1,114 @@ +#undef DMAPI5_PARAM_RUNTIME_INFORMATION_FILE +#undef DMAPI5_BRIDGE_DATA +#undef DMAPI5_TOPIC_DATA + +#undef DMAPI5_BRIDGE_COMMAND_PORT_UPDATE +#undef DMAPI5_BRIDGE_COMMAND_VALIDATE +#undef DMAPI5_BRIDGE_COMMAND_PRIME +#undef DMAPI5_BRIDGE_COMMAND_REBOOT +#undef DMAPI5_BRIDGE_COMMAND_KILL +#undef DMAPI5_BRIDGE_COMMAND_CHAT_SEND + +#undef DMAPI5_PARAMETER_ACCESS_IDENTIFIER +#undef DMAPI5_RESPONSE_ERROR_MESSAGE + +#undef DMAPI5_BRIDGE_PARAMETER_COMMAND_TYPE +#undef DMAPI5_BRIDGE_PARAMETER_CURRENT_PORT +#undef DMAPI5_BRIDGE_PARAMETER_VERSION +#undef DMAPI5_BRIDGE_PARAMETER_CHAT_MESSAGE +#undef DMAPI5_BRIDGE_PARAMETER_MINIMUM_SECURITY_LEVEL + +#undef DMAPI5_BRIDGE_RESPONSE_NEW_PORT + +#undef DMAPI5_CHAT_MESSAGE_TEXT +#undef DMAPI5_CHAT_MESSAGE_CHANNEL_IDS + +#undef DMAPI5_RUNTIME_INFORMATION_ACCESS_IDENTIFIER +#undef DMAPI5_RUNTIME_INFORMATION_SERVER_VERSION +#undef DMAPI5_RUNTIME_INFORMATION_SERVER_PORT +#undef DMAPI5_RUNTIME_INFORMATION_API_VALIDATE_ONLY +#undef DMAPI5_RUNTIME_INFORMATION_INSTANCE_NAME +#undef DMAPI5_RUNTIME_INFORMATION_REVISION +#undef DMAPI5_RUNTIME_INFORMATION_TEST_MERGES +#undef DMAPI5_RUNTIME_INFORMATION_SECURITY_LEVEL +#undef DMAPI5_RUNTIME_INFORMATION_CHAT_COMMANDS_JSON +#undef DMAPI5_RUNTIME_INFORMATION_CHAT_CHANNELS_JSON + +#undef DMAPI5_TEST_MERGE_TIME_MERGED +#undef DMAPI5_TEST_MERGE_REVISION +#undef DMAPI5_TEST_MERGE_TITLE_AT_MERGE +#undef DMAPI5_TEST_MERGE_BODY_AT_MERGE +#undef DMAPI5_TEST_MERGE_URL +#undef DMAPI5_TEST_MERGE_AUTHOR +#undef DMAPI5_TEST_MERGE_NUMBER +#undef DMAPI5_TEST_MERGE_PULL_REQUEST_REVISION +#undef DMAPI5_TEST_MERGE_COMMENT + +#undef DMAPI5_CHAT_COMMAND_NAME +#undef DMAPI5_CHAT_COMMAND_PARAMS +#undef DMAPI5_CHAT_COMMAND_USER + +#undef DMAPI5_EVENT_NOTIFICATION_TYPE +#undef DMAPI5_EVENT_NOTIFICATION_PARAMETERS + +#undef DMAPI5_TOPIC_COMMAND_CHAT_COMMAND +#undef DMAPI5_TOPIC_COMMAND_EVENT_NOTIFICATION +#undef DMAPI5_TOPIC_COMMAND_CHANGE_PORT +#undef DMAPI5_TOPIC_COMMAND_CHANGE_REBOOT_STATE +#undef DMAPI5_TOPIC_COMMAND_INSTANCE_RENAMED + +#undef DMAPI5_TOPIC_PARAMETER_COMMAND_TYPE +#undef DMAPI5_TOPIC_PARAMETER_CHAT_COMMAND +#undef DMAPI5_TOPIC_PARAMETER_EVENT_NOTIFICATION +#undef DMAPI5_TOPIC_PARAMETER_NEW_PORT +#undef DMAPI5_TOPIC_PARAMETER_NEW_REBOOT_STATE +#undef DMAPI5_TOPIC_PARAMETER_NEW_INSTANCE_NAME + +#undef DMAPI5_TOPIC_RESPONSE_COMMAND_RESPONSE_MESSAGE +#undef DMAPI5_TOPIC_RESPONSE_CHAT_RESPONSES + +#undef DMAPI5_REVISION_INFORMATION_COMMIT_SHA +#undef DMAPI5_REVISION_INFORMATION_ORIGIN_COMMIT_SHA + +#undef DMAPI5_CHAT_USER_ID +#undef DMAPI5_CHAT_USER_FRIENDLY_NAME +#undef DMAPI5_CHAT_USER_MENTION +#undef DMAPI5_CHAT_USER_CHANNEL + +#undef DMAPI5_CHAT_CHANNEL_ID +#undef DMAPI5_CHAT_CHANNEL_FRIENDLY_NAME +#undef DMAPI5_CHAT_CHANNEL_CONNECTION_NAME +#undef DMAPI5_CHAT_CHANNEL_IS_ADMIN_CHANNEL +#undef DMAPI5_CHAT_CHANNEL_IS_PRIVATE_CHANNEL +#undef DMAPI5_CHAT_CHANNEL_TAG + +#undef DMAPI5_CUSTOM_CHAT_COMMAND_NAME +#undef DMAPI5_CUSTOM_CHAT_COMMAND_HELP_TEXT +#undef DMAPI5_CUSTOM_CHAT_COMMAND_ADMIN_ONLY + +/* +The MIT License + +Copyright (c) 2020 Jordan Brown + +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. +*/ diff --git a/src/Tgstation.Server.Host/Components/Interop/Bridge/BridgeResponse.cs b/src/Tgstation.Server.Host/Components/Interop/Bridge/BridgeResponse.cs index 76801de132..82be2b15f5 100644 --- a/src/Tgstation.Server.Host/Components/Interop/Bridge/BridgeResponse.cs +++ b/src/Tgstation.Server.Host/Components/Interop/Bridge/BridgeResponse.cs @@ -6,7 +6,7 @@ public sealed class BridgeResponse : DMApiResponse { /// - /// The new port for requests. + /// The new port for requests. /// public ushort? NewPort { get; set; } } diff --git a/src/Tgstation.Server.Host/Components/Interop/DMApiConstants.cs b/src/Tgstation.Server.Host/Components/Interop/DMApiConstants.cs index 8a4e69bfb0..339f6984ab 100644 --- a/src/Tgstation.Server.Host/Components/Interop/DMApiConstants.cs +++ b/src/Tgstation.Server.Host/Components/Interop/DMApiConstants.cs @@ -23,7 +23,7 @@ namespace Tgstation.Server.Host.Components.Interop /// /// Parameter json is encoded in for topic requests. /// - public const string TopicData = "data"; + public const string TopicData = "tgs_data"; /// /// The DMAPI being used. diff --git a/tests/DMAPI/Test.dm b/tests/DMAPI/Test.dm index addf8c7603..cefcbe33ff 100644 --- a/tests/DMAPI/Test.dm +++ b/tests/DMAPI/Test.dm @@ -22,3 +22,10 @@ var/list/clients = list() /client/Del() clients -= src return ..() + +/datum/tgs_chat_command/echo + name = "echo" + help_text = "echos input parameters" + +/datum/tgs_chat_command/echo/Run(datum/tgs_chat_user/sender, params) + return "[sender.channel.connection_name]|[sender.channel.friendly_name]|[sender.friendly_name]: [params]"