Skip to content

Commit

Permalink
feat: add dynamic traefik config.
Browse files Browse the repository at this point in the history
  • Loading branch information
zicklag committed Jul 2, 2024
1 parent 7884767 commit 3ff64d9
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 9 deletions.
2 changes: 2 additions & 0 deletions .env.local
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ SMTP_SECURE="false"
SMTP_USER="dummy"
SMTP_PASS="dummy"

TRAEFIK_CONFIG_SERVICE_NAME="srv-weird@docker"
TRAEFIK_CONFIG_NAMESPACE="weird-one-dynamic-config"
PUBLIC_TRAEFIK_CONFIG_HOST="127.0.0.1:9523"

FEEDBACK_WEBHOOK=""
Expand Down
23 changes: 20 additions & 3 deletions backend/src/routes/profile.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,28 @@
use std::str::FromStr;
use std::{collections::HashMap, str::FromStr};

use axum::{
extract::{DefaultBodyLimit, Multipart},
response::Response,
routing::delete,
};
use futures::{pin_mut, StreamExt};
use weird::profile::{Profile, Username};
use weird::{
db::StringSerde, iroh::docs::AuthorId, profile::{Profile, Username}
};

use crate::ARGS;

use super::*;

pub fn install(router: Router<AppState>) -> Router<AppState> {
router
.route("/usernames", get(get_usernames))
.route("/profiles", get(get_profiles))
.route("/profile/username/:username", get(get_profile_by_name))
.route("/profile/username/:username/avatar", get(get_profile_avatar_by_name))
.route(
"/profile/username/:username/avatar",
get(get_profile_avatar_by_name),
)
.route("/profile/:user_id/avatar", get(get_profile_avatar))
.route(
"/profile/:user_id/avatar",
Expand All @@ -27,6 +33,17 @@ pub fn install(router: Router<AppState>) -> Router<AppState> {
.route("/profile/:user_id", delete(delete_profile))
}

async fn get_usernames(state: State<AppState>) -> AppResult<Json<HashMap<String, StringSerde<AuthorId>>>> {
let mut usernames = HashMap::default();
let stream = state.weird.get_usernames().await?;
pin_mut!(stream);
while let Some(result) = stream.next().await {
let (username, author_id) = result?;
usernames.insert(username, author_id.into());
}
Ok(Json(usernames))
}

async fn get_profiles(state: State<AppState>) -> AppResult<Json<Vec<Profile>>> {
let mut profiles = Vec::new();
let stream = state.weird.profiles().await?;
Expand Down
5 changes: 5 additions & 0 deletions backend/weird/src/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,11 @@ mod ser_de {
/// String-based serialize/deserialize wrapper.
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct StringSerde<T>(pub T);
impl<T> From<T> for StringSerde<T> {
fn from(value: T) -> Self {
Self(value)
}
}
impl<T: std::fmt::Display> serde::Serialize for StringSerde<T> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
Expand Down
17 changes: 16 additions & 1 deletion backend/weird/src/profile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
use std::{collections::HashMap, fmt::Debug, io::Cursor, str::FromStr};

use anyhow::Result;
use futures::{pin_mut, Stream, StreamExt};
use futures::{pin_mut, Stream, StreamExt, TryStreamExt};
use gdata::{GStoreBackend, GStoreValue, Key, KeySegment, Value};
use iroh::docs::{AuthorId, DocTicket, NamespaceId};
use once_cell::sync::Lazy;
Expand Down Expand Up @@ -635,6 +635,21 @@ impl<S> Weird<S> {
Ok((AuthorId::from(author_bytes), ns))
}

/// Get the list of usernames and the associated AuthorIDs for this instance.
pub async fn get_usernames(&self) -> Result<impl Stream<Item = Result<(String, AuthorId)>>> {
let usernames = self
.graph
.get_or_init_map((self.ns, &*USERNAMES_KEY))
.await?;
let stream = usernames.list_items().await?;
Ok(stream.and_then(|item| async move {
let username = item.last_key_segment().as_str()?.to_string();
let author_id: [u8; 32] = item.as_bytes()?[..].try_into()?;

Ok((username, author_id.into()))
}))
}

/// Get profile by name.
#[tracing::instrument(skip(self))]
pub async fn get_profile_by_name(&self, username: &Username) -> Result<Profile> {
Expand Down
37 changes: 32 additions & 5 deletions src/routes/(subsites)/traefik-config/+server.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,36 @@
import { env } from '$env/dynamic/private';
import { env as pubenv } from '$env/dynamic/public';
import { backendFetch } from '$lib/backend';
import { checkResponse } from '$lib/utils';
import { json, type RequestHandler } from '@sveltejs/kit';

export const GET: RequestHandler = () => {
return json({
http: {
services: {}
export const GET: RequestHandler = async ({ fetch }) => {
try {
const resp = await backendFetch(fetch, '/usernames');
await checkResponse(resp);
const usernames: string[] = Object.keys(await resp.json()).map((x) => x.split('@')[0]);

const routers: {
[key: string]: { rule: string; tls?: { certResolver: string }; service: string };
} = {};
for (const username of usernames) {
const routerName = `${env.TRAEFIK_CONFIG_NAMESPACE}-rtr-${username}`;
routers[routerName] = {
rule: `Host(${username}.${pubenv.PUBLIC_DOMAIN})`,
service: env.TRAEFIK_CONFIG_SERVICE_NAME,
tls: {
certResolver: 'letsencrypt'
}
};
}
});

return json({
http: {
routers
}
});
} catch (e) {
console.error('Error loading usernames while creating traefik config', e);
return json({});
}
};

0 comments on commit 3ff64d9

Please sign in to comment.