summaryrefslogtreecommitdiff
path: root/src/bahnhofname.gleam
diff options
context:
space:
mode:
authorstuebinm2023-10-30 11:49:03 +0100
committerstuebinm2023-10-30 12:48:44 +0100
commit194bccdc10d8e1213938348b203cb1db24ce67a6 (patch)
treed6b7753100c7f52d59cd29e73bd02fadacd6ec7b /src/bahnhofname.gleam
parentb231e47108f60beb3ad781b2e1e70e233bc36ab9 (diff)
update gleam & deps
Diffstat (limited to 'src/bahnhofname.gleam')
-rw-r--r--src/bahnhofname.gleam229
1 files changed, 132 insertions, 97 deletions
diff --git a/src/bahnhofname.gleam b/src/bahnhofname.gleam
index 725d0ae..0612587 100644
--- a/src/bahnhofname.gleam
+++ b/src/bahnhofname.gleam
@@ -1,7 +1,7 @@
import gleam/http/response.{Response}
-import gleam/http/request.{Request,get_header}
+import gleam/http/request.{Request, get_header}
import gleam/http.{Get}
-import gleam/bit_builder.{BitBuilder}
+import gleam/bit_builder
import gleam/erlang/process
import gleam/erlang/atom
import gleam/erlang/file
@@ -18,53 +18,69 @@ import gleam/result
import mist
const ds100_domain = "ds100.bahnhof.name"
+
const ril100_domain = "ril100.bahnhof.name"
+
const leitpunkt_domain = "leitpunkt.bahnhof.name"
+
const domain = "bahnhof.name"
+
const proto = "https://"
-external type Index
-external type Field
+type Index
+
+type Field
+
+@external(erlang, "Elixir.Haystack.Index", "new")
+fn index_new(a: atom.Atom) -> Index
+
+@external(erlang, "Elixir.Haystack.Index", "ref")
+fn index_ref(a: Index, b: Field) -> Index
+
+@external(erlang, "Elixir.Haystack.Index", "field")
+fn index_field(a: Index, b: Field) -> Index
+
+@external(erlang, "Elixir.Haystack.Index.Field", "term")
+fn field_term(a: String) -> Field
+
+@external(erlang, "Elixir.Haystack.Index.Field", "new")
+fn field_new(a: String) -> Field
+
+@external(erlang, "Elixir.Haystack.Index", "add")
+fn index_add(a: Index, b: List(a)) -> Index
-external fn index_new(atom.Atom) -> Index =
- "Elixir.Haystack.Index" "new"
+@external(erlang, "Elixir.IO", "inspect")
+pub fn inspect(a: a) -> a
-external fn index_ref(Index, Field) -> Index =
- "Elixir.Haystack.Index" "ref"
+type Query
-external fn index_field(Index, Field) -> Index =
- "Elixir.Haystack.Index" "field"
+type Clause
-external fn field_term(String) -> Field =
- "Elixir.Haystack.Index.Field" "term"
+type Expression
-external fn field_new(String) -> Field =
- "Elixir.Haystack.Index.Field" "new"
+@external(erlang, "Elixir.Haystack.Query", "new")
+fn query_new() -> Query
-external fn index_add(Index, List(a)) -> Index =
- "Elixir.Haystack.Index" "add"
+@external(erlang, "Elixir.Haystack.Query", "clause")
+fn query_clause(a: Query, b: Clause) -> Query
-pub external fn inspect(a) -> a =
- "Elixir.IO" "inspect"
+@external(erlang, "Elixir.Haystack.Query", "run")
+fn query_run(a: Query, b: Index) -> List(Map(atom.Atom, String))
-external type Query
-external type Clause
-external type Expression
-external fn query_new() -> Query =
- "Elixir.Haystack.Query" "new"
-external fn query_clause(Query, Clause) -> Query =
- "Elixir.Haystack.Query" "clause"
-external fn query_run(Query, Index) -> List(Map(atom.Atom, String)) =
- "Elixir.Haystack.Query" "run"
-external fn clause_new(atom.Atom) -> Clause =
- "Elixir.Haystack.Query.Clause" "new"
-external fn query_expressions(Clause, List(Expression)) -> Clause =
- "Elixir.Haystack.Query.Clause" "expressions"
-external fn query_expression_new(atom.Atom, List(#(atom.Atom, String))) -> Expression =
- "Elixir.Haystack.Query.Expression" "new"
+@external(erlang, "Elixir.Haystack.Query.Clause", "new")
+fn clause_new(a: atom.Atom) -> Clause
-external fn tokenize(String) -> List(Map(atom.Atom, String)) =
- "Elixir.Haystack.Tokenizer" "tokenize"
+@external(erlang, "Elixir.Haystack.Query.Clause", "expressions")
+fn query_expressions(a: Clause, b: List(Expression)) -> Clause
+
+@external(erlang, "Elixir.Haystack.Query.Expression", "new")
+fn query_expression_new(
+ a: atom.Atom,
+ b: List(#(atom.Atom, String)),
+) -> Expression
+
+@external(erlang, "Elixir.Haystack.Tokenizer", "tokenize")
+fn tokenize(a: String) -> List(Map(atom.Atom, String))
type IdKind {
DS100
@@ -100,7 +116,7 @@ fn unpercent(encoded: String) -> String {
|> list.prepend(bit_string.from_string(head))
|> bit_string.concat
|> bit_string.to_string
- |> result.map(fn (str) { string.replace(str, "_", " ") })
+ |> result.map(fn(str) { string.replace(str, "_", " ") })
res
}
@@ -116,7 +132,7 @@ fn lookup_exact(query: String, lookup: Map(String, String)) -> #(Int, String) {
fn lookup_fuzzy(
query: String,
kind: IdKind,
- fuzzy: fn(String, IdKind) -> Matched(String)
+ fuzzy: fn(String, IdKind) -> Matched(String),
) -> #(Int, String) {
case fuzzy(query, kind) {
Exact(res) -> #(200, res)
@@ -125,7 +141,7 @@ fn lookup_fuzzy(
}
}
-fn if_not(res: #(Int,t), fallback: fn() -> #(Int,t)) -> #(Int,t) {
+fn if_not(res: #(Int, t), fallback: fn() -> #(Int, t)) -> #(Int, t) {
inspect(case res {
#(200, _) -> res
_ -> fallback()
@@ -136,43 +152,43 @@ fn lookup_station(
request: Request(t),
ds100_to_name: Map(String, String),
leitpunkt_to_name: Map(String, String),
- fuzzy: fn (String, IdKind) -> Matched(String)
-) -> Response(BitBuilder) {
+ fuzzy: fn(String, IdKind) -> Matched(String),
+) -> Response(mist.ResponseData) {
let #(code, text) = case request {
// blackhole favicon.ico requests instead of using the index
Request(method: Get, path: "/favicon.ico", ..) -> #(404, "")
Request(method: Get, path: "/help", ..)
| Request(method: Get, path: "/", ..) -> #(
200,
- "ril100 → Name: " <> proto<>ril100_domain<>"/HG\n" <>
- "Name → ril100: " <> proto<>ril100_domain <> "/Göttingen\n\n" <>
- "Leitpunkt → Name: " <> proto<>leitpunkt_domain<>"/GOE\n" <>
- "Name → Leitpunkt: " <> proto<>leitpunkt_domain <> "/Göttingen\n\n"<>
- "Fuzzy:" <> proto<>domain<>"/...",
+ "ril100 → Name: " <> proto <> ril100_domain <> "/HG\n" <> "Name → ril100: " <> proto <> ril100_domain <> "/Göttingen\n\n" <> "Leitpunkt → Name: " <> proto <> leitpunkt_domain <> "/GOE\n" <> "Name → Leitpunkt: " <> proto <> leitpunkt_domain <> "/Göttingen\n\n" <> "Fuzzy:" <> proto <> domain <> "/...",
)
Request(method: Get, path: "/" <> path, ..) -> {
let query = unpercent(path)
case get_header(request, "x-forwarded-host") {
- Ok(domain) if domain == leitpunkt_domain -> query
+ Ok(domain) if domain == leitpunkt_domain ->
+ query
|> lookup_exact(leitpunkt_to_name)
- |> if_not(fn() {lookup_fuzzy(query,Leitpunkt,fuzzy)})
- Ok(domain) if domain == ril100_domain || domain == ds100_domain -> query
+ |> if_not(fn() { lookup_fuzzy(query, Leitpunkt, fuzzy) })
+ Ok(domain) if domain == ril100_domain || domain == ds100_domain ->
+ query
|> lookup_exact(ds100_to_name)
- |> if_not(fn() {lookup_fuzzy(query,DS100, fuzzy)})
+ |> if_not(fn() { lookup_fuzzy(query, DS100, fuzzy) })
_ -> {
let by_ds100 = lookup_exact(query, ds100_to_name)
let by_lp = lookup_exact(query, leitpunkt_to_name)
case #(by_ds100.0, by_lp.0) {
- #(200, _) -> #(302, proto<>ril100_domain<>"/"<>path)
- #(_, 200) -> #(302, proto<>leitpunkt_domain<>"/"<>path)
- _ -> #(302, proto<>ril100_domain<>"/"<>path)
+ #(200, _) -> #(302, proto <> ril100_domain <> "/" <> path)
+ #(_, 200) -> #(302, proto <> leitpunkt_domain <> "/" <> path)
+ _ -> #(302, proto <> ril100_domain <> "/" <> path)
}
}
}
}
- _ -> #(404, "intended usage is e.g. curl " <> proto<>domain<>"/FF")
+ _ -> #(404, "intended usage is e.g. curl " <> proto <> domain <> "/FF")
}
- let body = bit_builder.from_string(text)
+ let body = text
+ |> bit_builder.from_string
+ |> mist.Bytes
response.new(code)
|> response.prepend_header(
@@ -184,17 +200,20 @@ fn lookup_station(
"https://stuebinm.eu/git/bahnhof.name",
)
|> response.prepend_header("content-type", "text/plain; charset=utf8")
- |> fn (a) { case code == 302 {
- True -> response.prepend_header(a, "location", text)
- _ -> a
- } }
+ |> fn(a) {
+ case code == 302 {
+ True -> response.prepend_header(a, "location", text)
+ _ -> a
+ }
+ }
|> response.set_body(body)
}
pub fn main() {
let assert Ok(bahn_ril100) = fetch_data()
- let ds100s = read_csv(bahn_ril100)
+ let ds100s =
+ read_csv(bahn_ril100)
|> list.filter_map(fn(fields) {
case fields {
[_, ds100, name, ..] -> Ok(#(name, ds100))
@@ -215,22 +234,31 @@ pub fn main() {
let name_to_leitpunkt = map.from_list(leitpunkte)
let ds100_to_name = map.from_list(list.map(ds100s, swap))
let leitpunkt_to_name = map.from_list(list.map(leitpunkte, swap))
- let ds100index = index_new(atom.create_from_string("ds100"))
+ let ds100index =
+ index_new(atom.create_from_string("ds100"))
|> index_ref(field_term("id"))
|> index_field(field_new("name"))
- |> index_add(ds100s
- |> list.map(fn(tuple) {case tuple {
- #(name, ds100)
- -> map.from_list([#("id", ds100), #("name", name)]
- )}}))
- let leitpunkt_index = index_new(atom.create_from_string("leitpunkt"))
+ |> index_add(
+ ds100s
+ |> list.map(fn(tuple) {
+ case tuple {
+ #(name, ds100) -> map.from_list([#("id", ds100), #("name", name)])
+ }
+ }),
+ )
+ let leitpunkt_index =
+ index_new(atom.create_from_string("leitpunkt"))
|> index_ref(field_term("id"))
|> index_field(field_new("name"))
- |> index_add(leitpunkte
- |> list.map(fn(tuple) {case tuple {
- #(name, leitpunkt)
- -> map.from_list([#("id", leitpunkt), #("name", name)]
- )}}))
+ |> index_add(
+ leitpunkte
+ |> list.map(fn(tuple) {
+ case tuple {
+ #(name, leitpunkt) ->
+ map.from_list([#("id", leitpunkt), #("name", name)])
+ }
+ }),
+ )
let ref = atom.create_from_string("ref")
let fuzzy = fn(searchterm: String, kind: IdKind) -> List(String) {
@@ -242,26 +270,36 @@ pub fn main() {
let match = atom.create_from_string("match")
let field = atom.create_from_string("field")
let term = atom.create_from_string("term")
- let expressions = tokenize(inspect(searchterm))
- |> list.filter_map(fn (a) { map.get(a, atom.create_from_string("v")) })
- |> list.map(fn (token) { query_expression_new(match, [#(field, "name"), #(term, token)]) })
- let clause = query_expressions(clause_new(atom.create_from_string("all")), expressions)
+ let expressions =
+ tokenize(inspect(searchterm))
+ |> list.filter_map(fn(a) { map.get(a, atom.create_from_string("v")) })
+ |> list.map(fn(token) {
+ query_expression_new(match, [#(field, "name"), #(term, token)])
+ })
+ let clause =
+ query_expressions(clause_new(atom.create_from_string("all")), expressions)
let query = query_clause(query, clause)
- let matches = query_run(query, index)
- |> list.filter_map(fn (a) { map.get(a, ref) })
+ let matches =
+ query_run(query, index)
+ |> list.filter_map(fn(a) { map.get(a, ref) })
inspect(matches)
case list.length(matches) > 5 {
True -> {
let query = query_new()
- let clause = query_expressions(
- clause_new(atom.create_from_string("all")),
- [query_expression_new(match, [#(field, "name"), #(term, "hbf")]) , ..expressions]
- )
+ let clause =
+ query_expressions(
+ clause_new(atom.create_from_string("all")),
+ [
+ query_expression_new(match, [#(field, "name"), #(term, "hbf")]),
+ ..expressions
+ ],
+ )
let query = query_clause(query, clause)
- let narrow = query_run(query, index)
- |> list.filter_map(fn (a) { map.get(a, ref) })
+ let narrow =
+ query_run(query, index)
+ |> list.filter_map(fn(a) { map.get(a, ref) })
case narrow {
[] -> matches
_ -> narrow
@@ -279,10 +317,9 @@ pub fn main() {
case map.get(stations, searchterm) {
Ok(id) -> Exact(id)
_ -> {
- let results = fuzzy(searchterm, kind)
- |> list.filter_map(fn (res) {
- map.get(ids, string.uppercase(res))
- })
+ let results =
+ fuzzy(searchterm, kind)
+ |> list.filter_map(fn(res) { map.get(ids, string.uppercase(res)) })
case results {
[res] -> Fuzzy(res)
[res, ..] -> Fuzzy(res)
@@ -294,16 +331,14 @@ pub fn main() {
io.println("compiled indices, starting server …")
- let _ = mist.run_service(
- 2345,
- fn(req) { lookup_station(
- req,
- ds100_to_name,
- leitpunkt_to_name,
- exact_then_fuzzy
- ) },
- max_body_limit: 100,
- )
+ let assert Ok(_) =
+ fn(req: Request(mist.Connection)) -> Response(mist.ResponseData) {
+ lookup_station(req, ds100_to_name, leitpunkt_to_name, exact_then_fuzzy)
+ }
+ |> mist.new
+ |> mist.port(2345)
+ |> mist.start_http
+
process.sleep_forever()
}