diff --git a/code/__DEFINES/_versions.dm b/code/__DEFINES/_versions.dm new file mode 100644 index 00000000000..83a18de6f73 --- /dev/null +++ b/code/__DEFINES/_versions.dm @@ -0,0 +1,2 @@ +/// Version of RUST-G that this codebase wants +#define RUST_G_VERSION "0.5.0-P" diff --git a/code/__DEFINES/rust_g.dm b/code/__DEFINES/rust_g.dm index 6a331a6131f..4ee84eda941 100644 --- a/code/__DEFINES/rust_g.dm +++ b/code/__DEFINES/rust_g.dm @@ -1,80 +1,130 @@ +// rust_g.dm - DM API for rust_g extension library +// +// To configure, create a `rust_g.config.dm` and set what you care about from +// the following options: +// +// #define RUST_G "path/to/rust_g" +// Override the .dll/.so detection logic with a fixed path or with detection +// logic of your own. +// +// #define RUSTG_OVERRIDE_BUILTINS +// Enable replacement rust-g functions for certain builtins. Off by default. + #ifndef RUST_G -/// Locator for the RUSTG DLL or SO depending on system type. Override if needed. -#define RUST_G (world.system_type == UNIX ? "./librust_g.so" : "./rust_g.dll") +// Default automatic RUST_G detection. +// On Windows, looks in the standard places for `rust_g.dll`. +// On Linux, looks in `.`, `$LD_LIBRARY_PATH`, and `~/.byond/bin` for either of +// `librust_g.so` (preferred) or `rust_g` (old). + +/* This comment bypasses grep checks */ /var/__rust_g + +/proc/__detect_rust_g() + if (world.system_type == UNIX) + if (fexists("./librust_g.so")) + // No need for LD_LIBRARY_PATH badness. + return __rust_g = "./librust_g.so" + else if (fexists("./rust_g")) + // Old dumb filename. + return __rust_g = "./rust_g" + else if (fexists("[world.GetConfig("env", "HOME")]/.byond/bin/rust_g")) + // Old dumb filename in `~/.byond/bin`. + return __rust_g = "rust_g" + else + // It's not in the current directory, so try others + return __rust_g = "librust_g.so" + else + return __rust_g = "rust_g.dll" + +#define RUST_G (__rust_g || __detect_rust_g()) #endif -// Gets the version of RUSTG +/// Gets the version of rust_g /proc/rustg_get_version() return call(RUST_G, "get_version")() -// Defines for internal job subsystem // -#define RUSTG_JOB_NO_RESULTS_YET "NO RESULTS YET" -#define RUSTG_JOB_NO_SUCH_JOB "NO SUCH JOB" -#define RUSTG_JOB_ERROR "JOB PANICKED" +// Cellular Noise Operations // -// DMI related operations // +/** + * This proc generates a cellular automata noise grid which can be used in procedural generation methods. + * + * Returns a single string that goes row by row, with values of 1 representing an alive cell, and a value of 0 representing a dead cell. + * + * Arguments: + * * percentage: The chance of a turf starting closed + * * smoothing_iterations: The amount of iterations the cellular automata simulates before returning the results + * * birth_limit: If the number of neighboring cells is higher than this amount, a cell is born + * * death_limit: If the number of neighboring cells is lower than this amount, a cell dies + * * width: The width of the grid. + * * height: The height of the grid. + */ +#define rustg_cnoise_generate(percentage, smoothing_iterations, birth_limit, death_limit, width, height) \ + call(RUST_G, "cnoise_generate")(percentage, smoothing_iterations, birth_limit, death_limit, width, height) + +// DMI Operations // #define rustg_dmi_strip_metadata(fname) call(RUST_G, "dmi_strip_metadata")(fname) #define rustg_dmi_create_png(path, width, height, data) call(RUST_G, "dmi_create_png")(path, width, height, data) +#define rustg_dmi_resize_png(path, width, height, resizetype) call(RUST_G, "dmi_resize_png")(path, width, height, resizetype) -// Noise related operations // -#define rustg_noise_get_at_coordinates(seed, x, y) call(RUST_G, "noise_get_at_coordinates")(seed, x, y) - -// File related operations // +// File Operations // #define rustg_file_read(fname) call(RUST_G, "file_read")(fname) +#define rustg_file_exists(fname) call(RUST_G, "file_exists")(fname) #define rustg_file_write(text, fname) call(RUST_G, "file_write")(text, fname) #define rustg_file_append(text, fname) call(RUST_G, "file_append")(text, fname) #ifdef RUSTG_OVERRIDE_BUILTINS -#define file2text(fname) rustg_file_read(fname) -#define text2file(text, fname) rustg_file_append(text, fname) + #define file2text(fname) rustg_file_read("[fname]") + #define text2file(text, fname) rustg_file_append(text, "[fname]") #endif -// Git related operations // +// Git Operations // #define rustg_git_revparse(rev) call(RUST_G, "rg_git_revparse")(rev) #define rustg_git_commit_date(rev) call(RUST_G, "rg_git_commit_date")(rev) -// Hash related operations // +// Hashing Operations // #define rustg_hash_string(algorithm, text) call(RUST_G, "hash_string")(algorithm, text) #define rustg_hash_file(algorithm, fname) call(RUST_G, "hash_file")(algorithm, fname) +#define rustg_hash_generate_totp(seed) call(RUST_G, "generate_totp")(seed) +#define rustg_hash_generate_totp_tolerance(seed, tolerance) call(RUST_G, "generate_totp_tolerance")(seed, tolerance) #define RUSTG_HASH_MD5 "md5" #define RUSTG_HASH_SHA1 "sha1" #define RUSTG_HASH_SHA256 "sha256" #define RUSTG_HASH_SHA512 "sha512" +#define RUSTG_HASH_XXH64 "xxh64" +#define RUSTG_HASH_BASE64 "base64" #ifdef RUSTG_OVERRIDE_BUILTINS -#define md5(thing) (isfile(thing) ? rustg_hash_file(RUSTG_HASH_MD5, "[thing]") : rustg_hash_string(RUSTG_HASH_MD5, thing)) + #define md5(thing) (isfile(thing) ? rustg_hash_file(RUSTG_HASH_MD5, "[thing]") : rustg_hash_string(RUSTG_HASH_MD5, thing)) #endif -// Logging stuff // -#define rustg_log_write(fname, text) call(RUST_G, "log_write")(fname, text) -/proc/rustg_log_close_all() return call(RUST_G, "log_close_all")() - -// URL encoding stuff -#define rustg_url_encode(text) call(RUST_G, "url_encode")(text) -#define rustg_url_decode(text) call(RUST_G, "url_decode")(text) - -#ifdef RUSTG_OVERRIDE_BUILTINS -#define url_encode(text) rustg_url_encode(text) -#define url_decode(text) rustg_url_decode(text) -#endif - -// HTTP library stuff // +// HTTP Operations // #define RUSTG_HTTP_METHOD_GET "get" #define RUSTG_HTTP_METHOD_PUT "put" #define RUSTG_HTTP_METHOD_DELETE "delete" #define RUSTG_HTTP_METHOD_PATCH "patch" #define RUSTG_HTTP_METHOD_HEAD "head" #define RUSTG_HTTP_METHOD_POST "post" - -// Commented out because this thing locks up the entire DD process when you use it -// DO NOT USE FOR THE LOVE OF GOD -// #define rustg_http_request_blocking(method, url, body, headers) call(RUST_G, "http_request_blocking")(method, url, body, headers) -#define rustg_http_request_async(method, url, body, headers) call(RUST_G, "http_request_async")(method, url, body, headers) +#define rustg_http_request_blocking(method, url, body, headers, options) call(RUST_G, "http_request_blocking")(method, url, body, headers, options) +#define rustg_http_request_async(method, url, body, headers, options) call(RUST_G, "http_request_async")(method, url, body, headers, options) #define rustg_http_check_request(req_id) call(RUST_G, "http_check_request")(req_id) /proc/rustg_create_async_http_client() return call(RUST_G, "start_http_client")() /proc/rustg_close_async_http_client() return call(RUST_G, "shutdown_http_client")() -// SQL stuff // +// Jobs Subsystem Operations // +#define RUSTG_JOB_NO_RESULTS_YET "NO RESULTS YET" +#define RUSTG_JOB_NO_SUCH_JOB "NO SUCH JOB" +#define RUSTG_JOB_ERROR "JOB PANICKED" + +// JSON Operations // +#define rustg_json_is_valid(text) (call(RUST_G, "json_is_valid")(text) == "true") + +// Logging Operations // +#define rustg_log_write(fname, text) call(RUST_G, "log_write")(fname, text) +/proc/rustg_log_close_all() return call(RUST_G, "log_close_all")() + +// Noise Operations // +#define rustg_noise_get_at_coordinates(seed, x, y) call(RUST_G, "noise_get_at_coordinates")(seed, x, y) + +// SQL Opeartions // #define rustg_sql_connect_pool(options) call(RUST_G, "sql_connect_pool")(options) #define rustg_sql_query_async(handle, query, params) call(RUST_G, "sql_query_async")(handle, query, params) #define rustg_sql_query_blocking(handle, query, params) call(RUST_G, "sql_query_blocking")(handle, query, params) @@ -82,8 +132,19 @@ #define rustg_sql_disconnect_pool(handle) call(RUST_G, "sql_disconnect_pool")(handle) #define rustg_sql_check_query(job_id) call(RUST_G, "sql_check_query")("[job_id]") -// toml2json stuff // -#define rustg_toml2json(tomlfile) call(RUST_G, "toml2json")(tomlfile) +// TOML Operations // +#define rustg_read_toml_file(path) json_decode(call(RUST_G, "toml_file_to_json")(path) || "null") + +// Unzip Operations // +#define rustg_unzip_download_async(url, unzip_directory) call(RUST_G, "unzip_download_async")(url, unzip_directory) +#define rustg_unzip_check(job_id) call(RUST_G, "unzip_check")("[job_id]") + +// URL Encoder/Decoder Operations // +#define rustg_url_encode(text) call(RUST_G, "url_encode")("[text]") +#define rustg_url_decode(text) call(RUST_G, "url_decode")(text) + +#ifdef RUSTG_OVERRIDE_BUILTINS + #define url_encode(text) rustg_url_encode(text) + #define url_decode(text) rustg_url_decode(text) +#endif -// RUSTG Version // -#define RUST_G_VERSION "0.4.5-P3" diff --git a/code/controllers/configuration/configuration_core.dm b/code/controllers/configuration/configuration_core.dm index d9494c31652..2a97b937c8e 100644 --- a/code/controllers/configuration/configuration_core.dm +++ b/code/controllers/configuration/configuration_core.dm @@ -85,8 +85,7 @@ GLOBAL_DATUM_INIT(configuration, /datum/server_configuration, new()) var/config_file = "config/config.toml" if(!fexists(config_file)) config_file = "config/example/config.toml" // Fallback to example if user hasnt setup config properly - var/raw_json = rustg_toml2json(config_file) - var/list/raw_config_data = json_decode(raw_json) + var/raw_config_data = rustg_read_toml_file(config_file) // Now pass through all our stuff admin.load_data(raw_config_data["admin_configuration"]) diff --git a/code/datums/http.dm b/code/datums/http.dm index e7ba1620854..6679b859c65 100644 --- a/code/datums/http.dm +++ b/code/datums/http.dm @@ -19,6 +19,8 @@ var/headers /// URL that the request is being sent to var/url + /// If present, response body will be saved to this file. + var/output_file /// The raw response, which will be decoeded into a [/datum/http_response] var/_raw_response /// Callback for executing after async requests. Will be called with an argument of [/datum/http_response] as first argument @@ -42,7 +44,7 @@ THE METHODS IN THIS FILE ARE TO BE USED BY THE SUBSYSTEM AS A MANGEMENT HUB * * _body - The body of the request, if applicable * * _headers - Associative list of HTTP headers to send, if applicab;e */ -/datum/http_request/proc/prepare(_method, _url, _body = "", list/_headers) +/datum/http_request/proc/prepare(_method, _url, _body = "", list/_headers, _output_file) if(!length(_headers)) headers = "" else @@ -51,6 +53,7 @@ THE METHODS IN THIS FILE ARE TO BE USED BY THE SUBSYSTEM AS A MANGEMENT HUB method = _method url = _url body = _body + output_file = _output_file /** * Blocking executor @@ -60,7 +63,7 @@ THE METHODS IN THIS FILE ARE TO BE USED BY THE SUBSYSTEM AS A MANGEMENT HUB */ /datum/http_request/proc/execute_blocking() CRASH("Attempted to execute a blocking HTTP request") - // _raw_response = rustg_http_request_blocking(method, url, body, headers) + // _raw_response = rustg_http_request_blocking(method, url, body, headers, build_options()) /** * Async execution starter @@ -73,7 +76,7 @@ THE METHODS IN THIS FILE ARE TO BE USED BY THE SUBSYSTEM AS A MANGEMENT HUB if(in_progress) CRASH("Attempted to re-use a request object.") - id = rustg_http_request_async(method, url, body, headers) + id = rustg_http_request_async(method, url, body, headers, build_options()) if(isnull(text2num(id))) _raw_response = "Proc error: [id]" @@ -81,6 +84,16 @@ THE METHODS IN THIS FILE ARE TO BE USED BY THE SUBSYSTEM AS A MANGEMENT HUB else in_progress = TRUE +/** + * Options builder + * + * Builds options for if we want to download files with SShttp + */ +/datum/http_request/proc/build_options() + if(output_file) + return json_encode(list("output_filename" = output_file, "body_filename" = null)) + return null + /** * Async completion checker * diff --git a/librust_g.so b/librust_g.so index 1f059e0b2ce..63d3e053d9e 100644 Binary files a/librust_g.so and b/librust_g.so differ diff --git a/paradise.dme b/paradise.dme index dfcad75c3b4..3335290c461 100644 --- a/paradise.dme +++ b/paradise.dme @@ -23,6 +23,7 @@ #include "code\__DEFINES\_spacemandmm.dm" #include "code\__DEFINES\_tgs_defines.dm" #include "code\__DEFINES\_tick.dm" +#include "code\__DEFINES\_versions.dm" #include "code\__DEFINES\access.dm" #include "code\__DEFINES\admin.dm" #include "code\__DEFINES\antagonists.dm" diff --git a/rust_g.dll b/rust_g.dll index ed4ac5bc38b..a4b6f9074bd 100644 Binary files a/rust_g.dll and b/rust_g.dll differ diff --git a/tools/ci/validate_rustg_windows.py b/tools/ci/validate_rustg_windows.py index 787bafb9a60..1c3c883ae5e 100644 --- a/tools/ci/validate_rustg_windows.py +++ b/tools/ci/validate_rustg_windows.py @@ -37,7 +37,7 @@ else: fail("RUSTG DM header file does NOT exist") # Parse the version from the DM file -f = open("code/__DEFINES/rust_g.dm", "r") +f = open("code/__DEFINES/_versions.dm", "r") lines = f.readlines() f.close() dm_version = None @@ -92,16 +92,16 @@ else: # Make sure we can parse TOML string_array = c_char_p * 1 sa = string_array(bytes(ci_toml_file_location, "ascii")) -rustg_dll.toml2json.argtypes = [c_int, c_char_p * 1] +rustg_dll.toml_file_to_json.argtypes = [c_int, c_char_p * 1] # Set args for JSON retrieval -rustg_dll.toml2json.restype = c_char_p +rustg_dll.toml_file_to_json.restype = c_char_p try: # Run it - output_json = rustg_dll.toml2json(1, sa).decode() + output_json = rustg_dll.toml_file_to_json(1, sa).decode() json.loads(output_json) - success("toml2json conversion successful") + success("toml_file_to_json successful") except Exception: - fail("Failed to convert toml2json") + fail("Failed to run toml_file_to_json") exit(0) # Success