+9
-1
slingshot/src/main.rs
+9
-1
slingshot/src/main.rs
···
23
23
/// where to keep disk caches
24
24
#[arg(long)]
25
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>,
26
34
}
27
35
28
36
#[tokio::main]
···
78
86
let server_shutdown = shutdown.clone();
79
87
let server_cache_handle = cache.clone();
80
88
tasks.spawn(async move {
81
-
serve(server_cache_handle, repo, server_shutdown).await?;
89
+
serve(server_cache_handle, repo, args.host, server_shutdown).await?;
82
90
Ok(())
83
91
});
84
92
+39
-2
slingshot/src/server.rs
+39
-2
slingshot/src/server.rs
···
1
1
use crate::{CachedRecord, Repo, error::ServerError};
2
2
use foyer::HybridCache;
3
+
use serde::Serialize;
3
4
use std::sync::Arc;
4
5
use tokio_util::sync::CancellationToken;
5
6
6
-
use poem::{Route, Server, listener::TcpListener};
7
+
use poem::{Endpoint, Route, Server, endpoint::make_sync, listener::TcpListener};
7
8
use poem_openapi::{
8
9
ApiResponse, Object, OpenApi, OpenApiService, param::Query, payload::Json, types::Example,
9
10
};
···
191
192
// those are a little bit important
192
193
}
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
+
194
226
pub async fn serve(
195
227
cache: HybridCache<String, CachedRecord>,
196
228
repo: Repo,
229
+
host: Option<String>,
197
230
_shutdown: CancellationToken,
198
231
) -> Result<(), ServerError> {
199
232
let repo = Arc::new(repo);
···
202
235
.server("http://localhost:3000")
203
236
.url_prefix("/xrpc");
204
237
205
-
let app = Route::new()
238
+
let mut app = Route::new()
206
239
.nest("/", api_service.scalar())
207
240
.nest("/openapi.json", api_service.spec_endpoint())
208
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
+
};
209
246
210
247
Server::new(TcpListener::bind("127.0.0.1:3000"))
211
248
.run(app)