From 16580bc85660a9a7a6811f9dce81ee5a6f2eaec3 Mon Sep 17 00:00:00 2001 From: "Leah (ctucx)" Date: Mon, 8 Mar 2021 12:45:22 +0100 Subject: [PATCH] use submodule for hafas-client --- .gitmodules | 3 + src/backend/hafas.nim | 7 - src/backend/hafas/api/journeys.nim | 79 ------- src/backend/hafas/api/refresh_journey.nim | 23 -- src/backend/hafas/api/suggestions.nim | 29 --- src/backend/hafas/errors.nim | 199 ------------------ src/backend/hafas/parse/accessibility.nim | 6 - src/backend/hafas/parse/date.nim | 31 --- src/backend/hafas/parse/journey.nim | 38 ---- src/backend/hafas/parse/journeys_response.nim | 27 --- src/backend/hafas/parse/leg.nim | 70 ------ src/backend/hafas/parse/line.nim | 71 ------- src/backend/hafas/parse/msg.nim | 12 -- src/backend/hafas/parse/operator.nim | 9 - src/backend/hafas/parse/point.nim | 78 ------- src/backend/hafas/parse/polyline.nim | 73 ------- src/backend/hafas/parse/products.nim | 37 ---- src/backend/hafas/parse/remark.nim | 32 --- src/backend/hafas/parse/stopover.nim | 33 --- src/backend/hafas/todo | 10 - src/backend/hafas/types.nim | 53 ----- src/backend/hafas/util.nim | 57 ----- src/endpoints/journeys.nim | 2 +- src/endpoints/moreJourneys.nim | 4 +- src/endpoints/refreshJourney.nim | 4 +- src/endpoints/suggestions.nim | 2 +- src/hafas | 1 + 27 files changed, 10 insertions(+), 980 deletions(-) create mode 100644 .gitmodules delete mode 100644 src/backend/hafas.nim delete mode 100644 src/backend/hafas/api/journeys.nim delete mode 100644 src/backend/hafas/api/refresh_journey.nim delete mode 100644 src/backend/hafas/api/suggestions.nim delete mode 100644 src/backend/hafas/errors.nim delete mode 100644 src/backend/hafas/parse/accessibility.nim delete mode 100644 src/backend/hafas/parse/date.nim delete mode 100644 src/backend/hafas/parse/journey.nim delete mode 100644 src/backend/hafas/parse/journeys_response.nim delete mode 100644 src/backend/hafas/parse/leg.nim delete mode 100644 src/backend/hafas/parse/line.nim delete mode 100644 src/backend/hafas/parse/msg.nim delete mode 100644 src/backend/hafas/parse/operator.nim delete mode 100644 src/backend/hafas/parse/point.nim delete mode 100644 src/backend/hafas/parse/polyline.nim delete mode 100644 src/backend/hafas/parse/products.nim delete mode 100644 src/backend/hafas/parse/remark.nim delete mode 100644 src/backend/hafas/parse/stopover.nim delete mode 100644 src/backend/hafas/todo delete mode 100644 src/backend/hafas/types.nim delete mode 100644 src/backend/hafas/util.nim create mode 160000 src/hafas diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..dca2950 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "src/hafas"] + path = src/hafas + url = https://cgit.ctu.cx/hafas.nim diff --git a/src/backend/hafas.nim b/src/backend/hafas.nim deleted file mode 100644 index e73862f..0000000 --- a/src/backend/hafas.nim +++ /dev/null @@ -1,7 +0,0 @@ -import hafas/api/journeys -import hafas/api/suggestions -import hafas/api/refresh_journey - -export journeys -export suggestions -export refresh_journey diff --git a/src/backend/hafas/api/journeys.nim b/src/backend/hafas/api/journeys.nim deleted file mode 100644 index aa3e4cd..0000000 --- a/src/backend/hafas/api/journeys.nim +++ /dev/null @@ -1,79 +0,0 @@ -import ../parse/products -import ../parse/point -import ../parse/accessibility -import ../parse/journeys_response -import ../types -import ../util -import json -import times -import asyncdispatch -import options - -proc journeys*(params: JourneysParams): Future[JourneysResponse] {.async.} = - var `when` = now().toTime() - var isDeparture = true - if params.departure.isSome: - `when` = params.departure.get.fromUnix - elif params.arrival.isSome: - `when` = params.arrival.get.fromUnix - isDeparture = false - - let req = %* { - "cfg": { - "polyEnc": "GPA" - }, - "meth": "TripSearch", - "req": { - "ctxScr": nil, - "getPasslist": params.stopovers.get(false), - "maxChg": params.transfers.get(-1), - "minChgTime": params.transferTime.get(0), - "numF": params.results.get(5), - "depLocL": [ params.fromPoint.formatPoint() ], - "viaLocL": [], - "arrLocL": [ params.toPoint.formatPoint() ], - "jnyFltrL": [ - { - "type": "PROD", - "mode": "INC", - "value": $formatProducts(params.products.get(parseProducts(1023))), - }, - { - "type": "META", - "mode": "INC", - "meta": formatAccessibility(params.accessibility.get(Accessibility.none)), - } - ], - "gisFltrL": [], - "getTariff": params.tickets.get(true), - "ushrp": params.startWithWalking.get(true), - "getPT": true, - "getIV": false, - "getPolyline": params.polylines.get(false), - "outFrwd": isDeparture, - "outDate": `when`.format("yyyyMMdd"), - "outTime": `when`.format("HHmmss"), - "trfReq": { - "jnyCl": 2, - "tvlrProf": [ - { - "type": "E", - "redtnCard": nil - } - ], - "cType": "PK" - } - } - } - - if params.laterRef.isSome: - req["req"]["ctxScr"] = %* params.laterRef.get - elif params.earlierRef.isSome: - req["req"]["ctxScr"] = %* params.earlierRef.get - - if params.viaPoint.isSome: - let viaPoint = params.viaPoint.get - req["req"]["viaLocL"] = %* [{ "loc": viaPoint.formatPoint() }] - - let data = await request(req) - return parseJourneysResponse(data) diff --git a/src/backend/hafas/api/refresh_journey.nim b/src/backend/hafas/api/refresh_journey.nim deleted file mode 100644 index 9eb1a55..0000000 --- a/src/backend/hafas/api/refresh_journey.nim +++ /dev/null @@ -1,23 +0,0 @@ -import ../types -import ../parse/journeys_response -import ../util -import json -import asyncdispatch -import options - -proc refreshJourney*(params: RefreshJourneyParams): Future[Journey] {.async.} = - let req = %* { - "cfg": { - }, - "meth": "Reconstruction", - "req": { - "ctxRecon": params.refreshToken, - "getIST": true, - "getPasslist": params.stopovers.get(false), - "getPolyline": params.polylines.get(false), - "getTariff": params.tickets.get(false), - } - } - - let data = await request(req) - return parseJourneysResponse(data, true).journeys[0] diff --git a/src/backend/hafas/api/suggestions.nim b/src/backend/hafas/api/suggestions.nim deleted file mode 100644 index 18a2ed6..0000000 --- a/src/backend/hafas/api/suggestions.nim +++ /dev/null @@ -1,29 +0,0 @@ -import ../../../types -import ../parse/point -import ../util -import json -import asyncdispatch -import sequtils -import options - -proc suggestions*(params: SuggestionsParams): Future[seq[Point]] {.async.} = - let req = %* { - "cfg": { - "polyEnc": "GPA" - }, - "meth": "LocMatch", - "req": { - "input": { - "loc": { - "type": "ALL", - "name": params.query & "?" - }, - "maxLoc": params.results.get(10), - "field": "S" - } - } - } - let data = await request(req) - let locs = data["res"]["match"]["locL"].getElems() - - return locs.map(parsePoint) diff --git a/src/backend/hafas/errors.nim b/src/backend/hafas/errors.nim deleted file mode 100644 index 0ab1270..0000000 --- a/src/backend/hafas/errors.nim +++ /dev/null @@ -1,199 +0,0 @@ -import asynchttpserver -import ../../types - -proc parseError*(errstr: string): hafasException = - case errstr: - of "H_UNKNOWN": - return hafasException( - code: SERVER_ERROR, - message: "unknown internal error", - statusCode: Http500, - ) - of "AUTH": - return hafasException( - code: ACCESS_DENIED, - message: "invalid or missing authentication data", - statusCode: Http401, - ) - of "R0001": - return hafasException( - code: INVALID_REQUEST, - message: "unknown method", - statusCode: Http400, - ) - of "R0002": - return hafasException( - code: INVALID_REQUEST, - message: "invalid or missing request parameters", - statusCode: Http400, - ) - of "R0007": - return hafasException( - code: SERVER_ERROR, - message: "internal communication error", - statusCode: Http500, - ) - of "R5000": - return hafasException( - code: ACCESS_DENIED, - message: "access denied", - statusCode: Http401, - ) - of "S1": - return hafasException( - code: SERVER_ERROR, - message: "journeys search: a connection to the backend server couldn\'t be established", - statusCode: Http503, - ) - of "LOCATION": - return hafasException( - code: INVALID_REQUEST, - message: "location/stop not found", - statusCode: Http400, - ) - of "H390": - return hafasException( - code: INVALID_REQUEST, - message: "journeys search: departure/arrival station replaced", - statusCode: Http400, - ) - of "H410": - return hafasException( - code: SERVER_ERROR, - message: "journeys search: incomplete response due to timetable change" - ) - of "H455": - return hafasException( - code: INVALID_REQUEST, - message: "journeys search: prolonged stop", - statusCode: Http400, - ) - of "H460": - return hafasException( - code: INVALID_REQUEST, - message: "journeys search: stop(s) passed multiple times", - statusCode: Http400, - ) - of "H500": - return hafasException( - code: INVALID_REQUEST, - message: "journeys search: too many trains, connection is not complete", - statusCode: Http400, - ) - of "H890": - return hafasException( - code: NOT_FOUND, - message: "journeys search unsuccessful", - statusCode: Http404, - ) - of "H891": - return hafasException( - code: NOT_FOUND, - message: "journeys search: no route found, try with an intermediate stations", - statusCode: Http404, - ) - of "H892": - return hafasException( - code: INVALID_REQUEST, - message: "journeys search: query too complex, try less intermediate stations", - statusCode: Http400, - ) - of "H895": - return hafasException( - code: INVALID_REQUEST, - message: "journeys search: departure & arrival are too near", - statusCode: Http400, - ) - of "H899": - return hafasException( - code: SERVER_ERROR, - message: "journeys search unsuccessful or incomplete due to timetable change" - ) - of "H900": - return hafasException( - code: SERVER_ERROR, - message: "journeys search unsuccessful or incomplete due to timetable change" - ) - of "H9220": - return hafasException( - code: NOT_FOUND, - message: "journeys search: no stations found close to the address", - statusCode: Http400, - ) - of "H9230": - return hafasException( - code: SERVER_ERROR, - message: "journeys search: an internal error occured", - statusCode: Http500, - ) - of "H9240": - return hafasException( - code: NOT_FOUND, - message: "journeys search unsuccessful", - statusCode: Http404, - ) - of "H9250": - return hafasException( - code: SERVER_ERROR, - message: "journeys search: leg query interrupted", - statusCode: Http500, - ) - of "H9260": - return hafasException( - code: INVALID_REQUEST, - message: "journeys search: unknown departure station", - statusCode: Http400, - ) - of "H9280": - return hafasException( - code: INVALID_REQUEST, - message: "journeys search: unknown intermediate station", - statusCode: Http400, - ) - of "H9300": - return hafasException( - code: INVALID_REQUEST, - message: "journeys search: unknown arrival station", - statusCode: Http400, - ) - of "H9320": - return hafasException( - code: INVALID_REQUEST, - message: "journeys search: the input is incorrect or incomplete", - statusCode: Http400, - ) - of "H9360": - return hafasException( - code: INVALID_REQUEST, - message: "journeys search: error in a data field", - statusCode: Http400, - ) - of "H9380": - return hafasException( - code: INVALID_REQUEST, - message: "journeys search: departure/arrival/intermediate station defined more than once", - statusCode: Http400, - ) - of "SQ001": - return hafasException( - code: SERVER_ERROR, - message: "no departures/arrivals data available", - statusCode: Http503, - ) - of "SQ005": - return hafasException( - code: NOT_FOUND, - message: "no trips found", - statusCode: Http404, - ) - of "TI001": - return hafasException( - code: SERVER_ERROR, - message: "no trip info available", - statusCode: Http503, - ) - return hafasException( - code: SERVER_ERROR, - message: "unknown HAFAS exception " & errstr, - statusCode: Http500, - ) diff --git a/src/backend/hafas/parse/accessibility.nim b/src/backend/hafas/parse/accessibility.nim deleted file mode 100644 index b0093b1..0000000 --- a/src/backend/hafas/parse/accessibility.nim +++ /dev/null @@ -1,6 +0,0 @@ -import ../types - -proc formatAccessibility*(a: Accessibility): string = - if a == none: result = "notBarrierfree" - elif a == partial: result = "limitedBarrierfree" - elif a == complete: result = "completeBarrierfree" diff --git a/src/backend/hafas/parse/date.nim b/src/backend/hafas/parse/date.nim deleted file mode 100644 index de04406..0000000 --- a/src/backend/hafas/parse/date.nim +++ /dev/null @@ -1,31 +0,0 @@ -import ../types -import options -import strutils -import times - -proc parseDate*(common: CommonData, time: Option[string], tzoffset: Option[int]): Option[int64] = - if time.isNone: - return none(int64) - - let tzoffset = tzoffset.get(60) # FIXME: sometimes no time zone is given. how to deal with that? - let date = common.dateStr - var time = time.get - var dayoffset = 0 - - if time.len == 8: - dayoffset = parseInt(time[0..1]) - time = time[2..7] - - var tzoffhours = align($(int(tzoffset / 60)), 2, '0') - var tzoffmins = align($(tzoffset mod 60), 2, '0') - var tzoff = tzoffhours & ":" & tzoffmins - if tzoffset >= 0: - tzoff = "+" & tzoff - - let datestr = date & time & tzoff - let dateformat = "yyyyMMddHHmmsszzz" - var dt = datestr.parse(dateformat) - - dt = dt + initTimeInterval(days = dayoffset) - return some(dt.toTime().toUnix()) - diff --git a/src/backend/hafas/parse/journey.nim b/src/backend/hafas/parse/journey.nim deleted file mode 100644 index b6ebafc..0000000 --- a/src/backend/hafas/parse/journey.nim +++ /dev/null @@ -1,38 +0,0 @@ -import ../types -import json -import leg -import options - -proc mkParseJourney*(common: CommonData): proc = - proc parseJourney(j: JsonNode): Journey = - var common = common - common.dateStr = j{"date"}.getStr() - - if j{"trfRes"}{"statusCode"}.getStr == "OK": - result.price = some(Price( - amount: j["trfRes"]["fareSetL"][0]["fareL"][0]["prc"].getInt / 100, - currency: some("Euro"), - )) - - result.refreshToken = j{"ctxRecon"}.getStr() - result.legs = j{"secL"}.getElems().map(mkParseLeg(common)) - result.lastUpdated = common.timeStamp - - # combine walking legs - var i = -1 - var firstWalking = -1 - while true: - inc(i) - if i >= len(result.legs): break - if result.legs[i].isWalking: - if firstWalking == -1: - firstWalking = i - else: - result.legs[firstWalking].arrival = result.legs[i].arrival - result.legs[firstWalking].distance.get += result.legs[i].distance.get - result.legs.delete(i) - dec(i) - else: - firstWalking = -1 - - return parseJourney diff --git a/src/backend/hafas/parse/journeys_response.nim b/src/backend/hafas/parse/journeys_response.nim deleted file mode 100644 index 5eb84e5..0000000 --- a/src/backend/hafas/parse/journeys_response.nim +++ /dev/null @@ -1,27 +0,0 @@ -import ../types -import ./remark -import ./point -import ./operator -import ./journey -import ./line -import ./polyline -import json -import sequtils -import strutils - -proc parseJourneysResponse*(data: JsonNode, isRefresh: bool = false): JourneysResponse = - let points = map(data["res"]["common"]["locL"].getElems(), parsePoint) - let operators = map(data["res"]["common"]["opL"].getElems(), parseOperator) - let remarks = map(data["res"]["common"]["remL"].getElems(), parseRemark) - let lines = data["res"]["common"]["prodL"] - let polylines = map(data["res"]["common"]["polyL"].getElems(), mkParsePolyline(points)) - let timestamp = parseInt(data["res"]["planrtTS"].getStr()) - let common = CommonData(points: points, operators: operators, remarks: remarks, lines: lines, polylines: polylines, timestamp: timestamp) - - result.journeys = data["res"]["outConL"].getElems().map(mkParseJourney(common)) - if not isRefresh: - if data["res"].hasKey("outCtxScrB"): - result.earlierRef = data["res"]["outCtxScrB"].getStr() - - if data["res"].hasKey("outCtxScrF"): - result.laterRef = data["res"]["outCtxScrF"].getStr() diff --git a/src/backend/hafas/parse/leg.nim b/src/backend/hafas/parse/leg.nim deleted file mode 100644 index 50aacb5..0000000 --- a/src/backend/hafas/parse/leg.nim +++ /dev/null @@ -1,70 +0,0 @@ -import ../types -import ./stopover -import ./msg -import ./date -import ./line -import json -import options - -proc parseLegPart(common: CommonData, lp: JsonNode): LegPart = - let h = lp.to(HafasStopParams) - let plannedDepartureTime = parseDate(common, h.dTimeS, h.dTZOffset) - let plannedArrivalTime = parseDate(common, h.aTimeS, h.aTZOffset) - - if h.dPlatfS.isSome: result.plannedPlatform = h.dPlatfS - elif h.aPlatfS.isSome: result.plannedPlatform = h.aPlatfS - if h.dPlatfR.isSome: result.prognosedPlatform = h.dPlatfR - elif h.aPlatfR.isSome: result.prognosedPlatform = h.aPlatfR - if h.dTimeR.isSome: result.prognosedTime = parseDate(common, h.dTimeR, h.dTZOffset) - elif h.aTimeR.isSome: result.prognosedTime = parseDate(common, h.aTimeR, h.aTZOffset) - - if plannedDepartureTime.isSome: result.plannedTime = plannedDepartureTime.get - elif plannedArrivalTime.isSome: result.plannedTime = plannedArrivalTime.get - else: raise newException(CatchableError, "missing departure and arrival time for leg") - - result.point = common.points[h.locX.get] - -proc mkParseLeg*(common: CommonData): proc = - proc parseLeg(l: JsonNode): Leg = - - if l{"jny"}{"polyG"}{"polyXL"}.getElems().len() > 0: - result.polyline = some(Polyline( - type: "FeatureCollection", - )) - for n in l{"jny"}{"polyG"}{"polyXL"}.getElems(): - result.polyline.get.features &= common.polylines[n.getInt()].features - - let typeStr = l{"type"}.getStr() - - echo typeStr - - if typeStr == "JNY": - result.direction = some(l{"jny"}{"dirTxt"}.getStr()) - result.tripId = some(l{"jny"}{"jid"}.getStr()) - result.line = common.parseLine(l["jny"]["prodX"].getInt()) - - let stopovers = l{"jny"}{"stopL"}.getElems() - if stopovers.len > 0: - result.stopovers = some(stopovers.map(mkParseStopover(common))) - - let remarks = l{"jny"}{"msgL"}.getElems() - if remarks.len > 0: - result.remarks = some(remarks.map(mkParseMsg(common))) - - elif typeStr == "WALK": - result.isWalking = true - result.distance = some(l{"gis"}{"dist"}.getInt()) - - elif typeStr == "TRSF" or typeStr == "DEVI": - result.isTransfer = true - - else: - raise newException(CatchableError, "Unimplemented hafas leg type: " & typeStr) - - result.departure = common.parseLegPart(l{"dep"}) - result.arrival = common.parseLegPart(l{"arr"}) - - result.cancelled = l{"dep"}{"dCncl"}.getBool(false) or l{"arr"}{"aCncl"}.getBool(false) - - return parseLeg - diff --git a/src/backend/hafas/parse/line.nim b/src/backend/hafas/parse/line.nim deleted file mode 100644 index c37d390..0000000 --- a/src/backend/hafas/parse/line.nim +++ /dev/null @@ -1,71 +0,0 @@ -import ../types -import ../util -import ./products -import json -import options -import tables -import httpClient -import asyncdispatch - - -var trainTypes = initTable[string, string]() -var trainTypesShort = initTable[string, string]() - -proc fetchTrainTypes() {.async.} = - var client = newAsyncHttpClient() - let resp = await client.getContent("https://lib.finalrewind.org/dbdb/ice_type.json") - let data = parseJson(resp) - for key, info in pairs(data): - if info{"type"}.getStr != "" and info{"type"}.getStr != "EC" and info{"type"}.getStr != "IC": - trainTypes[key] = info{"type"}.getStr - if info{"short"}.getStr != "": - trainTypesShort[key] = info{"short"}.getStr - -asyncCheck fetchTrainTypes() - - -proc parseLine*(common: CommonData, i: int): Option[Line] = - let l = common.lines[i] - - # unparsable - if l{"cls"}.getInt == 0: - return options.none(Line) - - let line = l.to(HafasProd) - var res = Line() - - res.name = line.name - res.product = parseProduct(line.cls) - res.tripNum = line.prodCtx.num - - if not isNone(line.prodCtx.catOut): - res.productName = get(line.prodCtx.catOut) - else: - res.productName = "?" - - res.fullProductName = line.prodCtx.catOutL - res.id = slug(line.prodCtx.lineId.get(line.name)) - - if line.opX.isSome: - res.operator = some(common.operators[line.opX.get]) - - # DB - - if res.productName == "IC" or res.productName == "ICE" or res.productName == "EC" or res.productName == "ECE": - if trainTypes.contains(res.tripNum) and trainTypes[res.tripNum] != res.productName: - res.trainType = some(trainTypes[res.tripNum]) - if trainTypesShort.contains(res.tripNum): - res.trainTypeShort = some(trainTypesShort[res.tripNum]) - - if line.nameS.isSome and (res.product == bus or res.product == tram or res.product == ferry): - res.name = line.nameS.get - - if line.addName.isSome: - # swap name and addName - res.additionalName = some(res.name) - res.name = line.addName.get - - # End DB - - res.mode = MODES[int(res.product)] - return some(res) diff --git a/src/backend/hafas/parse/msg.nim b/src/backend/hafas/parse/msg.nim deleted file mode 100644 index 3e04a38..0000000 --- a/src/backend/hafas/parse/msg.nim +++ /dev/null @@ -1,12 +0,0 @@ -import ../types -import json - -proc mkParseMsg*(common: CommonData): proc = - proc parseMsg(m: JsonNode): Remark = - let typeStr = m{"type"}.getStr() - if typeStr != "REM": - raise newException(CatchableError, "Unimplemented hafas msg type: " & typeStr) - return common.remarks[m{"remX"}.getInt()] - - return parseMsg - diff --git a/src/backend/hafas/parse/operator.nim b/src/backend/hafas/parse/operator.nim deleted file mode 100644 index b7b7712..0000000 --- a/src/backend/hafas/parse/operator.nim +++ /dev/null @@ -1,9 +0,0 @@ -import ../../../types -import ../util -import json - -proc parseOperator*(op: JsonNode): Operator = - return (%* { - "name": op{"name"}, - "id": %* slug(op{"name"}.getStr()), - }).to(Operator) diff --git a/src/backend/hafas/parse/point.nim b/src/backend/hafas/parse/point.nim deleted file mode 100644 index 38451e4..0000000 --- a/src/backend/hafas/parse/point.nim +++ /dev/null @@ -1,78 +0,0 @@ -import ../types -import ./products -import json -import options -import tables - -proc parsePoint*(loc: JsonNode): Point = - let typeStr = loc{"type"}.getStr() - if typeStr == "S": - result.stop = some(Stop( - id: loc{"extId"}.getStr(), - name: loc{"name"}.getStr(), - location: Location( - latitude: loc{"crd"}{"y"}.getInt() / 1000000, - longitude: loc{"crd"}{"x"}.getInt() / 1000000, - ), - products: parseProducts(loc{"pCls"}.getInt()), - )) - elif typeStr == "P": - result.location = some(Location( - id: some(loc{"extId"}.getStr()), - name: some(loc{"name"}.getStr()), - latitude: loc{"crd"}{"y"}.getInt() / 1000000, - longitude: loc{"crd"}{"x"}.getInt() / 1000000, - )) - elif typeStr == "A": - result.location = some(Location( - address: some(loc{"name"}.getStr()), - latitude: loc{"crd"}{"y"}.getInt() / 1000000, - longitude: loc{"crd"}{"x"}.getInt() / 1000000, - )) - else: - raise newException(CatchableError, "Unimplemented hafas loc type: " & typeStr) - -proc formatLocationIdentifier(d: Table[string, string]): string = - for key, val in d: - result &= key - result &= "=" - result &= val - result &= "@" - -proc formatCoord(c: float): string = - return $int(c * 1000000) - -proc formatPoint*(point: Point): JsonNode = - if point.stop.isSome: - let stop = point.stop.get - return %* { - "type": "S", - "lid": formatLocationIdentifier({ - "A": "1", - "L": $stop.id, - }.toTable), - } - elif point.location.isSome: - let loc = point.location.get - if loc.address.isSome: - return %* { - "type": "A", - "lid": formatLocationIdentifier({ - "A": "2", - "O": loc.address.get, - "X": formatCoord(loc.longitude), - "Y": formatCoord(loc.latitude), - }.toTable), - } - elif loc.name.isSome and loc.id.isSome: - return %* { - "type": "P", - "lid": formatLocationIdentifier({ - "A": "4", - "O": loc.address.get, - "L": loc.id.get, - "X": formatCoord(loc.longitude), - "Y": formatCoord(loc.latitude), - }.toTable), - } - raise newException(CatchableError, "Cannot format HAFAS location") diff --git a/src/backend/hafas/parse/polyline.nim b/src/backend/hafas/parse/polyline.nim deleted file mode 100644 index 1da6aa3..0000000 --- a/src/backend/hafas/parse/polyline.nim +++ /dev/null @@ -1,73 +0,0 @@ -import ../types -import json -import options -import math - -proc gpsDistance(fromLat: float, fromLon: float, toLat: float, toLon: float): float = - proc toRad(x: float): float = x * PI / 180 - let dLat = toRad(toLat - fromLat) - let dLon = toRad(toLon - fromLon) - let fromLat = toRad(fromLat) - let toLat = toRad(toLat) - let a = pow(sin(dLat / 2), 2) + (pow(sin(dLon / 2), 2) * cos(fromLat) * cos(toLat)) - let c = 2 * arctan2(sqrt(a), sqrt(1 - a)) - return 6371 * c - -proc parseIntegers(str: string): seq[int] = - var byte = 0 - var current = 0 - var bits = 0 - for c in str: - byte = int(c) - 63 - current = current or (( byte and 31 ) shl bits) - bits += 5 - - if byte < 32: - if (current and 1) == 1: - current = -current - current = current shr 1 - - result.add(current) - - current = 0 - bits = 0 - -proc mkParsePolyline*(points: seq[Point]): proc = - proc parsePolyline(l: JsonNode): Polyline = - let line = l.to(HafasPolyLine) - - result.type = "FeatureCollection" - - var lat = 0 - var lon = 0 - - let ints = parseIntegers(line.crdEncYX) - var i = 0 - while i < len(ints): - lat += ints[i] - lon += ints[i+1] - result.features.add(Feature( - type: "Feature", - geometry: FeatureGeometry( - type: "Point", - coordinates: @[lon / 100000, lat / 100000], - ), - )) - i += 2 - - if line.ppLocRefL.isSome: - for p in line.ppLocRefL.get: - result.features[p.ppIdx].properties = points[p.locX].stop - - # sort out coordinates closer than 5m to their neighbours - var j = 1 - while true: - if j >= len(result.features): break - let last = result.features[j-1].geometry.coordinates - let current = result.features[j].geometry.coordinates - if gpsDistance(last[1], last[0], current[1], current[0]) <= 0.005: - result.features.delete(j) - continue - j += 1 - - return parsePolyline diff --git a/src/backend/hafas/parse/products.nim b/src/backend/hafas/parse/products.nim deleted file mode 100644 index ba2d084..0000000 --- a/src/backend/hafas/parse/products.nim +++ /dev/null @@ -1,37 +0,0 @@ -import ../../../types -import bitops - -proc parseProduct*(cls: int): Product = - var tmp = cls - var res = 0 - while tmp > 1: - tmp = tmp shr 1 - res += 1 - - return Product(res) - -proc parseProducts*(pCls: int): Products = - return Products( - nationalExp: pCls.testBit(0), - national: pCls.testBit(1), - regionalExp: pCls.testBit(2), - regional: pCls.testBit(3), - suburban: pCls.testBit(4), - bus: pCls.testBit(5), - ferry: pCls.testBit(6), - subway: pCls.testBit(7), - tram: pCls.testBit(8), - taxi: pCls.testBit(9), - ) - -proc formatProducts*(p: Products): int = - if p.nationalExp: result.setBit(0) - if p.national: result.setBit(1) - if p.regionalExp: result.setBit(2) - if p.regional: result.setBit(3) - if p.suburban: result.setBit(4) - if p.bus: result.setBit(5) - if p.ferry: result.setBit(6) - if p.subway: result.setBit(7) - if p.tram: result.setBit(8) - if p.taxi: result.setBit(9) diff --git a/src/backend/hafas/parse/remark.nim b/src/backend/hafas/parse/remark.nim deleted file mode 100644 index 63ffc8b..0000000 --- a/src/backend/hafas/parse/remark.nim +++ /dev/null @@ -1,32 +0,0 @@ -import ../../../types -import json - -proc parseRemark*(rem: JsonNode): Remark = - let typeStr = rem{"type"}.getStr() - if typeStr == "M" or typeStr == "P": - return (%* { - "type": %* "status", - "summary": rem{"txtS"}, - "code": rem{"code"}, - "text": rem{"txtN"}, - }).to(Remark) - elif typeStr == "L": - return (%* { - "type": %* "status", - "code": %* "alternative-trip", - "text": rem{"txtN"}, - "tripId": rem{"jid"}, - }).to(Remark) - elif typeStr == "A" or typeStr == "I" or typeStr == "H": - return (%* { - "type": %* "hint", - "code": rem{"code"}, - "text": rem{"txtN"}, - }).to(Remark) - else: - # TODO: parse more accurately - return (%* { - "type": %* "status", - "code": rem{"code"}, - "text": rem{"txtN"}, - }).to(Remark) diff --git a/src/backend/hafas/parse/stopover.nim b/src/backend/hafas/parse/stopover.nim deleted file mode 100644 index 67bb74a..0000000 --- a/src/backend/hafas/parse/stopover.nim +++ /dev/null @@ -1,33 +0,0 @@ -import ../types -import ./date -import options -import json - -proc parseStopoverPart(common: CommonData, mode: string, h: HafasStopParams): StopoverPart = - - if (mode != "arrival"): - result.plannedPlatform = h.dPlatfS - result.prognosedPlatform = h.dPlatfR - result.plannedTime = parseDate(common, h.dTimeS, h.dTZOffset) - result.prognosedTime = parseDate(common, h.dTimeR, h.dTZOffset) - else: - result.plannedPlatform = h.aPlatfS - result.prognosedPlatform = h.aPlatfR - result.plannedTime = parseDate(common, h.aTimeS, h.aTZOffset) - result.prognosedTime = parseDate(common, h.aTimeR, h.aTZOffset) - -proc mkParseStopover*(common: CommonData): proc = - proc parseStopover(s: JsonNode): Stopover = - let typeStr = s{"type"}.getStr() - if typeStr != "N": - echo pretty(s) - raise newException(CatchableError, "Unimplemented hafas stopover type: " & typeStr) - - let h = s.to(HafasStopParams) - result.stop = common.points[s{"locX"}.getInt()].stop.get - result.cancelled = h.aCncl.get(false) or h.dCncl.get(false) - result.arrival = common.parseStopoverPart("arrival", h) - result.departure = common.parseStopoverPart("departure", h) - - return parseStopover - diff --git a/src/backend/hafas/todo b/src/backend/hafas/todo deleted file mode 100644 index 96dfd9f..0000000 --- a/src/backend/hafas/todo +++ /dev/null @@ -1,10 +0,0 @@ -- implement leg parsing with nim types -- check and pass back hafas errors -- isAdd (is additional stop) -- hafas information manager (him) remarks -- cycle information -- price information -- reachable -- profiles -- mark current alternatives -- stations diff --git a/src/backend/hafas/types.nim b/src/backend/hafas/types.nim deleted file mode 100644 index d36baa4..0000000 --- a/src/backend/hafas/types.nim +++ /dev/null @@ -1,53 +0,0 @@ -import ../../types -import options -export types -import json - -type - CommonData* = object - lines*: JsonNode - remarks*: seq[Remark] - operators*: seq[Operator] - points*: seq[Point] - polylines*: seq[Polyline] - dateStr*: string - timestamp*: int64 - - HafasStopParams* = object - aTimeS*: Option[string] - aPlatfS*: Option[string] - aTZOffset*: Option[int] - aCncl*: Option[bool] - aTimeR*: Option[string] - aPlatfR*: Option[string] - dTimeS*: Option[string] - dPlatfS*: Option[string] - dTZOffset*: Option[int] - dCncl*: Option[bool] - dTimeR*: Option[string] - dPlatfR*: Option[string] - locX*: Option[int] - - HafasProdCtx* = object - name*: string - num*: string - catOut*: Option[string] - catOutL*: string - lineId*: Option[string] - - HafasProd* = object - name*: string - cls*: int - icoX*: int - nameS*: Option[string] - addName*: Option[string] - opX*: Option[int] - prodCtx*: HafasProdCtx - - HafasLocRef* = object - ppIdx*: int - locX*: int - - HafasPolyline* = object - crdEncYX*: string - ppLocRefL*: Option[seq[HafasLocRef]] diff --git a/src/backend/hafas/util.nim b/src/backend/hafas/util.nim deleted file mode 100644 index 44dba35..0000000 --- a/src/backend/hafas/util.nim +++ /dev/null @@ -1,57 +0,0 @@ -import httpclient -import asyncdispatch -import md5 -import json -import strutils -import errors - -proc slug*(s: string): string = - for c in s: - if c.isAlphaNumeric(): - result &= c.toLowerAscii() - else: - result &= '-' - -proc request*(req: JsonNode): Future[JsonNode] {.async.} = - let client = newAsyncHttpClient() - - let body = %*{ - "lang": "de", - "svcReqL": [req] - } - - # TODO: move to profile - body["svcReqL"][0]["cfg"]["rtMode"] = %* "HYBRID" - body["client"] = %* { - "id": "DB", - "v": "16040000", - "type": "IPH", - "name": "DB Navigator" - } - body["ext"] = %* "DB.R19.04.a" - body["ver"] = %* "1.16" - body["auth"] = %* { - "type": "AID", - "aid": "n91dB8Z77MLdoR0K" - } - let salt = "bdI8UVj40K5fvxwf" - let bodytext = $body - let checksum = $toMD5(bodytext & salt) - let url = "https://reiseauskunft.bahn.de/bin/mgate.exe?checksum=" & checksum - - client.headers = newHttpHeaders({ - "Content-Type": "application/json", - "Accept": "application/json", - "user-agent": "my-awesome-e5f276d8fe6cprogram", - }) - - #echo pretty body - let req = await client.request(url, httpMethod = HttpPost, body = $body) - let resp = await req.body - let data = parseJson(resp) - - let error = data{"svcResL"}{0}{"err"}.getStr() - if error != "OK": - raise parseError(error) - - return data{"svcResL"}{0} diff --git a/src/endpoints/journeys.nim b/src/endpoints/journeys.nim index dbff0ff..7b4fdc9 100644 --- a/src/endpoints/journeys.nim +++ b/src/endpoints/journeys.nim @@ -1,5 +1,5 @@ import json, tables, options, asyncdispatch -import ../types, ../backend/hafas, ../cache +import ../types, ../hafas/hafas, ../cache when not defined(release): import hotcodereloading diff --git a/src/endpoints/moreJourneys.nim b/src/endpoints/moreJourneys.nim index 707702f..f1aac8b 100644 --- a/src/endpoints/moreJourneys.nim +++ b/src/endpoints/moreJourneys.nim @@ -1,5 +1,5 @@ import json, tables, options, asyncdispatch, strutils -import ../types, ../cache_types, ../backend/hafas, ../cache +import ../types, ../cache_types, ../hafas/hafas, ../cache proc moreJourneysEndpoint*(requestData: JsonNode): Future[JsonNode] {.async.} = var reqId = requestData{"reqId"}.getStr() @@ -39,4 +39,4 @@ proc moreJourneysEndpoint*(requestData: JsonNode): Future[JsonNode] {.async.} = return response else: - raise newException(errorException, "MISSING_VALUES") \ No newline at end of file + raise newException(errorException, "MISSING_VALUES") diff --git a/src/endpoints/refreshJourney.nim b/src/endpoints/refreshJourney.nim index 64828ec..5d2ea15 100644 --- a/src/endpoints/refreshJourney.nim +++ b/src/endpoints/refreshJourney.nim @@ -1,5 +1,5 @@ import json, tables, options, asyncdispatch, strutils -import ../types, ../cache_types, ../backend/hafas, ../cache +import ../types, ../cache_types, ../hafas/hafas, ../cache proc refreshJourneyEndpoint*(requestData: JsonNode): Future[JsonNode] {.async.} = let reqId = requestData{"reqId"}.getStr() @@ -34,4 +34,4 @@ proc refreshJourneyEndpoint*(requestData: JsonNode): Future[JsonNode] {.async.} delete(response["journeys"][journeyId]["legs"][legKey], "cycle") delete(response["journeys"][journeyId]["legs"][legKey], "tripId") - return response \ No newline at end of file + return response diff --git a/src/endpoints/suggestions.nim b/src/endpoints/suggestions.nim index 6b6c135..c598089 100644 --- a/src/endpoints/suggestions.nim +++ b/src/endpoints/suggestions.nim @@ -1,5 +1,5 @@ import json, options, asyncdispatch -import ../types, ../backend/hafas +import ../types, ../hafas/hafas const ds100Json = staticRead "../../ds100reverse.json" diff --git a/src/hafas b/src/hafas new file mode 160000 index 0000000..e815bbf --- /dev/null +++ b/src/hafas @@ -0,0 +1 @@ +Subproject commit e815bbfd2ef4f49c4e3a757739a60d802bcc53f5