Skip to content

Commit

Permalink
Merge pull request #13 from Lumos-SS13/tgs-dmapi-update
Browse files Browse the repository at this point in the history
Automatic TGS DMAPI Update
  • Loading branch information
iknowdude00 authored Mar 29, 2023
2 parents 9a0114e + e0588c2 commit e7e3f18
Show file tree
Hide file tree
Showing 16 changed files with 244 additions and 38 deletions.
119 changes: 111 additions & 8 deletions 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 "6.0.6"
#define TGS_DMAPI_VERSION "6.1.0"

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

Expand Down Expand Up @@ -227,6 +227,8 @@
var/is_private_channel
/// Tag string associated with the channel in TGS
var/custom_tag
/// [TRUE]/[FALSE] if the channel supports embeds
var/embeds_supported

// Represents a chat user
/datum/tgs_chat_user
Expand Down Expand Up @@ -258,14 +260,115 @@
var/admin_only = FALSE

/**
* Process command activation. Should return a string to respond to the issuer with.
* Process command activation. Should return a [/datum/tgs_message_content] to respond to the issuer with.
*
* sender - The [/datum/tgs_chat_user] who issued the command.
* params - The trimmed string following the command `/datum/tgs_chat_command/var/name].
*/
/datum/tgs_chat_command/proc/Run(datum/tgs_chat_user/sender, params)
CRASH("[type] has no implementation for Run()")

/// User definable chat message
/datum/tgs_message_content
/// The tring content of the message. Must be provided in New().
var/text

/// The [/datum/tgs_chat_embed] to embed in the message. Not supported on all chat providers.
var/datum/tgs_chat_embed/structure/embed

/datum/tgs_message_content/New(text)
if(!istext(text))
TGS_ERROR_LOG("[/datum/tgs_message_content] created with no text!")
text = null

src.text = text

/// User definable chat embed. Currently mirrors Discord chat embeds. See https://discord.com/developers/docs/resources/channel#embed-object-embed-structure for details.
/datum/tgs_chat_embed/structure
var/title
var/description
var/url

/// Timestamp must be encoded as: time2text(world.timeofday, "YYYY-MM-DD hh:mm:ss"). Use the active timezone.
var/timestamp

/// Colour must be #AARRGGBB or #RRGGBB hex string
var/colour

/// See https://discord.com/developers/docs/resources/channel#embed-object-embed-image-structure for details.
var/datum/tgs_chat_embed/media/image

/// See https://discord.com/developers/docs/resources/channel#embed-object-embed-thumbnail-structure for details.
var/datum/tgs_chat_embed/media/thumbnail

/// See https://discord.com/developers/docs/resources/channel#embed-object-embed-image-structure for details.
var/datum/tgs_chat_embed/media/video

var/datum/tgs_chat_embed/footer/footer
var/datum/tgs_chat_embed/provider/provider
var/datum/tgs_chat_embed/provider/author/author

var/list/datum/tgs_chat_embed/field/fields

/// Common datum for similar discord embed medias
/datum/tgs_chat_embed/media
/// Must be set in New().
var/url
var/width
var/height
var/proxy_url

/datum/tgs_chat_embed/media/New(url)
if(!istext(url))
CRASH("[/datum/tgs_chat_embed/media] created with no url!")

src.url = url

/// See https://discord.com/developers/docs/resources/channel#embed-object-embed-footer-structure for details.
/datum/tgs_chat_embed/footer
/// Must be set in New().
var/text
var/icon_url
var/proxy_icon_url

/datum/tgs_chat_embed/footer/New(text)
if(!istext(text))
CRASH("[/datum/tgs_chat_embed/footer] created with no text!")

src.text = text

/// See https://discord.com/developers/docs/resources/channel#embed-object-embed-provider-structure for details.
/datum/tgs_chat_embed/provider
var/name
var/url

/// See https://discord.com/developers/docs/resources/channel#embed-object-embed-author-structure for details. Must have name set in New().
/datum/tgs_chat_embed/provider/author
var/icon_url
var/proxy_icon_url

/datum/tgs_chat_embed/provider/author/New(name)
if(!istext(name))
CRASH("[/datum/tgs_chat_embed/provider/author] created with no name!")

src.name = name

/// See https://discord.com/developers/docs/resources/channel#embed-object-embed-field-structure for details. Must have name and value set in New().
/datum/tgs_chat_embed/field
var/name
var/value
var/is_inline

/datum/tgs_chat_embed/field/New(name, value)
if(!istext(name))
CRASH("[/datum/tgs_chat_embed/field] created with no name!")

if(!istext(value))
CRASH("[/datum/tgs_chat_embed/field] created with no value!")

src.name = name
src.value = value

// API FUNCTIONS

/// Returns the maximum supported [/datum/tgs_version] of the DMAPI.
Expand Down Expand Up @@ -296,30 +399,30 @@
/**
* Send a message to connected chats.
*
* message - The string to send.
* message - The [/datum/tgs_message_content] to send.
* admin_only: If [TRUE], message will be sent to admin connected chats. Vice-versa applies.
*/
/world/proc/TgsTargetedChatBroadcast(message, admin_only = FALSE)
/world/proc/TgsTargetedChatBroadcast(datum/tgs_message_content/message, admin_only = FALSE)
return

/**
* Send a private message to a specific user.
*
* message - The string to send.
* message - The [/datum/tgs_message_content] to send.
* user: The [/datum/tgs_chat_user] to PM.
*/
/world/proc/TgsChatPrivateMessage(message, datum/tgs_chat_user/user)
/world/proc/TgsChatPrivateMessage(datum/tgs_message_content/message, datum/tgs_chat_user/user)
return

// The following functions will sleep if a call to TgsNew() is sleeping

/**
* Send a message to connected chats that are flagged as game-related in TGS.
*
* message - The string to send.
* message - The [/datum/tgs_message_content] to send.
* channels - Optional list of [/datum/tgs_chat_channel]s to restrict the message to.
*/
/world/proc/TgsChatBroadcast(message, list/channels = null)
/world/proc/TgsChatBroadcast(datum/tgs_message_content/message, list/channels = null)
return

/// Returns the current [/datum/tgs_version] of TGS if it is running the server, null otherwise.
Expand Down
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
-
2 changes: 2 additions & 0 deletions code/modules/tgs/core/datum.dm
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ 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
Expand Down
1 change: 1 addition & 0 deletions code/modules/tgs/includes.dm
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@
#include "v5\_defines.dm"
#include "v5\api.dm"
#include "v5\commands.dm"
#include "v5\serializers.dm"
#include "v5\undefs.dm"
9 changes: 6 additions & 3 deletions code/modules/tgs/v3210/api.dm
Original file line number Diff line number Diff line change
Expand Up @@ -193,16 +193,19 @@
/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
5 changes: 4 additions & 1 deletion code/modules/tgs/v3210/commands.dm
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,7 @@
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?.text || TRUE
15 changes: 9 additions & 6 deletions code/modules/tgs/v4/api.dm
Original file line number Diff line number Diff line change
Expand Up @@ -256,33 +256,36 @@
/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)
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)
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
8 changes: 4 additions & 4 deletions code/modules/tgs/v4/commands.dm
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,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?.text
return "Unknown command: [command]!"
2 changes: 2 additions & 0 deletions code/modules/tgs/v5/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

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.
- [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.
- [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.4.0"
3 changes: 2 additions & 1 deletion code/modules/tgs/v5/_defines.dm
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
#define DMAPI5_BRIDGE_RESPONSE_NEW_PORT "newPort"
#define DMAPI5_BRIDGE_RESPONSE_RUNTIME_INFORMATION "runtimeInformation"

#define DMAPI5_CHAT_MESSAGE_TEXT "text"
#define DMAPI5_CHAT_MESSAGE_CHANNEL_IDS "channelIds"

#define DMAPI5_RUNTIME_INFORMATION_ACCESS_IDENTIFIER "accessIdentifier"
Expand Down Expand Up @@ -75,6 +74,7 @@
#define DMAPI5_TOPIC_PARAMETER_CHAT_UPDATE "chatUpdate"
#define DMAPI5_TOPIC_PARAMETER_NEW_SERVER_VERSION "newServerVersion"

#define DMAPI5_TOPIC_RESPONSE_COMMAND_RESPONSE "commandResponse"
#define DMAPI5_TOPIC_RESPONSE_COMMAND_RESPONSE_MESSAGE "commandResponseMessage"
#define DMAPI5_TOPIC_RESPONSE_CHAT_RESPONSES "chatResponses"

Expand All @@ -93,6 +93,7 @@
#define DMAPI5_CHAT_CHANNEL_IS_ADMIN_CHANNEL "isAdminChannel"
#define DMAPI5_CHAT_CHANNEL_IS_PRIVATE_CHANNEL "isPrivateChannel"
#define DMAPI5_CHAT_CHANNEL_TAG "tag"
#define DMAPI5_CHAT_CHANNEL_EMBEDS_SUPPORTED "embedsSupported"

#define DMAPI5_CUSTOM_CHAT_COMMAND_NAME "name"
#define DMAPI5_CUSTOM_CHAT_COMMAND_HELP_TEXT "helpText"
Expand Down
31 changes: 24 additions & 7 deletions code/modules/tgs/v5/api.dm
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

/datum/tgs_api/v5/ApiVersion()
return new /datum/tgs_version(
#include "interop_version.dm"
#include "__interop_version.dm"
)

/datum/tgs_api/v5/OnWorldNew(minimum_required_security_level)
Expand Down Expand Up @@ -104,6 +104,7 @@
return json_encode(response)

/datum/tgs_api/v5/OnTopic(T)
RequireInitialBridgeResponse()
var/list/params = params2list(T)
var/json = params[DMAPI5_TOPIC_DATA]
if(!json)
Expand Down Expand Up @@ -297,7 +298,15 @@
RequireInitialBridgeResponse()
return revision

/datum/tgs_api/v5/ChatBroadcast(message, list/channels)
// Common proc b/c it's used by the V3/V4 APIs
/datum/tgs_api/proc/UpgradeDeprecatedChatMessage(datum/tgs_message_content/message)
if(!istext(message))
return message

TGS_WARNING_LOG("Received legacy string when a [/datum/tgs_message_content] was expected. Please audit all calls to TgsChatBroadcast, TgsChatTargetedBroadcast, and TgsChatPrivateMessage to ensure they use the new /datum.")
return new /datum/tgs_message_content(message)

/datum/tgs_api/v5/ChatBroadcast(datum/tgs_message_content/message, list/channels)
if(!length(channels))
channels = ChatChannelInfo()

Expand All @@ -306,26 +315,33 @@
var/datum/tgs_chat_channel/channel = I
ids += channel.id

message = list(DMAPI5_CHAT_MESSAGE_TEXT = message, DMAPI5_CHAT_MESSAGE_CHANNEL_IDS = ids)
message = UpgradeDeprecatedChatMessage(message)
message = message._interop_serialize()
message[DMAPI5_CHAT_MESSAGE_CHANNEL_IDS] = ids
if(intercepted_message_queue)
intercepted_message_queue += list(message)
else
Bridge(DMAPI5_BRIDGE_COMMAND_CHAT_SEND, list(DMAPI5_BRIDGE_PARAMETER_CHAT_MESSAGE = message))

/datum/tgs_api/v5/ChatTargetedBroadcast(message, admin_only)
/datum/tgs_api/v5/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(DMAPI5_CHAT_MESSAGE_TEXT = message, DMAPI5_CHAT_MESSAGE_CHANNEL_IDS = channels)

message = UpgradeDeprecatedChatMessage(message)
message = message._interop_serialize()
message[DMAPI5_CHAT_MESSAGE_CHANNEL_IDS] = channels
if(intercepted_message_queue)
intercepted_message_queue += list(message)
else
Bridge(DMAPI5_BRIDGE_COMMAND_CHAT_SEND, list(DMAPI5_BRIDGE_PARAMETER_CHAT_MESSAGE = message))

/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))
/datum/tgs_api/v5/ChatPrivateMessage(datum/tgs_message_content/message, datum/tgs_chat_user/user)
message = UpgradeDeprecatedChatMessage(message)
message = message._interop_serialize()
message[DMAPI5_CHAT_MESSAGE_CHANNEL_IDS] = list(user.channel.id)
if(intercepted_message_queue)
intercepted_message_queue += list(message)
else
Expand Down Expand Up @@ -354,6 +370,7 @@
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]
channel.embeds_supported = channel_json[DMAPI5_CHAT_CHANNEL_EMBEDS_SUPPORTED]
return channel

/datum/tgs_api/v5/SecurityLevel()
Expand Down
Loading

0 comments on commit e7e3f18

Please sign in to comment.