upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/src/http
diff options
context:
space:
mode:
authorDanConwayDev <DanConwayDev@protonmail.com>2025-11-19 11:55:32 +0000
committerDanConwayDev <DanConwayDev@protonmail.com>2025-11-19 15:43:29 +0000
commitfa065ad128882755f2a988d6203b59a2ab5e38ff (patch)
treee8326de70a6e6ea56b5bf4250e0a00a3cda4afed /src/http
parent98c6fa4bfa897ff0b8f9c95ea698d4d065b5e9f3 (diff)
add landing page and nostr-relay-builder relay on same port
Diffstat (limited to 'src/http')
-rw-r--r--src/http/landing.rs37
-rw-r--r--src/http/mod.rs31
-rw-r--r--src/http/websocket.rs73
3 files changed, 141 insertions, 0 deletions
diff --git a/src/http/landing.rs b/src/http/landing.rs
new file mode 100644
index 0000000..35e49e5
--- /dev/null
+++ b/src/http/landing.rs
@@ -0,0 +1,37 @@
1/// Landing Page Handler
2///
3/// Serves the HTML landing page or upgrades to WebSocket for Nostr relay connections.
4
5use actix_web::{web, HttpRequest, HttpResponse, Result};
6use nostr_relay_builder::LocalRelay;
7
8use crate::config::Config;
9
10/// Handle landing page or WebSocket upgrade
11pub async fn handle(
12 req: HttpRequest,
13 stream: web::Payload,
14 config: web::Data<Config>,
15 relay: web::Data<LocalRelay>,
16) -> Result<HttpResponse> {
17 // Check if this is a WebSocket upgrade request
18 if let Some(upgrade) = req.headers().get("upgrade") {
19 if upgrade.to_str().unwrap_or("").eq_ignore_ascii_case("websocket") {
20 // Delegate to WebSocket handler
21 return crate::http::websocket::handle(req, stream, relay).await;
22 }
23 }
24
25 // Otherwise, serve the landing page
26 let html = format!(
27 include_str!("../../templates/landing.html"),
28 relay_name = config.relay_name,
29 relay_description = config.relay_description,
30 domain = config.domain,
31 bind_address = config.bind_address,
32 );
33
34 Ok(HttpResponse::Ok()
35 .content_type("text/html; charset=utf-8")
36 .body(html))
37} \ No newline at end of file
diff --git a/src/http/mod.rs b/src/http/mod.rs
new file mode 100644
index 0000000..286e8ff
--- /dev/null
+++ b/src/http/mod.rs
@@ -0,0 +1,31 @@
1/// HTTP Server Module
2///
3/// Provides actix-web HTTP server with WebSocket upgrade support for the Nostr relay.
4
5pub mod landing;
6pub mod websocket;
7
8use actix_web::{middleware, web, App, HttpServer};
9use nostr_relay_builder::LocalRelay;
10
11use crate::config::Config;
12
13/// Start the HTTP server with integrated Nostr relay
14pub async fn run_server(config: Config, relay: LocalRelay) -> anyhow::Result<()> {
15 let bind_addr = config.bind_address.clone();
16
17 tracing::info!("Starting HTTP server on {}", bind_addr);
18
19 HttpServer::new(move || {
20 App::new()
21 .app_data(web::Data::new(config.clone()))
22 .app_data(web::Data::new(relay.clone()))
23 .wrap(middleware::Logger::default())
24 .route("/", web::get().to(landing::handle))
25 })
26 .bind(&bind_addr)?
27 .run()
28 .await?;
29
30 Ok(())
31} \ No newline at end of file
diff --git a/src/http/websocket.rs b/src/http/websocket.rs
new file mode 100644
index 0000000..7af847a
--- /dev/null
+++ b/src/http/websocket.rs
@@ -0,0 +1,73 @@
1/// WebSocket Handler
2///
3/// Handles WebSocket upgrade requests and passes connections to the Nostr relay.
4
5use actix_web::{web, HttpRequest, HttpResponse, Result, Error};
6use actix_ws::Message;
7use futures_util::StreamExt;
8use nostr_relay_builder::LocalRelay;
9
10/// Handle WebSocket upgrade and relay connection
11pub async fn handle(
12 req: HttpRequest,
13 stream: web::Payload,
14 relay: web::Data<LocalRelay>,
15) -> Result<HttpResponse, Error> {
16 let (response, mut session, mut msg_stream) = actix_ws::handle(&req, stream)?;
17
18 let peer_addr = req.peer_addr()
19 .unwrap_or_else(|| "0.0.0.0:0".parse().unwrap());
20
21 tracing::debug!("WebSocket connection from {}", peer_addr);
22
23 // Spawn task to handle the WebSocket connection
24 // TODO: Will use relay.take_connection() for full Nostr relay integration
25 let _relay = relay.get_ref().clone();
26 actix_web::rt::spawn(async move {
27 // Create a channel to communicate between actix-ws and relay
28 let (tx, mut rx) = tokio::sync::mpsc::unbounded_channel();
29
30 // Spawn task to send messages from relay to client
31 let mut session_clone = session.clone();
32 actix_web::rt::spawn(async move {
33 while let Some(msg) = rx.recv().await {
34 if session_clone.text(msg).await.is_err() {
35 break;
36 }
37 }
38 });
39
40 // Handle incoming messages from client
41 while let Some(Ok(msg)) = msg_stream.next().await {
42 match msg {
43 Message::Text(text) => {
44 // For now, just echo back - will integrate with relay in next phase
45 tracing::debug!("Received text message: {}", text);
46 if let Err(e) = tx.send(text.to_string()) {
47 tracing::error!("Failed to send message: {}", e);
48 break;
49 }
50 }
51 Message::Binary(_) => {
52 tracing::warn!("Received unexpected binary message");
53 }
54 Message::Close(_) => {
55 tracing::debug!("Client closed connection");
56 break;
57 }
58 Message::Ping(bytes) => {
59 if session.pong(&bytes).await.is_err() {
60 break;
61 }
62 }
63 Message::Pong(_) => {}
64 Message::Continuation(_) => {}
65 Message::Nop => {}
66 }
67 }
68
69 tracing::debug!("WebSocket connection closed for {}", peer_addr);
70 });
71
72 Ok(response)
73} \ No newline at end of file