Compare commits
16 Commits
letterbox-
...
letterbox-
| Author | SHA1 | Date | |
|---|---|---|---|
| 122e949072 | |||
| 9a69b4c51e | |||
| 251151244b | |||
| 9d232b666b | |||
| 1832d77e78 | |||
| aca6bce1ff | |||
| 7bb2f405da | |||
| 60e2824167 | |||
| cffc228b3a | |||
| 318c366d82 | |||
| 90d7f79ca0 | |||
| 3f87038776 | |||
| 92b880f03b | |||
| 94f1e84857 | |||
| 221b4f10df | |||
| 225615f4ea |
119
Cargo.lock
generated
119
Cargo.lock
generated
@@ -81,6 +81,56 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstream"
|
||||||
|
version = "0.6.18"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b"
|
||||||
|
dependencies = [
|
||||||
|
"anstyle",
|
||||||
|
"anstyle-parse",
|
||||||
|
"anstyle-query",
|
||||||
|
"anstyle-wincon",
|
||||||
|
"colorchoice",
|
||||||
|
"is_terminal_polyfill",
|
||||||
|
"utf8parse",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle"
|
||||||
|
version = "1.0.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle-parse"
|
||||||
|
version = "0.2.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9"
|
||||||
|
dependencies = [
|
||||||
|
"utf8parse",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle-query"
|
||||||
|
version = "1.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c"
|
||||||
|
dependencies = [
|
||||||
|
"windows-sys 0.59.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle-wincon"
|
||||||
|
version = "3.0.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e"
|
||||||
|
dependencies = [
|
||||||
|
"anstyle",
|
||||||
|
"once_cell",
|
||||||
|
"windows-sys 0.59.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anyhow"
|
name = "anyhow"
|
||||||
version = "1.0.98"
|
version = "1.0.98"
|
||||||
@@ -811,6 +861,46 @@ dependencies = [
|
|||||||
"windows-link",
|
"windows-link",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap"
|
||||||
|
version = "4.5.36"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2df961d8c8a0d08aa9945718ccf584145eee3f3aa06cddbeac12933781102e04"
|
||||||
|
dependencies = [
|
||||||
|
"clap_builder",
|
||||||
|
"clap_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_builder"
|
||||||
|
version = "4.5.36"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "132dbda40fb6753878316a489d5a1242a8ef2f0d9e47ba01c951ea8aa7d013a5"
|
||||||
|
dependencies = [
|
||||||
|
"anstream",
|
||||||
|
"anstyle",
|
||||||
|
"clap_lex",
|
||||||
|
"strsim 0.11.1",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_derive"
|
||||||
|
version = "4.5.32"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "09176aae279615badda0765c0c0b3f6ed53f4709118af73cf4655d85d1530cd7"
|
||||||
|
dependencies = [
|
||||||
|
"heck 0.5.0",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.100",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_lex"
|
||||||
|
version = "0.7.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cloudabi"
|
name = "cloudabi"
|
||||||
version = "0.0.3"
|
version = "0.0.3"
|
||||||
@@ -820,6 +910,12 @@ dependencies = [
|
|||||||
"bitflags 1.3.2",
|
"bitflags 1.3.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "colorchoice"
|
||||||
|
version = "1.0.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "combine"
|
name = "combine"
|
||||||
version = "4.6.7"
|
version = "4.6.7"
|
||||||
@@ -2831,6 +2927,12 @@ version = "2.11.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130"
|
checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "is_terminal_polyfill"
|
||||||
|
version = "1.70.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itertools"
|
name = "itertools"
|
||||||
version = "0.14.0"
|
version = "0.14.0"
|
||||||
@@ -2893,7 +2995,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "letterbox-notmuch"
|
name = "letterbox-notmuch"
|
||||||
version = "0.15.0"
|
version = "0.15.7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"itertools",
|
"itertools",
|
||||||
"log",
|
"log",
|
||||||
@@ -2908,14 +3010,14 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "letterbox-procmail2notmuch"
|
name = "letterbox-procmail2notmuch"
|
||||||
version = "0.15.0"
|
version = "0.15.7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "letterbox-server"
|
name = "letterbox-server"
|
||||||
version = "0.15.0"
|
version = "0.15.7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ammonia",
|
"ammonia",
|
||||||
"anyhow",
|
"anyhow",
|
||||||
@@ -2928,6 +3030,7 @@ dependencies = [
|
|||||||
"build-info-build",
|
"build-info-build",
|
||||||
"cacher",
|
"cacher",
|
||||||
"chrono",
|
"chrono",
|
||||||
|
"clap",
|
||||||
"css-inline",
|
"css-inline",
|
||||||
"futures 0.3.31",
|
"futures 0.3.31",
|
||||||
"headers",
|
"headers",
|
||||||
@@ -2958,7 +3061,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "letterbox-shared"
|
name = "letterbox-shared"
|
||||||
version = "0.15.0"
|
version = "0.15.7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"build-info",
|
"build-info",
|
||||||
"letterbox-notmuch",
|
"letterbox-notmuch",
|
||||||
@@ -2968,7 +3071,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "letterbox-web"
|
name = "letterbox-web"
|
||||||
version = "0.15.0"
|
version = "0.15.7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"build-info",
|
"build-info",
|
||||||
"build-info-build",
|
"build-info-build",
|
||||||
@@ -6816,6 +6919,12 @@ version = "1.0.4"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
|
checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "utf8parse"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uuid"
|
name = "uuid"
|
||||||
version = "1.16.0"
|
version = "1.16.0"
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ authors = ["Bill Thiede <git@xinu.tv>"]
|
|||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "UNLICENSED"
|
license = "UNLICENSED"
|
||||||
publish = ["xinu"]
|
publish = ["xinu"]
|
||||||
version = "0.15.0"
|
version = "0.15.7"
|
||||||
repository = "https://git.z.xinu.tv/wathiede/letterbox"
|
repository = "https://git.z.xinu.tv/wathiede/letterbox"
|
||||||
|
|
||||||
[profile.dev]
|
[profile.dev]
|
||||||
|
|||||||
2
dev.sh
2
dev.sh
@@ -3,5 +3,5 @@ tmux new-session -d -s letterbox-dev
|
|||||||
tmux rename-window web
|
tmux rename-window web
|
||||||
tmux send-keys "cd web; trunk serve -w ../.git -w ../shared -w ../notmuch -w ./" C-m
|
tmux send-keys "cd web; trunk serve -w ../.git -w ../shared -w ../notmuch -w ./" C-m
|
||||||
tmux new-window -n server
|
tmux new-window -n server
|
||||||
tmux send-keys "cd server; cargo watch -c -x run -w ../.git -w ../shared -w ../notmuch -w ./" C-m
|
tmux send-keys "cd server; cargo watch -c -w ../.git -w ../shared -w ../notmuch -w ./ -x 'run postgres://newsreader@nixos-07.h.xinu.tv/newsreader ../target/database/newsreader /tmp/letterbox/slurp'" C-m
|
||||||
tmux attach -d -t letterbox-dev
|
tmux attach -d -t letterbox-dev
|
||||||
|
|||||||
@@ -22,12 +22,13 @@ axum-macros = "0.5.0"
|
|||||||
build-info = "0.0.40"
|
build-info = "0.0.40"
|
||||||
cacher = { version = "0.2.0", registry = "xinu" }
|
cacher = { version = "0.2.0", registry = "xinu" }
|
||||||
chrono = "0.4.39"
|
chrono = "0.4.39"
|
||||||
|
clap = { version = "4.5.36", features = ["derive"] }
|
||||||
css-inline = "0.14.0"
|
css-inline = "0.14.0"
|
||||||
futures = "0.3.31"
|
futures = "0.3.31"
|
||||||
headers = "0.4.0"
|
headers = "0.4.0"
|
||||||
html-escape = "0.2.13"
|
html-escape = "0.2.13"
|
||||||
letterbox-notmuch = { version = "0.15.0", path = "../notmuch", registry = "xinu" }
|
letterbox-notmuch = { version = "0.15.7", path = "../notmuch", registry = "xinu" }
|
||||||
letterbox-shared = { version = "0.15.0", path = "../shared", registry = "xinu" }
|
letterbox-shared = { version = "0.15.7", path = "../shared", registry = "xinu" }
|
||||||
linkify = "0.10.0"
|
linkify = "0.10.0"
|
||||||
log = "0.4.17"
|
log = "0.4.17"
|
||||||
lol_html = "2.0.0"
|
lol_html = "2.0.0"
|
||||||
|
|||||||
@@ -8,23 +8,24 @@ use async_graphql_axum::{GraphQL, GraphQLSubscription};
|
|||||||
//allows to extract the IP of connecting user
|
//allows to extract the IP of connecting user
|
||||||
use axum::extract::connect_info::ConnectInfo;
|
use axum::extract::connect_info::ConnectInfo;
|
||||||
use axum::{
|
use axum::{
|
||||||
extract::{self, ws::WebSocketUpgrade, State},
|
extract::{self, ws::WebSocketUpgrade, Query, State},
|
||||||
http::{header, StatusCode},
|
http::{header, StatusCode},
|
||||||
response::{self, IntoResponse, Response},
|
response::{self, IntoResponse, Response},
|
||||||
routing::{any, get},
|
routing::{any, get, post},
|
||||||
Router,
|
Router,
|
||||||
};
|
};
|
||||||
use cacher::FilesystemCacher;
|
use cacher::FilesystemCacher;
|
||||||
|
use clap::Parser;
|
||||||
use letterbox_notmuch::Notmuch;
|
use letterbox_notmuch::Notmuch;
|
||||||
#[cfg(feature = "tantivy")]
|
#[cfg(feature = "tantivy")]
|
||||||
use letterbox_server::tantivy::TantivyConnection;
|
use letterbox_server::tantivy::TantivyConnection;
|
||||||
use letterbox_server::{
|
use letterbox_server::{
|
||||||
config::Config,
|
|
||||||
graphql::{compute_catchup_ids, Attachment, MutationRoot, QueryRoot, SubscriptionRoot},
|
graphql::{compute_catchup_ids, Attachment, MutationRoot, QueryRoot, SubscriptionRoot},
|
||||||
nm::{attachment_bytes, cid_attachment_bytes},
|
nm::{attachment_bytes, cid_attachment_bytes},
|
||||||
ws::ConnectionTracker,
|
ws::ConnectionTracker,
|
||||||
};
|
};
|
||||||
use letterbox_shared::WebsocketMessage;
|
use letterbox_shared::WebsocketMessage;
|
||||||
|
use serde::Deserialize;
|
||||||
use sqlx::postgres::PgPool;
|
use sqlx::postgres::PgPool;
|
||||||
use tokio::{net::TcpListener, sync::Mutex};
|
use tokio::{net::TcpListener, sync::Mutex};
|
||||||
use tower_http::trace::{DefaultMakeSpan, TraceLayer};
|
use tower_http::trace::{DefaultMakeSpan, TraceLayer};
|
||||||
@@ -157,20 +158,33 @@ async fn start_ws(
|
|||||||
connection_tracker, ..
|
connection_tracker, ..
|
||||||
}): State<AppState>,
|
}): State<AppState>,
|
||||||
) -> impl IntoResponse {
|
) -> impl IntoResponse {
|
||||||
|
info!("intiating websocket connection for {addr}");
|
||||||
ws.on_upgrade(async move |socket| connection_tracker.lock().await.add_peer(socket, addr).await)
|
ws.on_upgrade(async move |socket| connection_tracker.lock().await.add_peer(socket, addr).await)
|
||||||
}
|
}
|
||||||
#[axum_macros::debug_handler]
|
|
||||||
async fn test_handler(
|
#[derive(Debug, Deserialize)]
|
||||||
|
struct NotificationParams {
|
||||||
|
delay_ms: Option<u64>,
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn send_refresh_websocket_handler(
|
||||||
State(AppState {
|
State(AppState {
|
||||||
connection_tracker, ..
|
connection_tracker, ..
|
||||||
}): State<AppState>,
|
}): State<AppState>,
|
||||||
|
params: Query<NotificationParams>,
|
||||||
) -> impl IntoResponse {
|
) -> impl IntoResponse {
|
||||||
|
info!("send_refresh_websocket_handler params {params:?}");
|
||||||
|
if let Some(delay_ms) = params.delay_ms {
|
||||||
|
let delay = Duration::from_millis(delay_ms);
|
||||||
|
info!("sleeping {delay:?}");
|
||||||
|
tokio::time::sleep(delay).await;
|
||||||
|
}
|
||||||
connection_tracker
|
connection_tracker
|
||||||
.lock()
|
.lock()
|
||||||
.await
|
.await
|
||||||
.send_message_all(WebsocketMessage::RefreshMessages)
|
.send_message_all(WebsocketMessage::RefreshMessages)
|
||||||
.await;
|
.await;
|
||||||
"test triggered"
|
"refresh triggered"
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn watch_new(
|
async fn watch_new(
|
||||||
@@ -201,29 +215,33 @@ struct AppState {
|
|||||||
connection_tracker: Arc<Mutex<ConnectionTracker>>,
|
connection_tracker: Arc<Mutex<ConnectionTracker>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Parser)]
|
||||||
|
#[command(version, about, long_about = None)]
|
||||||
|
struct Cli {
|
||||||
|
#[arg(short, long, default_value = "0.0.0.0:9345")]
|
||||||
|
addr: SocketAddr,
|
||||||
|
newsreader_database_url: String,
|
||||||
|
newsreader_tantivy_db_path: String,
|
||||||
|
slurp_cache_path: String,
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> Result<(), Box<dyn Error>> {
|
async fn main() -> Result<(), Box<dyn Error>> {
|
||||||
|
let cli = Cli::parse();
|
||||||
let _guard = xtracing::init(env!("CARGO_BIN_NAME"))?;
|
let _guard = xtracing::init(env!("CARGO_BIN_NAME"))?;
|
||||||
build_info::build_info!(fn bi);
|
build_info::build_info!(fn bi);
|
||||||
info!("Build Info: {}", letterbox_shared::build_version(bi));
|
info!("Build Info: {}", letterbox_shared::build_version(bi));
|
||||||
// TODO: move these to config
|
if !std::fs::exists(&cli.slurp_cache_path)? {
|
||||||
let port = 9345;
|
info!("Creating slurp cache @ '{}'", &cli.slurp_cache_path);
|
||||||
let config = Config {
|
std::fs::create_dir_all(&cli.slurp_cache_path)?;
|
||||||
newsreader_database_url: "postgres://newsreader@nixos-07.h.xinu.tv/newsreader".to_string(),
|
|
||||||
newsreader_tantivy_db_path: "../target/database/newsreader".to_string(),
|
|
||||||
slurp_cache_path: "/tmp/letterbox/slurp".to_string(),
|
|
||||||
};
|
|
||||||
if !std::fs::exists(&config.slurp_cache_path)? {
|
|
||||||
info!("Creating slurp cache @ '{}'", &config.slurp_cache_path);
|
|
||||||
std::fs::create_dir_all(&config.slurp_cache_path)?;
|
|
||||||
}
|
}
|
||||||
let pool = PgPool::connect(&config.newsreader_database_url).await?;
|
let pool = PgPool::connect(&cli.newsreader_database_url).await?;
|
||||||
let nm = Notmuch::default();
|
let nm = Notmuch::default();
|
||||||
sqlx::migrate!("./migrations").run(&pool).await?;
|
sqlx::migrate!("./migrations").run(&pool).await?;
|
||||||
#[cfg(feature = "tantivy")]
|
#[cfg(feature = "tantivy")]
|
||||||
let tantivy_conn = TantivyConnection::new(&config.newsreader_tantivy_db_path)?;
|
let tantivy_conn = TantivyConnection::new(&cli.newsreader_tantivy_db_path)?;
|
||||||
|
|
||||||
let cacher = FilesystemCacher::new(&config.slurp_cache_path)?;
|
let cacher = FilesystemCacher::new(&cli.slurp_cache_path)?;
|
||||||
let schema = Schema::build(QueryRoot, MutationRoot, SubscriptionRoot)
|
let schema = Schema::build(QueryRoot, MutationRoot, SubscriptionRoot)
|
||||||
.data(nm.clone())
|
.data(nm.clone())
|
||||||
.data(cacher)
|
.data(cacher)
|
||||||
@@ -233,26 +251,29 @@ async fn main() -> Result<(), Box<dyn Error>> {
|
|||||||
|
|
||||||
let connection_tracker = Arc::new(Mutex::new(ConnectionTracker::default()));
|
let connection_tracker = Arc::new(Mutex::new(ConnectionTracker::default()));
|
||||||
let ct = Arc::clone(&connection_tracker);
|
let ct = Arc::clone(&connection_tracker);
|
||||||
let poll_time = Duration::from_secs(10);
|
let poll_time = Duration::from_secs(60);
|
||||||
let _h = tokio::spawn(watch_new(nm.clone(), pool, ct, poll_time));
|
let _h = tokio::spawn(watch_new(nm.clone(), pool, ct, poll_time));
|
||||||
|
|
||||||
let app = Router::new()
|
let api_routes = Router::new()
|
||||||
.route("/test", get(test_handler))
|
|
||||||
.route(
|
.route(
|
||||||
"/api/download/attachment/{id}/{idx}/{*rest}",
|
"/download/attachment/{id}/{idx}/{*rest}",
|
||||||
get(download_attachment),
|
get(download_attachment),
|
||||||
)
|
)
|
||||||
|
.route("/view/attachment/{id}/{idx}/{*rest}", get(view_attachment))
|
||||||
|
.route("/cid/{id}/{cid}", get(view_cid))
|
||||||
|
.route("/ws", any(start_ws))
|
||||||
|
.route_service("/graphql/ws", GraphQLSubscription::new(schema.clone()))
|
||||||
.route(
|
.route(
|
||||||
"/api/view/attachment/{id}/{idx}/{*rest}",
|
"/graphql/",
|
||||||
get(view_attachment),
|
|
||||||
)
|
|
||||||
.route("/api/cid/{id}/{cid}", get(view_cid))
|
|
||||||
.route("/api/ws", any(start_ws))
|
|
||||||
.route_service("/api/graphql/ws", GraphQLSubscription::new(schema.clone()))
|
|
||||||
.route(
|
|
||||||
"/api/graphql/",
|
|
||||||
get(graphiql).post_service(GraphQL::new(schema.clone())),
|
get(graphiql).post_service(GraphQL::new(schema.clone())),
|
||||||
)
|
);
|
||||||
|
|
||||||
|
let notification_routes = Router::new()
|
||||||
|
.route("/mail", post(send_refresh_websocket_handler))
|
||||||
|
.route("/news", post(send_refresh_websocket_handler));
|
||||||
|
let app = Router::new()
|
||||||
|
.nest("/api", api_routes)
|
||||||
|
.nest("/notification", notification_routes)
|
||||||
.with_state(AppState {
|
.with_state(AppState {
|
||||||
nm,
|
nm,
|
||||||
connection_tracker,
|
connection_tracker,
|
||||||
@@ -262,9 +283,7 @@ async fn main() -> Result<(), Box<dyn Error>> {
|
|||||||
.make_span_with(DefaultMakeSpan::default().include_headers(true)),
|
.make_span_with(DefaultMakeSpan::default().include_headers(true)),
|
||||||
);
|
);
|
||||||
|
|
||||||
let listener = TcpListener::bind(SocketAddr::from(([0, 0, 0, 0], port)))
|
let listener = TcpListener::bind(cli.addr).await.unwrap();
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
tracing::info!("listening on {}", listener.local_addr().unwrap());
|
tracing::info!("listening on {}", listener.local_addr().unwrap());
|
||||||
axum::serve(
|
axum::serve(
|
||||||
listener,
|
listener,
|
||||||
|
|||||||
@@ -12,6 +12,6 @@ version.workspace = true
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
build-info = "0.0.40"
|
build-info = "0.0.40"
|
||||||
letterbox-notmuch = { version = "0.15.0", path = "../notmuch", registry = "xinu" }
|
letterbox-notmuch = { version = "0.15.7", path = "../notmuch", registry = "xinu" }
|
||||||
serde = { version = "1.0.147", features = ["derive"] }
|
serde = { version = "1.0.147", features = ["derive"] }
|
||||||
strum_macros = "0.27.1"
|
strum_macros = "0.27.1"
|
||||||
|
|||||||
@@ -33,8 +33,8 @@ wasm-bindgen = "=0.2.100"
|
|||||||
uuid = { version = "1.13.1", features = [
|
uuid = { version = "1.13.1", features = [
|
||||||
"js",
|
"js",
|
||||||
] } # direct dep to set js feature, prevents Rng issues
|
] } # direct dep to set js feature, prevents Rng issues
|
||||||
letterbox-shared = { version = "0.15.0", path = "../shared", registry = "xinu" }
|
letterbox-shared = { version = "0.15.7", path = "../shared", registry = "xinu" }
|
||||||
letterbox-notmuch = { version = "0.15.0", path = "../notmuch", registry = "xinu" }
|
letterbox-notmuch = { version = "0.15.7", path = "../notmuch", registry = "xinu" }
|
||||||
seed_hooks = { version = "0.4.0", registry = "xinu" }
|
seed_hooks = { version = "0.4.0", registry = "xinu" }
|
||||||
strum_macros = "0.27.1"
|
strum_macros = "0.27.1"
|
||||||
gloo-console = "0.3.0"
|
gloo-console = "0.3.0"
|
||||||
|
|||||||
@@ -13,6 +13,9 @@ backend = "ws://localhost:9345/api/ws"
|
|||||||
[[proxy]]
|
[[proxy]]
|
||||||
backend = "http://localhost:9345/api/"
|
backend = "http://localhost:9345/api/"
|
||||||
|
|
||||||
|
[[proxy]]
|
||||||
|
backend = "http://localhost:9345/notification/"
|
||||||
|
|
||||||
[[hooks]]
|
[[hooks]]
|
||||||
stage = "pre_build"
|
stage = "pre_build"
|
||||||
command = "printf"
|
command = "printf"
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ pub fn init(url: Url, orders: &mut impl Orders<Msg>) -> Model {
|
|||||||
},
|
},
|
||||||
catchup: None,
|
catchup: None,
|
||||||
last_url: Url::current(),
|
last_url: Url::current(),
|
||||||
websocket: websocket::init(&mut orders.proxy(Msg::WebSocket)),
|
websocket: websocket::init("/api/ws", &mut orders.proxy(Msg::WebSocket)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -541,13 +541,19 @@ fn search_toolbar(
|
|||||||
tw_classes::button(),
|
tw_classes::button(),
|
||||||
IF!(!pager.has_previous_page => attrs!{ At::Disabled=>true }),
|
IF!(!pager.has_previous_page => attrs!{ At::Disabled=>true }),
|
||||||
"<",
|
"<",
|
||||||
IF!(pager.has_previous_page => ev(Ev::Click, |_| Msg::PreviousPage)),
|
IF!(pager.has_previous_page => ev(
|
||||||
|
Ev::Click, |_| Msg::MultiMsg(vec![
|
||||||
|
Msg::ScrollToTop,
|
||||||
|
Msg::PreviousPage]))),
|
||||||
],
|
],
|
||||||
button![
|
button![
|
||||||
tw_classes::button(),
|
tw_classes::button(),
|
||||||
IF!(!pager.has_next_page => attrs!{ At::Disabled=>true }),
|
IF!(!pager.has_next_page => attrs!{ At::Disabled=>true }),
|
||||||
">",
|
">",
|
||||||
IF!(pager.has_next_page => ev(Ev::Click, |_| Msg::NextPage))
|
IF!(pager.has_next_page => ev(
|
||||||
|
Ev::Click, |_| Msg::MultiMsg(vec![
|
||||||
|
Msg::ScrollToTop,
|
||||||
|
Msg::NextPage])))
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -78,13 +78,14 @@ pub struct ClientMessage {
|
|||||||
|
|
||||||
//const WS_URL: &str = "wss://9000.z.xinu.tv/api/ws";
|
//const WS_URL: &str = "wss://9000.z.xinu.tv/api/ws";
|
||||||
//const WS_URL: &str = "wss://9345.z.xinu.tv/api/graphql/ws";
|
//const WS_URL: &str = "wss://9345.z.xinu.tv/api/graphql/ws";
|
||||||
const WS_URL: &str = "wss://6758.z.xinu.tv/api/ws";
|
//const WS_URL: &str = "wss://6758.z.xinu.tv/api/ws";
|
||||||
|
|
||||||
// ------ ------
|
// ------ ------
|
||||||
// Model
|
// Model
|
||||||
// ------ ------
|
// ------ ------
|
||||||
|
|
||||||
pub struct Model {
|
pub struct Model {
|
||||||
|
ws_url: String,
|
||||||
web_socket: EventClient,
|
web_socket: EventClient,
|
||||||
web_socket_reconnector: Option<StreamHandle>,
|
web_socket_reconnector: Option<StreamHandle>,
|
||||||
pub updates: VecDeque<WebsocketMessage>,
|
pub updates: VecDeque<WebsocketMessage>,
|
||||||
@@ -94,9 +95,10 @@ pub struct Model {
|
|||||||
// Init
|
// Init
|
||||||
// ------ ------
|
// ------ ------
|
||||||
|
|
||||||
pub fn init(orders: &mut impl Orders<Msg>) -> Model {
|
pub fn init(ws_url: &str, orders: &mut impl Orders<Msg>) -> Model {
|
||||||
Model {
|
Model {
|
||||||
web_socket: create_websocket(orders).unwrap(),
|
ws_url: ws_url.to_string(),
|
||||||
|
web_socket: create_websocket(ws_url, orders).unwrap(),
|
||||||
web_socket_reconnector: None,
|
web_socket_reconnector: None,
|
||||||
updates: VecDeque::new(),
|
updates: VecDeque::new(),
|
||||||
}
|
}
|
||||||
@@ -155,7 +157,7 @@ Reason: {2}
|
|||||||
}
|
}
|
||||||
Msg::ReconnectWebSocket(retries) => {
|
Msg::ReconnectWebSocket(retries) => {
|
||||||
info!("Reconnect attempt: {}", retries);
|
info!("Reconnect attempt: {}", retries);
|
||||||
model.web_socket = create_websocket(orders).unwrap();
|
model.web_socket = create_websocket(&model.ws_url, orders).unwrap();
|
||||||
}
|
}
|
||||||
Msg::SendMessage(msg) => {
|
Msg::SendMessage(msg) => {
|
||||||
let txt = serde_json::to_string(&msg).unwrap();
|
let txt = serde_json::to_string(&msg).unwrap();
|
||||||
@@ -164,10 +166,10 @@ Reason: {2}
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_websocket(orders: &impl Orders<Msg>) -> Result<EventClient, WebSocketError> {
|
fn create_websocket(url: &str, orders: &impl Orders<Msg>) -> Result<EventClient, WebSocketError> {
|
||||||
let msg_sender = orders.msg_sender();
|
let msg_sender = orders.msg_sender();
|
||||||
|
|
||||||
let mut client = EventClient::new(WS_URL)?;
|
let mut client = EventClient::new(url)?;
|
||||||
|
|
||||||
client.set_on_error(Some(Box::new(|error| {
|
client.set_on_error(Some(Box::new(|error| {
|
||||||
gloo_console::error!("WS: ", error);
|
gloo_console::error!("WS: ", error);
|
||||||
|
|||||||
Reference in New Issue
Block a user