aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFuwn <[email protected]>2021-07-05 15:11:11 -0700
committerFuwn <[email protected]>2021-07-05 15:11:11 -0700
commitb15618cec3d3a111ebfbf82772bbe1ba0826d0fc (patch)
tree1d559cd246d803590967c1f438217168b15f3743
parentfeat(whirl_server): implement a demo of the REGOBJID and APPRACTR commands (diff)
downloadwhirl-b15618cec3d3a111ebfbf82772bbe1ba0826d0fc.tar.xz
whirl-b15618cec3d3a111ebfbf82772bbe1ba0826d0fc.zip
feat(whirl_api): /api/v1/worlds/vip endpoint
An endpoint for checking if a given user has VIP status at the time of request. Example usage: https://api.whirlsplash.org/api/v1/worlds/vip?username=fuwn will return `false`.
-rw-r--r--crates/whirl_api/Cargo.toml4
-rw-r--r--crates/whirl_api/src/lib.rs1
-rw-r--r--crates/whirl_api/src/routes/mod.rs1
-rw-r--r--crates/whirl_api/src/routes/worlds/mod.rs4
-rw-r--r--crates/whirl_api/src/routes/worlds/vip/mod.rs53
-rw-r--r--crates/whirl_api/src/routes/worlds/vip/structures.rs8
6 files changed, 71 insertions, 0 deletions
diff --git a/crates/whirl_api/Cargo.toml b/crates/whirl_api/Cargo.toml
index dc04cbf..626196d 100644
--- a/crates/whirl_api/Cargo.toml
+++ b/crates/whirl_api/Cargo.toml
@@ -22,6 +22,7 @@ sysinfo = "0.19.0"
whirl_common = { path = "../whirl_common" }
tokio = { version = "1.8.0", features = ["full"] }
num-traits = "0.2.14"
+qstring = "0.7.2"
# Serialization
serde = "1.0.126"
@@ -32,3 +33,6 @@ log = "0.4.14"
# Config
whirl_config = { path = "../whirl_config" }
+
+# Web
+curl = "0.4.38"
diff --git a/crates/whirl_api/src/lib.rs b/crates/whirl_api/src/lib.rs
index 3f09ce0..59de414 100644
--- a/crates/whirl_api/src/lib.rs
+++ b/crates/whirl_api/src/lib.rs
@@ -56,6 +56,7 @@ impl Api {
.wrap(actix_cors::Cors::default().allow_any_origin())
.service(resource("/").to(|| async { "Whirlsplash" }))
.service(resource("/api/v1/statistics").to(routes::stats::statistics))
+ .service(resource("/api/v1/worlds/vip").to(routes::worlds::vip::vip))
})
.bind(address)?
.run();
diff --git a/crates/whirl_api/src/routes/mod.rs b/crates/whirl_api/src/routes/mod.rs
index ca664cd..562e73d 100644
--- a/crates/whirl_api/src/routes/mod.rs
+++ b/crates/whirl_api/src/routes/mod.rs
@@ -2,3 +2,4 @@
// SPDX-License-Identifier: GPL-3.0-only
pub mod stats;
+pub mod worlds;
diff --git a/crates/whirl_api/src/routes/worlds/mod.rs b/crates/whirl_api/src/routes/worlds/mod.rs
new file mode 100644
index 0000000..32351f8
--- /dev/null
+++ b/crates/whirl_api/src/routes/worlds/mod.rs
@@ -0,0 +1,4 @@
+// Copyright (C) 2021-2021 The Whirlsplash Collective
+// SPDX-License-Identifier: GPL-3.0-only
+
+pub mod vip;
diff --git a/crates/whirl_api/src/routes/worlds/vip/mod.rs b/crates/whirl_api/src/routes/worlds/vip/mod.rs
new file mode 100644
index 0000000..c9455e6
--- /dev/null
+++ b/crates/whirl_api/src/routes/worlds/vip/mod.rs
@@ -0,0 +1,53 @@
+// Copyright (C) 2021-2021 The Whirlsplash Collective
+// SPDX-License-Identifier: GPL-3.0-only
+
+mod structures;
+
+use std::str::from_utf8;
+
+use actix_web::{HttpRequest, HttpResponse};
+
+use crate::routes::worlds::vip::structures::Vip;
+
+// error: this argument is passed by value, but not consumed in the function
+// body
+#[allow(clippy::needless_pass_by_value)]
+pub fn vip(req: HttpRequest) -> HttpResponse {
+ let queries = qstring::QString::from(req.query_string());
+ let mut easy = curl::easy::Easy::new();
+ let mut error = String::new();
+
+ let username = queries.get("username");
+ if username.is_none() || username.map_or(false, str::is_empty) {
+ error = "no username query parameter provided, defaulting to 'null'".to_string();
+ }
+
+ easy
+ .url(&format!(
+ "http://www-dynamic.us.worlds.net/cgi-bin/vip.pl?Username={}",
+ username.unwrap_or("null"),
+ ))
+ .unwrap();
+
+ let mut response = Vec::new();
+
+ // https://docs.rs/curl/0.4.6/curl/easy/struct.Easy.html
+ {
+ let mut transfer = easy.transfer();
+ transfer
+ .write_function(|data| {
+ response.extend_from_slice(data);
+ Ok(data.len())
+ })
+ .unwrap();
+ transfer.perform().unwrap();
+ }
+
+ HttpResponse::Ok().json(Vip {
+ vip: from_utf8(&response)
+ .unwrap()
+ .to_string()
+ .contains("You're already a VIP!"),
+ error: if error.is_empty() { None } else { Some(error) },
+ })
+}
diff --git a/crates/whirl_api/src/routes/worlds/vip/structures.rs b/crates/whirl_api/src/routes/worlds/vip/structures.rs
new file mode 100644
index 0000000..5438b49
--- /dev/null
+++ b/crates/whirl_api/src/routes/worlds/vip/structures.rs
@@ -0,0 +1,8 @@
+// Copyright (C) 2021-2021 The Whirlsplash Collective
+// SPDX-License-Identifier: GPL-3.0-only
+
+#[derive(Serialize)]
+pub struct Vip {
+ pub vip: bool,
+ pub error: Option<String>,
+}