mirror of
https://github.com/kjuulh/bitebuds.git
synced 2025-12-30 04:01:01 +01:00
Compare commits
8 Commits
f56f8c6818
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
06701ea7be
|
|||
|
502b9023d3
|
|||
|
079a076925
|
|||
| 9565aa03b8 | |||
|
|
044878d78e | ||
|
e39be808a7
|
|||
|
b60410276f
|
|||
|
2053220d01
|
37
.github/workflows/release.yml
vendored
Normal file
37
.github/workflows/release.yml
vendored
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
name: release
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- "main"
|
||||||
|
env:
|
||||||
|
CARGO_TERM_COLOR: always
|
||||||
|
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||||
|
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||||
|
_EXPERIMENTAL_DAGGER_CACHE_CONFIG: type=gha;mode=max
|
||||||
|
jobs:
|
||||||
|
deploy:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
- name: Update rust toolchain
|
||||||
|
run: rustup update stable && rustup default stable
|
||||||
|
- name: Set up cargo cache
|
||||||
|
uses: actions/cache@v3
|
||||||
|
continue-on-error: false
|
||||||
|
with:
|
||||||
|
path: "~/.cargo/bin/\n~/.cargo/registry/index/\n~/.cargo/registry/cache/\n~/.cargo/git/db/\ntarget/"
|
||||||
|
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
|
||||||
|
restore-keys: ${{ runner.os }}-cargo
|
||||||
|
- name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@v2
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v2.0.0
|
||||||
|
- name: Login to Docker Hub
|
||||||
|
uses: docker/login-action@v2
|
||||||
|
with:
|
||||||
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
- name: Run dagger [CI]
|
||||||
|
run: cargo run -p ci
|
||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -11,3 +11,4 @@ node_modules/
|
|||||||
test-results/
|
test-results/
|
||||||
end2end/playwright-report/
|
end2end/playwright-report/
|
||||||
playwright/.cache/
|
playwright/.cache/
|
||||||
|
.env
|
||||||
|
|||||||
1701
Cargo.lock
generated
1701
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
|||||||
[workspace]
|
[workspace]
|
||||||
members = [".", "crates/services", "crates/domain", "crates/biteme"]
|
members = [".", "crates/services", "crates/domain", "crates/biteme", "ci"]
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
domain = { path = "crates/domain" }
|
domain = { path = "crates/domain" }
|
||||||
@@ -11,7 +11,7 @@ chrono = { version = "0.4.23", features = ["serde"] }
|
|||||||
serde = { version = "1", features = ["derive"] }
|
serde = { version = "1", features = ["derive"] }
|
||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "ssr_modes_axum"
|
name = "ssr_modes"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
@@ -35,6 +35,8 @@ tower = { version = "0.4.13", optional = true }
|
|||||||
tower-http = { version = "0.3.4", features = ["fs"], optional = true }
|
tower-http = { version = "0.3.4", features = ["fs"], optional = true }
|
||||||
tokio = { version = "1", features = ["time"], optional = true }
|
tokio = { version = "1", features = ["time"], optional = true }
|
||||||
wasm-bindgen = "0.2"
|
wasm-bindgen = "0.2"
|
||||||
|
tracing-subscriber = { version = "0.3.16", optional = true }
|
||||||
|
tracing = { version = "0.1.37", features = ["log"], optional = true }
|
||||||
|
|
||||||
serde = { workspace = true }
|
serde = { workspace = true }
|
||||||
chrono = { workspace = true }
|
chrono = { workspace = true }
|
||||||
@@ -55,6 +57,8 @@ ssr = [
|
|||||||
"leptos_router/ssr",
|
"leptos_router/ssr",
|
||||||
"dep:leptos_axum",
|
"dep:leptos_axum",
|
||||||
"dep:services",
|
"dep:services",
|
||||||
|
"dep:tracing-subscriber",
|
||||||
|
"dep:tracing",
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.metadata.leptos]
|
[package.metadata.leptos]
|
||||||
|
|||||||
@@ -30,3 +30,8 @@ command = "cargo"
|
|||||||
args = ["install", "--path", "crates/biteme"]
|
args = ["install", "--path", "crates/biteme"]
|
||||||
workspace = false
|
workspace = false
|
||||||
install_crate = "cargo-all-features"
|
install_crate = "cargo-all-features"
|
||||||
|
|
||||||
|
[tasks.ci]
|
||||||
|
command = "cargo"
|
||||||
|
args = ["run", "-p", "ci"]
|
||||||
|
workspace = false
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ description: |
|
|||||||
God gammeldags oksesteg med en intens og fyldig brun sauce. Gammeldags oksesteg
|
God gammeldags oksesteg med en intens og fyldig brun sauce. Gammeldags oksesteg
|
||||||
er rigtig simremad som gør de fleste glade. Så server en gammeldags oksesteg for
|
er rigtig simremad som gør de fleste glade. Så server en gammeldags oksesteg for
|
||||||
din gæster... både de unge og de gamle.
|
din gæster... både de unge og de gamle.
|
||||||
time: 2023-03-06
|
time: 2025-03-06
|
||||||
---
|
---
|
||||||
|
|
||||||
Some article
|
Some article
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
14
ci/Cargo.toml
Normal file
14
ci/Cargo.toml
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
[package]
|
||||||
|
name = "ci"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
dagger-sdk = "0.2.20"
|
||||||
|
eyre = "0.6.8"
|
||||||
|
color-eyre = "0.6.2"
|
||||||
|
tokio = { version = "1.27.0", features = ["full"] }
|
||||||
|
chrono.workspace = true
|
||||||
|
dotenv = "0.15.0"
|
||||||
197
ci/src/main.rs
Normal file
197
ci/src/main.rs
Normal file
@@ -0,0 +1,197 @@
|
|||||||
|
#[tokio::main]
|
||||||
|
async fn main() -> eyre::Result<()> {
|
||||||
|
let _ = dotenv::dotenv();
|
||||||
|
let rust_image = "docker.io/rustlang/rust:nightly";
|
||||||
|
|
||||||
|
let client = dagger_sdk::connect().await?;
|
||||||
|
|
||||||
|
let workdir = client.host().directory_opts(
|
||||||
|
".",
|
||||||
|
dagger_sdk::HostDirectoryOpts {
|
||||||
|
exclude: Some(vec!["target/", ".git/"]),
|
||||||
|
include: None,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
let minio_url = "https://github.com/mozilla/sccache/releases/download/v0.3.3/sccache-v0.3.3-x86_64-unknown-linux-musl.tar.gz";
|
||||||
|
|
||||||
|
let sccache_download_cache = client.cache_volume("sccache_download");
|
||||||
|
let cargo_cache = client.cache_volume("cargo_cache");
|
||||||
|
|
||||||
|
// Main container
|
||||||
|
let rust_base = client
|
||||||
|
.container()
|
||||||
|
.from(rust_image)
|
||||||
|
.with_exec(vec!["apt-get", "update"])
|
||||||
|
.with_exec(vec!["apt-get", "install", "--yes", "libpq-dev", "wget"])
|
||||||
|
.with_exec(vec!["mkdir", "-p", "/src/downloads"])
|
||||||
|
.with_workdir("/src/downloads")
|
||||||
|
.with_mounted_cache("/src/downloads", sccache_download_cache.id().await?)
|
||||||
|
.with_exec(vec!["wget", minio_url])
|
||||||
|
.with_exec(vec![
|
||||||
|
"tar",
|
||||||
|
"xzf",
|
||||||
|
"sccache-v0.3.3-x86_64-unknown-linux-musl.tar.gz",
|
||||||
|
])
|
||||||
|
.with_exec(vec![
|
||||||
|
"mv",
|
||||||
|
"sccache-v0.3.3-x86_64-unknown-linux-musl/sccache",
|
||||||
|
"/usr/local/bin/sccache",
|
||||||
|
])
|
||||||
|
.with_exec(vec!["chmod", "+x", "/usr/local/bin/sccache"])
|
||||||
|
.with_env_variable("RUSTC_WRAPPER", "/usr/local/bin/sccache")
|
||||||
|
.with_env_variable(
|
||||||
|
"AWS_ACCESS_KEY_ID",
|
||||||
|
std::env::var("AWS_ACCESS_KEY_ID").unwrap_or("".into()),
|
||||||
|
)
|
||||||
|
.with_env_variable(
|
||||||
|
"AWS_SECRET_ACCESS_KEY",
|
||||||
|
std::env::var("AWS_SECRET_ACCESS_KEY").unwrap_or("".into()),
|
||||||
|
)
|
||||||
|
.with_env_variable("SCCACHE_BUCKET", "sccache")
|
||||||
|
.with_env_variable("SCCACHE_REGION", "auto")
|
||||||
|
.with_env_variable("SCCACHE_ENDPOINT", "https://api-minio.front.kjuulh.io")
|
||||||
|
.with_mounted_cache("~/.cargo", cargo_cache.id().await?)
|
||||||
|
.with_exec(vec!["rustup", "target", "add", "wasm32-unknown-unknown"])
|
||||||
|
.with_exec(vec!["cargo", "install", "cargo-chef"])
|
||||||
|
.with_exec(vec!["cargo", "install", "cargo-leptos"])
|
||||||
|
.with_workdir("/app");
|
||||||
|
|
||||||
|
let exit_code = rust_base.exit_code().await?;
|
||||||
|
if exit_code != 0 {
|
||||||
|
eyre::bail!("could not build base");
|
||||||
|
}
|
||||||
|
|
||||||
|
let target_cache = client.cache_volume("target_cache");
|
||||||
|
let rust_prepare = rust_base
|
||||||
|
.with_mounted_directory(".", workdir.id().await?)
|
||||||
|
.with_mounted_cache("target", target_cache.id().await?)
|
||||||
|
.with_exec(vec![
|
||||||
|
"cargo",
|
||||||
|
"chef",
|
||||||
|
"prepare",
|
||||||
|
"--recipe-path",
|
||||||
|
"recipe.json",
|
||||||
|
]);
|
||||||
|
|
||||||
|
let exit_code = rust_prepare.exit_code().await?;
|
||||||
|
if exit_code != 0 {
|
||||||
|
eyre::bail!("could not build prepare");
|
||||||
|
}
|
||||||
|
|
||||||
|
let target_rust_cache = client.cache_volume("target_rust_cache");
|
||||||
|
|
||||||
|
let rust_cacher = rust_base
|
||||||
|
.with_exec(vec!["apt", "update"])
|
||||||
|
.with_exec(vec![
|
||||||
|
"apt",
|
||||||
|
"install",
|
||||||
|
"pkg-config",
|
||||||
|
"openssl",
|
||||||
|
"libssl-dev",
|
||||||
|
"-y",
|
||||||
|
])
|
||||||
|
.with_exec(vec!["rustup", "target", "add", "wasm32-unknown-unknown"])
|
||||||
|
.with_file(
|
||||||
|
"/recipe.json",
|
||||||
|
rust_prepare.file("./recipe.json").id().await?,
|
||||||
|
)
|
||||||
|
.with_mounted_cache("target", target_rust_cache.id().await?)
|
||||||
|
.with_exec(vec![
|
||||||
|
"cargo",
|
||||||
|
"chef",
|
||||||
|
"cook",
|
||||||
|
"--release",
|
||||||
|
"--recipe-path",
|
||||||
|
"/recipe.json",
|
||||||
|
])
|
||||||
|
.with_mounted_directory(".", workdir.id().await?);
|
||||||
|
|
||||||
|
let exit_code = rust_cacher.exit_code().await?;
|
||||||
|
if exit_code != 0 {
|
||||||
|
eyre::bail!("could not build cacher");
|
||||||
|
}
|
||||||
|
|
||||||
|
let nodejs_cacher = client.cache_volume("node");
|
||||||
|
|
||||||
|
// something
|
||||||
|
|
||||||
|
let rust_pre_builder = rust_cacher
|
||||||
|
.with_exec(vec!["mkdir", "-p", "node"])
|
||||||
|
.with_mounted_cache("node", nodejs_cacher.id().await?)
|
||||||
|
.with_exec(vec![
|
||||||
|
"curl",
|
||||||
|
"-sL",
|
||||||
|
"https://deb.nodesource.com/setup_12.x",
|
||||||
|
"-o",
|
||||||
|
"node/node_12.txt",
|
||||||
|
])
|
||||||
|
.with_exec(vec!["chmod", "+x", "node/node_12.txt"])
|
||||||
|
.with_exec(vec!["bash", "-c", "node/node_12.txt"])
|
||||||
|
.with_exec(vec!["apt-get", "update"])
|
||||||
|
.with_exec(vec!["apt-get", "install", "nodejs"])
|
||||||
|
.with_exec(vec!["npm", "install", "-g", "sass"]);
|
||||||
|
|
||||||
|
let exit_code = rust_pre_builder.exit_code().await?;
|
||||||
|
if exit_code != 0 {
|
||||||
|
eyre::bail!("could not build rust_pre_builder");
|
||||||
|
}
|
||||||
|
|
||||||
|
let rust_builder = rust_pre_builder
|
||||||
|
.with_env_variable("LEPTOS_BROWSERQUERY", "defaults")
|
||||||
|
.with_exec(vec!["cargo", "leptos", "build", "--release"]);
|
||||||
|
|
||||||
|
let exit_code = rust_builder.exit_code().await?;
|
||||||
|
if exit_code != 0 {
|
||||||
|
eyre::bail!("could not build builder");
|
||||||
|
}
|
||||||
|
|
||||||
|
let tag = chrono::Utc::now().timestamp();
|
||||||
|
|
||||||
|
let prod_image = "debian:bullseye";
|
||||||
|
let prod = client
|
||||||
|
.container()
|
||||||
|
.from(prod_image)
|
||||||
|
.with_exec(vec!["apt", "update"])
|
||||||
|
.with_exec(vec!["apt", "install", "-y", "zlib1g", "git"])
|
||||||
|
.with_workdir("/app")
|
||||||
|
.with_file(
|
||||||
|
"/app/ssr_modes",
|
||||||
|
rust_builder
|
||||||
|
.file("/app/target/server/release/ssr_modes")
|
||||||
|
.id()
|
||||||
|
.await?,
|
||||||
|
)
|
||||||
|
.with_directory(
|
||||||
|
"/app/site",
|
||||||
|
rust_builder.directory("/app/target/site").id().await?,
|
||||||
|
)
|
||||||
|
.with_env_variable("LEPTOS_OUTPUT_NAME", "ssr_modes")
|
||||||
|
.with_env_variable("LEPTOS_SITE_ROOT", "site")
|
||||||
|
.with_env_variable("LEPTOS_SITE_PKG_DIR", "pkg")
|
||||||
|
.with_env_variable("LEPTOS_SITE_ADDR", "0.0.0.0:3000")
|
||||||
|
.with_env_variable("LEPTOS_RELOAD_PORT", "3001")
|
||||||
|
.with_entrypoint(vec!["/app/ssr_modes"]);
|
||||||
|
|
||||||
|
let image_tag = format!("docker.io/kasperhermansen/bitebuds:{tag}");
|
||||||
|
prod.publish(&image_tag).await?;
|
||||||
|
|
||||||
|
let update_deployment = client
|
||||||
|
.container()
|
||||||
|
.from("docker.io/kasperhermansen/update-deployment:1680548342")
|
||||||
|
.with_env_variable("GIT_USERNAME", "kjuulh")
|
||||||
|
.with_env_variable("GIT_PASSWORD", std::env::var("GIT_PASSWORD").unwrap())
|
||||||
|
.with_exec(vec![
|
||||||
|
"update-deployment",
|
||||||
|
"--repo",
|
||||||
|
"https://git.front.kjuulh.io/kjuulh/bitebuds-deployment.git",
|
||||||
|
"--service",
|
||||||
|
"bitebuds",
|
||||||
|
"--image",
|
||||||
|
&image_tag,
|
||||||
|
])
|
||||||
|
.exit_code()
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use domain::{Event, Image};
|
use domain::{Event, Image};
|
||||||
use inquire::validator::ValueRequiredValidator;
|
use inquire::validator::ValueRequiredValidator;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
@@ -9,7 +11,12 @@ async fn main() -> eyre::Result<()> {
|
|||||||
color_eyre::install()?;
|
color_eyre::install()?;
|
||||||
|
|
||||||
let cli = clap::Command::new("biteme")
|
let cli = clap::Command::new("biteme")
|
||||||
.subcommand(clap::Command::new("generate").subcommand(clap::Command::new("article")));
|
.subcommand_required(true)
|
||||||
|
.subcommand(
|
||||||
|
clap::Command::new("generate")
|
||||||
|
.subcommand_required(true)
|
||||||
|
.subcommand(clap::Command::new("article")),
|
||||||
|
);
|
||||||
|
|
||||||
let args = std::env::args();
|
let args = std::env::args();
|
||||||
|
|
||||||
@@ -89,7 +96,10 @@ async fn generate_article() -> eyre::Result<()> {
|
|||||||
description.unwrap_or("".into())
|
description.unwrap_or("".into())
|
||||||
);
|
);
|
||||||
|
|
||||||
tokio::fs::write(format!("articles/events/{}.md", slug), contents).await?;
|
let mut vault_path = PathBuf::from(std::env::var("BITEME_ROOT").unwrap());
|
||||||
|
vault_path.push(format!("areas/food/events/{}.md", slug));
|
||||||
|
|
||||||
|
tokio::fs::write(vault_path, contents).await?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ edition = "2021"
|
|||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
gitevents_sdk = { git = "https://github.com/kjuulh/gitevents.git", branch = "main" }
|
||||||
cached = "0.42.0"
|
cached = "0.42.0"
|
||||||
chrono = { version = "0.4.23", features = ["serde"] }
|
chrono = { version = "0.4.23", features = ["serde"] }
|
||||||
domain = { path = "../domain" }
|
domain = { path = "../domain" }
|
||||||
@@ -18,3 +19,4 @@ serde_json = "1.0.94"
|
|||||||
serde_yaml = "0.9.19"
|
serde_yaml = "0.9.19"
|
||||||
tokio = { version = "1.26.0", features = ["full"] }
|
tokio = { version = "1.26.0", features = ["full"] }
|
||||||
uuid = { version = "1.3.0", features = ["v4", "serde"] }
|
uuid = { version = "1.3.0", features = ["v4", "serde"] }
|
||||||
|
tracing = { version = "0.1.37", features = ["log"] }
|
||||||
|
|||||||
@@ -1,15 +1,10 @@
|
|||||||
|
use cached::proc_macro::once;
|
||||||
|
use domain::{Event, Image, Metadata};
|
||||||
|
use gitevents_sdk::events::EventResponse;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use cached::proc_macro::{cached, once};
|
|
||||||
use domain::{Event, Image, Metadata};
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
pub struct EventStore {
|
|
||||||
pub path: PathBuf,
|
|
||||||
events: Arc<tokio::sync::RwLock<Vec<Event>>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
pub struct RawImage {
|
pub struct RawImage {
|
||||||
pub url: String,
|
pub url: String,
|
||||||
@@ -81,28 +76,94 @@ impl From<RawImage> for Image {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct InnerEventStore {
|
||||||
|
url: Option<String>,
|
||||||
|
pub path: PathBuf,
|
||||||
|
events: Arc<tokio::sync::RwLock<Vec<Event>>>,
|
||||||
|
url_path: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct EventStore {
|
||||||
|
inner: Arc<InnerEventStore>,
|
||||||
|
}
|
||||||
|
|
||||||
impl EventStore {
|
impl EventStore {
|
||||||
pub fn new(path: PathBuf) -> Self {
|
pub fn new(path: PathBuf) -> Self {
|
||||||
|
let article_repo_url = std::env::var("BITE_ARTICLE_REPO_URL")
|
||||||
|
.map(|a| (a != "").then(|| a))
|
||||||
|
.unwrap_or(None);
|
||||||
|
let article_repo_path = std::env::var("BITE_ARTICLE_REPO_PATH")
|
||||||
|
.map(|a| (a != "").then(|| a))
|
||||||
|
.unwrap_or(None);
|
||||||
Self {
|
Self {
|
||||||
|
inner: Arc::new(InnerEventStore {
|
||||||
|
url: article_repo_url,
|
||||||
|
url_path: article_repo_path,
|
||||||
path,
|
path,
|
||||||
events: Default::default(),
|
events: Default::default(),
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn bootstrap(&self) -> eyre::Result<()> {
|
||||||
|
tracing::info!("boostrapping event_store");
|
||||||
|
//let mut event_path = self.inner.path.clone();
|
||||||
|
//event_path.push("events");
|
||||||
|
|
||||||
|
//let events = fetch_events(event_path.clone()).await?;
|
||||||
|
|
||||||
|
//let mut e = self.inner.events.write().await;
|
||||||
|
//*e = events;
|
||||||
|
|
||||||
|
if let Some(repo_url) = self.inner.url.clone() {
|
||||||
|
tracing::info!(repo_url = repo_url, "subscribing to repo");
|
||||||
|
let inner = self.inner.clone();
|
||||||
|
|
||||||
|
tokio::task::spawn(async move {
|
||||||
|
gitevents_sdk::builder::Builder::new()
|
||||||
|
.set_generic_git_url(repo_url)
|
||||||
|
.set_scheduler_opts(&gitevents_sdk::cron::SchedulerOpts {
|
||||||
|
duration: std::time::Duration::from_secs(30),
|
||||||
|
})
|
||||||
|
.action(move |req| {
|
||||||
|
let inner = inner.clone();
|
||||||
|
|
||||||
|
async move {
|
||||||
|
tracing::info!("updating articles");
|
||||||
|
let mut event_path = req.git.path.clone();
|
||||||
|
event_path.push(inner.url_path.as_ref().unwrap());
|
||||||
|
|
||||||
|
tracing::debug!(
|
||||||
|
path = event_path.display().to_string(),
|
||||||
|
"reading from"
|
||||||
|
);
|
||||||
|
|
||||||
|
let events = fetch_events(event_path).await.unwrap();
|
||||||
|
|
||||||
|
let mut e = inner.events.write().await;
|
||||||
|
*e = events.clone();
|
||||||
|
|
||||||
|
Ok(EventResponse {})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.execute()
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn get_upcoming_events(&self) -> eyre::Result<Vec<Event>> {
|
pub async fn get_upcoming_events(&self) -> eyre::Result<Vec<Event>> {
|
||||||
let mut event_path = self.path.clone();
|
let events = self.inner.events.read().await.clone();
|
||||||
event_path.push("events");
|
|
||||||
|
|
||||||
let events = fetch_events(event_path).await?;
|
|
||||||
|
|
||||||
let mut e = self.events.write().await;
|
|
||||||
*e = events.clone();
|
|
||||||
|
|
||||||
Ok(events)
|
Ok(events)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_event(&self, event_id: uuid::Uuid) -> eyre::Result<Option<Event>> {
|
pub async fn get_event(&self, event_id: uuid::Uuid) -> eyre::Result<Option<Event>> {
|
||||||
let events = self.events.read().await;
|
let events = self.inner.events.read().await;
|
||||||
|
|
||||||
let event = events.iter().find(|e| e.id == event_id);
|
let event = events.iter().find(|e| e.id == event_id);
|
||||||
|
|
||||||
@@ -110,7 +171,6 @@ impl EventStore {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[once(time = 60, result = true, sync_writes = true)]
|
|
||||||
pub async fn fetch_events(event_path: PathBuf) -> eyre::Result<Vec<Event>> {
|
pub async fn fetch_events(event_path: PathBuf) -> eyre::Result<Vec<Event>> {
|
||||||
let mut dir = tokio::fs::read_dir(event_path).await?;
|
let mut dir = tokio::fs::read_dir(event_path).await?;
|
||||||
|
|
||||||
@@ -140,8 +200,12 @@ pub async fn fetch_events(event_path: PathBuf) -> eyre::Result<Vec<Event>> {
|
|||||||
impl Default for EventStore {
|
impl Default for EventStore {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
inner: Arc::new(InnerEventStore {
|
||||||
|
url: Default::default(),
|
||||||
path: PathBuf::from("articles"),
|
path: PathBuf::from("articles"),
|
||||||
events: Default::default(),
|
events: Default::default(),
|
||||||
|
url_path: Some("articles/events".into()),
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
3
renovate.json
Normal file
3
renovate.json
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://docs.renovatebot.com/renovate-schema.json"
|
||||||
|
}
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use cfg_if::cfg_if;
|
use cfg_if::cfg_if;
|
||||||
use leptos::*;
|
use leptos::*;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
@@ -10,17 +12,15 @@ cfg_if! {
|
|||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref EVENTSTORE: EventStore = EventStore::default();
|
static ref EVENTSTORE: EventStore = EventStore::new(PathBuf::from("articles"));
|
||||||
}
|
}
|
||||||
async fn get_upcoming_events_fn() -> Result<UpcomingEventsOverview, ServerFnError> {
|
async fn get_upcoming_events_fn() -> Result<UpcomingEventsOverview, ServerFnError> {
|
||||||
let current_time = chrono::Utc::now();
|
|
||||||
|
|
||||||
let mut events: Vec<EventOverview> = EVENTSTORE
|
let mut events: Vec<EventOverview> = EVENTSTORE
|
||||||
.get_upcoming_events()
|
.get_upcoming_events()
|
||||||
.await
|
.await
|
||||||
.map_err(|e| ServerFnError::ServerError(e.to_string()))?
|
.map_err(|e| ServerFnError::ServerError(e.to_string()))?
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|d| d.time.gt(&chrono::Utc::now().date_naive()))
|
.filter(|d| d.time.ge(&chrono::Utc::now().date_naive()))
|
||||||
.map(|data| data.clone().into())
|
.map(|data| data.clone().into())
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
@@ -33,9 +33,12 @@ cfg_if! {
|
|||||||
.get_event(event_id)
|
.get_event(event_id)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| ServerFnError::ServerError(e.to_string()))?;
|
.map_err(|e| ServerFnError::ServerError(e.to_string()))?;
|
||||||
|
|
||||||
Ok(event)
|
Ok(event)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn boostrap() -> Result<(), ServerFnError> {
|
||||||
|
EVENTSTORE.bootstrap().await.map_err(|e| ServerFnError::ServerError(e.to_string()))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ pub fn App(cx: Scope) -> impl IntoView {
|
|||||||
<Stylesheet id="leptos" href="/pkg/ssr_modes.css" />
|
<Stylesheet id="leptos" href="/pkg/ssr_modes.css" />
|
||||||
<Title text="Bitebuds" />
|
<Title text="Bitebuds" />
|
||||||
|
|
||||||
|
<script defer="true" data-domain="bitebuds.front.kjuulh.io" src="https://plausible.front.kjuulh.io/js/script.js"/>
|
||||||
|
|
||||||
<Router>
|
<Router>
|
||||||
<div class="app grid lg:grid-cols-[25%,50%,25%] sm:grid-cols-[10%,80%,10%] grid-cols-[5%,90%,5%]">
|
<div class="app grid lg:grid-cols-[25%,50%,25%] sm:grid-cols-[10%,80%,10%] grid-cols-[5%,90%,5%]">
|
||||||
<main class="main col-start-2">
|
<main class="main col-start-2">
|
||||||
|
|||||||
25
src/main.rs
25
src/main.rs
@@ -1,16 +1,25 @@
|
|||||||
#[cfg(feature = "ssr")]
|
#[cfg(feature = "ssr")]
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
use axum::{
|
use axum::{extract::Extension, routing::post, Router};
|
||||||
extract::{Extension, Path},
|
|
||||||
routing::{get, post},
|
|
||||||
Router,
|
|
||||||
};
|
|
||||||
use leptos::*;
|
use leptos::*;
|
||||||
use leptos_axum::{generate_route_list, LeptosRoutes};
|
use leptos_axum::{generate_route_list, LeptosRoutes};
|
||||||
use ssr_modes_axum::app::*;
|
use ssr_modes::app::*;
|
||||||
use ssr_modes_axum::fallback::file_and_error_handler;
|
use ssr_modes::fallback::file_and_error_handler;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use tracing_subscriber::EnvFilter;
|
||||||
|
|
||||||
|
std::env::set_var(
|
||||||
|
"BITE_ARTICLE_REPO_URL",
|
||||||
|
"git@git.front.kjuulh.io:kjuulh/obsidian.git",
|
||||||
|
);
|
||||||
|
std::env::set_var("BITE_ARTICLE_REPO_PATH", "areas/food/events");
|
||||||
|
|
||||||
|
tracing_subscriber::fmt()
|
||||||
|
.with_env_filter(EnvFilter::from_default_env())
|
||||||
|
.init();
|
||||||
|
|
||||||
|
ssr_modes::api::events::boostrap().await.unwrap();
|
||||||
|
|
||||||
let conf = get_configuration(None).await.unwrap();
|
let conf = get_configuration(None).await.unwrap();
|
||||||
let addr = conf.leptos_options.site_addr;
|
let addr = conf.leptos_options.site_addr;
|
||||||
@@ -18,7 +27,7 @@ async fn main() {
|
|||||||
// Generate the list of routes in your Leptos App
|
// Generate the list of routes in your Leptos App
|
||||||
let routes = generate_route_list(|cx| view! { cx, <App/> }).await;
|
let routes = generate_route_list(|cx| view! { cx, <App/> }).await;
|
||||||
|
|
||||||
ssr_modes_axum::api::register();
|
ssr_modes::api::register();
|
||||||
|
|
||||||
let app = Router::new()
|
let app = Router::new()
|
||||||
.route("/api/*fn_name", post(leptos_axum::handle_server_fns))
|
.route("/api/*fn_name", post(leptos_axum::handle_server_fns))
|
||||||
|
|||||||
@@ -655,22 +655,6 @@ video {
|
|||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes bounce {
|
|
||||||
0%, 100% {
|
|
||||||
transform: translateY(-25%);
|
|
||||||
animation-timing-function: cubic-bezier(0.8,0,1,1);
|
|
||||||
}
|
|
||||||
|
|
||||||
50% {
|
|
||||||
transform: none;
|
|
||||||
animation-timing-function: cubic-bezier(0,0,0.2,1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.animate-bounce {
|
|
||||||
animation: bounce 1s infinite;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes pulse {
|
@keyframes pulse {
|
||||||
50% {
|
50% {
|
||||||
opacity: .5;
|
opacity: .5;
|
||||||
@@ -769,20 +753,6 @@ video {
|
|||||||
border-top-right-radius: 1rem;
|
border-top-right-radius: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.border {
|
|
||||||
border-width: 1px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.border-gray-400 {
|
|
||||||
--tw-border-opacity: 1;
|
|
||||||
border-color: rgb(156 163 175 / var(--tw-border-opacity));
|
|
||||||
}
|
|
||||||
|
|
||||||
.border-gray-300 {
|
|
||||||
--tw-border-opacity: 1;
|
|
||||||
border-color: rgb(209 213 219 / var(--tw-border-opacity));
|
|
||||||
}
|
|
||||||
|
|
||||||
.bg-gray-200 {
|
.bg-gray-200 {
|
||||||
--tw-bg-opacity: 1;
|
--tw-bg-opacity: 1;
|
||||||
background-color: rgb(229 231 235 / var(--tw-bg-opacity));
|
background-color: rgb(229 231 235 / var(--tw-bg-opacity));
|
||||||
|
|||||||
Reference in New Issue
Block a user