parent
f5095938b8
commit
62cd2f8f42
4 changed files with 38 additions and 44 deletions
|
@ -1,12 +1,14 @@
|
|||
import envoy
|
||||
import gleam/erlang/process.{type Subject}
|
||||
import gleam/int
|
||||
import gleam/pgo
|
||||
import gleam/result.{unwrap}
|
||||
import gleam/uri
|
||||
import ids/cuid.{type Message}
|
||||
import wisp
|
||||
|
||||
pub type Context {
|
||||
Context(db: pgo.Connection, config: Config)
|
||||
Context(db: pgo.Connection, config: Config, cuid: Subject(Message))
|
||||
}
|
||||
|
||||
pub type Config {
|
||||
|
@ -52,15 +54,6 @@ pub fn generate_url(
|
|||
|> result.map(uri.to_string)
|
||||
}
|
||||
|
||||
// fn get_path_or(var: String, default: List(String)) -> List(String) {
|
||||
// case envoy.get(var) {
|
||||
// Ok(path_raw) -> {
|
||||
// string.split(path_raw, "/")
|
||||
// }
|
||||
// Error(_) -> default
|
||||
// }
|
||||
// }
|
||||
|
||||
pub fn load_config_from_env() -> Config {
|
||||
let defaults =
|
||||
Config(
|
||||
|
|
|
@ -7,19 +7,19 @@ import gleam/list
|
|||
import gleam/pgo
|
||||
import gleam/result
|
||||
import gleam/string
|
||||
import ids/nanoid
|
||||
import ids/cuid
|
||||
import wisp.{type Request, type Response}
|
||||
|
||||
const schema = "
|
||||
CREATE TABLE IF NOT EXISTS \"File\" (
|
||||
nanoid VARCHAR(21) PRIMARY KEY,
|
||||
Md5Hash VARCHAR(32)
|
||||
Cuid CHAR(25) PRIMARY KEY,
|
||||
Md5Hash CHAR(32)
|
||||
FileName TEXT
|
||||
);
|
||||
"
|
||||
|
||||
pub type File {
|
||||
File(nano_id: String, md5_hash: String, file_name: String)
|
||||
File(cuid: String, md5_hash: String, file_name: String)
|
||||
}
|
||||
|
||||
pub fn prepare_database(ctx: Context) -> Result(Nil, pgo.QueryError) {
|
||||
|
@ -29,12 +29,12 @@ pub fn prepare_database(ctx: Context) -> Result(Nil, pgo.QueryError) {
|
|||
|
||||
pub fn store(file: File, ctx: Context) -> Result(String, Nil) {
|
||||
let sql =
|
||||
"INSERT INTO \"File\" (NanoID, Md5Hash) VALUES ($1, $2) RETURNING NanoID;"
|
||||
"INSERT INTO \"File\" (Cuid, Md5Hash) VALUES ($1, $2) RETURNING Cuid;"
|
||||
case
|
||||
pgo.execute(
|
||||
sql,
|
||||
ctx.db,
|
||||
[pgo.text(file.nano_id), pgo.text(file.md5_hash)],
|
||||
[pgo.text(file.cuid), pgo.text(file.md5_hash)],
|
||||
dynamic.element(0, dynamic.string),
|
||||
)
|
||||
{
|
||||
|
@ -44,20 +44,19 @@ pub fn store(file: File, ctx: Context) -> Result(String, Nil) {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn retrieve(nano_id: String, ctx: Context) -> Result(File, Nil) {
|
||||
let sql = "SELECT NanoID,Md5Hash,FileName FROM \"File\" WHERE NanoID = $1;"
|
||||
pub fn retrieve(cuid: String, ctx: Context) -> Result(File, Nil) {
|
||||
let sql = "SELECT Cuid,Md5Hash,FileName FROM \"File\" WHERE Cuid = $1;"
|
||||
case
|
||||
pgo.execute(
|
||||
sql,
|
||||
ctx.db,
|
||||
[pgo.text(nano_id)],
|
||||
[pgo.text(cuid)],
|
||||
dynamic.tuple3(dynamic.string, dynamic.string, dynamic.string),
|
||||
)
|
||||
{
|
||||
Ok(res) ->
|
||||
case res.rows |> list.first {
|
||||
Ok(#(nano_id, md5_hash, file_name)) ->
|
||||
Ok(File(nano_id, md5_hash, file_name))
|
||||
Ok(#(cuid, md5_hash, file_name)) -> Ok(File(cuid, md5_hash, file_name))
|
||||
_ -> Error(Nil)
|
||||
}
|
||||
_ -> Error(Nil)
|
||||
|
@ -84,8 +83,8 @@ pub fn serve_hash(req: Request, md5_hash: String) -> Response {
|
|||
pub fn handle_get(req: Request, ctx: Context) -> Response {
|
||||
use <- wisp.require_method(req, Get)
|
||||
case wisp.path_segments(req) {
|
||||
["f", nano_id] ->
|
||||
case retrieve(nano_id, ctx) {
|
||||
["f", cuid] ->
|
||||
case retrieve(cuid, ctx) {
|
||||
Ok(file) -> serve_hash(req, file.md5_hash)
|
||||
Error(_) -> wisp.not_found()
|
||||
}
|
||||
|
@ -99,9 +98,9 @@ pub fn handle_post(req: Request, ctx: Context) -> Response {
|
|||
|
||||
case wisp.path_segments(req) {
|
||||
["f", path] -> {
|
||||
let nano_id = nanoid.generate()
|
||||
let cuid = cuid.generate(ctx.cuid)
|
||||
let md5_hash = crypto.hash(crypto.Md5, body) |> bit_array.base16_encode
|
||||
let file = File(nano_id, md5_hash, path)
|
||||
let file = File(cuid, md5_hash, path)
|
||||
|
||||
case store(file, ctx) |> result.try(config.generate_url(_, "f", ctx)) {
|
||||
Ok(url) -> wisp.ok() |> wisp.string_body(url)
|
||||
|
|
|
@ -6,18 +6,18 @@ import gleam/pair
|
|||
import gleam/pgo
|
||||
import gleam/result
|
||||
import gleam/uri.{type Uri}
|
||||
import ids/nanoid
|
||||
import ids/cuid
|
||||
import wisp.{type Request, type Response}
|
||||
|
||||
const schema = "
|
||||
CREATE TABLE IF NOT EXISTS \"Link\" (
|
||||
NanoID VARCHAR(21) PRIMARY KEY,
|
||||
Cuid CHAR(25) PRIMARY KEY,
|
||||
TargetURL TEXT
|
||||
);
|
||||
"
|
||||
|
||||
pub type Link {
|
||||
Link(nano_id: String, target_url: Uri)
|
||||
Link(cuid: String, target_url: Uri)
|
||||
}
|
||||
|
||||
pub fn prepare_database(ctx: Context) -> Result(Nil, pgo.QueryError) {
|
||||
|
@ -27,12 +27,12 @@ pub fn prepare_database(ctx: Context) -> Result(Nil, pgo.QueryError) {
|
|||
|
||||
pub fn store(link: Link, ctx: Context) -> Result(String, Nil) {
|
||||
let sql =
|
||||
"INSERT INTO \"Link\" (NanoID, TargetURL) VALUES ($1, $2) RETURNING NanoID;"
|
||||
"INSERT INTO \"Link\" (Cuid, TargetURL) VALUES ($1, $2) RETURNING Cuid;"
|
||||
case
|
||||
pgo.execute(
|
||||
sql,
|
||||
ctx.db,
|
||||
[pgo.text(link.nano_id), pgo.text(link.target_url |> uri.to_string)],
|
||||
[pgo.text(link.cuid), pgo.text(link.target_url |> uri.to_string)],
|
||||
dynamic.element(0, dynamic.string),
|
||||
)
|
||||
{
|
||||
|
@ -42,26 +42,26 @@ pub fn store(link: Link, ctx: Context) -> Result(String, Nil) {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn retrieve(nano_id: String, ctx: Context) -> Result(Link, Nil) {
|
||||
let sql = "SELECT NanoID,TargetURL FROM \"Link\" WHERE NanoID = $1;"
|
||||
pub fn retrieve(cuid: String, ctx: Context) -> Result(Link, Nil) {
|
||||
let sql = "SELECT Cuid,TargetURL FROM \"Link\" WHERE Cuid = $1;"
|
||||
case
|
||||
pgo.execute(
|
||||
sql,
|
||||
ctx.db,
|
||||
[pgo.text(nano_id)],
|
||||
[pgo.text(cuid)],
|
||||
dynamic.tuple2(dynamic.string, dynamic.string),
|
||||
)
|
||||
{
|
||||
Ok(res) -> {
|
||||
let sql_response = res.rows |> list.first
|
||||
let nano_id = sql_response |> result.map(pair.first)
|
||||
let cuid = sql_response |> result.map(pair.first)
|
||||
let target_url =
|
||||
sql_response |> result.map(pair.second) |> result.try(uri.parse)
|
||||
|
||||
{
|
||||
use nano_id <- result.try(nano_id)
|
||||
use cuid <- result.try(cuid)
|
||||
use target_url <- result.try(target_url)
|
||||
Ok(Link(nano_id, target_url))
|
||||
Ok(Link(cuid, target_url))
|
||||
}
|
||||
}
|
||||
_ -> Error(Nil)
|
||||
|
@ -69,7 +69,7 @@ pub fn retrieve(nano_id: String, ctx: Context) -> Result(Link, Nil) {
|
|||
}
|
||||
|
||||
pub fn handle_uri(url: Uri, ctx: Context) -> Response {
|
||||
store(nanoid.generate() |> Link(url), ctx)
|
||||
store(cuid.generate(ctx.cuid) |> Link(url), ctx)
|
||||
|> result.try(config.generate_url(_, "l", ctx))
|
||||
|> result.map(wisp.string_body(wisp.response(200), _))
|
||||
|> result.unwrap(wisp.response(500))
|
||||
|
@ -84,9 +84,9 @@ pub fn handle_root(req: Request, ctx: Context) -> Response {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn handle_nano_id(req: Request, nano_id: String, ctx: Context) -> Response {
|
||||
pub fn handle_cuid(req: Request, cuid: String, ctx: Context) -> Response {
|
||||
use <- wisp.require_method(req, Get)
|
||||
case retrieve(nano_id, ctx) {
|
||||
case retrieve(cuid, ctx) {
|
||||
Ok(link) -> wisp.redirect(link.target_url |> uri.to_string)
|
||||
Error(_) -> wisp.not_found()
|
||||
}
|
||||
|
@ -95,7 +95,7 @@ pub fn handle_nano_id(req: Request, nano_id: String, ctx: Context) -> Response {
|
|||
pub fn handle_request(req: Request, ctx: Context) -> Response {
|
||||
case wisp.path_segments(req) {
|
||||
["l"] -> handle_root(req, ctx)
|
||||
["l", nano_id] -> handle_nano_id(req, nano_id, ctx)
|
||||
["l", cuid] -> handle_cuid(req, cuid, ctx)
|
||||
_ -> wisp.not_found()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
import app/config.{type Config, type Context, Context}
|
||||
import app/config.{type Context, Context}
|
||||
import app/router
|
||||
import gleam/erlang/process
|
||||
import gleam/pgo
|
||||
import ids/cuid
|
||||
import mist
|
||||
import wisp
|
||||
|
||||
fn with_context(continue: fn(Context) -> Nil) -> Nil {
|
||||
let config = config.load_config_from_env()
|
||||
let assert Ok(cuid) = cuid.start()
|
||||
let db =
|
||||
pgo.connect(
|
||||
pgo.Config(
|
||||
|
@ -16,7 +18,7 @@ fn with_context(continue: fn(Context) -> Nil) -> Nil {
|
|||
pool_size: config.postgres_pool_size,
|
||||
),
|
||||
)
|
||||
let ctx = Context(db: db, config: config)
|
||||
let ctx = Context(db: db, config: config, cuid: cuid)
|
||||
|
||||
continue(ctx)
|
||||
|
||||
|
@ -30,9 +32,9 @@ pub fn main() {
|
|||
|
||||
let assert Ok(_) =
|
||||
router.handle_request(_, ctx)
|
||||
|> wisp.mist_handler(config.secret_key_base)
|
||||
|> wisp.mist_handler(ctx.config.secret_key_base)
|
||||
|> mist.new
|
||||
|> mist.port(config.port)
|
||||
|> mist.port(ctx.config.port)
|
||||
|> mist.start_http
|
||||
|
||||
process.sleep_forever()
|
||||
|
|
Loading…
Add table
Reference in a new issue