summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorChloe Kudryavtsev <toast@toastin.space>2019-03-01 02:09:59 -0500
committerChloe Kudryavtsev <toast@toastin.space>2019-03-01 02:09:59 -0500
commite287de2d1c1db4a5ffc0cc0a0c5d03bb7e909500 (patch)
tree056cf1128213c1f394be4f1f5e7d6a909b5d0441
parentRemove -X from curl invocation (diff)
Abstract out storage
This means that various redis failures will get caught. Also opens up the possibility of PUT (for naming). Also simplified health checks! And, of course, makes it easier to swap backends later, if needed.
-rw-r--r--source/storage.d41
-rw-r--r--source/web.d36
2 files changed, 56 insertions, 21 deletions
diff --git a/source/storage.d b/source/storage.d
new file mode 100644
index 0000000..730c5ab
--- /dev/null
+++ b/source/storage.d
@@ -0,0 +1,41 @@
+module brpaste.storage;
+
+import vibe.vibe;
+
+class RedisStorage {
+ private RedisDatabase client;
+
+ this(URL url = URL("redis://127.0.0.1")) {
+ client = connectRedisDB(url);
+ }
+
+ void isDown() {
+ enforceHTTP(healthy, HTTPStatus.serviceUnavailable, "Redis is down.");
+ }
+
+ bool healthy() {
+ try {
+ client.client.ping;
+ } catch (Exception e) {
+ return false;
+ }
+ return true;
+ }
+
+ auto get(in string key) {
+ isDown;
+ enforceHTTP(client.exists(key), HTTPStatus.notFound, key ~ " not found.");
+ return client.get(key);
+ }
+
+ void put(in string key, in string data) {
+ isDown;
+ client.set(key, data);
+ }
+
+ void putCollision(in string key, in string data) {
+ isDown;
+ enforceHTTP(! client.exists(key), HTTPStatus.unprocessableEntity, key ~ " already exists.");
+ put(key, data);
+ }
+}
diff --git a/source/web.d b/source/web.d
index eddd55e..16dbbb9 100644
--- a/source/web.d
+++ b/source/web.d
@@ -1,29 +1,31 @@
module brpaste.web;
import brpaste.hash;
+import brpaste.storage;
import vibe.vibe;
-RedisDatabase client;
+RedisStorage store;
-void id(HTTPServerRequest req, HTTPServerResponse res) {
+string idCommon(in HTTPServerRequest req) {
string id = req.params["id"];
+ return store.get(id);
+}
+
+void id(HTTPServerRequest req, HTTPServerResponse res) {
string language = "none";
// TODO: rewrite the next two lines once #2273 is resolved
if ("lang" in req.query) language = req.query["lang"];
else if (req.query.length > 0) language = req.query.byKey.front;
- enforceHTTP(client.exists(id), HTTPStatus.notFound, "No paste under " ~ id ~ ".");
- auto data = client.get(id);
+ auto data = idCommon(req);
render!("code.dt", data, language)(res);
}
void rawId(HTTPServerRequest req, HTTPServerResponse res) {
- string id = req.params["id"];
- enforceHTTP(client.exists(id), HTTPStatus.notFound, "No paste under " ~ id ~ ".");
-
- auto data = client.get(id);
res.contentType = "text/plain";
+
+ auto data = idCommon(req);
res.writeBody(data);
}
@@ -32,31 +34,23 @@ void post(HTTPServerRequest req, HTTPServerResponse res) {
auto data = req.form["data"];
auto hash = data.hash;
- client.set(hash, data);
+ store.put(hash, data);
res.statusCode = HTTPStatus.created;
res.writeBody(hash);
}
void health(HTTPServerRequest req, HTTPServerResponse res) {
res.statusCode = HTTPStatus.noContent;
- scope(exit) res.writeBody("");
+ scope(success) res.writeBody("");
// Redis
- try {
- client.client.ping;
- } catch (Exception e) {
- logCritical("Redis is down!");
- res.statusCode = HTTPStatus.serviceUnavailable;
- res.statusPhrase = "Backend Storage Unavailable";
- res.headers["Retry-After"] = "60";
- }
+ store.isDown;
}
shared static this() {
// setup redis
- string path = "redis://127.0.0.1";
+ string path;
readOption("redis|r", &path, "The URL to use to connect to redis");
- URL redis = path;
- client = connectRedisDB(redis);
+ store = path.empty ? new RedisStorage : new RedisStorage(URL(path));
}