From 5f27e441f47f2565b941b321a9939d54357e1654 Mon Sep 17 00:00:00 2001 From: stuebinm Date: Thu, 16 Apr 2026 01:23:50 +0200 Subject: meta: reorganisation, rename "token" to "trackerId" --- lib/API.hs | 23 +++++++-------- lib/Config.hs | 5 ++-- lib/Extrapolation.hs | 2 +- lib/Persist.hs | 57 +++++++++++++++++++++++++------------- lib/Server/Base.hs | 4 +-- lib/Server/Frontend/OnboardUnit.hs | 28 +++++++++---------- lib/Server/Frontend/Routes.hs | 5 ++-- lib/Server/Frontend/Tickets.hs | 34 +++++++++++------------ lib/Server/GTFS_RT.hs | 16 +++++------ lib/Server/Ingest.hs | 43 ++++++++++++++-------------- lib/Server/Subscribe.hs | 6 ++-- lib/Yesod/Orphans.hs | 11 +++++--- 12 files changed, 129 insertions(+), 105 deletions(-) (limited to 'lib') diff --git a/lib/API.hs b/lib/API.hs index 416f71e..12d5ba6 100644 --- a/lib/API.hs +++ b/lib/API.hs @@ -54,7 +54,7 @@ import Servant.API.ContentTypes (Accept (..)) -- | a bare ping as sent by a tracker device data SentPing = SentPing - { sentPingToken :: TrackerId + { sentPingTrackerId :: TrackerId , sentPingGeopos :: Geopos , sentPingTimestamp :: UTCTime } deriving (Generic) @@ -66,24 +66,25 @@ instance FromJSON SentPing where type API = -- ingress API (put this behind BasicAuth?) -- TODO: perhaps require a first ping for registration? - "tracker" :> "register" :> ReqBody '[JSON] RegisterJson :> Post '[JSON] Token + "tracker" :> "register" :> ReqBody '[JSON] RegisterJson :> Post '[JSON] TrackerId :<|> "tracker" :> "ping" :> ReqBody '[JSON] SentPing :> Post '[JSON] (Maybe TrainAnchor) :<|> "tracker" :> "ping" :> "ws" :> WebSocket :<|> "ticker" :> "current" :> Get '[JSON] Value :<|> "ticket" :> "subscribe" :> Capture "Ticket Id" UUID :> WebSocket - :<|> "debug" :> "pings" :> Get '[JSON] (Map Token [TrainPing]) - :<|> "debug" :> "pings" :> Capture "Ticket Id" UUID :> Get '[JSON] [TrainPing] + :<|> "debug" :> "pings" :> Get '[JSON] (Map UUID [Ping]) + :<|> "debug" :> "pings" :> Capture "Ticket Id" UUID :> Get '[JSON] [Ping] :<|> "gtfs.zip" :> Get '[OctetStream] GTFSFile :<|> "gtfs" :> GtfsRealtimeAPI -type GtfsRealtimeAPI = "servicealerts" :> Get '[Proto] FeedMessage - :<|> "tripupdates" :> Get '[Proto] FeedMessage - :<|> "vehiclepositions" :> Get '[Proto] FeedMessage +type GtfsRealtimeAPI = "servicealerts" :> QueryFlag "force" :> Get '[Proto] FeedMessage + :<|> "tripupdates" :> QueryFlag "force" :> Get '[Proto] FeedMessage + :<|> "vehiclepositions" :> QueryFlag "force" :> Get '[Proto] FeedMessage + type CompleteAPI = - "api" :> "openapi" :> Get '[JSON] Swagger - :<|> "api" :> API + {- "api" :> "openapi" :> Get '[JSON] Swagger + :<|> -} "api" :> "v1" :> API :<|> "metrics" :> Get '[PlainText] Text :<|> "assets" :> Raw :<|> Raw -- hook for yesod frontend @@ -107,7 +108,7 @@ instance ToSchema Value where declareNamedSchema _ = pure $ NamedSchema (Just "json") $ mempty & type_ ?~ SwaggerObject instance ToSchema SentPing where - declareNamedSchema = genericDeclareNamedSchema (GTFS.swaggerOptions "trainPing") + declareNamedSchema = genericDeclareNamedSchema (GTFS.swaggerOptions "ping") @@ -117,7 +118,7 @@ instance HasSwagger WebSocket where { _swaggerPaths = singleton "/" $ mempty { _pathItemGet = Just $ mempty { _operationSummary = Just "this is a websocket endpoint!" - , _operationDescription = Just "this is a websocket endpoint meant for continious operations, e.g. sending many trainPings one after the other. Unfortunately OpenAPI 2.0 is not suitable to thoroughly model it (hence this text)." + , _operationDescription = Just "this is a websocket endpoint meant for continious operations, e.g. sending many pings one after the other. Unfortunately OpenAPI 2.0 is not suitable to thoroughly model it (hence this text)." , _operationSchemes = Just [ Wss ] , _operationConsumes = Just $ MimeList [ "application/json" ] , _operationProduces = Just $ MimeList [ "application/json" ] diff --git a/lib/Config.hs b/lib/Config.hs index 88206f1..c7fd4e4 100644 --- a/lib/Config.hs +++ b/lib/Config.hs @@ -35,6 +35,7 @@ data ServerConfig = ServerConfig , serverConfigDebugMode :: Bool , serverConfigLogin :: Maybe UffdConfig , serverConfigLogging :: LoggingConfig + , serverConfigBeSilent :: Bool } deriving (Generic) data LoggingConfig = LoggingConfig @@ -62,7 +63,7 @@ instance Config UffdConfig where instance Config LoggingConfig where readConfig = LoggingConfig - <$> readOptionalValue [key|ntfyToken|] + <$> readOptionalValue [key|ntfyTrackerId|] <*> readValue "tracktrain" [key|ntfyTopic|] <*> readValue "tracktrain" [key|name|] @@ -108,4 +109,4 @@ instance Config ServerConfig where <*> readValue False [key|debugmode|] <*> readNestedOptional [key|login|] <*> readNested [key|logging|] - + <*> readValue False [key|beSilent|] diff --git a/lib/Extrapolation.hs b/lib/Extrapolation.hs index 759b31e..071e5fa 100644 --- a/lib/Extrapolation.hs +++ b/lib/Extrapolation.hs @@ -29,7 +29,7 @@ import Persist (Geopos (..), ShapePoint (shapePointGeopos), Station (..), Stop (..), Ticket (..), TicketId, - Token (..), Tracker (..), + TrackerId (..), Tracker (..), TrainAnchor (..)) import Server.Util (utcToSeconds) diff --git a/lib/Persist.hs b/lib/Persist.hs index 637155a..405e815 100644 --- a/lib/Persist.hs +++ b/lib/Persist.hs @@ -10,7 +10,7 @@ -- also a few little convenience functions for using persistent. module Persist where -import Data.Aeson (FromJSON, ToJSON, ToJSONKey) +import Data.Aeson (FromJSON, ToJSON, ToJSONKey, Value) import Data.Swagger (ToParamSchema (..), ToSchema (..), genericDeclareNamedSchema) import Data.Text (Text) @@ -50,17 +50,18 @@ import MultiLangText (MultiLangText) import Server.Util (runLogging) import Web.PathPieces (PathPiece) import Yesod (Lang) +import qualified OwnTracks -newtype Token = Token UUID - deriving newtype - ( Show, ToJSON, FromJSON, Eq, Ord, FromHttpApiData - , ToJSONKey, PersistField, PersistFieldSql, PathPiece - , ToHttpApiData, Read ) -instance ToSchema Token where - declareNamedSchema _ = declareNamedSchema (Proxy @String) -instance ToParamSchema Token where - toParamSchema _ = toParamSchema (Proxy @String) +-- newtype TrackerId = TrackerId UUID +-- deriving newtype +-- ( Show, ToJSON, FromJSON, Eq, Ord, FromHttpApiData +-- , ToJSONKey, PersistField, PersistFieldSql, PathPiece +-- , ToHttpApiData, Read ) +-- instance ToSchema TrackerId where +-- declareNamedSchema _ = declareNamedSchema (Proxy @String) +-- instance ToParamSchema TrackerId where +-- toParamSchema _ = toParamSchema (Proxy @String) deriving newtype instance PersistField GTFS.Seconds deriving newtype instance PersistFieldSql GTFS.Seconds @@ -86,6 +87,13 @@ latitude = fst . unGeoPos longitude :: Geopos -> Double longitude = snd . unGeoPos +-- TODO: this is horrible. make a custom status msg type instead? +derivePersistFieldJSON "Value" + +-- We derive these here so that OwnTracks.* can become its own package eventually +derivePersistFieldJSON "OwnTracks.Status" + + share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persistLowerCase| Ticket sql=tt_ticket Id UUID default=uuid_generate_v4() @@ -121,27 +129,37 @@ ShapePoint sql=tt_shape_point Shape sql=tt_shape --- | tokens which have been issued -Tracker sql=tt_tracker_token - Id Token default=uuid_generate_v4() +-- | trackerIds which have been issued +Tracker sql=tt_tracker + Id UUID default=uuid_generate_v4() + name Text Unique expires UTCTime blocked Bool agent Text currentTicket TicketId Maybe deriving Eq Show Generic +TrackerStatus sql=tt_tracker_status + tracker TrackerId + timestamp UTCTime + status OwnTracks.Status + TrackerTicket ticket TicketId OnDeleteCascade OnUpdateCascade tracker TrackerId OnDeleteCascade OnUpdateCascade UniqueTrackerTicket ticket tracker -- raw frames as received from OBUs -TrainPing json sql=tt_trip_ping - ticket TicketId OnDeleteCascade OnUpdateCascade - token TrackerId OnDeleteSetNull OnUpdateCascade +Ping json sql=tt_trip_ping + ticket TicketId Maybe OnDeleteCascade OnUpdateCascade + trackerId TrackerId OnDeleteSetNull OnUpdateCascade geopos Geopos + -- accuracy Int Maybe + -- altitute Int Maybe + -- battery Int Maybe + -- TODO timestamp UTCTime - sequence Double + sequence Double Maybe deriving Show Generic Eq -- status of a train somewhen in time (may be in the future), @@ -156,6 +174,7 @@ TrainAnchor json sql=tt_trip_anchor deriving Show Generic Eq -- TODO: multi-language support? +-- announcements for the gtfs realtime Announcement json sql=tt_announcements Id UUID default=uuid_generate_v4() ticket TicketId OnDeleteCascade OnUpdateCascade @@ -177,8 +196,8 @@ instance ToSchema TicketId where declareNamedSchema _ = declareNamedSchema (Proxy @UUID) instance ToSchema TrackerId where declareNamedSchema _ = declareNamedSchema (Proxy @UUID) -instance ToSchema TrainPing where - declareNamedSchema = genericDeclareNamedSchema (GTFS.swaggerOptions "trainPing") +instance ToSchema Ping where + declareNamedSchema = genericDeclareNamedSchema (GTFS.swaggerOptions "ping") instance ToSchema TrainAnchor where declareNamedSchema = genericDeclareNamedSchema (GTFS.swaggerOptions "trainAnchor") instance ToSchema Announcement where diff --git a/lib/Server/Base.hs b/lib/Server/Base.hs index 14b77ca..17b5b4a 100644 --- a/lib/Server/Base.hs +++ b/lib/Server/Base.hs @@ -4,6 +4,6 @@ module Server.Base (ServerState) where import Control.Concurrent.STM (TQueue, TVar) import qualified Data.Map as M import Data.UUID (UUID) -import Persist (TrainPing) +import Persist (Ping) -type ServerState = TVar (M.Map UUID [TQueue (Maybe TrainPing)]) +type ServerState = TVar (M.Map UUID [TQueue (Maybe Ping)]) diff --git a/lib/Server/Frontend/OnboardUnit.hs b/lib/Server/Frontend/OnboardUnit.hs index 6a8fe6e..967cb6c 100644 --- a/lib/Server/Frontend/OnboardUnit.hs +++ b/lib/Server/Frontend/OnboardUnit.hs @@ -28,7 +28,7 @@ getOnboardTrackerR = do defaultLayout [whamlet|

Tracker - Token: + TrackerId:

Status

_{MsgNone} @@ -44,7 +44,7 @@ getOnboardTrackerR = do defaultLayout [whamlet|