Skip to content

Commit

Permalink
Automatic TGS DMAPI Update (#2758)
Browse files Browse the repository at this point in the history
This pull request updates the TGS DMAPI to the latest version. Please
note any breaking or unimplemented changes before merging.

Co-authored-by: github-actions <[email protected]>
Co-authored-by: Mark Suckerberg <[email protected]>
  • Loading branch information
3 people authored Feb 29, 2024
1 parent c540cbe commit c16b93d
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 c16b93d

Please sign in to comment.