Skip to content

Commit

Permalink
Merge pull request #1 from vlggms/tgs-dmapi-update
Browse files Browse the repository at this point in the history
Update TGS DMAPI
  • Loading branch information
EgorDinamit authored Jan 22, 2024
2 parents 7606358 + caf9794 commit 99c8df4
Show file tree
Hide file tree
Showing 23 changed files with 934 additions and 290 deletions.
251 changes: 190 additions & 61 deletions code/__DEFINES/tgs.dm

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion code/modules/tgs/LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
The MIT License

Copyright (c) 2017 Jordan Brown
Copyright (c) 2017-2023 Jordan Brown

Permission is hereby granted, free of charge,
to any person obtaining a copy of this software and
Expand Down
2 changes: 1 addition & 1 deletion code/modules/tgs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ This folder should be placed on it's own inside a codebase that wishes to use th
- The other versioned folders contain code for the different DMAPI versions.
- [v3210](./v3210) contains the final TGS3 API.
- [v4](./v4) is the legacy DMAPI 4 (Used in TGS 4.0.X versions).
- [v5](./v5) is the current DMAPI version used by TGS4 >=4.1.
- [v5](./v5) is the current DMAPI version used by TGS >=4.1.
- [LICENSE](./LICENSE) is the MIT license for the DMAPI.

APIs communicate with TGS in two ways. All versions implement TGS -> DM communication using /world/Topic. DM -> TGS communication, called the bridge method, is different for each version.
3 changes: 2 additions & 1 deletion code/modules/tgs/core/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ This folder contains all DMAPI code not directly involved in an API.
- [_definitions.dm](./definitions.dm) contains defines needed across DMAPI internals.
- [core.dm](./core.dm) contains the implementations of the `/world/proc/TgsXXX()` procs. Many map directly to the `/datum/tgs_api` functions. It also contains the /datum selection and setup code.
- [datum.dm](./datum.dm) contains the `/datum/tgs_api` declarations that all APIs must implement.
- [tgs_version.dm](./tgs_version.dm) contains the `/datum/tgs_version` definition
- [tgs_version.dm](./tgs_version.dm) contains the `/datum/tgs_version` definition
-
8 changes: 8 additions & 0 deletions code/modules/tgs/core/_definitions.dm
Original file line number Diff line number Diff line change
@@ -1,2 +1,10 @@
#if DM_VERSION < 510
#error The TGS DMAPI does not support BYOND versions < 510!
#endif

#define TGS_UNIMPLEMENTED "___unimplemented"
#define TGS_VERSION_PARAMETER "server_service_version"

#ifndef TGS_DEBUG_LOG
#define TGS_DEBUG_LOG(message)
#endif
7 changes: 6 additions & 1 deletion code/modules/tgs/core/core.dm
Original file line number Diff line number Diff line change
Expand Up @@ -153,4 +153,9 @@
/world/TgsSecurityLevel()
var/datum/tgs_api/api = TGS_READ_GLOBAL(tgs)
if(api)
api.SecurityLevel()
return api.SecurityLevel()

/world/TgsVisibility()
var/datum/tgs_api/api = TGS_READ_GLOBAL(tgs)
if(api)
return api.Visibility()
14 changes: 14 additions & 0 deletions code/modules/tgs/core/datum.dm
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,22 @@ TGS_DEFINE_AND_SET_GLOBAL(tgs, null)
var/datum/tgs_version/version
var/datum/tgs_event_handler/event_handler

var/list/warned_deprecated_command_runs

/datum/tgs_api/New(datum/tgs_event_handler/event_handler, datum/tgs_version/version)
. = ..()
src.event_handler = event_handler
src.version = version

/datum/tgs_api/proc/TerminateWorld()
while(TRUE)
TGS_DEBUG_LOG("About to terminate world. Tick: [world.time], sleep_offline: [world.sleep_offline]")
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)
TGS_DEBUG_LOG("BYOND DIDN'T TERMINATE THE WORLD!!! TICK IS: [world.time], sleep_offline: [world.sleep_offline]")

/datum/tgs_api/latest
parent_type = /datum/tgs_api/v5

Expand Down Expand Up @@ -55,3 +66,6 @@ TGS_PROTECT_DATUM(/datum/tgs_api)

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

/datum/tgs_api/proc/Visibility()
return TGS_UNIMPLEMENTED
4 changes: 4 additions & 0 deletions code/modules/tgs/includes.dm
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,9 @@

#include "v5\_defines.dm"
#include "v5\api.dm"
#include "v5\bridge.dm"
#include "v5\chunking.dm"
#include "v5\commands.dm"
#include "v5\serializers.dm"
#include "v5\topic.dm"
#include "v5\undefs.dm"
48 changes: 32 additions & 16 deletions code/modules/tgs/v3210/api.dm
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@

#define SERVICE_RETURN_SUCCESS "SUCCESS"

#define TGS_FILE2LIST(filename) (splittext(trim_left(trim_right(file2text(filename))), "\n"))

/datum/tgs_api/v3210
var/reboot_mode = REBOOT_MODE_NORMAL
var/comms_key
Expand All @@ -53,24 +55,29 @@
return copytext(text, 1, i + 1)
return ""

/datum/tgs_api/v3210/proc/file2list(filename)
return splittext(trim_left(trim_right(file2text(filename))), "\n")

/datum/tgs_api/v3210/OnWorldNew(minimum_required_security_level)
. = FALSE

comms_key = world.params[SERVICE_WORLD_PARAM]
instance_name = world.params[SERVICE_INSTANCE_PARAM]
if(!instance_name)
instance_name = "TG Station Server" //maybe just upgraded
instance_name = "TG Station Server" //maybe just upgraded

var/list/logs = file2list(".git/logs/HEAD")
var/list/logs = TGS_FILE2LIST(".git/logs/HEAD")
if(logs.len)
logs = splittext(logs[logs.len - 1], " ")
commit = logs[2]
logs = file2list(".git/logs/refs/remotes/origin/master")
logs = splittext(logs[logs.len], " ")
if (logs.len >= 2)
commit = logs[2]
else
TGS_ERROR_LOG("Error parsing commit logs")

logs = TGS_FILE2LIST(".git/logs/refs/remotes/origin/master")
if(logs.len)
originmastercommit = splittext(logs[logs.len - 1], " ")[2]
logs = splittext(logs[logs.len], " ")
if (logs.len >= 2)
originmastercommit = logs[2]
else
TGS_ERROR_LOG("Error parsing origin commmit logs")

if(world.system_type != MS_WINDOWS)
TGS_ERROR_LOG("This API version is only supported on Windows. Not running on Windows. Aborting initialization!")
Expand All @@ -92,14 +99,18 @@
if(skip_compat_check && !fexists(SERVICE_INTERFACE_DLL))
TGS_ERROR_LOG("Service parameter present but no interface DLL detected. This is symptomatic of running a service less than version 3.1! Please upgrade.")
return
call(SERVICE_INTERFACE_DLL, SERVICE_INTERFACE_FUNCTION)(instance_name, command) //trust no retval
#if DM_VERSION >= 515
call_ext(SERVICE_INTERFACE_DLL, SERVICE_INTERFACE_FUNCTION)(instance_name, command) //trust no retval
#else
call(SERVICE_INTERFACE_DLL, SERVICE_INTERFACE_FUNCTION)(instance_name, command) //trust no retval
#endif
return TRUE

/datum/tgs_api/v3210/OnTopic(T)
var/list/params = params2list(T)
var/their_sCK = params[SERVICE_CMD_PARAM_KEY]
if(!their_sCK)
return FALSE //continue world/Topic
return FALSE //continue world/Topic

if(their_sCK != comms_key)
return "Invalid comms key!";
Expand Down Expand Up @@ -168,30 +179,33 @@
/datum/tgs_api/v3210/Revision()
if(!warned_revison)
var/datum/tgs_version/api_version = ApiVersion()
TGS_ERROR_LOG("Use of TgsRevision on [api_version.deprefixed_parameter] origin_commit only points to master!")
TGS_WARNING_LOG("Use of TgsRevision on [api_version.deprefixed_parameter] origin_commit only points to master!")
warned_revison = TRUE
var/datum/tgs_revision_information/ri = new
ri.commit = commit
ri.origin_commit = originmastercommit
return ri

/datum/tgs_api/v3210/EndProcess()
sleep(world.tick_lag) //flush the buffers
sleep(world.tick_lag) //flush the buffers
ExportService(SERVICE_REQUEST_KILL_PROCESS)

/datum/tgs_api/v3210/ChatChannelInfo()
return list() // :omegalul:

/datum/tgs_api/v3210/ChatBroadcast(message, list/channels)
/datum/tgs_api/v3210/ChatBroadcast(datum/tgs_message_content/message, list/channels)
if(channels)
return TGS_UNIMPLEMENTED
message = UpgradeDeprecatedChatMessage(message)
ChatTargetedBroadcast(message, TRUE)
ChatTargetedBroadcast(message, FALSE)

/datum/tgs_api/v3210/ChatTargetedBroadcast(message, admin_only)
ExportService("[admin_only ? SERVICE_REQUEST_IRC_ADMIN_CHANNEL_MESSAGE : SERVICE_REQUEST_IRC_BROADCAST] [message]")
/datum/tgs_api/v3210/ChatTargetedBroadcast(datum/tgs_message_content/message, admin_only)
message = UpgradeDeprecatedChatMessage(message)
ExportService("[admin_only ? SERVICE_REQUEST_IRC_ADMIN_CHANNEL_MESSAGE : SERVICE_REQUEST_IRC_BROADCAST] [message.text]")

/datum/tgs_api/v3210/ChatPrivateMessage(message, datum/tgs_chat_user/user)
UpgradeDeprecatedChatMessage(message)
return TGS_UNIMPLEMENTED

/datum/tgs_api/v3210/SecurityLevel()
Expand Down Expand Up @@ -226,3 +240,5 @@
#undef SERVICE_REQUEST_API_VERSION

#undef SERVICE_RETURN_SUCCESS

#undef TGS_FILE2LIST
12 changes: 9 additions & 3 deletions code/modules/tgs/v3210/commands.dm
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,12 @@
var/warned_about_the_dangers_of_robutussin = !warnings_only
for(var/I in typesof(/datum/tgs_chat_command) - /datum/tgs_chat_command)
if(!warned_about_the_dangers_of_robutussin)
TGS_ERROR_LOG("Custom chat commands in [ApiVersion()] lacks the /datum/tgs_chat_user/sender.channel field!")
TGS_WARNING_LOG("Custom chat commands in [ApiVersion()] lacks the /datum/tgs_chat_user/sender.channel field!")
warned_about_the_dangers_of_robutussin = TRUE
var/datum/tgs_chat_command/stc = I
if(stc.ignore_type == I)
continue

var/command_name = initial(stc.name)
if(!command_name || findtext(command_name, " ") || findtext(command_name, "'") || findtext(command_name, "\""))
if(warnings_only && !warned_command_names[command_name])
Expand Down Expand Up @@ -44,9 +47,12 @@
user.friendly_name = sender

// Discord hack, fix the mention if it's only numbers (fuck you IRC trolls)
var/regex/discord_id_regex = regex(@"^[0-9]+$")
var/regex/discord_id_regex = regex("^\[0-9\]+$")
if(findtext(sender, discord_id_regex))
sender = "<@[sender]>"

user.mention = sender
return stc.Run(user, params) || TRUE
var/datum/tgs_message_content/result = stc.Run(user, params)
result = UpgradeDeprecatedCommandResponse(result, command)

return result ? result.text : TRUE
41 changes: 27 additions & 14 deletions code/modules/tgs/v4/api.dm
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@
if(cached_json["apiValidateOnly"])
TGS_INFO_LOG("Validating API and exiting...")
Export(TGS4_COMM_VALIDATE, list(TGS4_PARAMETER_DATA = "[minimum_required_security_level]"))
del(world)
TerminateWorld()

security_level = cached_json["securityLevel"]
chat_channels_json_path = cached_json["chatChannelsJson"]
Expand Down Expand Up @@ -118,7 +118,7 @@
var/list/params = params2list(T)
var/their_sCK = params[TGS4_INTEROP_ACCESS_IDENTIFIER]
if(!their_sCK)
return FALSE //continue world/Topic
return FALSE //continue world/Topic

if(their_sCK != access_identifier)
return "Invalid comms key!";
Expand Down Expand Up @@ -188,24 +188,24 @@
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)
TerminateWorld()

//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
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)
TerminateWorld()

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)
TerminateWorld()

if(new_port != world.port && !world.OpenPort(new_port))
TGS_ERROR_LOG("Unable to open port [new_port]![TGS4_PORT_CRITFAIL_MESSAGE]")
del(world)
TerminateWorld()
requesting_new_port = FALSE

while(export_lock)
Expand Down Expand Up @@ -235,7 +235,7 @@

var/port = result[TGS4_PARAMETER_DATA]
if(!isnum(port))
return //this is valid, server may just want use to reboot
return //this is valid, server may just want use to reboot

if(port == 0)
//to byond 0 means any port and "none" means close vOv
Expand All @@ -256,33 +256,46 @@
/datum/tgs_api/v4/Revision()
return cached_revision

/datum/tgs_api/v4/ChatBroadcast(message, list/channels)
/datum/tgs_api/v4/ChatBroadcast(datum/tgs_message_content/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 = UpgradeDeprecatedChatMessage(message)

if (!length(channels))
return

message = list("message" = message.text, "channelIds" = ids)
if(intercepted_message_queue)
intercepted_message_queue += list(message)
else
Export(TGS4_COMM_CHAT, message)

/datum/tgs_api/v4/ChatTargetedBroadcast(message, admin_only)
/datum/tgs_api/v4/ChatTargetedBroadcast(datum/tgs_message_content/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 = UpgradeDeprecatedChatMessage(message)

if (!length(channels))
return

message = list("message" = message.text, "channelIds" = 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/v4/ChatPrivateMessage(datum/tgs_message_content/message, datum/tgs_chat_user/user)
message = UpgradeDeprecatedChatMessage(message)
message = list("message" = message.text, "channelIds" = list(user.channel.id))
if(intercepted_message_queue)
intercepted_message_queue += list(message)
else
Expand Down
11 changes: 7 additions & 4 deletions code/modules/tgs/v4/commands.dm
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
custom_commands = list()
for(var/I in typesof(/datum/tgs_chat_command) - /datum/tgs_chat_command)
var/datum/tgs_chat_command/stc = new I
if(stc.ignore_type == I)
continue

var/command_name = stc.name
if(!command_name || findtext(command_name, " ") || findtext(command_name, "'") || findtext(command_name, "\""))
TGS_ERROR_LOG("Custom command [command_name] ([I]) can't be used as it is empty or contains illegal characters!")
Expand Down Expand Up @@ -34,8 +37,8 @@

var/datum/tgs_chat_command/sc = custom_commands[command]
if(sc)
var/result = sc.Run(u, params)
if(result == null)
result = ""
return result
var/datum/tgs_message_content/result = sc.Run(u, params)
result = UpgradeDeprecatedCommandResponse(result, command)

return result ? result.text : TRUE
return "Unknown command: [command]!"
5 changes: 5 additions & 0 deletions code/modules/tgs/v5/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@

This DMAPI implements bridge requests using HTTP GET requests to TGS. It has no security restrictions.

- [__interop_version.dm](./__interop_version.dm) contains the version of the API used between the DMAPI and TGS.
- [_defines.dm](./_defines.dm) contains constant definitions.
- [api.dm](./api.dm) contains the bulk of the API code.
- [bridge.dm](./bridge.dm) contains functions related to making bridge requests.
- [chunking.dm](./chunking.dm) contains common function for splitting large raw data sets into chunks BYOND can natively process.
- [commands.dm](./commands.dm) contains functions relating to `/datum/tgs_chat_command`s.
- [serializers.dm](./serializers.dm) contains function to help convert interop `/datum`s into a JSON encodable `list()` format.
- [topic.dm](./topic.dm) contains functions related to processing topic requests.
- [undefs.dm](./undefs.dm) Undoes the work of `_defines.dm`.
1 change: 1 addition & 0 deletions code/modules/tgs/v5/__interop_version.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"5.7.0"
Loading

0 comments on commit 99c8df4

Please sign in to comment.