refactor(webapi)!: put all API under path /_blah

This commit is contained in:
oxalica 2024-09-19 04:56:57 -04:00
parent ab756f78ab
commit 0c28c00c3d
5 changed files with 34 additions and 28 deletions

View file

@ -129,7 +129,7 @@ impl AppState {
type ArcState = State<Arc<AppState>>; type ArcState = State<Arc<AppState>>;
pub fn router(st: Arc<AppState>) -> Router { pub fn router(st: Arc<AppState>) -> Router {
Router::new() let router = Router::new()
.route("/ws", get(handle_ws)) .route("/ws", get(handle_ws))
.route("/user/me", get(user_get).post(user_register)) .route("/user/me", get(user_get).post(user_register))
.route("/room", get(room_list)) .route("/room", get(room_list))
@ -153,7 +153,8 @@ pub fn router(st: Arc<AppState>) -> Router {
HeaderName::from_static(X_BLAH_DIFFICULTY), HeaderName::from_static(X_BLAH_DIFFICULTY),
]), ]),
) )
.with_state(st) .with_state(st);
Router::new().nest("/_blah", router)
} }
type RE<T> = R<T, ApiError>; type RE<T> = R<T, ApiError>;

View file

@ -95,8 +95,9 @@ fn socket_activate() {
} }
let resp = rt.block_on(async { let resp = rt.block_on(async {
let url = format!("http://127.0.0.1:{local_port}/_blah/room?filter=public");
let fut = async { let fut = async {
reqwest::get(format!("http://127.0.0.1:{local_port}/room?filter=public")) reqwest::get(url)
.await .await
.unwrap() .unwrap()
.error_for_status() .error_for_status()

View file

@ -130,7 +130,11 @@ struct Server {
impl Server { impl Server {
fn url(&self, rhs: impl fmt::Display) -> String { fn url(&self, rhs: impl fmt::Display) -> String {
format!("http://{}:{}{}", LOCALHOST, self.port, rhs) format!("{}/_blah{}", self.domain(), rhs)
}
fn domain(&self) -> String {
format!("http://{}:{}", LOCALHOST, self.port)
} }
fn rng(&self) -> impl DerefMut<Target = impl RngCore> + use<'_> { fn rng(&self) -> impl DerefMut<Target = impl RngCore> + use<'_> {
@ -881,7 +885,7 @@ async fn register(server: Server) {
register_fast(&req) register_fast(&req)
.await .await
.expect_api_err(StatusCode::BAD_REQUEST, "invalid_server_url"); .expect_api_err(StatusCode::BAD_REQUEST, "invalid_server_url");
req.server_url = server.url("").parse().unwrap(); req.server_url = server.domain().parse().unwrap();
register_fast(&req) register_fast(&req)
.await .await

View file

@ -6,7 +6,7 @@ info:
paths: paths:
# OAPI does not support WebSocket interface definitions. # OAPI does not support WebSocket interface definitions.
# See: https://github.com/OAI/OpenAPI-Specification/issues/55#issuecomment-929382279 # See: https://github.com/OAI/OpenAPI-Specification/issues/55#issuecomment-929382279
/ws: /_blah/ws:
get: get:
summary: WebSocket endpoint summary: WebSocket endpoint
description: | description: |
@ -46,7 +46,7 @@ paths:
schema: schema:
$ref: '#/components/schemas/WSServerToClient' $ref: '#/components/schemas/WSServerToClient'
/user/me: /_blah/user/me:
get: get:
summary: Check registration status of the current user summary: Check registration status of the current user
parameters: parameters:
@ -131,7 +131,7 @@ paths:
schema: schema:
$ref: '#/components/schemas/ApiError' $ref: '#/components/schemas/ApiError'
/room: /_blah/room:
get: get:
summary: List rooms summary: List rooms
parameters: parameters:
@ -190,7 +190,7 @@ paths:
schema: schema:
$ref: '#/components/schemas/ApiError' $ref: '#/components/schemas/ApiError'
/room/create: /_blah/room/create:
post: post:
summary: Create a room summary: Create a room
@ -238,7 +238,7 @@ paths:
schema: schema:
$ref: '#/components/schemas/ApiError' $ref: '#/components/schemas/ApiError'
/room/{rid}: /_blah/room/{rid}:
get: get:
summary: Get room metadata summary: Get room metadata
parameters: parameters:
@ -264,7 +264,7 @@ paths:
schema: schema:
$ref: '#/components/schemas/ApiError' $ref: '#/components/schemas/ApiError'
/room/{rid}/admin: /_blah/room/{rid}/admin:
post: post:
summary: Room management summary: Room management
@ -295,7 +295,7 @@ paths:
schema: schema:
$ref: '#/components/schemas/ApiError' $ref: '#/components/schemas/ApiError'
/room/{rid}/feed.json: /_blah/room/{rid}/feed.json:
get: get:
summary: Get JSON feed of room summary: Get JSON feed of room
description: | description: |
@ -316,7 +316,7 @@ paths:
schema: schema:
$ref: '#/components/schemas/ApiError' $ref: '#/components/schemas/ApiError'
/room/{rid}/msg: /_blah/room/{rid}/msg:
get: get:
summary: List messages in a room summary: List messages in a room
description: | description: |
@ -395,7 +395,7 @@ paths:
schema: schema:
$ref: '#/components/schemas/ApiError' $ref: '#/components/schemas/ApiError'
/room/{rid}/msg/{cid}/seen: /_blah/room/{rid}/msg/{cid}/seen:
post: post:
summary: Mark a message seen summary: Mark a message seen
description: | description: |

View file

@ -6,7 +6,7 @@ const roomsInput = document.querySelector('#rooms');
const joinNewRoomInput = document.querySelector('#join-new-room'); const joinNewRoomInput = document.querySelector('#join-new-room');
const chatInput = document.querySelector('#chat'); const chatInput = document.querySelector('#chat');
let serverUrl = null; let apiUrl = null;
let curRoom = null; let curRoom = null;
let ws = null; let ws = null;
let keypair = null; let keypair = null;
@ -117,19 +117,19 @@ async function register() {
const idUrl = prompt('id_url:', defaultConfig.id_url || ''); const idUrl = prompt('id_url:', defaultConfig.id_url || '');
if (idUrl === null) return; if (idUrl === null) return;
const getResp = await fetch(`${serverUrl}/user/me`, { const getResp = await fetch(`${apiUrl}/user/me`, {
cache: 'no-store' cache: 'no-store'
}) })
console.log(getResp.headers); console.log(getResp.headers);
const challenge = getResp.headers.get('x-blah-nonce'); const challenge = getResp.headers.get('x-blah-nonce');
if (challenge === null) throw new Error('cannot get challenge nonce'); if (challenge === null) throw new Error('cannot get challenge nonce');
const postResp = await signAndPost(`${serverUrl}/user/me`, { const postResp = await signAndPost(`${apiUrl}/user/me`, {
// sorted fields. // sorted fields.
challenge_nonce: parseInt(challenge), challenge_nonce: parseInt(challenge),
id_key: getIdPubkey(), id_key: getIdPubkey(),
id_url: norm(idUrl), id_url: norm(idUrl),
server_url: norm(serverUrl), server_url: norm(apiUrl),
typ: 'user_register', typ: 'user_register',
}) })
if (!postResp.ok) throw new Error(`status ${getResp.status}: ${(await getResp.json()).error.message}`); if (!postResp.ok) throw new Error(`status ${getResp.status}: ${(await getResp.json()).error.message}`);
@ -219,7 +219,7 @@ async function enterRoom(rid) {
roomsInput.value = rid; roomsInput.value = rid;
genAuthHeader() genAuthHeader()
.then(opts => fetch(`${serverUrl}/room/${rid}`, opts)) .then(opts => fetch(`${apiUrl}/room/${rid}`, opts))
.then(async (resp) => [resp.status, await resp.json()]) .then(async (resp) => [resp.status, await resp.json()])
.then(async ([status, json]) => { .then(async ([status, json]) => {
if (status !== 200) throw new Error(`status ${status}: ${json.error.message}`); if (status !== 200) throw new Error(`status ${status}: ${json.error.message}`);
@ -230,7 +230,7 @@ async function enterRoom(rid) {
}); });
genAuthHeader() genAuthHeader()
.then(opts => fetch(`${serverUrl}/room/${rid}/msg`, opts)) .then(opts => fetch(`${apiUrl}/room/${rid}/msg`, opts))
.then(async (resp) => { return [resp.status, await resp.json()]; }) .then(async (resp) => { return [resp.status, await resp.json()]; })
.then(async ([status, json]) => { .then(async ([status, json]) => {
if (status !== 200) throw new Error(`status ${status}: ${json.error.message}`); if (status !== 200) throw new Error(`status ${status}: ${json.error.message}`);
@ -256,7 +256,7 @@ async function connectServer(newServerUrl) {
log(`invalid url: ${e}`); log(`invalid url: ${e}`);
return; return;
} }
serverUrl = newServerUrl; apiUrl = wsUrl.toString() + '_blah';
if (ws !== null) { if (ws !== null) {
ws.close(); ws.close();
@ -264,12 +264,12 @@ async function connectServer(newServerUrl) {
log('connecting server'); log('connecting server');
wsUrl.protocol = wsUrl.protocol == 'http:' ? 'ws:' : 'wss:'; wsUrl.protocol = wsUrl.protocol == 'http:' ? 'ws:' : 'wss:';
wsUrl.pathname += wsUrl.pathname.endsWith('/') ? 'ws' : '/ws'; wsUrl.pathname += '_blah/ws';
ws = new WebSocket(wsUrl); ws = new WebSocket(wsUrl);
ws.onopen = async (_) => { ws.onopen = async (_) => {
const auth = await signData({ typ: 'auth' }); const auth = await signData({ typ: 'auth' });
await ws.send(auth); await ws.send(auth);
log(`listening events on server: ${serverUrl}`); log(`listening events on server: ${newServerUrl}`);
} }
ws.onclose = (e) => { ws.onclose = (e) => {
console.error(e); console.error(e);
@ -310,7 +310,7 @@ async function loadRoomList(autoJoin) {
targetEl.value = ''; targetEl.value = '';
try { try {
const resp = await fetch(`${serverUrl}/room?filter=${filter}`, await genAuthHeader()) const resp = await fetch(`${apiUrl}/room?filter=${filter}`, await genAuthHeader())
const json = await resp.json() const json = await resp.json()
if (resp.status !== 200) throw new Error(`status ${resp.status}: ${json.error.message}`); if (resp.status !== 200) throw new Error(`status ${resp.status}: ${json.error.message}`);
for (const { rid, title, attrs, last_msg, last_seen_cid } of json.rooms) { for (const { rid, title, attrs, last_msg, last_seen_cid } of json.rooms) {
@ -343,7 +343,7 @@ async function loadRoomList(autoJoin) {
async function joinRoom(rid) { async function joinRoom(rid) {
try { try {
joinNewRoomInput.disabled = true; joinNewRoomInput.disabled = true;
await signAndPost(`${serverUrl}/room/${rid}/admin`, { await signAndPost(`${apiUrl}/room/${rid}/admin`, {
// sorted fields. // sorted fields.
permission: 1, // POST_CHAT permission: 1, // POST_CHAT
room: rid, room: rid,
@ -363,7 +363,7 @@ async function joinRoom(rid) {
async function leaveRoom() { async function leaveRoom() {
try { try {
await signAndPost(`${serverUrl}/room/${curRoom}/admin`, { await signAndPost(`${apiUrl}/room/${curRoom}/admin`, {
room: curRoom, room: curRoom,
typ: 'remove_member', typ: 'remove_member',
user: await getActPubkey(), user: await getActPubkey(),
@ -428,7 +428,7 @@ async function postChat(text) {
} else { } else {
richText = [text]; richText = [text];
} }
await signAndPost(`${serverUrl}/room/${curRoom}/msg`, { await signAndPost(`${apiUrl}/room/${curRoom}/msg`, {
// sorted fields. // sorted fields.
rich_text: richText, rich_text: richText,
room: curRoom, room: curRoom,
@ -445,7 +445,7 @@ async function postChat(text) {
async function markSeen() { async function markSeen() {
try { try {
const resp = await fetch(`${serverUrl}/room/${curRoom}/msg/${lastCid}/seen`, { const resp = await fetch(`${apiUrl}/room/${curRoom}/msg/${lastCid}/seen`, {
method: 'POST', method: 'POST',
headers: (await genAuthHeader()).headers, headers: (await genAuthHeader()).headers,
}) })