summaryrefslogtreecommitdiff
path: root/src/bahnhofname.gleam
diff options
context:
space:
mode:
Diffstat (limited to 'src/bahnhofname.gleam')
-rw-r--r--src/bahnhofname.gleam110
1 files changed, 88 insertions, 22 deletions
diff --git a/src/bahnhofname.gleam b/src/bahnhofname.gleam
index 0612587..fe3b10f 100644
--- a/src/bahnhofname.gleam
+++ b/src/bahnhofname.gleam
@@ -89,7 +89,7 @@ type IdKind {
type Matched(t) {
Exact(t)
- Fuzzy(t)
+ Fuzzy(t, t)
Failed
}
@@ -136,7 +136,7 @@ fn lookup_fuzzy(
) -> #(Int, String) {
case fuzzy(query, kind) {
Exact(res) -> #(200, res)
- Fuzzy(res) -> #(302, res)
+ Fuzzy(res, _) -> #(302, res)
Failed -> #(404, "??")
}
}
@@ -148,31 +148,72 @@ fn if_not(res: #(Int, t), fallback: fn() -> #(Int, t)) -> #(Int, t) {
})
}
+
fn lookup_station(
request: Request(t),
ds100_to_name: Map(String, String),
leitpunkt_to_name: Map(String, String),
+ lookup_platform: fn(String) -> String,
fuzzy: fn(String, IdKind) -> Matched(String),
) -> Response(mist.ResponseData) {
- let #(code, text) = case request {
+ let #(#(code, text), is_html) = case request {
// blackhole favicon.ico requests instead of using the index
- Request(method: Get, path: "/favicon.ico", ..) -> #(404, "")
+ Request(method: Get, path: "/favicon.ico", ..) -> #(#(404, ""), False)
Request(method: Get, path: "/help", ..)
- | Request(method: Get, path: "/", ..) -> #(
+ | 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 <> "/...",
+ ), False)
Request(method: Get, path: "/" <> path, ..) -> {
- let query = unpercent(path)
- case get_header(request, "x-forwarded-host") {
- Ok(domain) if domain == leitpunkt_domain ->
+ let raw_query = unpercent(path)
+ let show_platforms = string.ends_with(raw_query, "/gleis")
+ || string.ends_with(raw_query, "/bahnsteig")
+ || string.ends_with(raw_query, "/platforms")
+ || string.ends_with(raw_query, "/tracks")
+ || string.ends_with(raw_query, "/platform")
+ || string.ends_with(raw_query, "/track")
+ let query = raw_query
+ |> string.replace("/gleis","")
+ |> string.replace("/bahnsteig","")
+ |> string.replace("/platforms","")
+ |> string.replace("/tracks","")
+ |> string.replace("/platform","")
+ |> string.replace("/track","")
+ case #(show_platforms, get_header(request, "x-forwarded-host")) {
+ #(False, 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 ->
+ |> pair.new(False)
+ #(False, Ok(domain)) if domain == ril100_domain || domain == ds100_domain ->
query
|> lookup_exact(ds100_to_name)
|> if_not(fn() { lookup_fuzzy(query, DS100, fuzzy) })
+ |> pair.new(False)
+ #(True, Ok(domain)) if domain == leitpunkt_domain -> {
+ let query = case map.get(leitpunkt_to_name, query) {
+ Ok(name) -> name
+ _ -> query
+ }
+ case fuzzy(query, DS100) {
+ Exact(code) -> #(200, lookup_platform(code))
+ Fuzzy(_, code) -> #(200, lookup_platform(code))
+ _ -> #(404, "")
+ } |> pair.new(True)
+ }
+ #(True, Ok(domain)) if domain == ril100_domain || domain == ds100_domain ->
+ case lookup_exact(query, ds100_to_name) {
+ #(200,_) -> #(200, lookup_platform(query))
+ _ -> case fuzzy(query, DS100) {
+ Exact(code) -> #(200, lookup_platform(code))
+ Fuzzy(_, code) -> #(200, lookup_platform(code))
+ _ -> #(404, "")
+ }
+ } |> pair.new(True)
_ -> {
let by_ds100 = lookup_exact(query, ds100_to_name)
let by_lp = lookup_exact(query, leitpunkt_to_name)
@@ -180,16 +221,21 @@ fn lookup_station(
#(200, _) -> #(302, proto <> ril100_domain <> "/" <> path)
#(_, 200) -> #(302, proto <> leitpunkt_domain <> "/" <> path)
_ -> #(302, proto <> ril100_domain <> "/" <> path)
- }
+ } |> pair.new(False)
}
}
}
- _ -> #(404, "intended usage is e.g. curl " <> proto <> domain <> "/FF")
+ _ -> #(#(404, "intended usage is e.g. curl " <> proto <> domain <> "/FF"), False)
}
let body = text
|> bit_builder.from_string
|> mist.Bytes
+ let content_type = case is_html {
+ True -> "text/html; charset=utf8"
+ False -> "text/plain; charset=utf8"
+ }
+
response.new(code)
|> response.prepend_header(
"x-data-source",
@@ -199,7 +245,7 @@ fn lookup_station(
"x-sources-at",
"https://stuebinm.eu/git/bahnhof.name",
)
- |> response.prepend_header("content-type", "text/plain; charset=utf8")
+ |> response.prepend_header("content-type", content_type)
|> fn(a) {
case code == 302 {
True -> response.prepend_header(a, "location", text)
@@ -210,10 +256,10 @@ fn lookup_station(
}
pub fn main() {
- let assert Ok(bahn_ril100) = fetch_data()
+ let assert Ok(bahn_ril100) = file.read("data/DBNetz-Betriebsstellenverzeichnis-Stand2021-10.csv")
let ds100s =
- read_csv(bahn_ril100)
+ read_csv(bahn_ril100, ";")
|> list.filter_map(fn(fields) {
case fields {
[_, ds100, name, ..] -> Ok(#(name, ds100))
@@ -222,13 +268,15 @@ pub fn main() {
})
let assert Ok(leitpunkte_raw) = file.read("data/leitpunkte.csv")
let leitpunkte =
- read_csv(leitpunkte_raw)
+ read_csv(leitpunkte_raw, ";")
|> list.filter_map(fn(fields) {
case fields {
[lp, name, _ds100] -> Ok(#(name, lp))
_ -> Error(fields)
}
})
+ let assert Ok(platforms_raw) = file.read("data/platforms.tsv")
+ let platforms = read_csv(platforms_raw, "\t")
let name_to_ds100 = map.from_list(ds100s)
let name_to_leitpunkt = map.from_list(leitpunkte)
@@ -321,19 +369,36 @@ pub fn main() {
fuzzy(searchterm, kind)
|> list.filter_map(fn(res) { map.get(ids, string.uppercase(res)) })
case results {
- [res] -> Fuzzy(res)
- [res, ..] -> Fuzzy(res)
+ [res] -> {
+ let assert Ok(station) = map.get(stations, res)
+ Fuzzy(res, station)
+ }
+ [res, ..] -> {
+ let assert Ok(station) = map.get(stations, res)
+ Fuzzy(res, station)
+ }
_ -> Failed
}
}
}
}
+ let lookup_platform = fn(ds100: String) -> String {
+ inspect(ds100)
+ platforms
+ |> list.filter(fn(a) { list.first(a) == Ok(ds100) })
+ |> list.map(fn(line) { case line {
+ [_code,osmid,osmtype,info] -> "<a href=\"https://osm.org/"<>osmtype<>"/"<>osmid<>"\">"<>info<>"</a>"
+ }})
+ |> string.join("<br>\n")
+ |> inspect
+ }
+
io.println("compiled indices, starting server …")
let assert Ok(_) =
fn(req: Request(mist.Connection)) -> Response(mist.ResponseData) {
- lookup_station(req, ds100_to_name, leitpunkt_to_name, exact_then_fuzzy)
+ lookup_station(req, ds100_to_name, leitpunkt_to_name, lookup_platform, exact_then_fuzzy)
}
|> mist.new
|> mist.port(2345)
@@ -348,17 +413,18 @@ fn fetch_data() -> Result(String, hackney.Error) {
"https://download-data.deutschebahn.com/static/datasets/betriebsstellen/DBNetz-Betriebsstellenverzeichnis-Stand2021-10.csv",
)
let assert Ok(request) = request.from_uri(uri)
+ io.println("got response")
let assert Ok(response) = hackney.send(request)
// some ü are corrupted for some reason
Ok(string.replace(response.body, "�", "ü"))
}
-fn read_csv(contents) -> List(List(String)) {
+fn read_csv(contents, sep) -> List(List(String)) {
contents
// the file doesn't use quotes, so this is fine
|> string.split(on: "\n")
// drop CSV header
|> list.drop(1)
- |> list.map(fn(a) { string.split(a, on: ";") })
+ |> list.map(fn(a) { string.split(a, on: sep) })
}