giving up on db schema in favor of prototyping
This commit is contained in:
parent
9676f7d7e1
commit
aa3902f1a4
8 changed files with 298 additions and 6 deletions
|
@ -0,0 +1,45 @@
|
||||||
|
use sea_orm_migration::prelude::*;
|
||||||
|
|
||||||
|
pub struct Migration;
|
||||||
|
|
||||||
|
impl MigrationName for Migration {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"m20240217_000000_create_route_table" // Make sure this matches with the file name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl MigrationTrait for Migration {
|
||||||
|
// Define how to apply this migration: Create the table.
|
||||||
|
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||||
|
manager
|
||||||
|
.create_table(
|
||||||
|
Table::create()
|
||||||
|
.table(RouteStopRelation::Table)
|
||||||
|
.col(
|
||||||
|
ColumnDef::new(RouteStopRelation::RouteId)
|
||||||
|
.integer()
|
||||||
|
.not_null()
|
||||||
|
.primary_key(),
|
||||||
|
)
|
||||||
|
.col(ColumnDef::new(RouteStopRelationRoute::Name).string().not_null())
|
||||||
|
.col(ColumnDef::new(RouteStopRelationBakery::ProfitMargin).double().not_null())
|
||||||
|
.to_owned(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
|
// Define how to rollback this migration: Drop the Bakery table.
|
||||||
|
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||||
|
manager
|
||||||
|
.drop_table(Table::drop().table(Bakery::Table).to_owned())
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Iden)]
|
||||||
|
pub enum RouteStopRelation{
|
||||||
|
Table,
|
||||||
|
RouteId,
|
||||||
|
StopId,
|
||||||
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
use sea_orm_migration::prelude::*;
|
||||||
|
|
||||||
|
pub struct Migration;
|
||||||
|
|
||||||
|
impl MigrationName for Migration {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"m20240217_000000_create_route_table" // Make sure this matches with the file name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl MigrationTrait for Migration {
|
||||||
|
// Define how to apply this migration: Create the table.
|
||||||
|
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||||
|
manager
|
||||||
|
.create_table(
|
||||||
|
Table::create()
|
||||||
|
.table(Route::Table)
|
||||||
|
.col(
|
||||||
|
ColumnDef::new(Route::Id)
|
||||||
|
.integer()
|
||||||
|
.not_null()
|
||||||
|
.auto_increment()
|
||||||
|
.primary_key(),
|
||||||
|
)
|
||||||
|
.col(ColumnDef::new(Route::Name).string().not_null())
|
||||||
|
.to_owned(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
|
// Define how to rollback this migration: Drop the Bakery table.
|
||||||
|
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||||
|
manager
|
||||||
|
.drop_table(Table::drop().table(Bakery::Table).to_owned())
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Iden)]
|
||||||
|
pub enum Route {
|
||||||
|
Table,
|
||||||
|
Id,
|
||||||
|
Name,
|
||||||
|
}
|
50
src/main.rs
50
src/main.rs
|
@ -2,9 +2,11 @@ extern crate tokio;
|
||||||
extern crate reqwest;
|
extern crate reqwest;
|
||||||
extern crate tide;
|
extern crate tide;
|
||||||
extern crate anyhow;
|
extern crate anyhow;
|
||||||
extern crate sea_orm;
|
//extern crate sea_orm;
|
||||||
|
|
||||||
mod state;
|
mod state;
|
||||||
|
mod route;
|
||||||
|
mod stop;
|
||||||
|
|
||||||
use tide::prelude::*;
|
use tide::prelude::*;
|
||||||
|
|
||||||
|
@ -13,7 +15,8 @@ async fn main() -> anyhow::Result<()> {
|
||||||
let mut app = tide::with_state(state::State::new().await?);
|
let mut app = tide::with_state(state::State::new().await?);
|
||||||
|
|
||||||
app.at("/path").get(transit_path);
|
app.at("/path").get(transit_path);
|
||||||
app.at("/time-to-arrive").get(transit_estimate);
|
app.at("/time_to_arrive").get(transit_estimate);
|
||||||
|
app.at("/route_draw").get(bus_route_draw);
|
||||||
|
|
||||||
// TODO: change to 0.0.0.0 when docker image done
|
// TODO: change to 0.0.0.0 when docker image done
|
||||||
app.listen("127.0.0.1:8080").await?;
|
app.listen("127.0.0.1:8080").await?;
|
||||||
|
@ -21,12 +24,51 @@ async fn main() -> anyhow::Result<()> {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// return the best path with the request specifying ISO time, lat and longitude in query params
|
/// return the best path of buses with the request specifying ISO time, lat and longitude in query params
|
||||||
|
/// Example return
|
||||||
|
/// {
|
||||||
|
/// "path": [
|
||||||
|
/// {
|
||||||
|
/// "route_name": "WS Outbound",
|
||||||
|
/// "enter_stop_id": 3,
|
||||||
|
/// "exit_stop_id": 10,
|
||||||
|
/// "enter_stop_coords": {"lat":23.3512, "lon": 1231.123123}
|
||||||
|
/// },
|
||||||
|
/// ...
|
||||||
|
/// ]
|
||||||
|
/// }
|
||||||
async fn transit_path(mut req: tide::Request<state::State>)->tide::Result{
|
async fn transit_path(mut req: tide::Request<state::State>)->tide::Result{
|
||||||
Ok("".into())
|
Ok("".into())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// return the num of estimated seconds for bus id and stop ids given in query params
|
/// return the num of estimated seconds for stop ids given in query params
|
||||||
|
/// example return:
|
||||||
|
/// 23
|
||||||
async fn transit_estimate(mut req: tide::Request<state::State>)->tide::Result{
|
async fn transit_estimate(mut req: tide::Request<state::State>)->tide::Result{
|
||||||
Ok("".into())
|
Ok("".into())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// return the coord pairs as json and line color forgiven route id in query params
|
||||||
|
/// Example return:
|
||||||
|
/// {"color":"#0000ff", "stops":[[-75,23],[-21,72]]}
|
||||||
|
async fn bus_route_draw(mut req: tide::Request<state::State>)->tide::Result{
|
||||||
|
match req.query::<RouteDrawQuery>()?.id.split("_").collect::<Vec<&str>>()[..] {
|
||||||
|
["OCCT", id] => {
|
||||||
|
let route = route::occt_route_get(id.parse());
|
||||||
|
},
|
||||||
|
["BC", id] => {
|
||||||
|
let route = route::broome_county_route_get(id.parse());
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
return Ok(tide::Response::builder(400).body("Error: invalid id").into())
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
Ok("".into())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(serde::Deserialize)]
|
||||||
|
struct RouteDrawQuery{
|
||||||
|
id: String
|
||||||
|
}
|
||||||
|
|
||||||
|
|
91
src/route.rs
Normal file
91
src/route.rs
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
|
||||||
|
struct Route {
|
||||||
|
id:u32,
|
||||||
|
name: String,
|
||||||
|
short_name: String,
|
||||||
|
color: String,
|
||||||
|
poly_line: String,
|
||||||
|
stops: Vec<crate::stop::Stop>
|
||||||
|
}
|
||||||
|
#[derive(serde::Deserialize)]
|
||||||
|
struct OcctRoute {
|
||||||
|
id:u32,
|
||||||
|
name: String,
|
||||||
|
#[serde(rename(deserialize = "abbr"))]
|
||||||
|
short_name: String,
|
||||||
|
#[serde(rename(deserialize = "encLine"))]
|
||||||
|
poly_line: String,
|
||||||
|
stops:Vec<u32>,
|
||||||
|
color: String
|
||||||
|
}
|
||||||
|
//impl From<OcctRoute> for Route{
|
||||||
|
// fn from(OcctRoute{id,name,short_name,poly_line,stops, color}: OcctRoute) -> Self {
|
||||||
|
// Self {
|
||||||
|
// id,
|
||||||
|
// name,
|
||||||
|
// short_name,
|
||||||
|
// color,
|
||||||
|
// poly_line,
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
#[derive(serde::Deserialize)]
|
||||||
|
struct BCRoute{
|
||||||
|
id:u32,
|
||||||
|
name: String,
|
||||||
|
short_name: String,
|
||||||
|
color: String,
|
||||||
|
path: Vec<f64>,
|
||||||
|
active: bool,
|
||||||
|
stops:Vec<u32>
|
||||||
|
}
|
||||||
|
#[derive(serde::Deserialize)]
|
||||||
|
struct OcctWrap{
|
||||||
|
get_routes:Vec<OcctRoute>
|
||||||
|
}
|
||||||
|
async fn occt_routes_get()->anyhow::Result<Vec<Route>>{
|
||||||
|
let resp = reqwest::get("http://binghamtonupublic.etaspot.net/service.php?service=get_routes&token=TESTING").await?;
|
||||||
|
let body = resp.text().await?;
|
||||||
|
let OcctWrap{get_routes: routes} = serde_json::from_str(body.as_str())?;
|
||||||
|
let stops = crate::stop::occt_stops_get().await?;
|
||||||
|
let routes = routes.into_iter().map(|route|{
|
||||||
|
let stops = stops.iter()
|
||||||
|
.filter(|stop|{
|
||||||
|
route.stops.iter().any(|id|*id==stop.id)
|
||||||
|
}).map(Clone::clone).collect();
|
||||||
|
|
||||||
|
Route{
|
||||||
|
id:route.id,
|
||||||
|
color:route.color,
|
||||||
|
name:route.name,
|
||||||
|
poly_line:route.poly_line,
|
||||||
|
short_name: route.short_name,
|
||||||
|
stops
|
||||||
|
}
|
||||||
|
}).collect();
|
||||||
|
Ok(routes)
|
||||||
|
|
||||||
|
}
|
||||||
|
async fn broom_county_routes_get()->anyhow::Result<Route>{
|
||||||
|
let resp = reqwest::get("https://bctransit.doublemap.com/map/v2/routes").await?;
|
||||||
|
let body = resp.text().await?;
|
||||||
|
let routes:Vec<BCRoute> = serde_json::from_str(body.as_str())?;
|
||||||
|
let stops = crate::stop::BC_stops_get().await?;
|
||||||
|
let routes = routes.into_iter().map(|route|{
|
||||||
|
let stops = stops.iter()
|
||||||
|
.filter(|stop|{
|
||||||
|
route.stops.iter().any(|id|*id==stop.id)
|
||||||
|
}).map(Clone::clone).collect();
|
||||||
|
let poly_line = crate::stop::poly_encode_stops(stops).await;
|
||||||
|
Route{
|
||||||
|
id:route.id,
|
||||||
|
color:route.color,
|
||||||
|
name:route.name,
|
||||||
|
poly_line,
|
||||||
|
short_name: route.short_name,
|
||||||
|
stops
|
||||||
|
}
|
||||||
|
}).collect();
|
||||||
|
Ok(routes)
|
||||||
|
}
|
|
@ -1,13 +1,13 @@
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct State{
|
pub struct State{
|
||||||
pub db: sea_orm::DatabaseConnection
|
//pub db: sea_orm::DatabaseConnection
|
||||||
}
|
}
|
||||||
|
|
||||||
const DEFAULT_DB_CONN:&'static str = "sqlite://default_db.db";
|
const DEFAULT_DB_CONN:&'static str = "sqlite://default_db.db";
|
||||||
impl State{
|
impl State{
|
||||||
pub async fn new() -> anyhow::Result<Self> {
|
pub async fn new() -> anyhow::Result<Self> {
|
||||||
Ok(Self{
|
Ok(Self{
|
||||||
db: sea_orm::Database::connect(DEFAULT_DB_CONN).await?
|
//db: sea_orm::Database::connect(DEFAULT_DB_CONN).await?
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
69
src/stop.rs
Normal file
69
src/stop.rs
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct Stop{
|
||||||
|
pub id:u32,
|
||||||
|
pub name:String,
|
||||||
|
pub lat: f64,
|
||||||
|
pub lon: f64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(serde::Deserialize)]
|
||||||
|
struct OcctStop{
|
||||||
|
id:u32,
|
||||||
|
name:String,
|
||||||
|
lat: f64,
|
||||||
|
#[serde(rename(deserialize = "lng"))]
|
||||||
|
lon: f64,
|
||||||
|
}
|
||||||
|
impl From<OcctStop> for Stop{
|
||||||
|
fn from(OcctStop{id,name,lat,lon}: OcctStop) -> Self {
|
||||||
|
Self {
|
||||||
|
id,
|
||||||
|
name,
|
||||||
|
lat,
|
||||||
|
lon
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[derive(serde::Deserialize)]
|
||||||
|
struct BCStop{
|
||||||
|
id:u32,
|
||||||
|
name:String,
|
||||||
|
lat: f64,
|
||||||
|
lon: f64,
|
||||||
|
}
|
||||||
|
impl From<BCStop> for Stop{
|
||||||
|
fn from(BCStop{id,name,lat,lon}: BCStop) -> Self {
|
||||||
|
Self {
|
||||||
|
id,
|
||||||
|
name,
|
||||||
|
lat,
|
||||||
|
lon
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn occt_stops_get()->anyhow::Result<Vec<Stop>>{
|
||||||
|
Ok(Vec::new())
|
||||||
|
}
|
||||||
|
pub async fn BC_stops_get()->anyhow::Result<Vec<Stop>>{
|
||||||
|
Ok(Vec::new())
|
||||||
|
}
|
||||||
|
pub fn poly_encode_stops<I:IntoIterator<Item=Stop>>(stops:I)->String{
|
||||||
|
stops.into_iter()
|
||||||
|
.map(|stop|{
|
||||||
|
enc_float(stop.lat)
|
||||||
|
})
|
||||||
|
.reduce(|s1,s2|s1+&s2)
|
||||||
|
fn enc_float(num:f64)->String{
|
||||||
|
let mut working:i32 = (num*1e5).round();
|
||||||
|
//hopethis does what's needed
|
||||||
|
working<<=1;
|
||||||
|
if num < 0 {
|
||||||
|
working = !working;
|
||||||
|
}
|
||||||
|
let mut bits:[bool;30] = [false;30];
|
||||||
|
for i in 0..30{
|
||||||
|
bits[i] = working % 2 == 1;
|
||||||
|
working >>=1;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue