From e19a83f9be3e709db408b33be3b68924147c335d Mon Sep 17 00:00:00 2001 From: AffectedArc07 <25063394+AffectedArc07@users.noreply.github.com> Date: Tue, 17 Aug 2021 14:05:46 +0100 Subject: [PATCH] SSinstancing (I need to test this with 2 machines) --- .../configuration/configuration_core.dm | 39 +++++------- .../sections/instancing_configuration.dm | 20 ++++++ code/controllers/subsystem/instancing.dm | 63 +++++++++++++++++++ code/datums/peer_server.dm | 32 ++++++++++ code/modules/admin/admin_verbs.dm | 3 +- code/modules/admin/verbs/view_instances.dm | 22 +++++++ code/modules/world_topic/server_discovery.dm | 12 ++++ config/example/config.toml | 16 +++++ paradise.dme | 5 ++ 9 files changed, 186 insertions(+), 26 deletions(-) create mode 100644 code/controllers/configuration/sections/instancing_configuration.dm create mode 100644 code/controllers/subsystem/instancing.dm create mode 100644 code/datums/peer_server.dm create mode 100644 code/modules/admin/verbs/view_instances.dm create mode 100644 code/modules/world_topic/server_discovery.dm diff --git a/code/controllers/configuration/configuration_core.dm b/code/controllers/configuration/configuration_core.dm index c8b490e26cc..33f4e45d76c 100644 --- a/code/controllers/configuration/configuration_core.dm +++ b/code/controllers/configuration/configuration_core.dm @@ -24,6 +24,8 @@ GLOBAL_DATUM_INIT(configuration, /datum/server_configuration, new()) var/datum/configuration_section/gateway_configuration/gateway /// Holder for the general configuration datum var/datum/configuration_section/general_configuration/general + /// Holder for the instancing configuration datum + var/datum/configuration_section/instancing_configuration/instancing /// Holder for the IPIntel configuration datum var/datum/configuration_section/ipintel_configuration/ipintel /// Holder for the job configuration datum @@ -79,6 +81,7 @@ GLOBAL_DATUM_INIT(configuration, /datum/server_configuration, new()) gamemode = new() gateway = new() general = new() + instancing = new() ipintel = new() jobs = new() logging = new() @@ -98,6 +101,15 @@ GLOBAL_DATUM_INIT(configuration, /datum/server_configuration, new()) raw_data = json_decode(raw_json) // Now pass through all our stuff + load_all_sections() + + // Clear our list to save RAM + raw_data = list() + + // And report the load + DIRECT_OUTPUT(world.log, "Config loaded in [stop_watch(start)]s") + +/datum/server_configuration/proc/load_all_sections() safe_load(admin, "admin_configuration") safe_load(afk, "afk_configuration") safe_load(custom_sprites, "custom_sprites_configuration") @@ -107,6 +119,7 @@ GLOBAL_DATUM_INIT(configuration, /datum/server_configuration, new()) safe_load(gamemode, "gamemode_configuration") safe_load(gateway, "gateway_configuration") safe_load(general, "general_configuration") + safe_load(instancing, "instancing_configuration") safe_load(ipintel, "ipintel_configuration") safe_load(jobs, "job_configuration") safe_load(logging, "logging_configuration") @@ -118,12 +131,6 @@ GLOBAL_DATUM_INIT(configuration, /datum/server_configuration, new()) safe_load(url, "url_configuration") safe_load(vote, "voting_configuration") - // Clear our list to save RAM - raw_data = list() - - // And report the load - DIRECT_OUTPUT(world.log, "Config loaded in [stop_watch(start)]s") - // Proc to load up instance-specific overrides /datum/server_configuration/proc/load_overrides() var/override_file = "config/overrides_[world.port].toml" @@ -140,25 +147,7 @@ GLOBAL_DATUM_INIT(configuration, /datum/server_configuration, new()) // Now safely load our overrides. // Due to the nature of config wrappers, only vars that exist in the config file are applied to the config datums. // This means that an override missing a key doesnt null it out from the main server - safe_load(admin, "admin_configuration") - safe_load(afk, "afk_configuration") - safe_load(custom_sprites, "custom_sprites_configuration") - safe_load(database, "database_configuration") - safe_load(discord, "discord_configuration") - safe_load(event, "event_configuration") - safe_load(gamemode, "gamemode_configuration") - safe_load(gateway, "gateway_configuration") - safe_load(general, "general_configuration") - safe_load(ipintel, "ipintel_configuration") - safe_load(jobs, "job_configuration") - safe_load(logging, "logging_configuration") - safe_load(mc, "mc_configuration") - safe_load(movement, "movement_configuration") - safe_load(overflow, "overflow_configuration") - safe_load(ruins, "ruin_configuration") - safe_load(system, "system_configuration") - safe_load(url, "url_configuration") - safe_load(vote, "voting_configuration") + load_all_sections() // Clear our list to save RAM raw_data = list() diff --git a/code/controllers/configuration/sections/instancing_configuration.dm b/code/controllers/configuration/sections/instancing_configuration.dm new file mode 100644 index 00000000000..bc5c6c8406a --- /dev/null +++ b/code/controllers/configuration/sections/instancing_configuration.dm @@ -0,0 +1,20 @@ +/// Config holder for stuff relating to multi-server instances +/datum/configuration_section/instancing_configuration + /// ID of this specific server + var/server_id = "paradise_main" + /// List of all peer servers + var/list/datum/peer_server/peers = list() + +/datum/configuration_section/instancing_configuration/load_data(list/data) + // Use the load wrappers here. That way the default isnt made 'null' if you comment out the config line + CONFIG_LOAD_STR(server_id, data["server_id"]) + + if(islist(data["peer_servers"])) + for(var/list/server in data["peer_servers"]) + if(server["server_port"] == world.port) // Skip our own instance + continue + var/datum/peer_server/PS = new() + PS.internal_ip = server["internal_ip"] + PS.server_port = server["server_port"] + PS.commskey = server["commskey"] + peers.Add(PS) diff --git a/code/controllers/subsystem/instancing.dm b/code/controllers/subsystem/instancing.dm new file mode 100644 index 00000000000..ec4c289bc86 --- /dev/null +++ b/code/controllers/subsystem/instancing.dm @@ -0,0 +1,63 @@ +SUBSYSTEM_DEF(instancing) + name = "Instancing" + runlevels = RUNLEVEL_INIT | RUNLEVEL_LOBBY | RUNLEVEL_SETUP | RUNLEVEL_GAME | RUNLEVEL_POSTGAME + /// Have we announced startup yet + var/startup_announced = FALSE + /// Is a check currently running? + var/check_running = FALSE + +/datum/controller/subsystem/instancing/Initialize(start_timeofday) + // Do an initial peer check + check_peers() + return ..() + +/datum/controller/subsystem/instancing/fire(resumed) + check_peers() + + +/** + * Refreshes all peers on the server + * + * Called periodically during fire() as well as when a new peer reports itself as online + * Only one instance of this proc may run at a time + * + */ +/datum/controller/subsystem/instancing/proc/check_peers() + set waitfor = FALSE // This has sleeps if it cant topic so we dont want to bog things down + if(check_running) + return + + check_running = TRUE // Dont allow multiple of these + // A NOTE TO ANYONE ELSE WHO LOOKS AT THIS + // THESE TIMINGS ARE A FUCKING NIGHTMARE AND YOU WILL NEED DEBUG LOGGING TO TEST THEM + // DO NOT FUCK WITH THE TIMINGS -aa + for(var/datum/peer_server/PS in GLOB.configuration.instancing.peers) + // If the server hasnt been discovered and its been more than 5 minutes + if((!PS.discovered && PS.last_operation_time + 5 MINUTES > world.time)) + continue + + if(PS.last_operation_time + 1 MINUTES > world.time) + continue // Only run main operations once every minute anyway + + var/peer_response = world.Export("byond://[PS.internal_ip]:[PS.server_port]?server_discovery&key=[PS.commskey]") + if(!peer_response) + PS.online = FALSE // Peer is offline + PS.last_operation_time = world.time + continue + + // We got a response + PS.discovered = TRUE + PS.online = TRUE + var/list/peer_data = json_decode(peer_response) + + PS.external_ip = peer_data["external_ip"] + PS.server_id = peer_data["server_id"] + PS.server_name = peer_data["server_name"] + PS.playercount = peer_data["playercount"] + + PS.last_operation_time = world.time + + check_running = FALSE + +/datum/controller/subsystem/instancing/proc/message_all_peers(include_offline = FALSE) + return diff --git a/code/datums/peer_server.dm b/code/datums/peer_server.dm new file mode 100644 index 00000000000..81f78be68b4 --- /dev/null +++ b/code/datums/peer_server.dm @@ -0,0 +1,32 @@ +/** + * # Peer server + * + * This datum is essentially a model class to represent another instance of Paracode running + * + * It contains communications passes, an internal IP to communicate to, an external IP for players to connect to + * + */ +/datum/peer_server + // The following options will be loaded from configuration + /// Peer server internal IP, used for communications + var/internal_ip + /// Port of the server + var/server_port = 0 + /// Comms key for this server + var/commskey + + // The following options will be pulled from the peer at runtime + /// Peer server external IP, used for routing players around + var/external_ip + /// Peer server ID, used internally. Pulled from the peer on startup. + var/server_id + /// Peer server name, presented to players. Pulled from the peer on startup. + var/server_name + /// Have we done initial data discovery yet? + var/discovered = FALSE + /// Is the peer server online? + var/online = FALSE + /// Playercount of the peer server on last ping + var/playercount + /// Last world.time that an operation was attempted + var/last_operation_time diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index 598705668ae..6a3103172ee 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -67,7 +67,8 @@ GLOBAL_LIST_INIT(admin_verbs_admin, list( /client/proc/toggle_mentor_chat, /client/proc/toggle_advanced_interaction, /*toggle admin ability to interact with not only machines, but also atoms such as buttons and doors*/ /client/proc/list_ssds_afks, - /client/proc/ccbdb_lookup_ckey + /client/proc/ccbdb_lookup_ckey, + /client/proc/view_instances )) GLOBAL_LIST_INIT(admin_verbs_ban, list( /client/proc/ban_panel, diff --git a/code/modules/admin/verbs/view_instances.dm b/code/modules/admin/verbs/view_instances.dm new file mode 100644 index 00000000000..3aa83809516 --- /dev/null +++ b/code/modules/admin/verbs/view_instances.dm @@ -0,0 +1,22 @@ +/client/proc/view_instances() + set name = "View Server Instances" + set desc = "View the running server instances" + set category = "Server" + + if(!check_rights(R_ADMIN)) + return + + to_chat(usr, "Server instances info") + for(var/datum/peer_server/PS in GLOB.configuration.instancing.peers) + // We havnt even been discovered, so we cant even be online + if(!PS.discovered) + to_chat(usr, "#[PS.server_port] (Undiscovered) - OFFLINE") + continue + + // We exist but arent online at the moment + if(!PS.online) + to_chat(usr, "ID [PS.server_id] - OFFLINE") + continue + + // If we are here, we are online, so we can do a rich report + to_chat(usr, "ID [PS.server_id] - ONLINE (Players: [PS.playercount])") diff --git a/code/modules/world_topic/server_discovery.dm b/code/modules/world_topic/server_discovery.dm new file mode 100644 index 00000000000..8558f5c380c --- /dev/null +++ b/code/modules/world_topic/server_discovery.dm @@ -0,0 +1,12 @@ +/datum/world_topic_handler/server_discovery + topic_key = "server_discovery" + requires_commskey = TRUE + +/datum/world_topic_handler/server_discovery/execute(list/input, key_valid) + // We need to send the stuff to make a /datum/peer_server on the other side + var/list/server_data = list() + server_data["external_ip"] = world.internet_address + server_data["server_id"] = GLOB.configuration.instancing.server_id + server_data["server_name"] = GLOB.configuration.general.server_name + server_data["playercount"] = length(GLOB.clients) + return json_encode(server_data) diff --git a/config/example/config.toml b/config/example/config.toml index 254f793221e..b73e378be14 100644 --- a/config/example/config.toml +++ b/config/example/config.toml @@ -22,6 +22,7 @@ # - gamemode_configuration # - gateway_configuration # - general_configuration +# - instancing_configuration # - ipintel_configuration # - job_configuration # - logging_configuration @@ -376,6 +377,21 @@ random_ai_lawset = true ################################################################ +[instancing_configuration] +# This section contains all the information for instancing servers (Multiple paracode servers on the same database) + +# ID of this specific server. Override when needed +server_id = "paradise_main" +# List of all peer servers. Add all of the servers inside this configuration. +# The code will ignore its own instance by port checking +peer_servers = [ + #{internal_ip = "10.0.0.30", server_port = 6666, commskey = "please_use_something_secure"} +] + + +################################################################ + + [ipintel_configuration] # This section contains all the information for IPIntel (The Anti VPN system) diff --git a/paradise.dme b/paradise.dme index 11176b1befe..25499536c1c 100644 --- a/paradise.dme +++ b/paradise.dme @@ -196,6 +196,7 @@ #include "code\controllers\configuration\sections\gamemode_configuration.dm" #include "code\controllers\configuration\sections\gateway_configuration.dm" #include "code\controllers\configuration\sections\general_configuration.dm" +#include "code\controllers\configuration\sections\instancing_configuration.dm" #include "code\controllers\configuration\sections\ipintel_configuration.dm" #include "code\controllers\configuration\sections\job_configuration.dm" #include "code\controllers\configuration\sections\logging_configuration.dm" @@ -228,6 +229,7 @@ #include "code\controllers\subsystem\icon_smooth.dm" #include "code\controllers\subsystem\idlenpcpool.dm" #include "code\controllers\subsystem\input.dm" +#include "code\controllers\subsystem\instancing.dm" #include "code\controllers\subsystem\ipintel.dm" #include "code\controllers\subsystem\jobs.dm" #include "code\controllers\subsystem\late_mapping.dm" @@ -288,6 +290,7 @@ #include "code\datums\mind.dm" #include "code\datums\mixed.dm" #include "code\datums\mutable_appearance.dm" +#include "code\datums\peer_server.dm" #include "code\datums\periodic_news.dm" #include "code\datums\pipe_datums.dm" #include "code\datums\progressbar.dm" @@ -1221,6 +1224,7 @@ #include "code\modules\admin\verbs\ticklag.dm" #include "code\modules\admin\verbs\toggledebugverbs.dm" #include "code\modules\admin\verbs\tripAI.dm" +#include "code\modules\admin\verbs\view_instances.dm" #include "code\modules\admin\verbs\vox_raiders.dm" #include "code\modules\admin\verbs\SDQL2\SDQL_2.dm" #include "code\modules\admin\verbs\SDQL2\SDQL_2_parser.dm" @@ -2508,6 +2512,7 @@ #include "code\modules\world_topic\manifest.dm" #include "code\modules\world_topic\ping.dm" #include "code\modules\world_topic\players.dm" +#include "code\modules\world_topic\server_discovery.dm" #include "code\modules\world_topic\status.dm" #include "goon\code\datums\browserOutput.dm" #include "interface\interface.dm"