diff options
| author | 2019-03-01 02:09:59 -0500 | |
|---|---|---|
| committer | 2019-03-01 02:09:59 -0500 | |
| commit | e287de2d1c1db4a5ffc0cc0a0c5d03bb7e909500 (patch) | |
| tree | 056cf1128213c1f394be4f1f5e7d6a909b5d0441 | |
| parent | Remove -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.d | 41 | ||||
| -rw-r--r-- | source/web.d | 36 |
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)); } |
