ci(sidecar): automated build + release workflow (Gitea Actions) #2

Merged
whitlocktech merged 3 commits from ci/sidecar-release into main 2026-07-14 16:46:09 +00:00
5 changed files with 38 additions and 18 deletions
Showing only changes of commit 359bb937b2 - Show all commits

View File

@@ -142,7 +142,10 @@ fn persist_token(path: &str, token: &str) -> anyhow::Result<()> {
let text = fs::read_to_string(path)?;
let line = format!("auth_token = \"{token}\"");
if text.lines().any(|l| l.trim_start().starts_with("auth_token")) {
if text
.lines()
.any(|l| l.trim_start().starts_with("auth_token"))
{
let out: String = text
.lines()
.map(|l| {

View File

@@ -96,7 +96,11 @@ async fn main() -> anyhow::Result<()> {
// Persist, then broadcast. `pong` and `ws.hello` are ephemeral chatter, not history.
if ev.kind != "pong" {
let t = ev.value.get("t").and_then(|v| v.as_i64()).unwrap_or_else(now_ms);
let t = ev
.value
.get("t")
.and_then(|v| v.as_i64())
.unwrap_or_else(now_ms);
let text = ev.value.to_string();
if let Err(e) = event_store.insert_event(t, &ev.kind, &text).await {
tracing::warn!(error = %e, "failed to persist event");

View File

@@ -56,10 +56,7 @@ impl Rpc {
) -> Result<Value, RpcError> {
let (tx, rx) = oneshot::channel();
self.pending
.lock()
.await
.insert(corr_val.to_string(), tx);
self.pending.lock().await.insert(corr_val.to_string(), tx);
if !shard.send(command.to_string()).await {
self.pending.lock().await.remove(corr_val);

View File

@@ -21,8 +21,8 @@ pub struct Store {
impl Store {
/// Opens (creating if absent) the SQLite database and ensures the schema exists.
pub async fn open(path: &str) -> anyhow::Result<Self> {
let opts = SqliteConnectOptions::from_str(&format!("sqlite://{path}"))?
.create_if_missing(true);
let opts =
SqliteConnectOptions::from_str(&format!("sqlite://{path}"))?.create_if_missing(true);
let pool = SqlitePoolOptions::new()
.max_connections(4)
@@ -78,7 +78,12 @@ impl Store {
self.recent(Some("economy.supply"), limit).await
}
pub async fn record_link(&self, account: &str, website_user_id: &str, t: i64) -> anyhow::Result<()> {
pub async fn record_link(
&self,
account: &str,
website_user_id: &str,
t: i64,
) -> anyhow::Result<()> {
sqlx::query(
"INSERT INTO links (account, website_user_id, linked_t) VALUES (?, ?, ?)
ON CONFLICT(account) DO UPDATE SET website_user_id = excluded.website_user_id, linked_t = excluded.linked_t",

View File

@@ -123,7 +123,8 @@ fn iso_ms(ms: i64) -> Option<String> {
if ms <= 0 {
return None;
}
chrono::DateTime::from_timestamp_millis(ms).map(|dt| dt.format("%Y-%m-%dT%H:%M:%SZ").to_string())
chrono::DateTime::from_timestamp_millis(ms)
.map(|dt| dt.format("%Y-%m-%dT%H:%M:%SZ").to_string())
}
// ---- gate: protocol check + auth ----
@@ -174,8 +175,15 @@ async fn gate(State(st): State<AppState>, req: Request, next: Next) -> Response
fn extract_token(req: &Request) -> Option<String> {
// Authorization: Bearer <token>
if let Some(v) = req.headers().get("authorization").and_then(|h| h.to_str().ok()) {
if let Some(rest) = v.strip_prefix("Bearer ").or_else(|| v.strip_prefix("bearer ")) {
if let Some(v) = req
.headers()
.get("authorization")
.and_then(|h| h.to_str().ok())
{
if let Some(rest) = v
.strip_prefix("Bearer ")
.or_else(|| v.strip_prefix("bearer "))
{
return Some(rest.trim().to_string());
}
}
@@ -349,7 +357,10 @@ async fn page_respond(
Path(id): Path<String>,
Json(body): Json<Value>,
) -> impl IntoResponse {
let message = body.get("message").and_then(|m| m.as_str()).unwrap_or_default();
let message = body
.get("message")
.and_then(|m| m.as_str())
.unwrap_or_default();
if message.trim().is_empty() {
return (
StatusCode::BAD_REQUEST,
@@ -439,7 +450,10 @@ async fn vendors(State(st): State<AppState>, Path(account): Path<String>) -> imp
/// Body: {"code":"AB12CD","websiteUserId":"9931"}. Correlated on `code`.
async fn link_confirm(State(st): State<AppState>, Json(body): Json<Value>) -> impl IntoResponse {
let code = body.get("code").and_then(|c| c.as_str()).unwrap_or_default();
let code = body
.get("code")
.and_then(|c| c.as_str())
.unwrap_or_default();
let web_id = body
.get("websiteUserId")
.and_then(|w| w.as_str())
@@ -501,10 +515,7 @@ async fn towncrier_add(State(st): State<AppState>, Json(body): Json<Value>) -> i
respond(st.rpc.call(&st.shard, cmd, &id).await)
}
async fn towncrier_remove(
State(st): State<AppState>,
Path(id): Path<String>,
) -> impl IntoResponse {
async fn towncrier_remove(State(st): State<AppState>, Path(id): Path<String>) -> impl IntoResponse {
let cmd = json!({"kind":"towncrier.remove","id":id});
respond(st.rpc.call(&st.shard, cmd, &id).await)
}