Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 11 additions & 30 deletions common/src/api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,7 @@ impl Client {
url
}

fn get(&self, path: Cow<'static, str>) -> crate::http::RequestBuilder {
let mut req = self.client.get(self.url_join(&path));
fn add_authentication(&self, mut req: RequestBuilder) -> RequestBuilder {
if let Some(auth_cookie) = &self.auth_cookie {
req = req.header(AUTH_COOKIE_HEADER, auth_cookie);
}
Expand All @@ -121,38 +120,20 @@ impl Client {
req
}

fn post(&self, path: Cow<'static, str>) -> crate::http::RequestBuilder {
let mut req = self.client.post(self.url_join(&path));
if let Some(auth_cookie) = &self.auth_cookie {
req = req.header(AUTH_COOKIE_HEADER, auth_cookie);
}

if let Some(worker_key) = &self.worker_key {
req = req.header(WORKER_KEY_HEADER, worker_key);
}

if let Some(signup_secret) = &self.signup_secret {
req = req.header(SIGNUP_SECRET_HEADER, signup_secret);
}

req
fn get(&self, path: Cow<'static, str>) -> RequestBuilder {
self.add_authentication(self.client.get(self.url_join(&path)))
}

fn delete(&self, path: Cow<'static, str>) -> crate::http::RequestBuilder {
let mut req = self.client.delete(self.url_join(&path));
if let Some(auth_cookie) = &self.auth_cookie {
req = req.header(AUTH_COOKIE_HEADER, auth_cookie);
}

if let Some(worker_key) = &self.worker_key {
req = req.header(WORKER_KEY_HEADER, worker_key);
}
fn post(&self, path: Cow<'static, str>) -> RequestBuilder {
self.add_authentication(self.client.post(self.url_join(&path)))
}

if let Some(signup_secret) = &self.signup_secret {
req = req.header(SIGNUP_SECRET_HEADER, signup_secret);
}
fn put(&self, path: Cow<'static, str>) -> RequestBuilder {
self.add_authentication(self.client.put(self.url_join(&path)))
}

req
fn delete(&self, path: Cow<'static, str>) -> RequestBuilder {
self.add_authentication(self.client.delete(self.url_join(&path)))
}
}

Expand Down
125 changes: 125 additions & 0 deletions common/src/api/v1/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,20 @@ pub trait WorkerRestApi {
async fn register_worker(&self, request: RegisterWorkerRequest) -> Result<()>;
async fn get_worker(&self, id: i32) -> Result<Worker>;
async fn unregister_worker(&self, id: i32) -> Result<()>;
async fn get_worker_tags(&self, id: i32) -> Result<Vec<String>>;
async fn set_worker_tags(&self, id: i32, tags: Vec<String>) -> Result<()>;
async fn create_worker_tag(&self, id: i32, tag: String) -> Result<()>;
async fn delete_worker_tag(&self, id: i32, tag: String) -> Result<()>;
}

#[async_trait]
pub trait TagRestApi {
async fn get_tags(&self) -> Result<Vec<String>>;
async fn create_tag(&self, request: CreateTagRequest) -> Result<String>;
async fn delete_tag(&self, tag: String) -> Result<()>;
async fn get_tag_rules(&self, tag: String) -> Result<Vec<TagRule>>;
async fn create_tag_rule(&self, tag: String, request: CreateTagRuleRequest) -> Result<TagRule>;
async fn delete_tag_rule(&self, tag: String, tag_rule_id: i32) -> Result<()>;
}

#[async_trait]
Expand Down Expand Up @@ -664,4 +678,115 @@ impl WorkerRestApi for Client {

Ok(())
}

async fn get_worker_tags(&self, id: i32) -> Result<Vec<String>> {
let tags = self
.get(Cow::Owned(format!("api/v1/workers/{id}/tags")))
.send()
.await?
.error_for_status()?
.json()
.await?;

Ok(tags)
}

async fn set_worker_tags(&self, id: i32, tags: Vec<String>) -> Result<()> {
self.put(Cow::Owned(format!("api/v1/workers/{id}/tags")))
.json(&tags)
.send_encoded()
.await?
.error_for_status()?;

Ok(())
}

async fn create_worker_tag(&self, id: i32, tag: String) -> Result<()> {
self.put(Cow::Owned(format!("api/v1/workers/{id}/tags/{tag}")))
.send()
.await?
.error_for_status()?;

Ok(())
}

async fn delete_worker_tag(&self, id: i32, tag: String) -> Result<()> {
self.delete(Cow::Owned(format!("api/v1/workers/{id}/tags/{tag}")))
.send()
.await?
.error_for_status()?;

Ok(())
}
}

#[async_trait]
impl TagRestApi for Client {
async fn get_tags(&self) -> Result<Vec<String>> {
let records = self
.get(Cow::Borrowed("api/v1/tags"))
.send()
.await?
.error_for_status()?
.json()
.await?;

Ok(records)
}

async fn create_tag(&self, request: CreateTagRequest) -> Result<String> {
let record = self
.post(Cow::Borrowed("api/v1/tags"))
.json(&request)
.send_encoded()
.await?
.error_for_status()?
.json()
.await?;

Ok(record)
}

async fn delete_tag(&self, tag: String) -> Result<()> {
self.delete(Cow::Owned(format!("api/v1/tags/{tag}")))
.send()
.await?
.error_for_status()?;

Ok(())
}

async fn get_tag_rules(&self, tag: String) -> Result<Vec<TagRule>> {
let records = self
.get(Cow::Owned(format!("api/v1/tags/{tag}")))
.send()
.await?
.error_for_status()?
.json()
.await?;

Ok(records)
}

async fn create_tag_rule(&self, tag: String, request: CreateTagRuleRequest) -> Result<TagRule> {
let record = self
.post(Cow::Owned(format!("api/v1/tags/{tag}")))
.json(&request)
.send_encoded()
.await?
.error_for_status()?
.json()
.await?;

Ok(record)
}

async fn delete_tag_rule(&self, tag: String, tag_rule_id: i32) -> Result<()> {
self.delete(Cow::Owned(format!("api/v1/tags/{tag}/{tag_rule_id}")))
.send()
.await?
.error_for_status()?;

Ok(())
}
}
2 changes: 2 additions & 0 deletions common/src/api/v1/models/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ mod dashboard;
mod meta;
mod package;
mod queue;
mod tag;
mod worker;

pub use build::*;
Expand All @@ -11,6 +12,7 @@ pub use meta::*;
pub use package::*;
pub use queue::*;
use serde::{Deserialize, Serialize};
pub use tag::*;
pub use worker::*;

#[derive(Debug, Clone, Serialize, Deserialize)]
Expand Down
23 changes: 23 additions & 0 deletions common/src/api/v1/models/tag.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#[cfg(feature = "diesel")]
use diesel::Queryable;
use serde::{Deserialize, Serialize};

#[derive(Debug, Serialize, Deserialize)]
pub struct CreateTagRequest {
pub tag: String,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct CreateTagRuleRequest {
pub name_pattern: String,
pub version_pattern: Option<String>,
}

#[derive(Debug, Serialize, Deserialize)]
#[cfg_attr(feature = "diesel", derive(Queryable))]
#[cfg_attr(feature = "diesel", diesel(check_for_backend(diesel::sqlite::Sqlite)))]
pub struct TagRule {
pub id: i32,
pub name_pattern: String,
pub version_pattern: Option<String>,
}
3 changes: 3 additions & 0 deletions daemon/migrations/2025-11-01-202819_worker-tags/down.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
DROP TABLE tag_rules;
DROP TABLE worker_tags;
DROP TABLE tags;
32 changes: 32 additions & 0 deletions daemon/migrations/2025-11-01-202819_worker-tags/up.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
CREATE TABLE tags
(
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
tag TEXT NOT NULL
);

CREATE UNIQUE INDEX tags_unique_idx ON tags (tag);

CREATE TABLE worker_tags
(
worker_id INTEGER NOT NULL REFERENCES workers ON DELETE CASCADE,
tag_id INTEGER NOT NULL REFERENCES tags ON DELETE CASCADE,

PRIMARY KEY (worker_id, tag_id)
);

CREATE INDEX worker_tags_worker_id_idx ON worker_tags (worker_id);
CREATE INDEX worker_tags_tag_id_idx ON worker_tags (tag_id);

CREATE TABLE tag_rules
(
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
tag_id INTEGER NOT NULL REFERENCES tags ON DELETE CASCADE,
name_pattern TEXT NOT NULL,
version_pattern TEXT
);

CREATE UNIQUE INDEX tag_rules_unique_idx ON tag_rules (tag_id,
name_pattern,
COALESCE(version_pattern, 'PLACEHOLDER'));

CREATE INDEX tag_rules_tag_id_idx ON tag_rules (tag_id);
2 changes: 2 additions & 0 deletions daemon/src/api/v1/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ mod dashboard;
mod meta;
mod package;
mod queue;
mod tag;
mod util;
mod worker;

Expand All @@ -11,4 +12,5 @@ pub use dashboard::*;
pub use meta::*;
pub use package::*;
pub use queue::*;
pub use tag::*;
pub use worker::*;
Loading
Loading