From c534cfd937c99606d0fca8a08be152bbcf3b6848 Mon Sep 17 00:00:00 2001 From: Erik Siebert Date: Thu, 4 Jul 2024 15:25:25 +0200 Subject: [PATCH] Implement Cycling Tracker endpoint placeholders --- .rustfmt.toml | 1 + Cargo.lock | 115 ++++++ Cargo.toml | 3 + build.rs | 7 +- data/route_guide_db.json | 702 --------------------------------- proto/cyclingtracker.proto | 100 +++++ proto/useless.proto | 105 ----- src/actor/grpc.rs | 43 +- src/cyclingtracker.bin | Bin 0 -> 5127 bytes src/lib.rs | 9 +- src/main.rs | 6 + src/service/auth.rs | 9 +- src/service/cycling_tracker.rs | 84 ++++ src/service/mod.rs | 4 +- src/service/route_guide.rs | 166 -------- src/useless.bin | Bin 4369 -> 0 bytes src/util/data.rs | 35 -- src/util/mod.rs | 1 - 18 files changed, 349 insertions(+), 1041 deletions(-) create mode 100644 .rustfmt.toml delete mode 100644 data/route_guide_db.json create mode 100644 proto/cyclingtracker.proto delete mode 100644 proto/useless.proto create mode 100644 src/cyclingtracker.bin create mode 100644 src/service/cycling_tracker.rs delete mode 100644 src/service/route_guide.rs delete mode 100644 src/useless.bin delete mode 100644 src/util/data.rs delete mode 100644 src/util/mod.rs diff --git a/.rustfmt.toml b/.rustfmt.toml new file mode 100644 index 0000000..baaae7e --- /dev/null +++ b/.rustfmt.toml @@ -0,0 +1 @@ +max_width = 88 \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 5fc0a1c..f563277 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -432,6 +432,12 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + [[package]] name = "libc" version = "0.2.155" @@ -494,6 +500,16 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "defc4c55412d89136f966bbb339008b474350e5e6e78d2714439c386b3137a03" +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + [[package]] name = "num_cpus" version = "1.16.0" @@ -519,6 +535,12 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + [[package]] name = "percent-encoding" version = "2.3.1" @@ -831,6 +853,15 @@ dependencies = [ "serde", ] +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + [[package]] name = "slab" version = "0.4.9" @@ -840,6 +871,12 @@ dependencies = [ "autocfg", ] +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + [[package]] name = "socket2" version = "0.5.7" @@ -902,6 +939,16 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "thread_local" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +dependencies = [ + "cfg-if", + "once_cell", +] + [[package]] name = "tokio" version = "1.38.0" @@ -1031,6 +1078,17 @@ dependencies = [ "tonic", ] +[[package]] +name = "tonic-types" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4aa089471d8d4c60ec3aef047739713a4695f0b309d4cea0073bc55201064f4" +dependencies = [ + "prost", + "prost-types", + "tonic", +] + [[package]] name = "tower" version = "0.4.13" @@ -1092,6 +1150,32 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +dependencies = [ + "nu-ansi-term", + "sharded-slab", + "smallvec", + "thread_local", + "tracing-core", + "tracing-log", ] [[package]] @@ -1126,8 +1210,17 @@ dependencies = [ "tonic", "tonic-build", "tonic-reflection", + "tonic-types", + "tracing", + "tracing-subscriber", ] +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + [[package]] name = "want" version = "0.3.1" @@ -1143,6 +1236,28 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + [[package]] name = "windows-sys" version = "0.48.0" diff --git a/Cargo.toml b/Cargo.toml index 8b8e469..1075ef7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,9 @@ async-stream = "0.2" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" rand = "0.8" +tonic-types = "0.11.0" +tracing = "0.1.40" +tracing-subscriber = "0.3.18" [build-dependencies] tonic-build = "0.11" diff --git a/build.rs b/build.rs index 32cbdb2..069226e 100644 --- a/build.rs +++ b/build.rs @@ -1,9 +1,8 @@ fn main() -> Result<(), Box> { tonic_build::configure() - .type_attribute(".uselesspackage.Point", "#[derive(Eq)]") - .type_attribute(".uselesspackage.Point", "#[derive(Hash)]") - .file_descriptor_set_path("src/useless.bin") - .compile(&["proto/useless.proto"], &["proto"]) + .file_descriptor_set_path("src/cyclingtracker.bin") + .compile(&["proto/cyclingtracker.proto"], &["proto"]) .unwrap(); + Ok(()) } diff --git a/data/route_guide_db.json b/data/route_guide_db.json deleted file mode 100644 index 732f099..0000000 --- a/data/route_guide_db.json +++ /dev/null @@ -1,702 +0,0 @@ -[ - { - "location": { - "latitude": 407838351, - "longitude": -746143763 - }, - "name": "Patriots Path, Mendham, NJ 07945, USA" - }, - { - "location": { - "latitude": 408122808, - "longitude": -743999179 - }, - "name": "101 New Jersey 10, Whippany, NJ 07981, USA" - }, - { - "location": { - "latitude": 413628156, - "longitude": -749015468 - }, - "name": "U.S. 6, Shohola, PA 18458, USA" - }, - { - "location": { - "latitude": 419999544, - "longitude": -740371136 - }, - "name": "5 Conners Road, Kingston, NY 12401, USA" - }, - { - "location": { - "latitude": 414008389, - "longitude": -743951297 - }, - "name": "Mid Hudson Psychiatric Center, New Hampton, NY 10958, USA" - }, - { - "location": { - "latitude": 419611318, - "longitude": -746524769 - }, - "name": "287 Flugertown Road, Livingston Manor, NY 12758, USA" - }, - { - "location": { - "latitude": 406109563, - "longitude": -742186778 - }, - "name": "4001 Tremley Point Road, Linden, NJ 07036, USA" - }, - { - "location": { - "latitude": 416802456, - "longitude": -742370183 - }, - "name": "352 South Mountain Road, Wallkill, NY 12589, USA" - }, - { - "location": { - "latitude": 412950425, - "longitude": -741077389 - }, - "name": "Bailey Turn Road, Harriman, NY 10926, USA" - }, - { - "location": { - "latitude": 412144655, - "longitude": -743949739 - }, - "name": "193-199 Wawayanda Road, Hewitt, NJ 07421, USA" - }, - { - "location": { - "latitude": 415736605, - "longitude": -742847522 - }, - "name": "406-496 Ward Avenue, Pine Bush, NY 12566, USA" - }, - { - "location": { - "latitude": 413843930, - "longitude": -740501726 - }, - "name": "162 Merrill Road, Highland Mills, NY 10930, USA" - }, - { - "location": { - "latitude": 410873075, - "longitude": -744459023 - }, - "name": "Clinton Road, West Milford, NJ 07480, USA" - }, - { - "location": { - "latitude": 412346009, - "longitude": -744026814 - }, - "name": "16 Old Brook Lane, Warwick, NY 10990, USA" - }, - { - "location": { - "latitude": 402948455, - "longitude": -747903913 - }, - "name": "3 Drake Lane, Pennington, NJ 08534, USA" - }, - { - "location": { - "latitude": 406337092, - "longitude": -740122226 - }, - "name": "6324 8th Avenue, Brooklyn, NY 11220, USA" - }, - { - "location": { - "latitude": 406421967, - "longitude": -747727624 - }, - "name": "1 Merck Access Road, Whitehouse Station, NJ 08889, USA" - }, - { - "location": { - "latitude": 416318082, - "longitude": -749677716 - }, - "name": "78-98 Schalck Road, Narrowsburg, NY 12764, USA" - }, - { - "location": { - "latitude": 415301720, - "longitude": -748416257 - }, - "name": "282 Lakeview Drive Road, Highland Lake, NY 12743, USA" - }, - { - "location": { - "latitude": 402647019, - "longitude": -747071791 - }, - "name": "330 Evelyn Avenue, Hamilton Township, NJ 08619, USA" - }, - { - "location": { - "latitude": 412567807, - "longitude": -741058078 - }, - "name": "New York State Reference Route 987E, Southfields, NY 10975, USA" - }, - { - "location": { - "latitude": 416855156, - "longitude": -744420597 - }, - "name": "103-271 Tempaloni Road, Ellenville, NY 12428, USA" - }, - { - "location": { - "latitude": 404663628, - "longitude": -744820157 - }, - "name": "1300 Airport Road, North Brunswick Township, NJ 08902, USA" - }, - { - "location": { - "latitude": 407113723, - "longitude": -749746483 - }, - "name": "" - }, - { - "location": { - "latitude": 402133926, - "longitude": -743613249 - }, - "name": "" - }, - { - "location": { - "latitude": 400273442, - "longitude": -741220915 - }, - "name": "" - }, - { - "location": { - "latitude": 411236786, - "longitude": -744070769 - }, - "name": "" - }, - { - "location": { - "latitude": 411633782, - "longitude": -746784970 - }, - "name": "211-225 Plains Road, Augusta, NJ 07822, USA" - }, - { - "location": { - "latitude": 415830701, - "longitude": -742952812 - }, - "name": "" - }, - { - "location": { - "latitude": 413447164, - "longitude": -748712898 - }, - "name": "165 Pedersen Ridge Road, Milford, PA 18337, USA" - }, - { - "location": { - "latitude": 405047245, - "longitude": -749800722 - }, - "name": "100-122 Locktown Road, Frenchtown, NJ 08825, USA" - }, - { - "location": { - "latitude": 418858923, - "longitude": -746156790 - }, - "name": "" - }, - { - "location": { - "latitude": 417951888, - "longitude": -748484944 - }, - "name": "650-652 Willi Hill Road, Swan Lake, NY 12783, USA" - }, - { - "location": { - "latitude": 407033786, - "longitude": -743977337 - }, - "name": "26 East 3rd Street, New Providence, NJ 07974, USA" - }, - { - "location": { - "latitude": 417548014, - "longitude": -740075041 - }, - "name": "" - }, - { - "location": { - "latitude": 410395868, - "longitude": -744972325 - }, - "name": "" - }, - { - "location": { - "latitude": 404615353, - "longitude": -745129803 - }, - "name": "" - }, - { - "location": { - "latitude": 406589790, - "longitude": -743560121 - }, - "name": "611 Lawrence Avenue, Westfield, NJ 07090, USA" - }, - { - "location": { - "latitude": 414653148, - "longitude": -740477477 - }, - "name": "18 Lannis Avenue, New Windsor, NY 12553, USA" - }, - { - "location": { - "latitude": 405957808, - "longitude": -743255336 - }, - "name": "82-104 Amherst Avenue, Colonia, NJ 07067, USA" - }, - { - "location": { - "latitude": 411733589, - "longitude": -741648093 - }, - "name": "170 Seven Lakes Drive, Sloatsburg, NY 10974, USA" - }, - { - "location": { - "latitude": 412676291, - "longitude": -742606606 - }, - "name": "1270 Lakes Road, Monroe, NY 10950, USA" - }, - { - "location": { - "latitude": 409224445, - "longitude": -748286738 - }, - "name": "509-535 Alphano Road, Great Meadows, NJ 07838, USA" - }, - { - "location": { - "latitude": 406523420, - "longitude": -742135517 - }, - "name": "652 Garden Street, Elizabeth, NJ 07202, USA" - }, - { - "location": { - "latitude": 401827388, - "longitude": -740294537 - }, - "name": "349 Sea Spray Court, Neptune City, NJ 07753, USA" - }, - { - "location": { - "latitude": 410564152, - "longitude": -743685054 - }, - "name": "13-17 Stanley Street, West Milford, NJ 07480, USA" - }, - { - "location": { - "latitude": 408472324, - "longitude": -740726046 - }, - "name": "47 Industrial Avenue, Teterboro, NJ 07608, USA" - }, - { - "location": { - "latitude": 412452168, - "longitude": -740214052 - }, - "name": "5 White Oak Lane, Stony Point, NY 10980, USA" - }, - { - "location": { - "latitude": 409146138, - "longitude": -746188906 - }, - "name": "Berkshire Valley Management Area Trail, Jefferson, NJ, USA" - }, - { - "location": { - "latitude": 404701380, - "longitude": -744781745 - }, - "name": "1007 Jersey Avenue, New Brunswick, NJ 08901, USA" - }, - { - "location": { - "latitude": 409642566, - "longitude": -746017679 - }, - "name": "6 East Emerald Isle Drive, Lake Hopatcong, NJ 07849, USA" - }, - { - "location": { - "latitude": 408031728, - "longitude": -748645385 - }, - "name": "1358-1474 New Jersey 57, Port Murray, NJ 07865, USA" - }, - { - "location": { - "latitude": 413700272, - "longitude": -742135189 - }, - "name": "367 Prospect Road, Chester, NY 10918, USA" - }, - { - "location": { - "latitude": 404310607, - "longitude": -740282632 - }, - "name": "10 Simon Lake Drive, Atlantic Highlands, NJ 07716, USA" - }, - { - "location": { - "latitude": 409319800, - "longitude": -746201391 - }, - "name": "11 Ward Street, Mount Arlington, NJ 07856, USA" - }, - { - "location": { - "latitude": 406685311, - "longitude": -742108603 - }, - "name": "300-398 Jefferson Avenue, Elizabeth, NJ 07201, USA" - }, - { - "location": { - "latitude": 419018117, - "longitude": -749142781 - }, - "name": "43 Dreher Road, Roscoe, NY 12776, USA" - }, - { - "location": { - "latitude": 412856162, - "longitude": -745148837 - }, - "name": "Swan Street, Pine Island, NY 10969, USA" - }, - { - "location": { - "latitude": 416560744, - "longitude": -746721964 - }, - "name": "66 Pleasantview Avenue, Monticello, NY 12701, USA" - }, - { - "location": { - "latitude": 405314270, - "longitude": -749836354 - }, - "name": "" - }, - { - "location": { - "latitude": 414219548, - "longitude": -743327440 - }, - "name": "" - }, - { - "location": { - "latitude": 415534177, - "longitude": -742900616 - }, - "name": "565 Winding Hills Road, Montgomery, NY 12549, USA" - }, - { - "location": { - "latitude": 406898530, - "longitude": -749127080 - }, - "name": "231 Rocky Run Road, Glen Gardner, NJ 08826, USA" - }, - { - "location": { - "latitude": 407586880, - "longitude": -741670168 - }, - "name": "100 Mount Pleasant Avenue, Newark, NJ 07104, USA" - }, - { - "location": { - "latitude": 400106455, - "longitude": -742870190 - }, - "name": "517-521 Huntington Drive, Manchester Township, NJ 08759, USA" - }, - { - "location": { - "latitude": 400066188, - "longitude": -746793294 - }, - "name": "" - }, - { - "location": { - "latitude": 418803880, - "longitude": -744102673 - }, - "name": "40 Mountain Road, Napanoch, NY 12458, USA" - }, - { - "location": { - "latitude": 414204288, - "longitude": -747895140 - }, - "name": "" - }, - { - "location": { - "latitude": 414777405, - "longitude": -740615601 - }, - "name": "" - }, - { - "location": { - "latitude": 415464475, - "longitude": -747175374 - }, - "name": "48 North Road, Forestburgh, NY 12777, USA" - }, - { - "location": { - "latitude": 404062378, - "longitude": -746376177 - }, - "name": "" - }, - { - "location": { - "latitude": 405688272, - "longitude": -749285130 - }, - "name": "" - }, - { - "location": { - "latitude": 400342070, - "longitude": -748788996 - }, - "name": "" - }, - { - "location": { - "latitude": 401809022, - "longitude": -744157964 - }, - "name": "" - }, - { - "location": { - "latitude": 404226644, - "longitude": -740517141 - }, - "name": "9 Thompson Avenue, Leonardo, NJ 07737, USA" - }, - { - "location": { - "latitude": 410322033, - "longitude": -747871659 - }, - "name": "" - }, - { - "location": { - "latitude": 407100674, - "longitude": -747742727 - }, - "name": "" - }, - { - "location": { - "latitude": 418811433, - "longitude": -741718005 - }, - "name": "213 Bush Road, Stone Ridge, NY 12484, USA" - }, - { - "location": { - "latitude": 415034302, - "longitude": -743850945 - }, - "name": "" - }, - { - "location": { - "latitude": 411349992, - "longitude": -743694161 - }, - "name": "" - }, - { - "location": { - "latitude": 404839914, - "longitude": -744759616 - }, - "name": "1-17 Bergen Court, New Brunswick, NJ 08901, USA" - }, - { - "location": { - "latitude": 414638017, - "longitude": -745957854 - }, - "name": "35 Oakland Valley Road, Cuddebackville, NY 12729, USA" - }, - { - "location": { - "latitude": 412127800, - "longitude": -740173578 - }, - "name": "" - }, - { - "location": { - "latitude": 401263460, - "longitude": -747964303 - }, - "name": "" - }, - { - "location": { - "latitude": 412843391, - "longitude": -749086026 - }, - "name": "" - }, - { - "location": { - "latitude": 418512773, - "longitude": -743067823 - }, - "name": "" - }, - { - "location": { - "latitude": 404318328, - "longitude": -740835638 - }, - "name": "42-102 Main Street, Belford, NJ 07718, USA" - }, - { - "location": { - "latitude": 419020746, - "longitude": -741172328 - }, - "name": "" - }, - { - "location": { - "latitude": 404080723, - "longitude": -746119569 - }, - "name": "" - }, - { - "location": { - "latitude": 401012643, - "longitude": -744035134 - }, - "name": "" - }, - { - "location": { - "latitude": 404306372, - "longitude": -741079661 - }, - "name": "" - }, - { - "location": { - "latitude": 403966326, - "longitude": -748519297 - }, - "name": "" - }, - { - "location": { - "latitude": 405002031, - "longitude": -748407866 - }, - "name": "" - }, - { - "location": { - "latitude": 409532885, - "longitude": -742200683 - }, - "name": "" - }, - { - "location": { - "latitude": 416851321, - "longitude": -742674555 - }, - "name": "" - }, - { - "location": { - "latitude": 406411633, - "longitude": -741722051 - }, - "name": "3387 Richmond Terrace, Staten Island, NY 10303, USA" - }, - { - "location": { - "latitude": 413069058, - "longitude": -744597778 - }, - "name": "261 Van Sickle Road, Goshen, NY 10924, USA" - }, - { - "location": { - "latitude": 418465462, - "longitude": -746859398 - }, - "name": "" - }, - { - "location": { - "latitude": 411733222, - "longitude": -744228360 - }, - "name": "" - }, - { - "location": { - "latitude": 410248224, - "longitude": -747127767 - }, - "name": "3 Hasta Way, Newton, NJ 07860, USA" - } -] \ No newline at end of file diff --git a/proto/cyclingtracker.proto b/proto/cyclingtracker.proto new file mode 100644 index 0000000..4df4ade --- /dev/null +++ b/proto/cyclingtracker.proto @@ -0,0 +1,100 @@ +syntax = "proto3"; + +package cyclingtracker; + +// Service for providing session tokens +service SessionAuth { + // Return a session token on successful login. + rpc Login(Credentials) returns (SessionToken) {} +} + +message Credentials { + // Username + string username = 1; + // Password + string password = 2; +} + +message SessionToken { + // Session token as a string. + string token = 1; +} + +// Service for tracking cycling activities +service CyclingTracker { + // Save an activity and return an activity summary. + // + // Summary includes measurement averages. + rpc SaveActivity(Activity) returns (ActivitySummary) {} + + // Return detailed measurements of a certain activity. Measurements are streamed + // rather than returned at once, since there might be a lot of measurements. + rpc GetMeasurements(ActivityRequest) returns (stream Measurement) {} + + // Records an ongoing activity and its measurements and returns an activity summary + // at the end of the activity. + rpc RecordActivity(stream Measurement) returns (ActivitySummary) {} + + rpc CreateTrainingPlan(TrainingPlan) returns (TrainingPlanToken) {} + + // Executes a training plan by adjusting resistance to fit a training plan + rpc ExecuteTrainingPlan(stream ActivityStep) returns (stream ControlStep) {} +} + +message Activity { + int32 id = 1; + float km_ridden = 2; + repeated Measurement measurements = 3; +} + +message Measurement { + float speed = 1; + int32 watts = 2; + int32 rpm = 3; + int32 resistance = 4; + int32 heartrate = 5; +} + +message ActivitySummary { + int32 id = 1; + float km_ridden = 2; + float avg_speed = 3; + int32 avg_watts = 4; + int32 avg_rpm = 5; + int32 avg_heartrate = 6; + repeated Measurement measurements = 7; +} + +message ActivityRequest { + int32 id = 1; +} + +message TrainingPlan { + message Step { + int32 watts = 1; + int32 duration = 2; + } + repeated Step steps = 1; +} + +message TrainingPlanToken { + int32 training_token = 1; +} + +enum StepType { + STARTING = 0; + IN_PROGRESS = 1; + ENDING = 2; +} + +message ActivityStep { + StepType type = 1; + optional TrainingPlanToken training_token = 2; + optional Measurement measurement = 3; +} + +message ControlStep { + StepType type = 1; + optional float resistance = 2; + optional int32 activity_summary_id = 3; +} \ No newline at end of file diff --git a/proto/useless.proto b/proto/useless.proto deleted file mode 100644 index 5d157ee..0000000 --- a/proto/useless.proto +++ /dev/null @@ -1,105 +0,0 @@ -syntax = "proto3"; - -package uselesspackage; - -service SessionAuth { - rpc Login(Credentials) returns (SessionToken) {} -} - -message Credentials { - string username = 1; - string password = 2; -} - -message SessionToken { - string token = 1; -} - -// Interface exported by the server. -service RouteGuide { - // A simple RPC. - // - // Obtains the feature at a given position. - // - // A feature with an empty name is returned if there's no feature at the given - // position. - rpc GetFeature(Point) returns (Feature) {} - - // A server-to-client streaming RPC. - // - // Obtains the Features available within the given Rectangle. Results are - // streamed rather than returned at once (e.g. in a response message with a - // repeated field), as the rectangle may cover a large area and contain a - // huge number of features. - rpc ListFeatures(Rectangle) returns (stream Feature) {} - - // A client-to-server streaming RPC. - // - // Accepts a stream of Points on a route being traversed, returning a - // RouteSummary when traversal is completed. - rpc RecordRoute(stream Point) returns (RouteSummary) {} - - // A Bidirectional streaming RPC. - // - // Accepts a stream of RouteNotes sent while a route is being traversed, - // while receiving other RouteNotes (e.g. from other users). - rpc RouteChat(stream RouteNote) returns (stream RouteNote) {} -} - -// Points are represented as latitude-longitude pairs in the E7 representation -// (degrees multiplied by 10**7 and rounded to the nearest integer). -// Latitudes should be in the range +/- 90 degrees and longitude should be in -// the range +/- 180 degrees (inclusive). -message Point { - int32 latitude = 1; - int32 longitude = 2; -} - -// A latitude-longitude rectangle, represented as two diagonally opposite -// points "lo" and "hi". -message Rectangle { - // One corner of the rectangle. - Point lo = 1; - - // The other corner of the rectangle. - Point hi = 2; -} - -// A feature names something at a given point. -// -// If a feature could not be named, the name is empty. -message Feature { - // The name of the feature. - string name = 1; - - // The point where the feature is detected. - Point location = 2; -} - -// A RouteNote is a message sent while at a given point. -message RouteNote { - // The location from which the message is sent. - Point location = 1; - - // The message to be sent. - string message = 2; -} - -// A RouteSummary is received in response to a RecordRoute rpc. -// -// It contains the number of individual points received, the number of -// detected features, and the total distance covered as the cumulative sum of -// the distance between each point. -message RouteSummary { - // The number of points received. - int32 point_count = 1; - - // The number of known features passed while traversing the route. - int32 feature_count = 2; - - // The distance covered in metres. - int32 distance = 3; - - // The duration of the traversal in seconds. - int32 elapsed_time = 4; -} \ No newline at end of file diff --git a/src/actor/grpc.rs b/src/actor/grpc.rs index 908a590..3783479 100644 --- a/src/actor/grpc.rs +++ b/src/actor/grpc.rs @@ -1,17 +1,18 @@ -use tonic_reflection; +use tonic_reflection::server::Builder; -use crate::useless_box::route_guide_server::RouteGuideServer; -use crate::useless_box::session_auth_server::SessionAuthServer; -use crate::useless_box::FILE_DESCRIPTOR_SET; +use crate::cycling_tracker::cycling_tracker_server::CyclingTrackerServer; +use crate::cycling_tracker::session_auth_server::SessionAuthServer; +use crate::cycling_tracker::FILE_DESCRIPTOR_SET; use tonic::{ metadata::MetadataValue, transport::{Identity, Server, ServerTlsConfig}, Request, Status, }; -use crate::service::RouteGuideService; +use crate::service::CyclingTrackerService; use crate::service::SessionAuthService; -use crate::util::data::populate; + +use tracing::info; pub struct GRPCActor { grpc_host_url: String, @@ -25,31 +26,25 @@ impl GRPCActor { } pub async fn run(&self) -> Result<(), Box> { - let data_dir = std::path::PathBuf::from_iter([std::env!("CARGO_MANIFEST_DIR"), "data/tls"]); - let cert = std::fs::read_to_string(data_dir.join("server.pem"))?; - let key = std::fs::read_to_string(data_dir.join("server.key"))?; - let identity = Identity::from_pem(cert, key); - - let reflection_svc = tonic_reflection::server::Builder::configure() + let reflection_svc = Builder::configure() .register_encoded_file_descriptor_set(FILE_DESCRIPTOR_SET) .build() .unwrap(); - let route_svc = RouteGuideServer::with_interceptor( - RouteGuideService { - features: populate(), - }, + let ct_svc = CyclingTrackerServer::with_interceptor( + CyclingTrackerService {}, check_session_token, ); + let auth_svc = SessionAuthServer::new(SessionAuthService {}); let addr = self.grpc_host_url.parse().unwrap(); - println!("RouteGuideServer listening on: {}", addr); + info!("CyclingTracker listening on: {}", addr); Server::builder() - .tls_config(ServerTlsConfig::new().identity(identity))? + .tls_config(config_tls()?)? .add_service(reflection_svc) - .add_service(route_svc) + .add_service(ct_svc) .add_service(auth_svc) .serve(addr) .await?; @@ -58,6 +53,16 @@ impl GRPCActor { } } +fn config_tls() -> Result> { + let data_dir = + std::path::PathBuf::from_iter([std::env!("CARGO_MANIFEST_DIR"), "data/tls"]); + let cert = std::fs::read_to_string(data_dir.join("server.pem")) + .map_err(|err| format!("Error reading public key file: {}", err))?; + let key = std::fs::read_to_string(data_dir.join("server.key")) + .map_err(|err| format!("Error reading private key file: {}", err))?; + Ok(ServerTlsConfig::new().identity(Identity::from_pem(cert, key))) +} + fn check_session_token(req: Request<()>) -> Result, Status> { let token: MetadataValue<_> = "Bearer session-token".parse().unwrap(); diff --git a/src/cyclingtracker.bin b/src/cyclingtracker.bin new file mode 100644 index 0000000000000000000000000000000000000000..3ae0af665f3a1935a7b2b52f54690ec4156891ad GIT binary patch literal 5127 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 sWnww1`~kZmV!Z literal 0 HcmV?d00001 diff --git a/src/lib.rs b/src/lib.rs index aabb817..8599345 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,13 +1,14 @@ pub mod actor; pub mod service; -pub mod util; use actor::GRPCActor; -pub mod useless_box { - tonic::include_proto!("uselesspackage"); +type GRPCResult = Result, tonic::Status>; - pub const FILE_DESCRIPTOR_SET: &[u8] = include_bytes!("useless.bin"); +pub mod cycling_tracker { + tonic::include_proto!("cyclingtracker"); + + pub const FILE_DESCRIPTOR_SET: &[u8] = include_bytes!("cyclingtracker.bin"); } pub struct App { diff --git a/src/main.rs b/src/main.rs index af0a6aa..396601c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,13 @@ +use tracing::{info, Level}; +use tracing_subscriber; use useless_box::App; #[tokio::main] async fn main() -> Result<(), Box> { + tracing_subscriber::fmt().with_max_level(Level::INFO).init(); + + info!("Starting gRPC server"); + let app = App::new(String::from("[::1]:10000")); app.run().await?; diff --git a/src/service/auth.rs b/src/service/auth.rs index ef0eb7e..cc05537 100644 --- a/src/service/auth.rs +++ b/src/service/auth.rs @@ -1,14 +1,17 @@ use tonic::{Request, Response, Status}; -use crate::useless_box::session_auth_server::SessionAuth; -use crate::useless_box::{Credentials, SessionToken}; +use crate::cycling_tracker::session_auth_server::SessionAuth; +use crate::cycling_tracker::{Credentials, SessionToken}; #[derive(Debug)] pub struct SessionAuthService {} #[tonic::async_trait] impl SessionAuth for SessionAuthService { - async fn login(&self, request: Request) -> Result, Status> { + async fn login( + &self, + request: Request, + ) -> Result, Status> { println!("Login = {:?}", request); let credentials = request.get_ref(); if credentials.username == "root" && credentials.password == "admin" { diff --git a/src/service/cycling_tracker.rs b/src/service/cycling_tracker.rs new file mode 100644 index 0000000..26eed8a --- /dev/null +++ b/src/service/cycling_tracker.rs @@ -0,0 +1,84 @@ +use std::pin::Pin; +use tokio::sync::mpsc; +use tokio_stream::{wrappers::ReceiverStream, Stream, StreamExt}; +use tonic::{Request, Response, Status, Streaming}; + +use crate::cycling_tracker::cycling_tracker_server::CyclingTracker; +use crate::cycling_tracker::{ + Activity, ActivityRequest, ActivityStep, ActivitySummary, ControlStep, Measurement, + TrainingPlan, TrainingPlanToken, +}; +use crate::GRPCResult; + +pub struct CyclingTrackerService {} + +#[tonic::async_trait] +impl CyclingTracker for CyclingTrackerService { + async fn save_activity( + &self, + request: Request, + ) -> GRPCResult { + Ok(Response::new(ActivitySummary::default())) + } + + type GetMeasurementsStream = ReceiverStream>; + + async fn get_measurements( + &self, + request: Request, + ) -> GRPCResult { + let (tx, rx) = mpsc::channel(4); + + tokio::spawn(async move { + tx.send(Ok(Measurement::default())).await.unwrap(); + + println!(" /// done sending"); + }); + + Ok(Response::new(ReceiverStream::new(rx))) + } + + async fn record_activity( + &self, + request: Request>, + ) -> GRPCResult { + let mut stream = request.into_inner(); + + let mut summary = ActivitySummary::default(); + + while let Some(measurement) = stream.next().await { + let measurement = measurement?; + + println!("Measurement = {:?}", measurement); + } + + Ok(Response::new(summary)) + } + + async fn create_training_plan( + &self, + request: Request, + ) -> GRPCResult { + Ok(Response::new(TrainingPlanToken::default())) + } + + type ExecuteTrainingPlanStream = + Pin> + Send + 'static>>; + + async fn execute_training_plan( + &self, + request: Request>, + ) -> GRPCResult { + let mut stream = request.into_inner(); + + let output = async_stream::try_stream! { + while let Some(activity_step) = stream.next().await { + yield ControlStep::default(); + } + }; + + Ok(Response::new( + Box::pin(output) as Self::ExecuteTrainingPlanStream + )) + } +} diff --git a/src/service/mod.rs b/src/service/mod.rs index b6c9c15..6439f2d 100644 --- a/src/service/mod.rs +++ b/src/service/mod.rs @@ -1,5 +1,5 @@ pub mod auth; -pub mod route_guide; +pub mod cycling_tracker; pub use auth::SessionAuthService; -pub use route_guide::RouteGuideService; +pub use cycling_tracker::CyclingTrackerService; diff --git a/src/service/route_guide.rs b/src/service/route_guide.rs deleted file mode 100644 index 37d7af0..0000000 --- a/src/service/route_guide.rs +++ /dev/null @@ -1,166 +0,0 @@ -use std::collections::HashMap; -use std::pin::Pin; -use std::time::Instant; - -use tokio::sync::mpsc; -use tokio_stream::{wrappers::ReceiverStream, Stream, StreamExt}; -use tonic::{Request, Response, Status}; - -use crate::useless_box::route_guide_server::RouteGuide; -use crate::useless_box::{Feature, Point, Rectangle, RouteNote, RouteSummary}; - -#[derive(Debug)] -pub struct RouteGuideService { - pub features: Vec, -} - -#[tonic::async_trait] -impl RouteGuide for RouteGuideService { - async fn get_feature(&self, request: Request) -> Result, Status> { - println!("GetFeature = {:?}", request); - - for feature in &self.features[..] { - if feature.location.as_ref() == Some(request.get_ref()) { - return Ok(Response::new(feature.clone())); - } - } - - Ok(Response::new(Feature::default())) - } - - type ListFeaturesStream = ReceiverStream>; - - async fn list_features( - &self, - request: Request, - ) -> Result, Status> { - println!("ListFeatures = {:?}", request); - - let (tx, rx) = mpsc::channel(4); - let features = self.features.clone(); - - tokio::spawn(async move { - for feature in &features[..] { - if in_range(feature.location.as_ref().unwrap(), request.get_ref()) { - println!(" => send {:?}", feature); - tx.send(Ok(feature.clone())).await.unwrap(); - } - } - - println!(" /// done sending"); - }); - - Ok(Response::new(ReceiverStream::new(rx))) - } - - async fn record_route( - &self, - request: Request>, - ) -> Result, Status> { - println!("RecordRoute"); - - let mut stream = request.into_inner(); - - let mut summary = RouteSummary::default(); - let mut last_point = None; - let now = Instant::now(); - - while let Some(point) = stream.next().await { - let point = point?; - - println!(" ==> Point = {:?}", point); - - // Increment the point count - summary.point_count += 1; - - // Find features - for feature in &self.features[..] { - if feature.location.as_ref() == Some(&point) { - summary.feature_count += 1; - } - } - - // Calculate the distance - if let Some(ref last_point) = last_point { - summary.distance += calc_distance(last_point, &point); - } - - last_point = Some(point); - } - - summary.elapsed_time = now.elapsed().as_secs() as i32; - - Ok(Response::new(summary)) - } - - type RouteChatStream = Pin> + Send + 'static>>; - - async fn route_chat( - &self, - request: Request>, - ) -> Result, Status> { - println!("RouteChat"); - - let mut notes = HashMap::new(); - let mut stream = request.into_inner(); - - let output = async_stream::try_stream! { - while let Some(note) = stream.next().await { - let note = note?; - - let location = note.location.clone().unwrap(); - - let location_notes = notes.entry(location).or_insert(vec![]); - location_notes.push(note); - - for note in location_notes { - yield note.clone(); - } - } - }; - - Ok(Response::new(Box::pin(output) as Self::RouteChatStream)) - } -} - -fn in_range(point: &Point, rect: &Rectangle) -> bool { - use std::cmp; - - let lo = rect.lo.as_ref().unwrap(); - let hi = rect.hi.as_ref().unwrap(); - - let left = cmp::min(lo.longitude, hi.longitude); - let right = cmp::max(lo.longitude, hi.longitude); - let top = cmp::max(lo.latitude, hi.latitude); - let bottom = cmp::min(lo.latitude, hi.latitude); - - point.longitude >= left - && point.longitude <= right - && point.latitude >= bottom - && point.latitude <= top -} - -/// Calculates the distance between two points using the "haversine" formula. -/// This code was taken from http://www.movable-type.co.uk/scripts/latlong.html. -fn calc_distance(p1: &Point, p2: &Point) -> i32 { - const CORD_FACTOR: f64 = 1e7; - const R: f64 = 6_371_000.0; // meters - - let lat1 = p1.latitude as f64 / CORD_FACTOR; - let lat2 = p2.latitude as f64 / CORD_FACTOR; - let lng1 = p1.longitude as f64 / CORD_FACTOR; - let lng2 = p2.longitude as f64 / CORD_FACTOR; - - let lat_rad1 = lat1.to_radians(); - let lat_rad2 = lat2.to_radians(); - - let delta_lat = (lat2 - lat1).to_radians(); - let delta_lng = (lng2 - lng1).to_radians(); - - let a = (delta_lat / 2f64).sin() * (delta_lat / 2f64).sin() - + (lat_rad1).cos() * (lat_rad2).cos() * (delta_lng / 2f64).sin() * (delta_lng / 2f64).sin(); - - let c = 2f64 * a.sqrt().atan2((1f64 - a).sqrt()); - - (R * c) as i32 -} diff --git a/src/useless.bin b/src/useless.bin deleted file mode 100644 index bd43a3124c282f4ad875ec68745056977cd788b7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4369 zcmai2-)|eo5xzSfX>uva_S%l5tC6mlw32_2vDC;)V7RraMs{i=wq+G)fxyO!w;~TF z?})plRK54PK#`~Rttg5<_h0Kj(0;SGd!!{fedFBjelzpU>^Cd1KX=&Tv``~e6un8F z>5MN~b0YiiD?hIaVva@Hbiql}&3CSrn&P9lsf6*g)Hci3$1R+lEQ!6}z&pq@L!Aa~94~ zV1DyW#GLgJb(a1(R<*73djy+JwfZj8>Vxw{?MGv&&hr&^WeiqPCrh|9J3shr!9c&6 zj>j@T<3DBX2~qp5pG{M3IH?~n^J$O1@Xy%dahaXnQc}BMKbD(NmpCcFZeOj`4E2@G z*Vuv@$w{H&cRE3Pgl4^Mza8S!)*IHgU9daVL;f39e~}H6l>g*>ZRT1ox_y3ezL7fK z);|NrOsY?(Nv!xU8GEXM`0DwsReSvi$^#!bZS2Hd zFtPEE1acv{`J#2a4WB=?J+e2H`jTK=`$QMxbV~&D!2j*vBG%xc=M8<KA1F4SA+Y}55CwHMKYd@ zlsI^`hrQzEk(NnX7zBIkgw#TcL2{x}G0BRA#D%u*3b)}j(L*6qp~e$^CP*VT!oKX-F-Y{1d9TMOotz$Hmc?T5#>Zi^^ zZtHip*}u!X0IM7PD*6ZAgcrtJ$fIB<+u;1$2#=g-V9hLti!*jWP$M z%-g{&qAr91lDC5^&cep+rV%Gv1FhRPN^$0xetK;4fd!z)O`|TfhI}3`F0oAm zi=`)k{ahRZsO<3n2kry>Nd-=1J*mKntS11^Kvu}ZeeZ=I_2)(q4IQ*gHdZ9xkdXPA zh1Nm_;@e}~OE9gk#$h7F;|>Tke6fIuBoZzw@IVP*w>IA%IjVXM5Luz+|7#Q*xB0`Jf7@&1hdLxOL(uz#MEZx#||h!flDSfIiH@+T z6d3+?B-#;g-UY}IgF>syGZk1?o~hMkvsCAXDX?5wWj*5=6EH^0tQpT0AC5j$79xS- zR><^Nh%00g@YptEBM6XFjMn+eAj230tI@p@d5VW0UJCTQG36?sGW0-6(VKXe#WNo? aqz9D`Qs4nfQ1VtI*yWX@hWYQuFa8I!jwe$9 diff --git a/src/util/data.rs b/src/util/data.rs deleted file mode 100644 index 63be3d2..0000000 --- a/src/util/data.rs +++ /dev/null @@ -1,35 +0,0 @@ -use serde::Deserialize; -use std::fs::File; - -#[derive(Debug, Deserialize)] -struct Feature { - location: Location, - name: String, -} - -#[derive(Debug, Deserialize)] -struct Location { - latitude: i32, - longitude: i32, -} - -#[allow(dead_code)] -pub fn populate() -> Vec { - let data_dir = std::path::PathBuf::from_iter([std::env!("CARGO_MANIFEST_DIR"), "data"]); - println!("Populating service with routes"); - let file = File::open(data_dir.join("route_guide_db.json")).expect("failed to open data file"); - - let decoded: Vec = - serde_json::from_reader(&file).expect("failed to deserialize features"); - - decoded - .into_iter() - .map(|feature| crate::useless_box::Feature { - name: feature.name, - location: Some(crate::useless_box::Point { - longitude: feature.location.longitude, - latitude: feature.location.latitude, - }), - }) - .collect() -} diff --git a/src/util/mod.rs b/src/util/mod.rs deleted file mode 100644 index 7a345e4..0000000 --- a/src/util/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod data;