Skip to content
Draft
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 35 additions & 5 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 3 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,9 @@ gix = { version = "0.72", optional = true, default-features = false, features =
] }
noise = { version = "0.9", optional = true }
redis = { version = "0.31", optional = true, features = ["ahash"] }
ureq = { version = "2.12", optional = true }
ureq = { version = "3.0", optional = true }
serde = { version = "1.0", optional = true, features = ["derive"] }
serde_json = { version = "1.0", optional = true }
once_cell = { version = "1.21", optional = true }
mysql = { git = "https://github.com/ZeWaka/rust-mysql-simple.git", tag = "v26.0.0", default-features = false, optional = true }
dashmap = { version = "6.1", optional = true, features = ["rayon", "serde"] }
zip = { version = "2.6", optional = true }
Expand Down Expand Up @@ -137,14 +136,13 @@ hash = [
"serde",
"serde_json",
]
http = ["ureq", "serde", "serde_json", "once_cell", "jobs"]
http = ["ureq", "serde", "serde_json", "jobs"]
iconforge = [
"dashmap",
"dep:dmi",
"hash",
"image",
"jobs",
"once_cell",
"png",
"rayon",
"serde",
Expand All @@ -156,7 +154,7 @@ json = ["serde", "serde_json"]
log = ["chrono"]
sanitize = ["ammonia", "serde_json"]
sound_len = ["symphonia"]
sql = ["mysql", "serde", "serde_json", "once_cell", "dashmap", "jobs"]
sql = ["mysql", "serde", "serde_json", "dashmap", "jobs"]
time = ["chrono"]
toml = ["serde", "serde_json", "toml-dep"]
url = ["url-dep", "percent-encoding"]
Expand Down
16 changes: 9 additions & 7 deletions build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,20 @@ fn main() {
let mut f = File::create("target/rust_g.dm").unwrap();

// header
writeln!(
f,
"{}",
std::fs::read_to_string(feature_dm_file!("main")).unwrap()
)
.unwrap();
let header_content = std::fs::read_to_string(feature_dm_file!("main")).unwrap();
writeln!(f, "{}", header_content).unwrap();

// jobs is a dependency of other features
if feature_dm_exists!("jobs") {
let jobs_content = std::fs::read_to_string(feature_dm_file!("jobs")).unwrap();
writeln!(f, "{}", jobs_content).unwrap();
}

for (key, _value) in std::env::vars() {
// CARGO_FEATURE_<name> — For each activated feature of the package being built, this environment variable will be present where <name> is the name of the feature uppercased and having - translated to _.
if let Some(uprfeature) = key.strip_prefix("CARGO_FEATURE_") {
let feature = uprfeature.to_lowercase().replace('_', "-"); // actual proper name of the enabled feature
if feature_dm_exists!(&feature) {
if feature != "jobs" && feature_dm_exists!(&feature) {
writeln!(
f,
"{}",
Expand Down
96 changes: 96 additions & 0 deletions dmsrc/http.dm
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,99 @@
#define rustg_http_request_blocking(method, url, body, headers, options) RUSTG_CALL(RUST_G, "http_request_blocking")(method, url, body, headers, options)
#define rustg_http_request_async(method, url, body, headers, options) RUSTG_CALL(RUST_G, "http_request_async")(method, url, body, headers, options)
#define rustg_http_check_request(req_id) RUSTG_CALL(RUST_G, "http_check_request")(req_id)

/datum/http_request
var/id
var/in_progress = FALSE

var/method
var/body
var/headers
var/url
/// If present, the request body will be read from this file.
var/input_file = null
/// If present, the response body will be saved to this file.
var/output_file = null
/// If present, request will timeout after this duration.
var/timeout_seconds

var/_raw_response

/datum/http_request/proc/prepare(method, url, body = "", list/headers, output_file, input_file, timeout_seconds)
if (!length(headers))
headers = ""
else
headers = json_encode(headers)

src.method = method
src.url = url
src.body = body
src.headers = headers
src.input_file = input_file
src.output_file = output_file
src.timeout_seconds = timeout_seconds

/datum/http_request/proc/execute_blocking()
_raw_response = rustg_http_request_blocking(method, url, body, headers, build_options())

/datum/http_request/proc/begin_async()
if (in_progress)
CRASH("Attempted to re-use a request object.")

id = rustg_http_request_async(method, url, body, headers, build_options())

if (isnull(text2num(id)))
stack_trace("Proc error: [id]")
_raw_response = "Proc error: [id]"
else
in_progress = TRUE

/datum/http_request/proc/build_options()
. = json_encode(list(
"input_filename" = (input_file ? input_file : null),
"output_filename" = (output_file ? output_file : null),
"timeout_seconds"=(timeout_seconds ? timeout_seconds : null)
))

/datum/http_request/proc/is_complete()
if (isnull(id))
return TRUE

if (!in_progress)
return TRUE

var/r = rustg_http_check_request(id)

if (r == RUSTG_JOB_NO_RESULTS_YET)
return FALSE
else
_raw_response = r
in_progress = FALSE
return TRUE

/datum/http_request/proc/into_response()
var/datum/http_response/R = new()

try
var/list/L = json_decode(_raw_response)
R.status_code = L["status_code"]
R.headers = L["headers"]
R.body = L["body"]
catch
R.errored = TRUE
R.error = _raw_response

return R

/datum/http_response
/// The HTTP Status code - e.g., `"404"`
var/status_code
/// The response body - e.g., `{ "message": "No query results for xyz." }`
var/body
/// A list of headers - e.g., list("Content-Type" = "application/json").
var/list/headers
/// If the request errored, this will be TRUE.
var/errored = FALSE
/// If there was a 4xx/5xx error or the request failed to be sent, this will be the error message - e.g., `"HTTP error: 404"`
/// If it's the former, `status_code` will be set.
var/error
60 changes: 42 additions & 18 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,21 @@ use std::{
};
use thiserror::Error;

#[cfg(feature = "http")]
use serde_json::Error as JsonError;
#[cfg(feature = "http")]
use ureq::Error as UreqError;

#[cfg(feature = "png")]
use image::error::ImageError;
#[cfg(feature = "png")]
use png::{DecodingError, EncodingError};

#[cfg(feature = "toml")]
use toml_dep::de::Error as TomlDeserializeError;
#[cfg(feature = "toml")]
use toml_dep::ser::Error as TomlSerializeError;

#[cfg(feature = "unzip")]
use zip::result::ZipError;

Expand All @@ -28,46 +38,60 @@ pub enum Error {
Io(#[from] io::Error),
#[error("Invalid algorithm specified.")]
InvalidAlgorithm,
#[cfg(feature = "png")]
#[error(transparent)]
ImageDecoding(#[from] DecodingError),
#[cfg(feature = "png")]
ParseInt(#[from] ParseIntError),
#[error(transparent)]
ImageEncoding(#[from] EncodingError),
ParseFloat(#[from] ParseFloatError),

#[cfg(feature = "hash")]
#[error("Unable to decode hex value.")]
HexDecode,

#[cfg(feature = "http")]
#[error(transparent)]
JsonSerialization(#[from] serde_json::Error),
JsonSerialization(#[from] JsonError),
#[cfg(feature = "http")]
#[error(transparent)]
ParseInt(#[from] ParseIntError),
Request(#[from] Box<UreqError>),
#[cfg(feature = "http")]
#[error("Unable to parse HTTP arguments: {0}")]
HttpParse(String),
#[cfg(feature = "http")]
#[error("HTTP response over size limit")]
HttpTooBig,

#[cfg(feature = "iconforge")]
#[error("IconForge error: {0}")]
IconForge(String),

#[cfg(feature = "png")]
#[error(transparent)]
ParseFloat(#[from] ParseFloatError),
ImageDecoding(#[from] DecodingError),
#[cfg(feature = "png")]
#[error(transparent)]
ImageEncoding(#[from] EncodingError),
#[cfg(feature = "png")]
#[error(transparent)]
GenericImage(#[from] ImageError),
#[cfg(feature = "png")]
#[error("Invalid png data.")]
InvalidPngData,
#[cfg(feature = "http")]
#[error(transparent)]
Request(#[from] Box<ureq::Error>),

#[cfg(feature = "sound_len")]
#[error("SoundLen error: {0}")]
SoundLen(String),

#[cfg(feature = "toml")]
#[error(transparent)]
TomlDeserialization(#[from] toml_dep::de::Error),
TomlDeserialization(#[from] TomlDeserializeError),
#[cfg(feature = "toml")]
#[error(transparent)]
TomlSerialization(#[from] toml_dep::ser::Error),
TomlSerialization(#[from] TomlSerializeError),

#[cfg(feature = "unzip")]
#[error(transparent)]
Unzip(#[from] ZipError),
#[cfg(feature = "hash")]
#[error("Unable to decode hex value.")]
HexDecode,
#[cfg(feature = "iconforge")]
#[error("IconForge error: {0}")]
IconForge(String),

#[error("Panic during function execution: {0}")]
Panic(String),
}
Expand Down
Loading
Loading