kinda stuck at this point so making a commit

This commit is contained in:
2024-10-31 00:19:02 +01:00
parent cd7d9fa3b7
commit 6d65463286
35 changed files with 44224 additions and 217 deletions

360
Cargo.lock generated
View File

@@ -125,7 +125,7 @@ dependencies = [
"ndk",
"ndk-context",
"ndk-sys",
"num_enum",
"num_enum 0.7.3",
"thiserror",
]
@@ -201,9 +201,9 @@ dependencies = [
[[package]]
name = "anyhow"
version = "1.0.90"
version = "1.0.91"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37bf3594c4c988a53154954629820791dde498571819ae4ca50ca811e060cc95"
checksum = "c042108f3ed77fd83760a5fd79b53be043192bb3b9dba91d8c574c0ada7850c8"
[[package]]
name = "anymap2"
@@ -225,7 +225,7 @@ checksum = "0ae92a5119aa49cdbcf6b9f893fe4e1d98b04ccbf82ee0584ad948a44a734dea"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.79",
"syn 2.0.85",
]
[[package]]
@@ -266,7 +266,7 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.79",
"syn 2.0.85",
]
[[package]]
@@ -277,7 +277,7 @@ checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.79",
"syn 2.0.85",
]
[[package]]
@@ -329,7 +329,7 @@ dependencies = [
"manyhow",
"proc-macro2",
"quote",
"syn 2.0.79",
"syn 2.0.85",
]
[[package]]
@@ -345,7 +345,7 @@ dependencies = [
"proc-macro2",
"quote",
"quote-use",
"syn 2.0.79",
"syn 2.0.85",
]
[[package]]
@@ -381,9 +381,11 @@ dependencies = [
"axum_session",
"axum_session_sqlx",
"base64 0.22.1",
"dashmap 6.1.0",
"derive_more",
"dotenvy",
"futures",
"hash-ids",
"http 1.1.0",
"jsonwebtoken",
"leptos",
@@ -395,6 +397,7 @@ dependencies = [
"serde",
"serde_qs 0.13.0",
"sha256",
"sqids",
"sqlx",
"tera",
"thiserror",
@@ -431,6 +434,7 @@ dependencies = [
"serde",
"serde_qs 0.13.0",
"sha256",
"simconnect-sdk",
"tauri-winrt-notification",
"thiserror",
"time",
@@ -452,6 +456,7 @@ version = "0.1.0"
dependencies = [
"anyhow",
"bincode",
"derive_more",
"flate2",
"serde",
"thiserror",
@@ -568,7 +573,7 @@ checksum = "57d123550fa8d071b7255cb0cc04dc302baa6c8c4a79f55701552684d8399bce"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.79",
"syn 2.0.85",
]
[[package]]
@@ -656,6 +661,29 @@ dependencies = [
"serde",
]
[[package]]
name = "bindgen"
version = "0.65.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cfdf7b466f9a4903edc73f95d6d2bcd5baf8ae620638762244d3f60143643cc5"
dependencies = [
"bitflags 1.3.2",
"cexpr",
"clang-sys",
"lazy_static",
"lazycell",
"log",
"peeking_take_while",
"prettyplease",
"proc-macro2",
"quote",
"regex",
"rustc-hash 1.1.0",
"shlex",
"syn 2.0.85",
"which",
]
[[package]]
name = "bit_field"
version = "0.10.2"
@@ -776,7 +804,7 @@ version = "0.18.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c878c71c2821aa2058722038a59a67583a4240524687c6028571c9b395ded61f"
dependencies = [
"darling",
"darling 0.14.4",
"proc-macro2",
"quote",
"syn 1.0.109",
@@ -862,6 +890,15 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c"
[[package]]
name = "cexpr"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
dependencies = [
"nom",
]
[[package]]
name = "cfg-expr"
version = "0.15.8"
@@ -944,6 +981,17 @@ dependencies = [
"inout",
]
[[package]]
name = "clang-sys"
version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4"
dependencies = [
"glob",
"libc",
"libloading 0.8.5",
]
[[package]]
name = "clap"
version = "4.5.20"
@@ -975,7 +1023,7 @@ dependencies = [
"heck 0.5.0",
"proc-macro2",
"quote",
"syn 2.0.79",
"syn 2.0.85",
]
[[package]]
@@ -1294,6 +1342,27 @@ dependencies = [
"typenum",
]
[[package]]
name = "csv"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac574ff4d437a7b5ad237ef331c17ccca63c46479e5b5453eb8e10bb99a759fe"
dependencies = [
"csv-core",
"itoa",
"ryu",
"serde",
]
[[package]]
name = "csv-core"
version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5efa2b3d7902f4b634a20cae3c9c4e6209dc4779feb6863329607560143efa70"
dependencies = [
"memchr",
]
[[package]]
name = "ctr"
version = "0.9.2"
@@ -1325,8 +1394,18 @@ version = "0.14.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850"
dependencies = [
"darling_core",
"darling_macro",
"darling_core 0.14.4",
"darling_macro 0.14.4",
]
[[package]]
name = "darling"
version = "0.20.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989"
dependencies = [
"darling_core 0.20.10",
"darling_macro 0.20.10",
]
[[package]]
@@ -1343,17 +1422,42 @@ dependencies = [
"syn 1.0.109",
]
[[package]]
name = "darling_core"
version = "0.20.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5"
dependencies = [
"fnv",
"ident_case",
"proc-macro2",
"quote",
"strsim 0.11.1",
"syn 2.0.85",
]
[[package]]
name = "darling_macro"
version = "0.14.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e"
dependencies = [
"darling_core",
"darling_core 0.14.4",
"quote",
"syn 1.0.109",
]
[[package]]
name = "darling_macro"
version = "0.20.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806"
dependencies = [
"darling_core 0.20.10",
"quote",
"syn 2.0.85",
]
[[package]]
name = "dashmap"
version = "5.5.3"
@@ -1415,7 +1519,38 @@ checksum = "62d671cc41a825ebabc75757b62d3d168c577f9149b2d49ece1dad1f72119d25"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.79",
"syn 2.0.85",
]
[[package]]
name = "derive_builder"
version = "0.20.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "507dfb09ea8b7fa618fcf76e953f4f5e192547945816d5358edffe39f6f94947"
dependencies = [
"derive_builder_macro",
]
[[package]]
name = "derive_builder_core"
version = "0.20.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8"
dependencies = [
"darling 0.20.10",
"proc-macro2",
"quote",
"syn 2.0.85",
]
[[package]]
name = "derive_builder_macro"
version = "0.20.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c"
dependencies = [
"derive_builder_core",
"syn 2.0.85",
]
[[package]]
@@ -1436,7 +1571,7 @@ dependencies = [
"convert_case",
"proc-macro2",
"quote",
"syn 2.0.79",
"syn 2.0.85",
"unicode-xid",
]
@@ -1496,7 +1631,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.79",
"syn 2.0.85",
]
[[package]]
@@ -1717,7 +1852,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.79",
"syn 2.0.85",
]
[[package]]
@@ -1812,7 +1947,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.79",
"syn 2.0.85",
]
[[package]]
@@ -2028,7 +2163,7 @@ dependencies = [
"proc-macro-error",
"proc-macro2",
"quote",
"syn 2.0.79",
"syn 2.0.85",
]
[[package]]
@@ -2041,6 +2176,12 @@ dependencies = [
"system-deps",
]
[[package]]
name = "glob"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
[[package]]
name = "globset"
version = "0.4.15"
@@ -2325,7 +2466,7 @@ dependencies = [
"proc-macro-error",
"proc-macro2",
"quote",
"syn 2.0.79",
"syn 2.0.85",
]
[[package]]
@@ -2338,6 +2479,12 @@ dependencies = [
"crunchy",
]
[[package]]
name = "hash-ids"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e637affe86ae6203fb90b3802aa235f00910799b60fbead4d770c42d3495a3af"
[[package]]
name = "hashbrown"
version = "0.13.2"
@@ -2728,7 +2875,7 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.79",
"syn 2.0.85",
]
[[package]]
@@ -2850,7 +2997,7 @@ checksum = "c34819042dc3d3971c46c2190835914dfbe0c3c13f61449b2997f4e9722dfa60"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.79",
"syn 2.0.85",
]
[[package]]
@@ -3018,6 +3165,12 @@ dependencies = [
"spin",
]
[[package]]
name = "lazycell"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
[[package]]
name = "lebe"
version = "0.5.2"
@@ -3125,7 +3278,7 @@ dependencies = [
"quote",
"rstml",
"serde",
"syn 2.0.79",
"syn 2.0.85",
"walkdir",
]
@@ -3161,7 +3314,7 @@ dependencies = [
"quote",
"rstml",
"server_fn_macro",
"syn 2.0.79",
"syn 2.0.85",
"tracing",
"uuid",
]
@@ -3485,7 +3638,7 @@ dependencies = [
"manyhow-macros",
"proc-macro2",
"quote",
"syn 2.0.79",
"syn 2.0.85",
]
[[package]]
@@ -3657,7 +3810,7 @@ dependencies = [
"jni-sys",
"log",
"ndk-sys",
"num_enum",
"num_enum 0.7.3",
"raw-window-handle",
"thiserror",
]
@@ -3768,7 +3921,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.79",
"syn 2.0.85",
]
[[package]]
@@ -3812,13 +3965,34 @@ dependencies = [
"libm",
]
[[package]]
name = "num_enum"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a015b430d3c108a207fd776d2e2196aaf8b1cf8cf93253e3a097ff3085076a1"
dependencies = [
"num_enum_derive 0.6.1",
]
[[package]]
name = "num_enum"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179"
dependencies = [
"num_enum_derive",
"num_enum_derive 0.7.3",
]
[[package]]
name = "num_enum_derive"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96667db765a921f7b295ffee8b60472b686a51d4f21c2ee4ffdb94c7013b65a6"
dependencies = [
"proc-macro-crate 1.3.1",
"proc-macro2",
"quote",
"syn 2.0.85",
]
[[package]]
@@ -3830,7 +4004,7 @@ dependencies = [
"proc-macro-crate 3.2.0",
"proc-macro2",
"quote",
"syn 2.0.79",
"syn 2.0.85",
]
[[package]]
@@ -4178,6 +4352,17 @@ dependencies = [
"windows-targets 0.52.6",
]
[[package]]
name = "parser"
version = "0.1.0"
dependencies = [
"anyhow",
"csv",
"ctrlc",
"serde",
"simconnect-sdk",
]
[[package]]
name = "password-hash"
version = "0.5.0"
@@ -4201,6 +4386,12 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd"
[[package]]
name = "peeking_take_while"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
[[package]]
name = "pem"
version = "3.0.4"
@@ -4257,7 +4448,7 @@ dependencies = [
"pest_meta",
"proc-macro2",
"quote",
"syn 2.0.79",
"syn 2.0.85",
]
[[package]]
@@ -4288,7 +4479,7 @@ checksum = "a4502d8515ca9f32f1fb543d987f63d95a14934883db45bdb48060b6b69257f8"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.79",
"syn 2.0.85",
]
[[package]]
@@ -4392,7 +4583,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "479cf940fbbb3426c32c5d5176f62ad57549a0bb84773423ba8be9d089f5faba"
dependencies = [
"proc-macro2",
"syn 2.0.79",
"syn 2.0.85",
]
[[package]]
@@ -4507,7 +4698,7 @@ checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.79",
"syn 2.0.85",
"version_check",
"yansi",
]
@@ -4528,7 +4719,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a65f2e60fbf1063868558d69c6beacf412dc755f9fc020f514b7955fc914fe30"
dependencies = [
"quote",
"syn 2.0.79",
"syn 2.0.85",
]
[[package]]
@@ -4649,7 +4840,7 @@ dependencies = [
"proc-macro-utils 0.10.0",
"proc-macro2",
"quote",
"syn 2.0.79",
"syn 2.0.85",
]
[[package]]
@@ -4949,7 +5140,7 @@ dependencies = [
"proc-macro2",
"proc-macro2-diagnostics",
"quote",
"syn 2.0.79",
"syn 2.0.85",
"syn_derive",
"thiserror",
]
@@ -5114,9 +5305,9 @@ dependencies = [
[[package]]
name = "serde"
version = "1.0.210"
version = "1.0.213"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a"
checksum = "3ea7893ff5e2466df8d720bb615088341b295f849602c6956047f8f80f0e9bc1"
dependencies = [
"serde_derive",
]
@@ -5145,13 +5336,13 @@ dependencies = [
[[package]]
name = "serde_derive"
version = "1.0.210"
version = "1.0.213"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f"
checksum = "7e85ad2009c50b58e87caa8cd6dac16bdf511bbfb7af6c33df902396aa480fa5"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.79",
"syn 2.0.85",
]
[[package]]
@@ -5273,7 +5464,7 @@ dependencies = [
"convert_case",
"proc-macro2",
"quote",
"syn 2.0.79",
"syn 2.0.85",
"xxhash-rust",
]
@@ -5284,7 +5475,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f2aa8119b558a17992e0ac1fd07f080099564f24532858811ce04f742542440"
dependencies = [
"server_fn_macro",
"syn 2.0.79",
"syn 2.0.85",
]
[[package]]
@@ -5356,6 +5547,27 @@ dependencies = [
"rand_core",
]
[[package]]
name = "simconnect-sdk"
version = "0.2.2"
dependencies = [
"bindgen",
"num_enum 0.6.1",
"simconnect-sdk-derive",
"thiserror",
"tracing",
]
[[package]]
name = "simconnect-sdk-derive"
version = "0.2.2"
dependencies = [
"once_cell",
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]]
name = "simd-adler32"
version = "0.3.7"
@@ -5474,6 +5686,18 @@ dependencies = [
"der",
]
[[package]]
name = "sqids"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f328f10ae594f0da04e5b2f82c089232697312661bca22d5d015a680c84639d"
dependencies = [
"derive_builder",
"serde",
"serde_json",
"thiserror",
]
[[package]]
name = "sqlformat"
version = "0.2.6"
@@ -5551,7 +5775,7 @@ dependencies = [
"quote",
"sqlx-core",
"sqlx-macros-core",
"syn 2.0.79",
"syn 2.0.85",
]
[[package]]
@@ -5574,7 +5798,7 @@ dependencies = [
"sqlx-mysql",
"sqlx-postgres",
"sqlx-sqlite",
"syn 2.0.79",
"syn 2.0.85",
"tempfile",
"tokio",
"url",
@@ -5756,9 +5980,9 @@ dependencies = [
[[package]]
name = "syn"
version = "2.0.79"
version = "2.0.85"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590"
checksum = "5023162dfcd14ef8f32034d8bcd4cc5ddc61ef7a247c024a33e24e1f24d21b56"
dependencies = [
"proc-macro2",
"quote",
@@ -5774,7 +5998,7 @@ dependencies = [
"proc-macro-error",
"proc-macro2",
"quote",
"syn 2.0.79",
"syn 2.0.85",
]
[[package]]
@@ -5800,7 +6024,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.79",
"syn 2.0.85",
]
[[package]]
@@ -5880,7 +6104,7 @@ checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.79",
"syn 2.0.85",
]
[[package]]
@@ -6020,7 +6244,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.79",
"syn 2.0.85",
]
[[package]]
@@ -6220,7 +6444,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.79",
"syn 2.0.85",
]
[[package]]
@@ -6343,7 +6567,7 @@ checksum = "1f718dfaf347dcb5b983bfc87608144b0bad87970aebcbea5ce44d2a30c08e63"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.79",
"syn 2.0.85",
]
[[package]]
@@ -6633,7 +6857,7 @@ dependencies = [
"once_cell",
"proc-macro2",
"quote",
"syn 2.0.79",
"syn 2.0.85",
"wasm-bindgen-shared",
]
@@ -6667,7 +6891,7 @@ checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.79",
"syn 2.0.85",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
@@ -6835,6 +7059,18 @@ version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53a85b86a771b1c87058196170769dd264f66c0782acf1ae6cc51bfd64b39082"
[[package]]
name = "which"
version = "4.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7"
dependencies = [
"either",
"home",
"once_cell",
"rustix",
]
[[package]]
name = "whoami"
version = "1.5.2"
@@ -6932,7 +7168,7 @@ checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.79",
"syn 2.0.85",
]
[[package]]
@@ -6943,7 +7179,7 @@ checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.79",
"syn 2.0.85",
]
[[package]]
@@ -7419,7 +7655,7 @@ checksum = "28cc31741b18cb6f1d5ff12f5b7523e3d6eb0852bbbad19d73905511d9849b95"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.79",
"syn 2.0.85",
"synstructure",
]
@@ -7441,7 +7677,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.79",
"syn 2.0.85",
]
[[package]]
@@ -7461,7 +7697,7 @@ checksum = "0ea7b4a3637ea8669cedf0f1fd5c286a17f3de97b8dd5a70a6c167a1730e63a5"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.79",
"syn 2.0.85",
"synstructure",
]
@@ -7490,7 +7726,7 @@ checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.79",
"syn 2.0.85",
]
[[package]]

View File

@@ -1,5 +1,5 @@
[workspace]
members = [".", "avam-client", "avam-protocol", "avam-wasm"]
members = [".", "avam-client", "avam-protocol", "avam-wasm", "parser"]
resolver = "2"
[package]
@@ -31,6 +31,7 @@ ssr = [
"dep:avam-protocol",
"dep:argon2",
"dep:dashmap",
"dep:axum",
"dep:axum-extra",
@@ -67,6 +68,7 @@ avam-protocol = { path = "./avam-protocol", optional = true }
anyhow = { version = "1.0.89", optional = false }
argon2 = { version = "0.5.3", optional = true }
derive_more = { version = "1.0.0", features = ["full"], optional = false }
dashmap = { version = "6.1.0", optional = true }
dotenvy = { version = "0.15.7", optional = true }
futures = { version = "0.3.31", optional = true }
rand = { version = "0.8.5", optional = true }
@@ -127,6 +129,8 @@ base64 = { version = "0.22.1", default-features = false }
jsonwebtoken = { version = "9.3.0", optional = true }
serde_qs = "0.13.0"
sha256 = { version = "1.5.0", optional = true } # this fucker has a dependency on tokio?!
sqids = "0.4.1"
hash-ids = "0.3.1"
[[workspace.metadata.leptos]]
name = "avam"

BIN
SimConnect.dll Normal file

Binary file not shown.

View File

@@ -4,8 +4,8 @@ version = "0.1.0"
edition = "2021"
[dependencies]
avam-protocol = { path = "../avam-protocol" }
anyhow = { version = "1.0" }
avam-protocol = { path = "../avam-protocol" }
base64 = { version = "0.22.1", default-features = false }
clap = { version = "4.5.20", features = ["derive"] }
config = "0.14.0"
@@ -28,6 +28,9 @@ reqwest = { version = "0.12.8", default-features = false, features = [
serde = { version = "1", features = ["derive"] }
serde_qs = "0.13.0"
sha256 = "1.5.0"
simconnect-sdk = { path = "D:/source/MSFS/simconnect-sdk-rs/simconnect-sdk", features = [
"derive",
] }
tauri-winrt-notification = "0.6.0"
thiserror = { version = "1.0" }
time = "0.3.36"
@@ -37,7 +40,7 @@ tokio-tungstenite = { version = "0.24.0", features = [
] }
toml = "0.8"
tracing = "0.1.40"
tracing-subscriber = { version = "0.3.18", features = ["time"] }
tracing-subscriber = { version = "0.3.18", features = ["time", "fmt", "std"] }
tray-icon = "0.19"
uuid = { version = "1.10.0", features = ["fast-rng", "serde", "v4"] }
winit = "0.30"

View File

@@ -1,5 +1,27 @@
use windres::Build;
fn main() {
Build::new().compile("icon.rc").unwrap();
fn main() -> std::io::Result<()> {
println!("cargo:rerun-if-changed=build.rs");
let target_os = std::env::var("CARGO_CFG_TARGET_OS");
if target_os.as_deref() == Ok("windows") {
let name = "Avii's Virtual Airline Manager";
let version = env!("CARGO_PKG_VERSION");
let mut sv = version.split('.').collect::<Vec<_>>();
while sv.len() < 4 {
sv.push("0");
}
let file_version = format!("{}, {}, {}, {}", sv[0], sv[1], sv[2], sv[3]);
windres::Build::new()
.define(
"THE_FILE",
Some(format!(r#""{name} Client Module""#).as_str()),
)
.define("THE_PROJECT", Some(format!(r#""{name}""#).as_str()))
.define("THE_VERSION", Some(format!(r#""{version}""#).as_str()))
.define("THE_FILEVERSION", Some(file_version.as_str()))
.compile("res/resource.rc")?;
for entry in std::fs::read_dir("res")? {
let entry = entry?;
println!("cargo:rerun-if-changed={}", entry.path().display());
}
}
Ok(())
}

View File

@@ -1 +0,0 @@
1 ICON "icon.ico"

View File

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -0,0 +1,28 @@
#pragma code_page(65001)
1 VERSIONINFO
FILEVERSION THE_FILEVERSION
PRODUCTVERSION THE_FILEVERSION
FILEFLAGSMASK 0x0000003Fl //VS_FFI_FILEFLAGSMASK
FILEFLAGS 0x0
FILEOS 0x00040004l //VOS_NT_WINDOWS32
FILETYPE 0x00000001l //VFT_APP
FILESUBTYPE 0x00000000l //VFT2_UNKNOWN
{
BLOCK "StringFileInfo"
{
BLOCK "040904B0"
{
VALUE "FileDescription", THE_FILE
VALUE "FileVersion", THE_VERSION
VALUE "ProductVersion", THE_VERSION
VALUE "ProductName", THE_PROJECT
}
}
BLOCK "VarFileInfo"
{
VALUE "Translation", 0x409, 0x4B0
}
}
1 ICON "res/icon.ico"

View File

@@ -86,7 +86,7 @@ pub async fn start(
Message::Binary(encoded_message)
}
d => {
tracing::info!("sending packet: {:?}", &d);
// tracing::info!("sending packet: {:#?}", &d);
let Ok(encoded_message) = d.encode() else {
tracing::error!(
"Unable to encode message for sending: {:#?}",

View File

@@ -262,13 +262,15 @@ fn init_logging() -> Result<(), anyhow::Error> {
#[cfg(not(debug_assertions))]
let file = File::options().append(true).open(&log_file)?;
let fmt = tracing_subscriber::fmt::layer().with_filter(tracing_subscriber::filter::filter_fn(
|metadata| metadata.level() < &Level::TRACE,
));
let fmt = tracing_subscriber::fmt::layer();
#[cfg(not(debug_assertions))]
let fmt = fmt.with_ansi(false).with_writer(Arc::new(file));
let fmt = fmt.with_filter(tracing_subscriber::filter::filter_fn(|metadata| {
metadata.level() < &Level::TRACE
}));
tracing_subscriber::registry().with(fmt).init();
Ok(())

View File

@@ -194,34 +194,6 @@ impl AuthorizeRequest {
scope,
}
}
// pub fn client_id(&self) -> uuid::Uuid {
// self.client_id
// }
// pub fn response_type(&self) -> ResponseType {
// self.response_type.clone()
// }
// pub fn state(&self) -> Option<String> {
// self.state.clone()
// }
// pub fn code_challenge(&self) -> String {
// self.code_challenge.clone()
// }
// pub fn code_challenge_method(&self) -> Option<CodeChallengeMethod> {
// self.code_challenge_method.clone()
// }
// pub fn redirect_uri(&self) -> String {
// self.redirect_uri.clone()
// }
// pub fn scope(&self) -> Option<String> {
// self.scope.clone()
// }
}
#[derive(Clone, Debug, Serialize, Deserialize)]

View File

@@ -1,18 +1,210 @@
use std::time::Duration;
mod models;
use avam_protocol::SimConnectPacket;
use core::ops::ControlFlow;
use models::*;
use simconnect_sdk::{Notification, Object, SimConnect as SC, SystemEvent, SystemEventRequest};
use std::{sync::Arc, time::Duration};
use tokio::{
sync::broadcast::{Receiver, Sender},
sync::{
broadcast::{Receiver, Sender},
RwLock,
},
time::sleep,
};
use crate::state_machine::Event;
pub struct SimState {
atc_id: String,
// gps location
// fuel state
// cargo state
// is landed
// is stopped
// etc
// basically, all the data we wanna send to socket
// we also need to know if we're in a flight here, and what flight,
// mission parameters etc maybe
// unless we just wanna keep that purely serverside..
// and only process incoming packets if there is an activem mission.
// the thing i _dont_ want, is to be invasive with alerts and notifications
// that the user is "forgetting" to start a flight etc with AVAM running
// basically, avam should be able to be running always without the user noticing
// any interaction is done via the dashboard
// starting, stopping, status etc
// eventually even with "realistic" flightplans, from time of takeoff, estimate time of arrival,
// and even have time-critical jobs that need to get finished before a set time
}
impl Default for SimState {
fn default() -> Self {
Self {
atc_id: String::from("AVAM"),
}
}
}
pub struct SimConnect {
simconnect_receiver: Receiver<SimConnectPacket>, // Data from the socket
socket_sender: Sender<SimConnectPacket>, // Data to the socket
sender: Sender<Event>,
receiver: Receiver<Event>,
state: Arc<RwLock<SimState>>,
}
impl SimConnect {
async fn open(&self, client: &mut SC) -> Result<(), anyhow::Error> {
client.subscribe_to_system_event(SystemEventRequest::AircraftLoaded)?;
client.subscribe_to_system_event(SystemEventRequest::SimStart)?;
let id = client.register_object::<AtcID>()?;
client.register_object::<Airplane>()?;
client.register_object::<Fuel>()?;
client.register_object::<Gps>()?;
client.register_object::<OnGround>()?;
client.register_object::<IsParked>()?;
let value = self.state.read().await.atc_id.clone();
tracing::info!("Updating ATC_ID: {}", &value);
client.set_data_on_sim_object_with_id(id, &mut atc_id(&value)?)?;
let _ = self.sender.send(Event::SimConnected);
Ok(())
}
async fn object(&self, _: &mut SC, object: &Object) -> Result<(), anyhow::Error> {
if let Ok(data) = Airplane::try_from(object) {
self.socket_sender
.send(SimConnectPacket::Airplane(avam_protocol::Airplane {
atc_type: data.atc_type,
atc_model: data.atc_model,
title: data.title,
category: data.category,
}))?;
// We've already got our data, there's no point in trying another in this iteration
return Ok(());
}
if let Ok(data) = Fuel::try_from(object) {
self.socket_sender
.send(SimConnectPacket::Fuel(avam_protocol::Fuel {
weight: data.weight,
center_quantity: data.center_quantity,
center_capacity: data.center_capacity,
center2_quantity: data.center2_quantity,
center2_capacity: data.center2_capacity,
center3_quantity: data.center3_quantity,
center3_capacity: data.center3_capacity,
left_main_quantity: data.left_main_quantity,
left_main_capacity: data.left_main_capacity,
left_aux_quantity: data.left_aux_quantity,
left_aux_capacity: data.left_aux_capacity,
left_tip_quantity: data.left_tip_quantity,
left_tip_capacity: data.left_tip_capacity,
right_main_quantity: data.right_main_quantity,
right_main_capacity: data.right_main_capacity,
right_aux_quantity: data.right_aux_quantity,
right_aux_capacity: data.right_aux_capacity,
right_tip_quantity: data.right_tip_quantity,
right_tip_capacity: data.right_tip_capacity,
external1_quantity: data.external1_quantity,
external1_capacity: data.external1_capacity,
external2_quantity: data.external2_quantity,
external2_capacity: data.external2_capacity,
}))?;
// We've already got our data, there's no point in trying another in this iteration
return Ok(());
}
if let Ok(data) = Gps::try_from(object) {
self.socket_sender
.send(SimConnectPacket::Gps(avam_protocol::Gps {
lat: data.lat,
lon: data.lon,
alt: data.alt,
}))?;
// We've already got our data, there's no point in trying another in this iteration
return Ok(());
}
if let Ok(data) = OnGround::try_from(object) {
self.socket_sender
.send(SimConnectPacket::OnGround(avam_protocol::OnGround {
sim_on_ground: data.sim_on_ground,
}))?;
// We've already got our data, there's no point in trying another in this iteration
return Ok(());
}
// Change to parking break state or something, unless we're a helicopter, then we dont have one
if let Ok(data) = IsParked::try_from(object) {
self.socket_sender
.send(SimConnectPacket::IsParked(avam_protocol::IsParked {
is_parked: data.is_parked,
}))?;
// We've already got our data, there's no point in trying another in this iteration
return Ok(());
}
Ok(())
}
async fn system_event(
&self,
client: &mut SC,
event: &SystemEvent,
) -> Result<(), anyhow::Error> {
match event {
SystemEvent::AircraftLoaded { .. } => {
tracing::info!("Aircraft Loaded!");
let id = client.get_object_id::<AtcID>()?;
let value = self.state.read().await.atc_id.clone();
tracing::info!("Updating ATC_ID: {}", &value);
for _ in 1..=10 {
client.set_data_on_sim_object_with_id(id, &mut atc_id(&value)?)?;
sleep(Duration::from_millis(50)).await;
}
}
SystemEvent::SimStart => {
tracing::info!("Sim Start");
}
// SystemEvent::OneSecond => todo!(),
// SystemEvent::FourSeconds => todo!(),
// SystemEvent::SixTimesPerSecond => todo!(),
// SystemEvent::AircraftLoaded { file_name } => todo!(),
// SystemEvent::Crashed => todo!(),
// SystemEvent::CrashReset => todo!(),
// SystemEvent::FlightSaved { file_name } => todo!(),
// SystemEvent::FlightPlanActivated { file_name } => todo!(),
// SystemEvent::FlightPlanDeactivated => todo!(),
// SystemEvent::Frame {
// frame_rate,
// sim_speed,
// } => todo!(),
// SystemEvent::Pause { state } => todo!(),
// SystemEvent::Paused => todo!(),
// SystemEvent::PauseFrame {
// frame_rate,
// sim_speed,
// } => todo!(),
// SystemEvent::PositionChanged => todo!(),
// SystemEvent::Sim { state } => todo!(),
// SystemEvent::SimStart => todo!(),
// SystemEvent::SimStop => todo!(),
// SystemEvent::Sound { state } => todo!(),
// SystemEvent::Unpaused => todo!(),
// SystemEvent::View { view } => todo!(),
_ => todo!(),
}
Ok(())
}
}
impl SimConnect {
@@ -27,23 +219,83 @@ impl SimConnect {
socket_sender,
sender,
receiver,
state: Default::default(),
}
}
pub async fn run(&self) -> Result<(), anyhow::Error> {
let mut receiver = self.receiver.resubscribe();
let mut simconnect_receiver = self.simconnect_receiver.resubscribe();
let state = self.state.clone();
let mut sc: Option<SC> = None;
loop {
if let Ok(Event::Quit) = receiver.try_recv() {
break;
}
// handle simconnect stuff here
if let Ok(packet) = simconnect_receiver.try_recv() {
match packet {
SimConnectPacket::AtcID(value) => {
state.write().await.atc_id = value.clone();
if let Some(client) = sc.as_mut() {
if let Ok(id) = client.get_object_id::<AtcID>() {
tracing::info!("Updating ATC_ID: {}", &value);
client.set_data_on_sim_object_with_id(id, &mut atc_id(&value)?)?;
}
}
}
SimConnectPacket::Fuel(_) => unreachable!(), // Outgoing packet, not handled here (yet) we probably need to set fuel state somehow
SimConnectPacket::Airplane(_) => unreachable!(),
SimConnectPacket::Gps(_) => unreachable!(), // Outgoing packet, not handled here (yet) we probably need to set position somehow
SimConnectPacket::OnGround(_) => unreachable!(), // Outgoing packet, not handled here
SimConnectPacket::IsParked(_) => unreachable!(), // Outgoing packet, not handled here
}
}
if sc.is_none() {
if let Ok(simconnect) = SC::new("Avii's Virtual Airline Manager") {
sc = Some(simconnect);
tracing::info!("Connected");
}
}
if let Some(client) = sc.as_mut() {
if self.handle(client).await.is_break() {
tracing::info!("Disconnected");
sc = None;
}
}
sleep(Duration::from_millis(100)).await;
}
Ok(())
}
async fn handle(&self, client: &mut SC) -> ControlFlow<(), ()> {
if let Ok(Some(event)) = client.get_next_dispatch() {
if let Err(e) = match event {
Notification::Open => self.open(client).await,
Notification::Object(ref object) => self.object(client, object).await,
Notification::SystemEvent(ref system_event) => {
self.system_event(client, system_event).await
}
// Notification::ClientEvent(ref client_event) => todo!(),
// Notification::AirportList(ref vec) => todo!(),
// Notification::WaypointList(ref vec) => todo!(),
// Notification::NdbList(ref vec) => todo!(),
// Notification::VorList(ref vec) => todo!(),
Notification::Quit => {
let _ = self.sender.send(Event::SimDisconnected);
return ControlFlow::Break(());
}
_ => todo!(),
} {
tracing::error!("Error handling SimConnect::Notification: {:#?}", e);
};
}
ControlFlow::Continue(())
}
}
pub async fn start(

View File

@@ -0,0 +1,123 @@
use std::ffi::CString;
use simconnect_sdk::SimConnectObject;
#[allow(unused)]
#[derive(Debug, Clone, SimConnectObject)]
#[simconnect(period = "second", condition = "changed")]
pub(super) struct AtcID {
#[simconnect(name = "ATC ID")]
pub value: String,
}
pub(super) fn atc_id(value: &str) -> Result<AtcIDCPacked, anyhow::Error> {
if value.len() > 10 {
return Err(anyhow::anyhow!("ATC_ID exceeding 10 characters"));
}
let cs = CString::new(value.to_uppercase())?;
let mut buffer = [0i8; 256];
for (i, b) in cs.to_bytes_with_nul().iter().enumerate() {
buffer[i] = *b as i8;
}
Ok(AtcIDCPacked { value: buffer })
}
#[derive(Debug, Clone, SimConnectObject)]
#[simconnect(period = "second", condition = "changed")]
pub(super) struct Airplane {
#[simconnect(name = "ATC TYPE")]
pub atc_type: String,
#[simconnect(name = "ATC MODEL")]
pub atc_model: String,
#[simconnect(name = "TITLE")]
pub title: String,
#[simconnect(name = "CATEGORY")]
pub category: String,
}
#[derive(Debug, Clone, SimConnectObject)]
#[simconnect(period = "second", condition = "changed")]
pub(super) struct Fuel {
#[simconnect(name = "FUEL TANK CENTER QUANTITY", unit = "gallons")]
pub center_quantity: f64,
#[simconnect(name = "FUEL TANK CENTER CAPACITY", unit = "gallons")]
pub center_capacity: f64,
#[simconnect(name = "FUEL TANK CENTER2 QUANTITY", unit = "gallons")]
pub center2_quantity: f64,
#[simconnect(name = "FUEL TANK CENTER2 CAPACITY", unit = "gallons")]
pub center2_capacity: f64,
#[simconnect(name = "FUEL TANK CENTER3 QUANTITY", unit = "gallons")]
pub center3_quantity: f64,
#[simconnect(name = "FUEL TANK CENTER3 CAPACITY", unit = "gallons")]
pub center3_capacity: f64,
#[simconnect(name = "FUEL TANK LEFT MAIN QUANTITY", unit = "gallons")]
pub left_main_quantity: f64,
#[simconnect(name = "FUEL TANK LEFT MAIN CAPACITY", unit = "gallons")]
pub left_main_capacity: f64,
#[simconnect(name = "FUEL TANK LEFT AUX QUANTITY", unit = "gallons")]
pub left_aux_quantity: f64,
#[simconnect(name = "FUEL TANK LEFT AUX CAPACITY", unit = "gallons")]
pub left_aux_capacity: f64,
#[simconnect(name = "FUEL TANK LEFT TIP QUANTITY", unit = "gallons")]
pub left_tip_quantity: f64,
#[simconnect(name = "FUEL TANK LEFT TIP CAPACITY", unit = "gallons")]
pub left_tip_capacity: f64,
#[simconnect(name = "FUEL TANK RIGHT MAIN QUANTITY", unit = "gallons")]
pub right_main_quantity: f64,
#[simconnect(name = "FUEL TANK RIGHT MAIN CAPACITY", unit = "gallons")]
pub right_main_capacity: f64,
#[simconnect(name = "FUEL TANK RIGHT AUX QUANTITY", unit = "gallons")]
pub right_aux_quantity: f64,
#[simconnect(name = "FUEL TANK RIGHT AUX CAPACITY", unit = "gallons")]
pub right_aux_capacity: f64,
#[simconnect(name = "FUEL TANK RIGHT TIP QUANTITY", unit = "gallons")]
pub right_tip_quantity: f64,
#[simconnect(name = "FUEL TANK RIGHT TIP CAPACITY", unit = "gallons")]
pub right_tip_capacity: f64,
#[simconnect(name = "FUEL TANK EXTERNAL1 QUANTITY", unit = "gallons")]
pub external1_quantity: f64,
#[simconnect(name = "FUEL TANK EXTERNAL1 CAPACITY", unit = "gallons")]
pub external1_capacity: f64,
#[simconnect(name = "FUEL TANK EXTERNAL2 QUANTITY", unit = "gallons")]
pub external2_quantity: f64,
#[simconnect(name = "FUEL TANK EXTERNAL2 CAPACITY", unit = "gallons")]
pub external2_capacity: f64,
#[simconnect(name = "FUEL WEIGHT PER GALLON", unit = "pounds")]
pub weight: f64,
}
#[derive(Debug, Clone, SimConnectObject)]
#[simconnect(period = "second", condition = "changed")]
pub(super) struct Gps {
#[simconnect(name = "PLANE LATITUDE", unit = "degrees")]
pub lat: f64,
#[simconnect(name = "PLANE LONGITUDE", unit = "degrees")]
pub lon: f64,
#[simconnect(name = "PLANE ALTITUDE", unit = "feet")]
pub alt: f64,
}
#[derive(Debug, Clone, SimConnectObject)]
#[simconnect(period = "second", condition = "changed")]
pub(super) struct OnGround {
#[simconnect(name = "SIM ON GROUND")]
pub sim_on_ground: bool,
}
#[derive(Debug, Clone, SimConnectObject)]
#[simconnect(period = "second", condition = "changed")]
pub(super) struct IsParked {
#[simconnect(name = "PLANE IN PARKING STATE")]
pub is_parked: bool,
}

View File

@@ -6,6 +6,7 @@ edition = "2021"
[dependencies]
anyhow = "1.0.90"
bincode = "1.3.3"
derive_more = "1.0.0"
flate2 = { version = "1.0.34", features = ["zlib-rs"] }
serde = { version = "1.0.210", features = ["derive"] }
thiserror = "1.0.64"

View File

@@ -1,18 +1,153 @@
use derive_more::derive::Display;
use serde::{de, Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
#[derive(Debug, Display, Clone, PartialEq, Eq, Deserialize, Serialize)]
pub enum SystemPacket {
Ping,
Pong,
Close { reason: String },
}
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
#[derive(Debug, Display, Clone, Deserialize, Serialize)]
pub enum SimConnectPacket {
// ..
AtcID(String),
Airplane(Airplane),
Fuel(Fuel),
Gps(Gps),
OnGround(OnGround),
IsParked(IsParked),
}
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
#[derive(Debug, Clone, Display, Deserialize, Serialize)]
#[display("[{atc_type} - {atc_model}] {title} ({category})")]
pub struct Airplane {
pub atc_type: String,
pub atc_model: String,
pub title: String,
pub category: String,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct Fuel {
pub center_quantity: f64,
pub center_capacity: f64,
pub center2_quantity: f64,
pub center2_capacity: f64,
pub center3_quantity: f64,
pub center3_capacity: f64,
pub left_main_quantity: f64,
pub left_main_capacity: f64,
pub left_aux_quantity: f64,
pub left_aux_capacity: f64,
pub left_tip_quantity: f64,
pub left_tip_capacity: f64,
pub right_main_quantity: f64,
pub right_main_capacity: f64,
pub right_aux_quantity: f64,
pub right_aux_capacity: f64,
pub right_tip_quantity: f64,
pub right_tip_capacity: f64,
pub external1_quantity: f64,
pub external1_capacity: f64,
pub external2_quantity: f64,
pub external2_capacity: f64,
pub weight: f64,
}
impl Fuel {
pub fn total_quantity(&self) -> f64 {
self.center_quantity
+ self.center2_quantity
+ self.center3_quantity
+ self.left_main_quantity
+ self.left_aux_quantity
+ self.left_tip_quantity
+ self.right_main_quantity
+ self.right_aux_quantity
+ self.right_tip_quantity
+ self.external1_quantity
+ self.external2_quantity
}
pub fn total_capacity(&self) -> f64 {
self.center_capacity
+ self.center2_capacity
+ self.center3_capacity
+ self.left_main_capacity
+ self.left_aux_capacity
+ self.left_tip_capacity
+ self.right_main_capacity
+ self.right_aux_capacity
+ self.right_tip_capacity
+ self.external1_capacity
+ self.external2_capacity
}
}
impl core::fmt::Display for Fuel {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let percent = (100.0 / self.total_capacity()) * self.total_quantity();
write!(
f,
"{}GL/{}GL ({}%)",
self.total_quantity(),
self.total_capacity(),
percent
)
}
}
#[derive(Debug, Clone, Display, Deserialize, Serialize)]
#[display("{lat}, {lon} at {alt}ft")]
pub struct Gps {
pub lat: f64,
pub lon: f64,
pub alt: f64,
}
#[derive(Debug, Clone, Display, Deserialize, Serialize)]
pub struct OnGround {
pub sim_on_ground: bool,
}
#[derive(Debug, Clone, Display, Deserialize, Serialize)]
pub struct IsParked {
pub is_parked: bool,
}
// #[derive(Debug, Display, Clone, Deserialize, Serialize)]
// #[display("[{icao}] {lat} {lon} {alt}")]
// pub struct Airport {
// pub icao: String,
// pub region: String,
// pub lat: f64,
// pub lon: f64,
// pub alt: f64,
// }
impl PartialEq for SimConnectPacket {
fn eq(&self, other: &Self) -> bool {
matches!(
(self, other),
(Self::AtcID(_), Self::AtcID(_)) | (Self::Fuel(_), Self::Fuel(_))
)
}
}
impl Eq for SimConnectPacket {}
#[derive(Debug, Display, Clone, PartialEq, Eq, Deserialize, Serialize)]
pub enum Packets {
System(SystemPacket),
SimConnect(SimConnectPacket),

View File

@@ -0,0 +1,2 @@
-- Add down migration script here
DROP TABLE "airports";

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,3 @@
-- Add down migration script here
DROP TABLE "ower_history";
DROP TABLE "aircrafts";

View File

@@ -0,0 +1,66 @@
-- Add up migration script here
CREATE TABLE "aircrafts" (
"id" uuid NOT NULL,
"registration" text NOT NULL,
"category" text NOT NULL,
"manufacturer" text NOT NULL,
"model" text NOT NULL,
"on_ground" boolean NOT NULL DEFAULT 1,
"created_at" timestamp DEFAULT CURRENT_TIMESTAMP,
"updated_at" timestamp DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "aircrafts_pkey" PRIMARY KEY ("id"),
CONSTRAINT "aircrafts_registration_unique" UNIQUE ("registration")
) WITH (oids = false);
CREATE TABLE "gps" (
"aircraft_id" uuid NOT NULL,
"latitude_deg" numeric NOT NULL,
"longitude_deg" numeric NOT NULL,
"elevation_ft" numeric NOT NULL,
"created_at" timestamp DEFAULT CURRENT_TIMESTAMP,
"updated_at" timestamp DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "gps_pkey" PRIMARY KEY ("aircraft_id")
)
CREATE TABLE "fuel" (
"aircraft_id" uuid NOT NULL,
"center_quantity" numeric,
"center_capacity" numeric,
"center2_quantity" numeric,
"center2_capacity" numeric,
"center3_quantity" numeric,
"center3_capacity" numeric,
"left_main_quantity" numeric,
"left_main_capacity" numeric,
"left_aux_quantity" numeric,
"left_aux_capacity" numeric,
"left_tip_quantity" numeric,
"left_tip_capacity" numeric,
"right_main_quantity" numeric,
"right_main_capacity" numeric,
"right_aux_quantity" numeric,
"right_aux_capacity" numeric,
"right_tip_quantity" numeric,
"right_tip_capacity" numeric,
"external1_quantity" numeric,
"external1_capacity" numeric,
"external2_quantity" numeric,
"external2_capacity" numeric,
"fuel_weight" numeric,
"created_at" timestamp DEFAULT CURRENT_TIMESTAMP,
"updated_at" timestamp DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "fuel_pkey" PRIMARY KEY ("aircraft_id")
)
-- If a player is in an aircraft that doesnt exist on our end, ask them to "purchace" it from the factory
-- What's the pricing going to look like though... hmm
-- If a pilot buys a new aircraft they need to get in it at least once to get all the fuel-cell data, we don't know beforehand how many tanks it has
-- after updating, the capacity should be > 0 to indicate which ones are used

View File

@@ -0,0 +1,2 @@
-- Add down migration script here
DROP TABLE "pilots";

View File

@@ -0,0 +1,25 @@
-- Add up migration script here
CREATE TABLE "pilots" (
"id" uuid NOT NULL, -- use the random-person-generator's id?
"user_id" uuid NOT NULL,
"full_name" text NOT NULL,
"date_of_birth" timestamp NOT NULL,
"gender" text NOT NULL,
"nationality" text NOT NULL,
"photo" text NOT NULL, -- base64 encoded image from RPG?
-- Pilot also needs to keep track of career progress
-- Flight lessons etc?
-- current location, i think we can use lat/lon to infer an airport location
"latitude_deg" numeric NOT NULL,
"longitude_deg" numeric NOT NULL,
CONSTRAINT "pilots_pkey" PRIMARY KEY ("id")
) WITH (oids = false);
-- Creating a new pilot from the following inputs:
-- Age (will determine year, but pick a random date) - depending if the RPG's API supports this
-- Gender
-- Nationality

View File

@@ -0,0 +1,4 @@
-- Add down migration script here
DROP TABLE "owner_history";
DROP TABLE "pilot_aircraft";
DROP TABLE "flight_log";

View File

@@ -0,0 +1,31 @@
-- Add up migration script here
CREATE TABLE "owner_history" (
"id" BIGSERIAL NOT NULL,
"aircraft_id" BIGSERIAL NOT NULL,
"pilot_id" uuid NOT NULL,
"since" timestamp DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "owner_history_pkey" PRIMARY KEY ("id")
);
-- Pilot currently occupying/flying aircraft
CREATE TABLE "pilot_current_aircraft" (
"pilot_id" uuid NOT NULL,
"aircraft_id" uuid NOT NULL,
CONSTRAINT "pilot_aircraft_pkey" PRIMARY KEY ("pilot_id", "aircraft_id"),
) WITH (oids = false);
CREATE TABLE "flight_log" (
"id" BIGSERIAL NOT NULL,
"pilot_id" uuid NOT NULL,
"aircraft_id" uuid NOT NULL,
"takeoff_time" timestamp DEFAULT CURRENT_TIMESTAMP,
"takeoff_latitude_deg" NUMERIC NOT NULL,
"takeoff_longitude_deg" NUMERIC NOT NULL,
"takeoff_elevation_ft" NUMERIC NOT NULL DEFAULT 0,
"landing" timestamp,
"landing_latitude_deg" NUMERIC NOT NULL,
"landing_longitude_deg" NUMERIC NOT NULL,
"landing_elevation_ft" NUMERIC NOT NULL DEFAULT 0,
CONSTRAINT "flight_log_pkey" PRIMARY KEY ("id")
);

13
parser/Cargo.toml Normal file
View File

@@ -0,0 +1,13 @@
[package]
name = "parser"
version = "0.1.0"
edition = "2021"
[dependencies]
anyhow = "1.0.91"
csv = "1.3.0"
ctrlc = "3.4.5"
serde = { version = "1.0.213", features = ["derive"] }
simconnect-sdk = { path = "D:/source/MSFS/simconnect-sdk-rs/simconnect-sdk", features = [
"derive",
] }

28
parser/src/ctrl_c.rs Normal file
View File

@@ -0,0 +1,28 @@
use std::sync::{
atomic::{AtomicU8, Ordering},
Arc,
};
pub struct CtrlC {
counter: Arc<AtomicU8>,
}
impl CtrlC {
pub fn new() -> Self {
let counter: Arc<AtomicU8> = Default::default();
let c = counter.clone();
ctrlc::set_handler(move || {
c.fetch_add(1, Ordering::SeqCst);
if c.load(Ordering::SeqCst) >= 3 {
std::process::exit(1);
}
})
.unwrap();
Self { counter }
}
pub fn count(&self) -> u8 {
self.counter.load(Ordering::SeqCst)
}
}

153
parser/src/main.rs Normal file
View File

@@ -0,0 +1,153 @@
mod ctrl_c;
use ctrl_c::CtrlC;
use std::{fs, io::Write, thread::sleep, time::Duration};
use serde::Deserialize;
use simconnect_sdk::{Notification, SimConnect, SystemEventRequest};
#[derive(Clone, Debug, Deserialize)]
struct Airport {
id: usize,
ident: String,
#[serde(rename = "type")]
airport_type: String,
name: String,
latitude_deg: f64,
longitude_deg: f64,
elevation_ft: Option<i32>,
continent: String,
iso_country: String,
iso_region: String,
municipality: String,
scheduled_service: String,
gps_code: String,
iata_code: String,
local_code: String,
home_link: String,
wikipedia_link: String,
keywords: String,
}
// cross reference ICAOs with data from the sim
fn main() -> Result<(), anyhow::Error> {
let Ok(mut simconnect) = SimConnect::new("Airport Crawler") else {
panic!("Game not running, gotta wait for it here");
};
let mut csv = csv::ReaderBuilder::new()
.has_headers(true)
.delimiter(b',')
.trim(csv::Trim::All)
.from_path("./airports.csv")?;
let airports = csv.deserialize::<Airport>().flatten().collect::<Vec<_>>();
let mut list = vec![];
let ctrl_c = CtrlC::new();
loop {
if ctrl_c.count() > 0 {
break;
}
if let Ok(Some(event)) = simconnect.get_next_dispatch() {
match event {
Notification::Open => {
// simconnect.subscribe_to_system_event(SystemEventRequest::FlightLoaded)?;
simconnect.request_facilities_list(simconnect_sdk::FacilityType::Airport)?;
}
Notification::AirportList(vec) => {
for a in &vec {
let Some(ap) = airports
.iter()
.find(|e| e.ident.to_lowercase() == a.ident.to_lowercase())
else {
let Some(ap) = airports
.iter()
.find(|e| e.local_code.to_lowercase() == a.ident.to_lowercase())
else {
// eprintln!("{} not found in as ident nor local_code", a.ident.to_lowercase());
list.push(Airport {
id: 0,
ident: a.ident.clone(),
airport_type: "N/A".to_string(),
name: "N/A".to_string(),
latitude_deg: a.lat,
longitude_deg: a.lon,
elevation_ft: Some(a.alt.round() as i32),
continent: "N/A".to_string(),
iso_country: "N/A".to_string(),
iso_region: "N/A".to_string(),
municipality: "N/A".to_string(),
scheduled_service: "N/A".to_string(),
gps_code: "N/A".to_string(),
iata_code: "N/A".to_string(),
local_code: "N/A".to_string(),
home_link: "N/A".to_string(),
wikipedia_link: "N/A".to_string(),
keywords: "N/A".to_string(),
});
continue;
};
let mut ap = ap.to_owned();
ap.ident = ap.local_code.clone();
list.push(ap);
continue;
};
list.push(ap.to_owned());
}
dbg!(&vec.len());
}
Notification::Quit => break,
_ => todo!(),
}
}
sleep(Duration::from_millis(16));
}
let mut writer = fs::File::create("./airports.sql")?;
let mut string_builder = String::new();
let mut i = 0;
string_builder += "INSERT INTO airports ( ident, airport_type, name, latitude_deg, longitude_deg, elevation_ft, iso_country, iso_region, municipality, scheduled_service, gps_code, iata_code, local_code, keywords ) VALUES\n";
for airport in list {
string_builder += &format!(
"\t('{}', '{}', '{}', {}, {}, {}, '{}', '{}', '{}', '{}', '{}', '{}', '{}', '{}')",
airport.ident.replace('\'', "''"),
airport.airport_type.replace('\'', "''"),
airport.name.replace('\'', "''"),
airport.latitude_deg,
airport.longitude_deg,
airport.elevation_ft.unwrap_or(0),
airport.iso_country.replace('\'', "''"),
airport.iso_region.replace('\'', "''"),
airport.municipality.replace('\'', "''"),
airport.scheduled_service.replace('\'', "''"),
airport.gps_code.replace('\'', "''"),
airport.iata_code.replace('\'', "''"),
airport.local_code.replace('\'', "''"),
airport.keywords.replace('\'', "''"),
);
if i == 50 {
i = 0;
string_builder += ";\n\nINSERT INTO airports ( ident, airport_type, name, latitude_deg, longitude_deg, elevation_ft, iso_country, iso_region, municipality, scheduled_service, gps_code, iata_code, local_code, keywords ) VALUES\n";
continue;
} else {
string_builder += ",\n";
}
i += 1;
}
writer.write_all(string_builder.as_bytes())?;
Ok(())
}

View File

@@ -9,6 +9,7 @@ const SMTP_USERNAME: &str = "SMTP_USERNAME";
const SMTP_PASSWORD: &str = "SMTP_PASSWORD";
const SMTP_SENDER: &str = "SMTP_SENDER";
const JWT_SECRET: &str = "JWT_SECRET";
const HASH_ID: &str = "HASH_ID";
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Config {
@@ -21,6 +22,7 @@ pub struct Config {
pub smtp_sender: String,
pub jwt_secret: String,
pub hash_id: String,
}
impl Config {
@@ -32,6 +34,7 @@ impl Config {
let smtp_password = load_env(SMTP_PASSWORD)?;
let smtp_sender = load_env(SMTP_SENDER)?;
let jwt_secret = load_env(JWT_SECRET)?;
let hash_id = load_env(HASH_ID)?;
Ok(Config {
database_url,
@@ -41,6 +44,7 @@ impl Config {
smtp_password,
smtp_sender,
jwt_secret,
hash_id,
})
}
}

View File

@@ -23,12 +23,16 @@ pub mod prelude {
pub use super::ports::*;
pub use super::service::*;
pub use crate::domain::leptos::check_user;
pub use crate::domain::leptos::flashbag::Alert;
pub use crate::domain::leptos::flashbag::Flash;
pub use crate::domain::leptos::flashbag::FlashBag;
pub use crate::domain::leptos::flashbag::FlashMessage;
pub use axum_session::SessionAnySession as Session;
pub use avam_protocol::*;
}
#[cfg(not(feature = "ssr"))]

View File

@@ -0,0 +1,32 @@
// max limit: 1.336.335
// Ok so i kinda wanna go all out on this one
// The basic things like
// Aircraft Manufacturer
// Aircraft Type
// Registration Number (up to 1.336.335, generated with auto incremented ids and hash_id)
// - Custom registration nr should be possible, "auto" increment will be a manual thing, check if it exists, if so, skip
// Build date
// Usage things
// Current fuel level in all possible tanks
// Current location and altitude
// Passangers and Cargo
// But also Logs
// Owner history
// Flight Logs which contains weights and balances, to and from etc
// Crashes and maintanance logs
// Most of these things can and will be automated / generated without the need for user input
// Maybe maintanance can be a thing where a plane can't be used for x time
// -----------------------
// The thing we actually need first is a factory
// Using the webinterface, we actually need to go to a factory to build us a new aircraft
// Hangars
// Hangars are on airports
// so we need those too

View File

@@ -1,3 +1,6 @@
use avam_protocol::Packets;
use tokio::sync::mpsc::Sender;
use crate::{
domain::api::models::oauth::*,
inbound::http::handlers::oauth::{AuthorizationCodeRequest, VerifyClientAuthorizationRequest},
@@ -7,6 +10,21 @@ use super::super::models::user::*;
use std::future::Future;
pub trait ApiService: Clone + Send + Sync + 'static {
// -- -
// Websocket
// ---
fn add_connection(&self, user: &User, sender: Sender<Packets>);
fn has_connection(&self, user: &User) -> bool;
fn remove_connection(&self, user: &User);
fn send(
&self,
user: &User,
packet: Packets,
) -> impl Future<Output = Result<(), anyhow::Error>> + Send;
// ---
// USER
// ---

View File

@@ -2,7 +2,10 @@
Module `service` provides the canonical implementation of the [ApiService] port. All
user-domain logic is defined here.
*/
use avam_protocol::Packets;
use axum_session::SessionAnySession;
use dashmap::DashMap;
use tokio::sync::mpsc::Sender;
use crate::inbound::http::handlers::oauth::AuthorizationCodeRequest;
use crate::inbound::http::handlers::oauth::GrantType;
@@ -25,6 +28,7 @@ where
{
repo: R,
notifier: N,
connections: DashMap<uuid::Uuid, Sender<Packets>>,
}
impl<R, N> Service<R, N>
@@ -33,7 +37,11 @@ where
N: Email,
{
pub fn new(repo: R, notifier: N) -> Self {
Self { repo, notifier }
Self {
repo,
notifier,
connections: DashMap::new(),
}
}
}
@@ -42,6 +50,25 @@ where
R: UserRepository + OAuthRepository,
N: Email,
{
fn add_connection(&self, user: &User, sender: Sender<Packets>) {
self.connections.insert(user.id(), sender);
}
fn has_connection(&self, user: &User) -> bool {
self.connections.contains_key(&user.id())
}
fn remove_connection(&self, user: &User) {
self.connections.remove(&user.id());
}
async fn send(&self, user: &User, packet: Packets) -> Result<(), anyhow::Error> {
if let Some(sender) = self.connections.get(&user.id()) {
sender.send(packet).await?;
}
Ok(())
}
async fn create_user(&self, req: CreateUserRequest) -> Result<User, CreateUserError> {
let result = self.repo.create_user(req).await;

View File

@@ -1,46 +1,54 @@
use leptos::*;
use leptos_router::ActionForm;
use crate::domain::api::prelude::User;
use crate::domain::api::prelude::*;
#[server]
async fn login_action(ident: String) -> Result<(), ServerFnError<String>> {
use crate::domain::api::prelude::*;
if ident.len() > 10 {
return Err(ServerFnError::WrappedServerError(
"ATC_ID exceeding 10 characters".into(),
));
}
let Some(user) = check_user().await? else {
return Err(ServerFnError::WrappedServerError("No user".into()));
};
let app = use_context::<AppService>().unwrap();
app.send(&user, Packets::SimConnect(SimConnectPacket::AtcID(ident)))
.await
.map_err(|e| format!("{:#?}", e))?;
Ok(())
}
/// Renders the home page of your application.
#[component]
pub fn DashboardPage(user: User) -> impl IntoView {
let submit = Action::<LoginAction, _>::server();
// let response = submit.value().read_only();
view! {
<section class="login is-fullheight">
<div class="columns is-fullheight">
<div class="column is-one-third-fullhd is-half-widescreen">
<div class="login_container">
<div style="margin: auto 0">
<div class="has-text-centered">
<img src="/android-chrome-192x192.png" alt={ crate::PROJECT_NAME }/>
</div>
<pre>Hello, { user.email().to_string() }!</pre>
<div class="content has-text-centered">
<a href="/auth/logout">Logout</a>
</div>
</div>
<footer>
<div class="content has-text-centered">
<p>
{ crate::PROJECT_NAME }
</p>
<p>
<span class="icon"><a href="https://git.avii.nl/AVAM/avam" class="is-link" target="_BLANK"><i class="fab fa-git-alt"></i></a></span>
<span class="icon"><a href="#" class="is-link" target="_BLANK"><i class="fab fa-discord"></i></a></span>
</p>
</div>
</footer>
</div>
</div>
<div class="column is-fullheight background is-hidden-mobile has-background-primary has-text-primary-invert">
</div>
<div class="p-10">
<pre>Hello, { user.email().to_string() }!</pre>
<div class="content has-text-centered link">
<a href="/auth/logout">Logout</a>
</div>
</section>
}.into_view()
<div>
<ActionForm action=submit>
<label class="input input-bordered flex items-center gap-2">
<i class="fas fa-envelope"></i>
<input type="text" placeholder="Registration Number" maxlength="10" name="ident" />
</label>
<div>
<input type="submit" value="Update" class="btn btn-block" />
</div>
</ActionForm>
</div>
</div>
}
.into_view()
}

View File

@@ -19,6 +19,7 @@ use tokio::{
sync::mpsc,
time::{sleep, Instant},
};
use tracing::info;
use crate::{
domain::api::{
@@ -39,10 +40,14 @@ pub async fn ws_handler<S: ApiService>(
) -> Result<impl IntoResponse, StatusCode> {
let auth_token = match auth_token {
Some(TypedHeader(token)) => Some(token.token().to_string()),
None => return Err(StatusCode::UNAUTHORIZED),
None => {
tracing::error!("No Authorization Header Supplied");
return Err(StatusCode::UNAUTHORIZED);
}
};
let Some(auth_token) = auth_token else {
tracing::error!("No Token Supplied");
return Err(StatusCode::UNAUTHORIZED);
};
@@ -72,10 +77,11 @@ pub async fn ws_handler<S: ApiService>(
.verify_client_authorization(VerifyClientAuthorizationRequest::new(user_id, client_id))
.await
else {
tracing::error!("Client {} not authorized by {}", client_id, user_id);
return Err(StatusCode::UNAUTHORIZED);
};
if app_state.has_connection(&user).await {
if app_state.api_service().has_connection(&user) {
return Err(StatusCode::CONFLICT);
}
@@ -93,7 +99,7 @@ async fn handle_socket<S: ApiService>(
// It'd know who's connected at all times and be able to send messages
let (sender, mut receiver) = mpsc::channel(10);
app_state.add_connection(&user, sender).await;
app_state.api_service().add_connection(&user, sender);
// This can probably be hella-abstracted away and be made a lot cleaner
let (mut writer, mut reader) = socket.split();
@@ -175,11 +181,12 @@ async fn handle_socket<S: ApiService>(
};
// remove the user/channel from AppState
app_state.remove_connection(&user).await;
app_state.api_service().remove_connection(&user);
// returning from the handler closes the websocket connection
tracing::debug!("Websocket context {who} destroyed");
}
async fn process_system_packet<S>(
app_state: AppState<S>,
user: &User,
@@ -193,6 +200,7 @@ where
SystemPacket::Ping => {
// send back pong
let _ = app_state
.api_service()
.send(user, Packets::System(SystemPacket::Pong))
.await;
}
@@ -216,7 +224,24 @@ async fn process_message<S>(
where
S: ApiService,
{
tracing::info!("< [{}]: {:?}", user.email(), packet);
// This needs to be abstracted away from here like actually
match packet {
SimConnectPacket::AtcID(id) => info!("[{}] Registration to {}", user.email(), id),
SimConnectPacket::Fuel(fuel) => info!("[{}] Fuel state: {}", user.email(), fuel),
SimConnectPacket::Airplane(airplane) => info!("[{}] Airplane: {}", user.email(), airplane),
SimConnectPacket::Gps(gps) => info!("[{}] Location: {}", user.email(), gps),
SimConnectPacket::OnGround(on_ground) => {
info!("[{}] On Ground: {}", user.email(), on_ground)
}
SimConnectPacket::IsParked(is_parked) => {
info!("[{}] Is Parked: {}", user.email(), is_parked)
}
}
// The airplane variant checks if the player is in the correct airplane for the selected job etc
// Send error if not and don't handle the flight
// tracing::info!("< [{}]: {:?}", user.email(), packet);
// On incoming packets, we use the internal api to store stuff to the database
// We'll use Server Side Events (SSE) to keep the dashboard up to date with the state of the database

View File

@@ -1,14 +1,9 @@
use std::{collections::HashMap, sync::Arc};
use std::sync::Arc;
use avam_protocol::Packets;
use axum::extract::FromRef;
use leptos::get_configuration;
use tokio::sync::{mpsc::Sender, RwLock};
use crate::{
config::Config,
domain::api::{ports::ApiService, prelude::User},
};
use crate::{config::Config, domain::api::ports::ApiService};
#[derive(Clone)]
/// The global application state shared between all request handlers.
@@ -19,7 +14,6 @@ where
pub leptos_options: leptos::LeptosOptions,
config: Arc<Config>,
api_service: Arc<S>,
connections: Arc<RwLock<HashMap<uuid::Uuid, Sender<Packets>>>>,
}
impl<S> AppState<S>
@@ -31,7 +25,6 @@ where
config: Arc::new(config),
leptos_options: get_configuration(None).await.unwrap().leptos_options,
api_service: Arc::new(api_service),
connections: Arc::new(RwLock::new(HashMap::new())),
}
}
@@ -44,30 +37,6 @@ where
}
}
impl<S> AppState<S>
where
S: ApiService,
{
pub async fn add_connection(&self, user: &User, sender: Sender<Packets>) {
self.connections.write().await.insert(user.id(), sender);
}
pub async fn has_connection(&self, user: &User) -> bool {
self.connections.read().await.contains_key(&user.id())
}
pub async fn remove_connection(&self, user: &User) {
self.connections.write().await.remove(&user.id());
}
pub async fn send(&self, user: &User, packet: Packets) -> Result<(), anyhow::Error> {
if let Some(sender) = self.connections.read().await.get(&user.id()) {
sender.send(packet).await?;
}
Ok(())
}
}
impl<S> FromRef<AppState<S>> for leptos::LeptosOptions
where
S: ApiService,

View File

@@ -968,34 +968,6 @@ html {
}
}
.footer {
display: grid;
width: 100%;
grid-auto-flow: row;
place-items: start;
-moz-column-gap: 1rem;
column-gap: 1rem;
row-gap: 2.5rem;
font-size: 0.875rem;
line-height: 1.25rem;
}
.footer > * {
display: grid;
place-items: start;
gap: 0.5rem;
}
@media (min-width: 48rem) {
.footer {
grid-auto-flow: column;
}
.footer-center {
grid-auto-flow: row dense;
}
}
.label {
display: flex;
-webkit-user-select: none;
@@ -1448,10 +1420,6 @@ html {
display: flex;
}
.contents {
display: contents;
}
.hidden {
display: none;
}
@@ -1504,6 +1472,10 @@ html {
background-position: center;
}
.p-10 {
padding: 2.5rem;
}
.px-1 {
padding-left: 0.25rem;
padding-right: 0.25rem;