Skip to content

Commit

Permalink
Update TGS DMAPI
Browse files Browse the repository at this point in the history
  • Loading branch information
tgstation-server committed Feb 29, 2024
1 parent 73637db commit 3643310
Show file tree
Hide file tree
Showing 10 changed files with 111 additions and 9 deletions.
19 changes: 18 additions & 1 deletion code/__DEFINES/tgs.dm
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// tgstation-server DMAPI

#define TGS_DMAPI_VERSION "7.0.2"
#define TGS_DMAPI_VERSION "7.1.1"

// All functions and datums outside this document are subject to change with any version and should not be relied on.

Expand Down Expand Up @@ -50,6 +50,13 @@

#endif

#ifndef TGS_FILE2TEXT_NATIVE
#ifdef file2text
#error Your codebase is re-defining the BYOND proc file2text. The DMAPI requires the native version to read the result of world.Export(). You can fix this by adding "#define TGS_FILE2TEXT_NATIVE file2text" before your override of file2text to allow the DMAPI to use the native version. This will only be used for world.Export(), not regular file accesses
#endif
#define TGS_FILE2TEXT_NATIVE file2text
#endif

// EVENT CODES

/// Before a reboot mode change, extras parameters are the current and new reboot mode enums.
Expand Down Expand Up @@ -490,6 +497,16 @@
/world/proc/TgsChatChannelInfo()
return

/**
* Trigger an event in TGS. Requires TGS version >= 6.3.0. Returns [TRUE] if the event was triggered successfully, [FALSE] otherwise. This function may sleep!
*
* event_name - The name of the event to trigger
* parameters - Optional list of string parameters to pass as arguments to the event script. The first parameter passed to a script will always be the running game's directory followed by these parameters.
* wait_for_completion - If set, this function will not return until the event has run to completion.
*/
/world/proc/TgsTriggerEvent(event_name, list/parameters, wait_for_completion = FALSE)
return

/*
The MIT License
Expand Down
8 changes: 8 additions & 0 deletions code/modules/tgs/core/core.dm
Original file line number Diff line number Diff line change
Expand Up @@ -166,3 +166,11 @@
var/datum/tgs_api/api = TGS_READ_GLOBAL(tgs)
if(api)
return api.Visibility()

/world/TgsTriggerEvent(event_name, list/parameters, wait_for_completion = FALSE)
var/datum/tgs_api/api = TGS_READ_GLOBAL(tgs)
if(api)
if(!istype(parameters, /list))
parameters = list()

return api.TriggerEvent(event_name, parameters, wait_for_completion)
5 changes: 4 additions & 1 deletion code/modules/tgs/core/datum.dm
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ TGS_DEFINE_AND_SET_GLOBAL(tgs, null)
world.sleep_offline = FALSE // https://www.byond.com/forum/post/2894866
del(world)
world.sleep_offline = FALSE // just in case, this is BYOND after all...
sleep(1)
sleep(world.tick_lag)
TGS_DEBUG_LOG("BYOND DIDN'T TERMINATE THE WORLD!!! TICK IS: [world.time], sleep_offline: [world.sleep_offline]")

/datum/tgs_api/latest
Expand Down Expand Up @@ -69,3 +69,6 @@ TGS_PROTECT_DATUM(/datum/tgs_api)

/datum/tgs_api/proc/Visibility()
return TGS_UNIMPLEMENTED

/datum/tgs_api/proc/TriggerEvent(event_name, list/parameters, wait_for_completion)
return FALSE
6 changes: 3 additions & 3 deletions code/modules/tgs/v4/api.dm
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@
var/json = json_encode(data)

while(requesting_new_port && !override_requesting_new_port)
sleep(1)
sleep(world.tick_lag)

//we need some port open at this point to facilitate return communication
if(!world.port)
Expand Down Expand Up @@ -209,15 +209,15 @@
requesting_new_port = FALSE

while(export_lock)
sleep(1)
sleep(world.tick_lag)
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)
sleep(world.tick_lag)

if(!last_interop_response)
TGS_ERROR_LOG("Failed to get export result for: [json]")
Expand Down
2 changes: 1 addition & 1 deletion code/modules/tgs/v5/__interop_version.dm
Original file line number Diff line number Diff line change
@@ -1 +1 @@
"5.8.0"
"5.9.0"
9 changes: 9 additions & 0 deletions code/modules/tgs/v5/_defines.dm
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#define DMAPI5_BRIDGE_COMMAND_KILL 4
#define DMAPI5_BRIDGE_COMMAND_CHAT_SEND 5
#define DMAPI5_BRIDGE_COMMAND_CHUNK 6
#define DMAPI5_BRIDGE_COMMAND_EVENT 7

#define DMAPI5_PARAMETER_ACCESS_IDENTIFIER "accessIdentifier"
#define DMAPI5_PARAMETER_CUSTOM_COMMANDS "customCommands"
Expand All @@ -34,6 +35,7 @@
#define DMAPI5_BRIDGE_PARAMETER_VERSION "version"
#define DMAPI5_BRIDGE_PARAMETER_CHAT_MESSAGE "chatMessage"
#define DMAPI5_BRIDGE_PARAMETER_MINIMUM_SECURITY_LEVEL "minimumSecurityLevel"
#define DMAPI5_BRIDGE_PARAMETER_EVENT_INVOCATION "eventInvocation"

#define DMAPI5_BRIDGE_RESPONSE_NEW_PORT "newPort"
#define DMAPI5_BRIDGE_RESPONSE_RUNTIME_INFORMATION "runtimeInformation"
Expand Down Expand Up @@ -81,6 +83,7 @@
#define DMAPI5_TOPIC_COMMAND_SEND_CHUNK 9
#define DMAPI5_TOPIC_COMMAND_RECEIVE_CHUNK 10
#define DMAPI5_TOPIC_COMMAND_RECEIVE_BROADCAST 11
#define DMAPI5_TOPIC_COMMAND_COMPLETE_EVENT 12

#define DMAPI5_TOPIC_PARAMETER_COMMAND_TYPE "commandType"
#define DMAPI5_TOPIC_PARAMETER_CHAT_COMMAND "chatCommand"
Expand Down Expand Up @@ -116,3 +119,9 @@
#define DMAPI5_CUSTOM_CHAT_COMMAND_NAME "name"
#define DMAPI5_CUSTOM_CHAT_COMMAND_HELP_TEXT "helpText"
#define DMAPI5_CUSTOM_CHAT_COMMAND_ADMIN_ONLY "adminOnly"

#define DMAPI5_EVENT_ID "eventId"

#define DMAPI5_EVENT_INVOCATION_NAME "eventName"
#define DMAPI5_EVENT_INVOCATION_PARAMETERS "parameters"
#define DMAPI5_EVENT_INVOCATION_NOTIFY_COMPLETION "notifyCompletion"
42 changes: 41 additions & 1 deletion code/modules/tgs/v5/api.dm
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
var/chunked_requests = 0
var/list/chunked_topics = list()

var/list/pending_events = list()

var/detached = FALSE

/datum/tgs_api/v5/New()
Expand All @@ -46,6 +48,10 @@

var/datum/tgs_version/api_version = ApiVersion()
version = null // we want this to be the TGS version, not the interop version

// sleep once to prevent an issue where world.Export on the first tick can hang indefinitely
sleep(world.tick_lag)

var/list/bridge_response = Bridge(DMAPI5_BRIDGE_COMMAND_STARTUP, list(DMAPI5_BRIDGE_PARAMETER_MINIMUM_SECURITY_LEVEL = minimum_required_security_level, DMAPI5_BRIDGE_PARAMETER_VERSION = api_version.raw_parameter, DMAPI5_PARAMETER_CUSTOM_COMMANDS = ListCustomCommands(), DMAPI5_PARAMETER_TOPIC_PORT = GetTopicPort()))
if(!istype(bridge_response))
TGS_ERROR_LOG("Failed initial bridge request!")
Expand Down Expand Up @@ -125,7 +131,7 @@
TGS_DEBUG_LOG("RequireInitialBridgeResponse: Starting sleep")
logged = TRUE

sleep(1)
sleep(world.tick_lag)

TGS_DEBUG_LOG("RequireInitialBridgeResponse: Passed")

Expand Down Expand Up @@ -249,6 +255,40 @@
WaitForReattach(TRUE)
return chat_channels.Copy()

/datum/tgs_api/v5/TriggerEvent(event_name, list/parameters, wait_for_completion)
RequireInitialBridgeResponse()
WaitForReattach(TRUE)

if(interop_version.minor < 9)
TGS_WARNING_LOG("Interop version too low for custom events!")
return FALSE

var/str_parameters = list()
for(var/i in parameters)
str_parameters += "[i]"

var/list/response = Bridge(DMAPI5_BRIDGE_COMMAND_EVENT, list(DMAPI5_BRIDGE_PARAMETER_EVENT_INVOCATION = list(DMAPI5_EVENT_INVOCATION_NAME = event_name, DMAPI5_EVENT_INVOCATION_PARAMETERS = str_parameters, DMAPI5_EVENT_INVOCATION_NOTIFY_COMPLETION = wait_for_completion)))
if(!response)
return FALSE

var/event_id = response[DMAPI5_EVENT_ID]
if(!event_id)
return FALSE

TGS_DEBUG_LOG("Created event ID: [event_id]")
if(!wait_for_completion)
return TRUE

TGS_DEBUG_LOG("Waiting for completion of event ID: [event_id]")

while(!pending_events[event_id])
sleep(world.tick_lag)

TGS_DEBUG_LOG("Completed wait on event ID: [event_id]")
pending_events -= event_id

return TRUE

/datum/tgs_api/v5/proc/DecodeChannels(chat_update_json)
TGS_DEBUG_LOG("DecodeChannels()")
var/list/chat_channels_json = chat_update_json[DMAPI5_CHAT_UPDATE_CHANNELS]
Expand Down
7 changes: 5 additions & 2 deletions code/modules/tgs/v5/bridge.dm
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@
if(detached)
// Wait up to one minute
for(var/i in 1 to 600)
sleep(1)
sleep(world.tick_lag)
if(!detached && (!require_channels || length(chat_channels)))
break

Expand All @@ -77,8 +77,11 @@
/datum/tgs_api/v5/proc/PerformBridgeRequest(bridge_request)
WaitForReattach(FALSE)

TGS_DEBUG_LOG("Bridge request start")
// This is an infinite sleep until we get a response
var/export_response = world.Export(bridge_request)
TGS_DEBUG_LOG("Bridge request complete")

if(!export_response)
TGS_ERROR_LOG("Failed bridge request: [bridge_request]")
return
Expand All @@ -88,7 +91,7 @@
TGS_ERROR_LOG("Failed bridge request, missing content!")
return

var/response_json = file2text(content)
var/response_json = TGS_FILE2TEXT_NATIVE(content)
if(!response_json)
TGS_ERROR_LOG("Failed bridge request, failed to load content!")
return
Expand Down
13 changes: 13 additions & 0 deletions code/modules/tgs/v5/topic.dm
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,10 @@
var/list/reattach_response = TopicResponse(error_message)
reattach_response[DMAPI5_PARAMETER_CUSTOM_COMMANDS] = ListCustomCommands()
reattach_response[DMAPI5_PARAMETER_TOPIC_PORT] = GetTopicPort()

for(var/eventId in pending_events)
pending_events[eventId] = TRUE

return reattach_response

if(DMAPI5_TOPIC_COMMAND_SEND_CHUNK)
Expand Down Expand Up @@ -276,6 +280,15 @@
TGS_WORLD_ANNOUNCE(message)
return TopicResponse()

if(DMAPI5_TOPIC_COMMAND_COMPLETE_EVENT)
var/event_id = topic_parameters[DMAPI5_EVENT_ID]
if (!istext(event_id))
return TopicResponse("Invalid or missing [DMAPI5_EVENT_ID]")

TGS_DEBUG_LOG("Completing event ID [event_id]...")
pending_events[event_id] = TRUE
return TopicResponse()

return TopicResponse("Unknown command: [command]")

/datum/tgs_api/v5/proc/WorldBroadcast(message)
Expand Down
9 changes: 9 additions & 0 deletions code/modules/tgs/v5/undefs.dm
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#undef DMAPI5_BRIDGE_COMMAND_KILL
#undef DMAPI5_BRIDGE_COMMAND_CHAT_SEND
#undef DMAPI5_BRIDGE_COMMAND_CHUNK
#undef DMAPI5_BRIDGE_COMMAND_EVENT

#undef DMAPI5_PARAMETER_ACCESS_IDENTIFIER
#undef DMAPI5_PARAMETER_CUSTOM_COMMANDS
Expand All @@ -34,6 +35,7 @@
#undef DMAPI5_BRIDGE_PARAMETER_VERSION
#undef DMAPI5_BRIDGE_PARAMETER_CHAT_MESSAGE
#undef DMAPI5_BRIDGE_PARAMETER_MINIMUM_SECURITY_LEVEL
#undef DMAPI5_BRIDGE_PARAMETER_EVENT_INVOCATION

#undef DMAPI5_BRIDGE_RESPONSE_NEW_PORT
#undef DMAPI5_BRIDGE_RESPONSE_RUNTIME_INFORMATION
Expand Down Expand Up @@ -81,6 +83,7 @@
#undef DMAPI5_TOPIC_COMMAND_SEND_CHUNK
#undef DMAPI5_TOPIC_COMMAND_RECEIVE_CHUNK
#undef DMAPI5_TOPIC_COMMAND_RECEIVE_BROADCAST
#undef DMAPI5_TOPIC_COMMAND_COMPLETE_EVENT

#undef DMAPI5_TOPIC_PARAMETER_COMMAND_TYPE
#undef DMAPI5_TOPIC_PARAMETER_CHAT_COMMAND
Expand Down Expand Up @@ -116,3 +119,9 @@
#undef DMAPI5_CUSTOM_CHAT_COMMAND_NAME
#undef DMAPI5_CUSTOM_CHAT_COMMAND_HELP_TEXT
#undef DMAPI5_CUSTOM_CHAT_COMMAND_ADMIN_ONLY

#undef DMAPI5_EVENT_ID

#undef DMAPI5_EVENT_INVOCATION_NAME
#undef DMAPI5_EVENT_INVOCATION_PARAMETERS
#undef DMAPI5_EVENT_INVOCATION_NOTIFY_COMPLETION

0 comments on commit 3643310

Please sign in to comment.