+9
-1
slingshot/src/main.rs
+9
-1
slingshot/src/main.rs
···
23
/// where to keep disk caches
24
#[arg(long)]
25
cache_dir: PathBuf,
26
}
27
28
#[tokio::main]
···
78
let server_shutdown = shutdown.clone();
79
let server_cache_handle = cache.clone();
80
tasks.spawn(async move {
81
-
serve(server_cache_handle, repo, server_shutdown).await?;
82
Ok(())
83
});
84
···
23
/// where to keep disk caches
24
#[arg(long)]
25
cache_dir: PathBuf,
26
+
/// the domain pointing to this server
27
+
///
28
+
/// if present:
29
+
/// - a did:web document will be served at /.well-known/did.json
30
+
/// - TODO: HTTPS certs will be automatically configured with Acme/letsencrypt
31
+
/// - TODO: a rate-limiter will be installed
32
+
#[arg(long)]
33
+
host: Option<String>,
34
}
35
36
#[tokio::main]
···
86
let server_shutdown = shutdown.clone();
87
let server_cache_handle = cache.clone();
88
tasks.spawn(async move {
89
+
serve(server_cache_handle, repo, args.host, server_shutdown).await?;
90
Ok(())
91
});
92
+39
-2
slingshot/src/server.rs
+39
-2
slingshot/src/server.rs
···
1
use crate::{CachedRecord, Repo, error::ServerError};
2
use foyer::HybridCache;
3
use std::sync::Arc;
4
use tokio_util::sync::CancellationToken;
5
6
-
use poem::{Route, Server, listener::TcpListener};
7
use poem_openapi::{
8
ApiResponse, Object, OpenApi, OpenApiService, param::Query, payload::Json, types::Example,
9
};
···
191
// those are a little bit important
192
}
193
194
pub async fn serve(
195
cache: HybridCache<String, CachedRecord>,
196
repo: Repo,
197
_shutdown: CancellationToken,
198
) -> Result<(), ServerError> {
199
let repo = Arc::new(repo);
···
202
.server("http://localhost:3000")
203
.url_prefix("/xrpc");
204
205
-
let app = Route::new()
206
.nest("/", api_service.scalar())
207
.nest("/openapi.json", api_service.spec_endpoint())
208
.nest("/xrpc/", api_service);
209
210
Server::new(TcpListener::bind("127.0.0.1:3000"))
211
.run(app)
···
1
use crate::{CachedRecord, Repo, error::ServerError};
2
use foyer::HybridCache;
3
+
use serde::Serialize;
4
use std::sync::Arc;
5
use tokio_util::sync::CancellationToken;
6
7
+
use poem::{Endpoint, Route, Server, endpoint::make_sync, listener::TcpListener};
8
use poem_openapi::{
9
ApiResponse, Object, OpenApi, OpenApiService, param::Query, payload::Json, types::Example,
10
};
···
192
// those are a little bit important
193
}
194
195
+
#[derive(Debug, Clone, Serialize)]
196
+
#[serde(rename_all = "camelCase")]
197
+
struct AppViewService {
198
+
id: String,
199
+
r#type: String,
200
+
service_endpoint: String,
201
+
}
202
+
#[derive(Debug, Clone, Serialize)]
203
+
struct AppViewDoc {
204
+
id: String,
205
+
service: [AppViewService; 1],
206
+
}
207
+
/// Serve a did document for did:web for this to be an xrpc appview
208
+
///
209
+
/// No slingshot endpoints currently require auth, so it's not necessary to do
210
+
/// service proxying, however clients may wish to:
211
+
///
212
+
/// - PDS proxying offers a level of client IP anonymity from slingshot
213
+
/// - slingshot *may* implement more generous per-user rate-limits for proxied requests in the future
214
+
fn get_did_doc(host: String) -> impl Endpoint {
215
+
let doc = poem::web::Json(AppViewDoc {
216
+
id: format!("did:web:{host}"),
217
+
service: [AppViewService {
218
+
id: "#slingshot".to_string(),
219
+
r#type: "SlingshotRecordProxy".to_string(),
220
+
service_endpoint: format!("https://{host}"),
221
+
}],
222
+
});
223
+
make_sync(move |_| doc.clone())
224
+
}
225
+
226
pub async fn serve(
227
cache: HybridCache<String, CachedRecord>,
228
repo: Repo,
229
+
host: Option<String>,
230
_shutdown: CancellationToken,
231
) -> Result<(), ServerError> {
232
let repo = Arc::new(repo);
···
235
.server("http://localhost:3000")
236
.url_prefix("/xrpc");
237
238
+
let mut app = Route::new()
239
.nest("/", api_service.scalar())
240
.nest("/openapi.json", api_service.spec_endpoint())
241
.nest("/xrpc/", api_service);
242
+
243
+
if let Some(host) = host {
244
+
app = app.at("/.well-known/did.json", get_did_doc(host));
245
+
};
246
247
Server::new(TcpListener::bind("127.0.0.1:3000"))
248
.run(app)