feat(card_db): Import card database from edopro GitHub repo
This commit is contained in:
parent
88da43e208
commit
a3ce7f8008
Cargo.lockCargo.tomlindex.html
migrations/2025-03-13-161839_create_cards
src
295
Cargo.lock
generated
295
Cargo.lock
generated
|
@ -122,6 +122,15 @@ version = "0.22.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
|
||||
|
||||
[[package]]
|
||||
name = "bincode"
|
||||
version = "1.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.9.0"
|
||||
|
@ -403,15 +412,22 @@ dependencies = [
|
|||
"diesel-derive-enum",
|
||||
"diesel_migrations",
|
||||
"futures",
|
||||
"futures-util",
|
||||
"gloo",
|
||||
"gloo-net 0.6.0",
|
||||
"leptos",
|
||||
"log",
|
||||
"serde",
|
||||
"serde-wasm-bindgen",
|
||||
"serde_json",
|
||||
"sqlite-wasm-rs",
|
||||
"thiserror 2.0.12",
|
||||
"thiserror-ext",
|
||||
"time",
|
||||
"url",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
"wasm-logger",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -624,6 +640,109 @@ version = "0.31.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
|
||||
|
||||
[[package]]
|
||||
name = "gloo"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d15282ece24eaf4bd338d73ef580c6714c8615155c4190c781290ee3fa0fd372"
|
||||
dependencies = [
|
||||
"gloo-console",
|
||||
"gloo-dialogs",
|
||||
"gloo-events",
|
||||
"gloo-file",
|
||||
"gloo-history",
|
||||
"gloo-net 0.5.0",
|
||||
"gloo-render",
|
||||
"gloo-storage",
|
||||
"gloo-timers",
|
||||
"gloo-utils",
|
||||
"gloo-worker",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gloo-console"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2a17868f56b4a24f677b17c8cb69958385102fa879418052d60b50bc1727e261"
|
||||
dependencies = [
|
||||
"gloo-utils",
|
||||
"js-sys",
|
||||
"serde",
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gloo-dialogs"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bf4748e10122b01435750ff530095b1217cf6546173459448b83913ebe7815df"
|
||||
dependencies = [
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gloo-events"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "27c26fb45f7c385ba980f5fa87ac677e363949e065a083722697ef1b2cc91e41"
|
||||
dependencies = [
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gloo-file"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97563d71863fb2824b2e974e754a81d19c4a7ec47b09ced8a0e6656b6d54bd1f"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"gloo-events",
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gloo-history"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "903f432be5ba34427eac5e16048ef65604a82061fe93789f2212afc73d8617d6"
|
||||
dependencies = [
|
||||
"getrandom 0.2.15",
|
||||
"gloo-events",
|
||||
"gloo-utils",
|
||||
"serde",
|
||||
"serde-wasm-bindgen",
|
||||
"serde_urlencoded",
|
||||
"thiserror 1.0.69",
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gloo-net"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43aaa242d1239a8822c15c645f02166398da4f8b5c4bae795c1f5b44e9eee173"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
"gloo-utils",
|
||||
"http 0.2.12",
|
||||
"js-sys",
|
||||
"pin-project",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror 1.0.69",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gloo-net"
|
||||
version = "0.6.0"
|
||||
|
@ -634,7 +753,7 @@ dependencies = [
|
|||
"futures-core",
|
||||
"futures-sink",
|
||||
"gloo-utils",
|
||||
"http",
|
||||
"http 1.2.0",
|
||||
"js-sys",
|
||||
"pin-project",
|
||||
"serde",
|
||||
|
@ -645,6 +764,43 @@ dependencies = [
|
|||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gloo-render"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56008b6744713a8e8d98ac3dcb7d06543d5662358c9c805b4ce2167ad4649833"
|
||||
dependencies = [
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gloo-storage"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fbc8031e8c92758af912f9bc08fbbadd3c6f3cfcbf6b64cdf3d6a81f0139277a"
|
||||
dependencies = [
|
||||
"gloo-utils",
|
||||
"js-sys",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror 1.0.69",
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gloo-timers"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gloo-utils"
|
||||
version = "0.2.0"
|
||||
|
@ -658,6 +814,37 @@ dependencies = [
|
|||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gloo-worker"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "085f262d7604911c8150162529cefab3782e91adb20202e8658f7275d2aefe5d"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"futures",
|
||||
"gloo-utils",
|
||||
"gloo-worker-macros",
|
||||
"js-sys",
|
||||
"pinned",
|
||||
"serde",
|
||||
"thiserror 1.0.69",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gloo-worker-macros"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "956caa58d4857bc9941749d55e4bd3000032d8212762586fa5705632967140e7"
|
||||
dependencies = [
|
||||
"proc-macro-crate",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "guardian"
|
||||
version = "1.3.0"
|
||||
|
@ -703,6 +890,17 @@ dependencies = [
|
|||
"utf8-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "http"
|
||||
version = "0.2.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"fnv",
|
||||
"itoa",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "http"
|
||||
version = "1.2.0"
|
||||
|
@ -1287,6 +1485,17 @@ version = "0.1.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||
|
||||
[[package]]
|
||||
name = "pinned"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a829027bd95e54cfe13e3e258a1ae7b645960553fb82b75ff852c29688ee595b"
|
||||
dependencies = [
|
||||
"futures",
|
||||
"rustversion",
|
||||
"thiserror 1.0.69",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.32"
|
||||
|
@ -1309,6 +1518,16 @@ dependencies = [
|
|||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-crate"
|
||||
version = "1.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"toml_edit 0.19.15",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error-attr2"
|
||||
version = "2.0.0"
|
||||
|
@ -1608,6 +1827,18 @@ dependencies = [
|
|||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_urlencoded"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd"
|
||||
dependencies = [
|
||||
"form_urlencoded",
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "server_fn"
|
||||
version = "0.7.7"
|
||||
|
@ -1618,8 +1849,8 @@ dependencies = [
|
|||
"const_format",
|
||||
"dashmap",
|
||||
"futures",
|
||||
"gloo-net",
|
||||
"http",
|
||||
"gloo-net 0.6.0",
|
||||
"http 1.2.0",
|
||||
"js-sys",
|
||||
"once_cell",
|
||||
"pin-project-lite",
|
||||
|
@ -1801,6 +2032,28 @@ dependencies = [
|
|||
"thiserror-impl 2.0.12",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-ext"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ef4323942237f7cc071061f2c5f0db919e6053c2cdf58c6bc974883073429737"
|
||||
dependencies = [
|
||||
"thiserror 1.0.69",
|
||||
"thiserror-ext-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-ext-derive"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "96541747c50e6c73e094737938f4f5dfaf50c48a31adff4197a3e2a481371674"
|
||||
dependencies = [
|
||||
"either",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.69"
|
||||
|
@ -1892,7 +2145,7 @@ dependencies = [
|
|||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
"toml_edit",
|
||||
"toml_edit 0.22.24",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1904,6 +2157,17 @@ dependencies = [
|
|||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_edit"
|
||||
version = "0.19.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"toml_datetime",
|
||||
"winnow 0.5.40",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_edit"
|
||||
version = "0.22.24"
|
||||
|
@ -1914,7 +2178,7 @@ dependencies = [
|
|||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
"winnow",
|
||||
"winnow 0.7.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2063,6 +2327,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"futures-core",
|
||||
"js-sys",
|
||||
"once_cell",
|
||||
"wasm-bindgen",
|
||||
|
@ -2101,6 +2366,17 @@ dependencies = [
|
|||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-logger"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "074649a66bb306c8f2068c9016395fa65d8e08d2affcbf95acf3c24c3ab19718"
|
||||
dependencies = [
|
||||
"log",
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-streams"
|
||||
version = "0.4.2"
|
||||
|
@ -2206,6 +2482,15 @@ version = "0.52.6"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
version = "0.5.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
version = "0.7.3"
|
||||
|
|
11
Cargo.toml
11
Cargo.toml
|
@ -15,9 +15,14 @@ serde_json = "1.0.140"
|
|||
thiserror = "2.0.12"
|
||||
url = "2.5.4"
|
||||
wasm-bindgen = "0.2.100"
|
||||
wasm-bindgen-futures = "0.4.50"
|
||||
wasm-bindgen-futures = { version = "0.4.50", features = ["futures-core-03-stream"] }
|
||||
diesel-derive-enum = { version = "2.1.0", features = ["sqlite"] }
|
||||
diesel_migrations = { git = "https://github.com/diesel-rs/diesel.git", features = ["sqlite"] }
|
||||
|
||||
[target.'cfg(all(target_family = "wasm", target_os = "unknown"))'.dependencies]
|
||||
time = { version = "0.3.39", features = ["parsing"] }
|
||||
wasm-logger = "0.2.0"
|
||||
log = "0.4.26"
|
||||
sqlite-wasm-rs = { version = ">=0.3.0, <0.4.0" , default-features = false, features = ["precompiled"]}
|
||||
thiserror-ext = "0.2.1"
|
||||
futures-util = "0.3.31"
|
||||
gloo = { version = "0.11.0", features = ["futures"] }
|
||||
gloo-net = { version = "0.6.0" }
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head></head>
|
||||
<head>
|
||||
<link data-trunk rel="rust" data-type="worker" data-bin="database_worker" data-weak-refs data-loader-shim />
|
||||
<link data-trunk rel="rust" data-bin="draft-manager" data-weak-refs />
|
||||
</head>
|
||||
<body></boy>
|
||||
</html>
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
-- This file should undo anything in `up.sql`
|
|
@ -1,7 +0,0 @@
|
|||
CREATE TABLE cards (
|
||||
password PRIMARY KEY,
|
||||
name VARCHAR NOT NULL,
|
||||
description TEXT NOT NULL,
|
||||
frame TEXT CHECK(frame IN ('normal', 'effect', 'ritual', 'fusion', 'synchro', 'xyz', 'link', 'normal_pendulum', 'effect_pendulum', 'ritual_pendulum', 'fusion_pendulum', 'synchro_pendulum', 'xyz_pendulum', 'spell', 'trap', 'token')) NOT NULL,
|
||||
image TEXT
|
||||
)
|
14
src/bin/database_worker.rs
Normal file
14
src/bin/database_worker.rs
Normal file
|
@ -0,0 +1,14 @@
|
|||
use draft_manager::database::BrowserDatabase;
|
||||
|
||||
fn main() {
|
||||
console_error_panic_hook::set_once();
|
||||
wasm_logger::init(wasm_logger::Config::default());
|
||||
|
||||
wasm_bindgen_futures::spawn_local(async {
|
||||
let a = BrowserDatabase::init_worker().await;
|
||||
|
||||
if let Err(e) = a {
|
||||
log::error!("{:?}", e);
|
||||
}
|
||||
})
|
||||
}
|
|
@ -1,13 +1,13 @@
|
|||
use leptos::prelude::*;
|
||||
|
||||
use crate::database::models::CardDetails;
|
||||
use crate::database::models::CardData;
|
||||
|
||||
#[component]
|
||||
pub fn Card(details: Option<CardDetails>) -> impl IntoView {
|
||||
pub fn Card(details: Option<CardData>) -> impl IntoView {
|
||||
match details {
|
||||
Some(details) => view! {
|
||||
<p>{details.name}</p>
|
||||
<span style="white-space: pre-line">{details.description}</span>
|
||||
<p>{details.id}</p>
|
||||
<span style="white-space: pre-line">{details.level}</span>
|
||||
}
|
||||
.into_any(),
|
||||
None => view! { <p>"Placeholder"</p> }.into_any(),
|
||||
|
|
|
@ -1,54 +1,60 @@
|
|||
use crate::database::{self, models::FrameType, schema::cards};
|
||||
use database::models::CardDetails;
|
||||
use diesel::{prelude::*, Connection};
|
||||
use diesel_migrations::{embed_migrations, EmbeddedMigrations, MigrationHarness};
|
||||
use thiserror::Error;
|
||||
use gloo::worker::{Registrable, Spawnable, WorkerBridge};
|
||||
|
||||
pub mod models;
|
||||
pub mod schema;
|
||||
mod worker;
|
||||
|
||||
const DB_URL: &str = "cards.db";
|
||||
const MIGRATIONS: EmbeddedMigrations = embed_migrations!("migrations");
|
||||
use sqlite_wasm_rs::export::{install_opfs_sahpool, OpfsSAHError};
|
||||
use thiserror_ext::AsReport;
|
||||
use worker::{DatabaseWorker, Query};
|
||||
|
||||
pub struct BrowserDatabase(SqliteConnection);
|
||||
use crate::utils::github_fetch_file;
|
||||
|
||||
pub struct BrowserDatabase {
|
||||
worker: WorkerBridge<DatabaseWorker>,
|
||||
}
|
||||
|
||||
impl BrowserDatabase {
|
||||
pub fn open() -> Result<Self> {
|
||||
let mut connection = SqliteConnection::establish(DB_URL)?;
|
||||
connection.run_pending_migrations(MIGRATIONS).unwrap();
|
||||
Ok(Self(connection))
|
||||
pub fn new() -> Self {
|
||||
let bridge = DatabaseWorker::spawner()
|
||||
.callback(move |o| {
|
||||
log::info!("{:?}", o);
|
||||
})
|
||||
.spawn_with_loader("/database_worker_loader.js");
|
||||
|
||||
log::debug!("Shoulda spawned a worker");
|
||||
|
||||
Self { worker: bridge }
|
||||
}
|
||||
|
||||
pub async fn get_card(&mut self, password: i32) -> Result<Option<CardDetails>> {
|
||||
match cards::dsl::cards.find(password).first(&mut self.0) {
|
||||
Ok(details) => Ok(Some(details)),
|
||||
Err(diesel::result::Error::NotFound) => Ok(None),
|
||||
Err(other) => Err(other.into()),
|
||||
}
|
||||
pub fn send_message(&self) {
|
||||
self.worker.send(Query::ByPassword(1861629));
|
||||
}
|
||||
|
||||
pub fn load_data(&mut self) -> Result<()> {
|
||||
let decode_talker = CardDetails {
|
||||
password: 1861629,
|
||||
name: "Decode Talker".to_owned(),
|
||||
description: "2+ Effect Monsters\r\nGains 500 ATK for each monster it points to. When your opponent activates a card or effect that targets a card(s) you control (Quick Effect): You can Tribute 1 monster this card points to; negate the activation, and if you do, destroy that card.".to_owned(),
|
||||
frame: FrameType::Link,
|
||||
image: "https://images.ygoprodeck.com/images/cards/1861629.jpg".to_owned()
|
||||
/// Initialize the database worker.
|
||||
///
|
||||
/// Must be executed in a worker script, not on the main thread.
|
||||
pub async fn init_worker() -> Result<(), OpfsSAHError> {
|
||||
log::debug!("Initializing database worker...");
|
||||
let sah_pool_util = install_opfs_sahpool(None, false).await?;
|
||||
|
||||
let babel_cdb = match github_fetch_file("ProjectIgnis", "BabelCDB", "cards.cdb").await {
|
||||
Ok(cdb) => cdb,
|
||||
Err(err) => {
|
||||
log::error!("{}", err.to_report_string());
|
||||
panic!("{:?}", err);
|
||||
}
|
||||
};
|
||||
|
||||
diesel::insert_into(cards::table)
|
||||
.values(decode_talker)
|
||||
.execute(&mut self.0)?;
|
||||
|
||||
sah_pool_util.import_db("/cards.db", &babel_cdb)?;
|
||||
DatabaseWorker::registrar().register();
|
||||
log::debug!("Database worker set up!");
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum BrowserDatabaseError {
|
||||
#[error("failed to connect to database")]
|
||||
DieselConnectionError(#[from] diesel::ConnectionError),
|
||||
#[error("failed to query database")]
|
||||
DieselQueryError(#[from] diesel::result::Error),
|
||||
impl Default for BrowserDatabase {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
type Result<T> = std::result::Result<T, BrowserDatabaseError>;
|
||||
|
|
|
@ -1,38 +1,79 @@
|
|||
use diesel::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::database::schema::cards;
|
||||
use crate::database::schema::datas;
|
||||
use crate::database::schema::texts;
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, Insertable, Selectable, Queryable)]
|
||||
#[diesel(table_name = cards)]
|
||||
#[derive(Debug, Selectable, Queryable)]
|
||||
#[diesel(table_name = datas)]
|
||||
#[diesel(check_for_backend(diesel::sqlite::Sqlite))]
|
||||
pub struct CardData {
|
||||
pub id: i32,
|
||||
pub ot: i32,
|
||||
pub alias: i32,
|
||||
pub setcode: i32,
|
||||
pub card_type: i32,
|
||||
pub atk: i32,
|
||||
pub def: i32,
|
||||
pub level: i32,
|
||||
pub race: i32,
|
||||
pub attribute: i32,
|
||||
pub category: i32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Associations, Selectable, Queryable)]
|
||||
#[diesel(table_name = texts)]
|
||||
#[diesel(belongs_to(CardData, foreign_key = id))]
|
||||
#[diesel(check_for_backend(diesel::sqlite::Sqlite))]
|
||||
pub struct CardTexts {
|
||||
pub id: i32,
|
||||
pub name: String,
|
||||
pub desc: String,
|
||||
pub str1: String,
|
||||
pub str2: String,
|
||||
pub str3: String,
|
||||
pub str4: String,
|
||||
pub str5: String,
|
||||
pub str6: String,
|
||||
pub str7: String,
|
||||
pub str8: String,
|
||||
pub str9: String,
|
||||
pub str10: String,
|
||||
pub str11: String,
|
||||
pub str12: String,
|
||||
pub str13: String,
|
||||
pub str14: String,
|
||||
pub str15: String,
|
||||
pub str16: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct CardDetails {
|
||||
pub password: i32,
|
||||
|
||||
pub name: String,
|
||||
pub description: String,
|
||||
|
||||
pub frame: FrameType,
|
||||
pub image: String,
|
||||
pub desc: String,
|
||||
pub card_type: i32,
|
||||
pub atk: i32,
|
||||
pub def: i32,
|
||||
pub level: i32,
|
||||
pub race: i32,
|
||||
pub attribute: i32,
|
||||
pub category: i32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, diesel_derive_enum::DbEnum)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum FrameType {
|
||||
Normal,
|
||||
Effect,
|
||||
Ritual,
|
||||
Fusion,
|
||||
Synchro,
|
||||
Xyz,
|
||||
Link,
|
||||
NormalPendulum,
|
||||
EffectPendulum,
|
||||
RitualPendulum,
|
||||
FusionPendulum,
|
||||
SynchroPendulum,
|
||||
XyzPendulum,
|
||||
Spell,
|
||||
Trap,
|
||||
Token,
|
||||
impl CardDetails {
|
||||
pub fn from_data(data: CardData, texts: CardTexts) -> Self {
|
||||
Self {
|
||||
password: data.id,
|
||||
name: texts.name,
|
||||
desc: texts.desc,
|
||||
card_type: data.card_type,
|
||||
atk: data.atk,
|
||||
def: data.def,
|
||||
level: data.level,
|
||||
race: data.race,
|
||||
attribute: data.attribute,
|
||||
category: data.category,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,40 @@
|
|||
diesel::table! {
|
||||
cards (password) {
|
||||
password -> Integer,
|
||||
name -> VarChar,
|
||||
description -> Text,
|
||||
frame -> crate::database::models::FrameTypeMapping,
|
||||
image -> Text,
|
||||
datas {
|
||||
id -> Integer,
|
||||
ot -> Integer,
|
||||
alias -> Integer,
|
||||
setcode -> Integer,
|
||||
#[sql_name = "type"]
|
||||
card_type -> Integer,
|
||||
atk -> Integer,
|
||||
def -> Integer,
|
||||
level -> Integer,
|
||||
race -> Integer,
|
||||
attribute -> Integer,
|
||||
category -> Integer,
|
||||
}
|
||||
}
|
||||
|
||||
diesel::table! {
|
||||
texts {
|
||||
id -> Integer,
|
||||
name -> Text,
|
||||
desc -> Text,
|
||||
str1 -> Text,
|
||||
str2 -> Text,
|
||||
str3 -> Text,
|
||||
str4 -> Text,
|
||||
str5 -> Text,
|
||||
str6 -> Text,
|
||||
str7 -> Text,
|
||||
str8 -> Text,
|
||||
str9 -> Text,
|
||||
str10 -> Text,
|
||||
str11 -> Text,
|
||||
str12 -> Text,
|
||||
str13 -> Text,
|
||||
str14 -> Text,
|
||||
str15 -> Text,
|
||||
str16 -> Text,
|
||||
}
|
||||
}
|
||||
|
|
140
src/database/worker.rs
Normal file
140
src/database/worker.rs
Normal file
|
@ -0,0 +1,140 @@
|
|||
use diesel::{prelude::*, Connection};
|
||||
use futures::TryFutureExt;
|
||||
use gloo::worker::{HandlerId, Worker, WorkerScope};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use thiserror::Error;
|
||||
use thiserror_ext::AsReport;
|
||||
use wasm_bindgen_futures::spawn_local;
|
||||
|
||||
use super::{
|
||||
models::CardDetails,
|
||||
schema::{datas, texts},
|
||||
};
|
||||
|
||||
const DB_URL: &str = "file:/cards.db?vfs=opfs-sahpool&mode=ro";
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub enum Query {
|
||||
ByPassword(i32),
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub enum Response {
|
||||
ByPassword(Option<CardDetails>),
|
||||
Error(String),
|
||||
}
|
||||
|
||||
pub struct DatabaseWorker {}
|
||||
|
||||
impl DatabaseWorker {
|
||||
async fn run_query(query: &Query) -> Result<Response> {
|
||||
let res = match query {
|
||||
Query::ByPassword(pw) => Response::ByPassword(Self::get_card(*pw).await?),
|
||||
};
|
||||
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
/// Open a connection to the database.
|
||||
///
|
||||
/// We do not hold a connection in memory because that requires
|
||||
/// lots of awkward multi-thread data management.
|
||||
fn open_connection() -> Result<SqliteConnection> {
|
||||
let connection = SqliteConnection::establish(DB_URL)?;
|
||||
Ok(connection)
|
||||
}
|
||||
|
||||
async fn get_card(password: i32) -> Result<Option<CardDetails>> {
|
||||
let mut connection = Self::open_connection()?;
|
||||
|
||||
let res = {
|
||||
let data = datas::dsl::datas.find(password).first(&mut connection)?;
|
||||
let texts = texts::dsl::texts.find(password).first(&mut connection)?;
|
||||
|
||||
Ok((data, texts))
|
||||
};
|
||||
|
||||
let Some((data, texts)) = match res {
|
||||
Ok(details) => Ok(Some(details)),
|
||||
Err(diesel::result::Error::NotFound) => Ok(None),
|
||||
Err(other) => Err(other),
|
||||
}?
|
||||
else {
|
||||
return Ok(None);
|
||||
};
|
||||
|
||||
// match datas::dsl::datas.find(password).first(&mut connection) {
|
||||
// Ok(details) => Ok(Some(details)),
|
||||
// Err(diesel::result::Error::NotFound) => Ok(None),
|
||||
// Err(other) => Err(other.into()),
|
||||
// };
|
||||
|
||||
Ok(Some(CardDetails::from_data(data, texts)))
|
||||
}
|
||||
|
||||
// pub async fn load_card_data(&mut self) -> Result<()> {
|
||||
// let last_updated =
|
||||
// utils::github_fetch_last_updated("ProjectIgnis", "BabelCDB", "cards.cdb").await?;
|
||||
// if last_updated > time::OffsetDateTime::UNIX_EPOCH {
|
||||
// let card_data =
|
||||
// utils::github_fetch_file("ProjectIgnis", "BabelCDB", "cards.cdb").await?;
|
||||
// self.opfs_util.import_db("cards.cdb", &card_data)?;
|
||||
// }
|
||||
|
||||
// let decode_talker = CardDetails {
|
||||
// password: 1861629,
|
||||
// name: "Decode Talker".to_owned(),
|
||||
// description: "2+ Effect Monsters\r\nGains 500 ATK for each monster it points to. When your opponent activates a card or effect that targets a card(s) you control (Quick Effect): You can Tribute 1 monster this card points to; negate the activation, and if you do, destroy that card.".to_owned(),
|
||||
// frame: FrameType::Link,
|
||||
// image: "https://images.ygoprodeck.com/images/cards/1861629.jpg".to_owned()
|
||||
// };
|
||||
|
||||
// diesel::insert_into(cards::table)
|
||||
// .values(decode_talker)
|
||||
// .execute(&mut self.connection)?;
|
||||
|
||||
// Ok(())
|
||||
// }
|
||||
}
|
||||
|
||||
impl Worker for DatabaseWorker {
|
||||
type Input = Query;
|
||||
type Message = ();
|
||||
type Output = std::result::Result<Response, String>;
|
||||
|
||||
fn create(_scope: &WorkerScope<Self>) -> Self {
|
||||
Self {}
|
||||
}
|
||||
|
||||
fn update(&mut self, _scope: &WorkerScope<Self>, _msg: Self::Message) {
|
||||
log::debug!("Unimplemented!");
|
||||
}
|
||||
|
||||
fn received(&mut self, scope: &WorkerScope<Self>, query: Self::Input, id: HandlerId) {
|
||||
let scope = scope.clone();
|
||||
|
||||
spawn_local(async move {
|
||||
let res = DatabaseWorker::run_query(&query)
|
||||
.map_err(|err| {
|
||||
log::error!("{}", err.to_report_string_pretty());
|
||||
format!("{}", err.as_report())
|
||||
})
|
||||
.await;
|
||||
|
||||
scope.respond(id, res);
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum BrowserDatabaseError {
|
||||
// #[error("failed to set up browser database storage")]
|
||||
// VFSError(#[from] sqlite_wasm_rs::export::OpfsSAHError),
|
||||
// #[error("could not fetch updated card database")]
|
||||
// CardDbFetchError(#[from] GithubError),
|
||||
#[error("failed to connect to database")]
|
||||
DieselConnectionError(#[from] diesel::ConnectionError),
|
||||
#[error("failed to query database")]
|
||||
DieselQueryError(#[from] diesel::result::Error),
|
||||
}
|
||||
type Result<T> = std::result::Result<T, BrowserDatabaseError>;
|
|
@ -1,3 +1,4 @@
|
|||
pub mod components;
|
||||
pub mod draft_list;
|
||||
pub mod database;
|
||||
pub mod draft_list;
|
||||
pub mod utils;
|
||||
|
|
39
src/main.rs
39
src/main.rs
|
@ -1,32 +1,37 @@
|
|||
use draft_manager::{components::card::Card, database::BrowserDatabase};
|
||||
use std::time::Duration;
|
||||
|
||||
use draft_manager::database::BrowserDatabase;
|
||||
use leptos::prelude::*;
|
||||
use wasm_bindgen_futures::spawn_local;
|
||||
|
||||
fn main() {
|
||||
console_error_panic_hook::set_once();
|
||||
wasm_logger::init(wasm_logger::Config::default());
|
||||
|
||||
log::debug!("Startin app database");
|
||||
let db = BrowserDatabase::new();
|
||||
log::debug!("Database initialized");
|
||||
|
||||
leptos::mount::mount_to_body(|| view! { <App /> });
|
||||
|
||||
spawn_local(async move {
|
||||
let db = db;
|
||||
|
||||
log::info!("Running loop!");
|
||||
db.send_message();
|
||||
|
||||
// We create a loop so that listeners can be held for forever.
|
||||
loop {
|
||||
gloo::timers::future::sleep(Duration::from_secs(3600)).await;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[component]
|
||||
fn App() -> impl IntoView {
|
||||
let card = LocalResource::new(|| async move {
|
||||
let mut database = BrowserDatabase::open()?;
|
||||
database.load_data()?;
|
||||
|
||||
database.get_card(1861629).await
|
||||
});
|
||||
|
||||
view! {
|
||||
<Transition fallback=move || {
|
||||
view! { <p>"Loading database..."</p> }
|
||||
}>
|
||||
{move || {
|
||||
card.read()
|
||||
.as_deref()
|
||||
.and_then(|card| {
|
||||
view! { <Card details=card.as_ref().unwrap().clone() /> }.into()
|
||||
})
|
||||
}}
|
||||
</Transition>
|
||||
}>{move || {}}</Transition>
|
||||
}
|
||||
}
|
||||
|
|
60
src/utils.rs
Normal file
60
src/utils.rs
Normal file
|
@ -0,0 +1,60 @@
|
|||
use gloo::net::http;
|
||||
use thiserror::Error;
|
||||
use time::{format_description::well_known::Rfc3339, OffsetDateTime};
|
||||
|
||||
const GITHUB_API: &str = "https://api.github.com";
|
||||
|
||||
pub async fn github_fetch_last_updated(
|
||||
owner: &str,
|
||||
repo: &str,
|
||||
path: &str,
|
||||
) -> Result<OffsetDateTime, GithubError> {
|
||||
let commit: Vec<serde_json::Value> = http::Request::get(&format!(
|
||||
"{GITHUB_API}/repos/{owner}/{repo}/commits?path={path}&page=1&per_page=1"
|
||||
))
|
||||
.send()
|
||||
.await?
|
||||
.json()
|
||||
.await?;
|
||||
|
||||
commit[0]
|
||||
.get("commit")
|
||||
.and_then(|commit| commit.get("committer"))
|
||||
.and_then(|committer| committer.get("date"))
|
||||
.map(|date| {
|
||||
OffsetDateTime::parse(
|
||||
date.as_str().ok_or(GithubError::MissingCommitDateError)?,
|
||||
&Rfc3339,
|
||||
)
|
||||
.map_err(|err| err.into())
|
||||
})
|
||||
.unwrap_or(Err(GithubError::MissingCommitDateError))
|
||||
}
|
||||
|
||||
pub async fn github_fetch_file(
|
||||
owner: &str,
|
||||
repo: &str,
|
||||
path: &str,
|
||||
) -> Result<Vec<u8>, GithubError> {
|
||||
http::Request::get(&format!(
|
||||
"{GITHUB_API}/repos/{owner}/{repo}/contents/{path}"
|
||||
))
|
||||
.header("Accept", "application/vnd.github.raw+json")
|
||||
.send()
|
||||
.await?
|
||||
.binary()
|
||||
.await
|
||||
.map_err(|err| err.into())
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum GithubError {
|
||||
#[error("no file returned from the given GitHub API")]
|
||||
NoSuchFile,
|
||||
#[error("failed to fetch from GitHub API")]
|
||||
RequestError(#[from] gloo::net::Error),
|
||||
#[error("file fetched from the GitHub API does not have a commit date")]
|
||||
MissingCommitDateError,
|
||||
#[error("date/time format reported for GitHub commit is invalid")]
|
||||
InvalidDateTimeError(#[from] time::error::Parse),
|
||||
}
|
Loading…
Reference in a new issue