switch to cuid
Some checks failed
test / test (push) Failing after 7s

This commit is contained in:
Luca Bilke 2024-07-01 21:19:35 +02:00
parent f5095938b8
commit 62cd2f8f42
No known key found for this signature in database
GPG key ID: C9E851809C1A5BDE
4 changed files with 38 additions and 44 deletions

View file

@ -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(

View file

@ -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)

View file

@ -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()
}
}

View file

@ -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()