完成 Editor Agent P2 持久任务与运行时收口
新增 Web Project runtime job、持久日志、lease、取消、expired、stale 和 active preview guard 状态机 接入 api-server Web Project runtime worker 与 TempDirBuildRuntime 构建执行链路 补齐 SpacetimeDB procedure、spacetime-client facade、shared contracts 和前端 web-project client 契约 更新 /editor/agent 的 runtime job 恢复、日志回填、SSE 重连、取消按钮和 active preview 刷新恢复 新增 P2 dev smoke 脚本,并让完整 npm run dev 默认以 all 角色启动 P2 worker 补充 P2 自动化测试、浏览器 smoke 验收记录、开发运维文档和 Hermes 踩坑记忆
This commit is contained in:
@@ -28,6 +28,11 @@ pub struct AppConfig {
|
||||
pub external_generation_worker_concurrency: usize,
|
||||
pub external_generation_worker_poll_interval: Duration,
|
||||
pub external_generation_worker_lease: Duration,
|
||||
pub web_project_runtime_worker_id: String,
|
||||
pub web_project_runtime_worker_concurrency: usize,
|
||||
pub web_project_runtime_worker_poll_interval: Duration,
|
||||
pub web_project_runtime_worker_lease: Duration,
|
||||
pub web_project_runtime_worker_dry_run_result: WebProjectRuntimeWorkerDryRunResult,
|
||||
pub external_generation_controller_min_workers: usize,
|
||||
pub external_generation_controller_max_workers: usize,
|
||||
pub external_generation_controller_target_jobs_per_worker: usize,
|
||||
@@ -196,6 +201,7 @@ pub enum ProcessRole {
|
||||
Api,
|
||||
ExternalGenerationWorker,
|
||||
ExternalGenerationController,
|
||||
WebProjectRuntimeWorker,
|
||||
All,
|
||||
}
|
||||
|
||||
@@ -205,6 +211,12 @@ pub enum ExternalGenerationMode {
|
||||
Queue,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub enum WebProjectRuntimeWorkerDryRunResult {
|
||||
Fail,
|
||||
Succeed,
|
||||
}
|
||||
|
||||
impl ExternalGenerationMode {
|
||||
pub fn as_str(self) -> &'static str {
|
||||
match self {
|
||||
@@ -218,12 +230,22 @@ impl ExternalGenerationMode {
|
||||
}
|
||||
}
|
||||
|
||||
impl WebProjectRuntimeWorkerDryRunResult {
|
||||
pub fn as_str(self) -> &'static str {
|
||||
match self {
|
||||
Self::Fail => "fail",
|
||||
Self::Succeed => "success",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ProcessRole {
|
||||
pub fn as_str(self) -> &'static str {
|
||||
match self {
|
||||
Self::Api => "api",
|
||||
Self::ExternalGenerationWorker => "external-generation-worker",
|
||||
Self::ExternalGenerationController => "external-generation-controller",
|
||||
Self::WebProjectRuntimeWorker => "web-project-runtime-worker",
|
||||
Self::All => "all",
|
||||
}
|
||||
}
|
||||
@@ -239,6 +261,10 @@ impl ProcessRole {
|
||||
pub fn runs_external_generation_controller(self) -> bool {
|
||||
matches!(self, Self::ExternalGenerationController)
|
||||
}
|
||||
|
||||
pub fn runs_web_project_runtime_worker(self) -> bool {
|
||||
matches!(self, Self::WebProjectRuntimeWorker | Self::All)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for AppConfig {
|
||||
@@ -254,6 +280,11 @@ impl Default for AppConfig {
|
||||
external_generation_worker_concurrency: 2,
|
||||
external_generation_worker_poll_interval: Duration::from_millis(2_000),
|
||||
external_generation_worker_lease: Duration::from_secs(3_600),
|
||||
web_project_runtime_worker_id: default_worker_id("web-project-runtime"),
|
||||
web_project_runtime_worker_concurrency: 2,
|
||||
web_project_runtime_worker_poll_interval: Duration::from_millis(2_000),
|
||||
web_project_runtime_worker_lease: Duration::from_secs(600),
|
||||
web_project_runtime_worker_dry_run_result: WebProjectRuntimeWorkerDryRunResult::Fail,
|
||||
external_generation_controller_min_workers: 1,
|
||||
external_generation_controller_max_workers: 8,
|
||||
external_generation_controller_target_jobs_per_worker: 2,
|
||||
@@ -495,6 +526,32 @@ impl AppConfig {
|
||||
]) {
|
||||
config.external_generation_worker_lease = Duration::from_secs(lease_seconds.max(1));
|
||||
}
|
||||
if let Some(worker_id) =
|
||||
read_first_non_empty_env(&["GENARRATIVE_WEB_PROJECT_RUNTIME_WORKER_ID"])
|
||||
{
|
||||
config.web_project_runtime_worker_id = worker_id;
|
||||
}
|
||||
if let Some(concurrency) =
|
||||
read_first_usize_env(&["GENARRATIVE_WEB_PROJECT_RUNTIME_WORKER_CONCURRENCY"])
|
||||
{
|
||||
config.web_project_runtime_worker_concurrency = concurrency.max(1);
|
||||
}
|
||||
if let Some(poll_interval_ms) = read_first_positive_u64_env(&[
|
||||
"GENARRATIVE_WEB_PROJECT_RUNTIME_WORKER_POLL_INTERVAL_MS",
|
||||
]) {
|
||||
config.web_project_runtime_worker_poll_interval =
|
||||
Duration::from_millis(poll_interval_ms);
|
||||
}
|
||||
if let Some(lease_seconds) = read_first_duration_seconds_env(&[
|
||||
"GENARRATIVE_WEB_PROJECT_RUNTIME_WORKER_LEASE_SECONDS",
|
||||
]) {
|
||||
config.web_project_runtime_worker_lease = Duration::from_secs(lease_seconds.max(1));
|
||||
}
|
||||
if let Some(dry_run_result) = read_first_web_project_runtime_worker_dry_run_result_env(&[
|
||||
"GENARRATIVE_WEB_PROJECT_RUNTIME_WORKER_DRY_RUN_RESULT",
|
||||
]) {
|
||||
config.web_project_runtime_worker_dry_run_result = dry_run_result;
|
||||
}
|
||||
if let Some(min_workers) =
|
||||
read_first_usize_env(&["GENARRATIVE_EXTERNAL_GENERATION_CONTROLLER_MIN_WORKERS"])
|
||||
{
|
||||
@@ -1270,6 +1327,16 @@ fn read_first_external_generation_mode_env(keys: &[&str]) -> Option<ExternalGene
|
||||
})
|
||||
}
|
||||
|
||||
fn read_first_web_project_runtime_worker_dry_run_result_env(
|
||||
keys: &[&str],
|
||||
) -> Option<WebProjectRuntimeWorkerDryRunResult> {
|
||||
keys.iter().find_map(|key| {
|
||||
env::var(key)
|
||||
.ok()
|
||||
.and_then(|value| parse_web_project_runtime_worker_dry_run_result(value.as_str()))
|
||||
})
|
||||
}
|
||||
|
||||
fn read_first_positive_u32_env(keys: &[&str]) -> Option<u32> {
|
||||
keys.iter().find_map(|key| {
|
||||
env::var(key)
|
||||
@@ -1324,6 +1391,13 @@ fn default_external_generation_worker_id() -> String {
|
||||
format!("{}-{}", host.trim(), std::process::id())
|
||||
}
|
||||
|
||||
fn default_worker_id(prefix: &str) -> String {
|
||||
let host = env::var("HOSTNAME")
|
||||
.or_else(|_| env::var("COMPUTERNAME"))
|
||||
.unwrap_or_else(|_| "local".to_string());
|
||||
format!("{}-{}-{}", prefix.trim(), host.trim(), std::process::id())
|
||||
}
|
||||
|
||||
fn parse_process_role(value: &str) -> Option<ProcessRole> {
|
||||
match trim_quoted_env_value(value).to_ascii_lowercase().as_str() {
|
||||
"api" => Some(ProcessRole::Api),
|
||||
@@ -1333,6 +1407,10 @@ fn parse_process_role(value: &str) -> Option<ProcessRole> {
|
||||
"external-generation-controller" | "external_generation_controller" | "controller" => {
|
||||
Some(ProcessRole::ExternalGenerationController)
|
||||
}
|
||||
"web-project-runtime-worker"
|
||||
| "web_project_runtime_worker"
|
||||
| "web-project-worker"
|
||||
| "web_project_worker" => Some(ProcessRole::WebProjectRuntimeWorker),
|
||||
"all" => Some(ProcessRole::All),
|
||||
_ => None,
|
||||
}
|
||||
@@ -1348,6 +1426,18 @@ fn parse_external_generation_mode(value: &str) -> Option<ExternalGenerationMode>
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_web_project_runtime_worker_dry_run_result(
|
||||
value: &str,
|
||||
) -> Option<WebProjectRuntimeWorkerDryRunResult> {
|
||||
match trim_quoted_env_value(value).to_ascii_lowercase().as_str() {
|
||||
"fail" | "failed" | "failure" | "error" => Some(WebProjectRuntimeWorkerDryRunResult::Fail),
|
||||
"success" | "succeed" | "succeeded" | "ok" => {
|
||||
Some(WebProjectRuntimeWorkerDryRunResult::Succeed)
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn trim_quoted_env_value(raw: &str) -> &str {
|
||||
let raw = raw.trim();
|
||||
raw.strip_prefix('"')
|
||||
@@ -1481,7 +1571,9 @@ fn parse_positive_u16(raw: &str) -> Option<u16> {
|
||||
mod tests {
|
||||
use super::{
|
||||
AppConfig, DEFAULT_VECTOR_ENGINE_IMAGE_REQUEST_TIMEOUT_MS, ExternalGenerationMode,
|
||||
LlmProvider, ProcessRole, parse_bool, parse_external_generation_mode, parse_process_role,
|
||||
LlmProvider, ProcessRole, WebProjectRuntimeWorkerDryRunResult, parse_bool,
|
||||
parse_external_generation_mode, parse_process_role,
|
||||
parse_web_project_runtime_worker_dry_run_result,
|
||||
};
|
||||
use std::sync::{Mutex, OnceLock};
|
||||
|
||||
@@ -1546,21 +1638,41 @@ mod tests {
|
||||
parse_process_role("'external_generation_controller'"),
|
||||
Some(ProcessRole::ExternalGenerationController)
|
||||
);
|
||||
assert_eq!(
|
||||
parse_process_role("\"web-project-runtime-worker\""),
|
||||
Some(ProcessRole::WebProjectRuntimeWorker)
|
||||
);
|
||||
assert_eq!(
|
||||
parse_process_role("'web_project_runtime_worker'"),
|
||||
Some(ProcessRole::WebProjectRuntimeWorker)
|
||||
);
|
||||
assert_eq!(
|
||||
parse_process_role("web-project-worker"),
|
||||
Some(ProcessRole::WebProjectRuntimeWorker)
|
||||
);
|
||||
assert_eq!(parse_process_role("all"), Some(ProcessRole::All));
|
||||
assert_eq!(parse_process_role("unknown"), None);
|
||||
|
||||
assert!(ProcessRole::Api.runs_http());
|
||||
assert!(!ProcessRole::Api.runs_external_generation_worker());
|
||||
assert!(!ProcessRole::Api.runs_external_generation_controller());
|
||||
assert!(!ProcessRole::Api.runs_web_project_runtime_worker());
|
||||
assert!(!ProcessRole::ExternalGenerationWorker.runs_http());
|
||||
assert!(ProcessRole::ExternalGenerationWorker.runs_external_generation_worker());
|
||||
assert!(!ProcessRole::ExternalGenerationWorker.runs_external_generation_controller());
|
||||
assert!(!ProcessRole::ExternalGenerationWorker.runs_web_project_runtime_worker());
|
||||
assert!(!ProcessRole::ExternalGenerationController.runs_http());
|
||||
assert!(!ProcessRole::ExternalGenerationController.runs_external_generation_worker());
|
||||
assert!(ProcessRole::ExternalGenerationController.runs_external_generation_controller());
|
||||
assert!(!ProcessRole::ExternalGenerationController.runs_web_project_runtime_worker());
|
||||
assert!(!ProcessRole::WebProjectRuntimeWorker.runs_http());
|
||||
assert!(!ProcessRole::WebProjectRuntimeWorker.runs_external_generation_worker());
|
||||
assert!(!ProcessRole::WebProjectRuntimeWorker.runs_external_generation_controller());
|
||||
assert!(ProcessRole::WebProjectRuntimeWorker.runs_web_project_runtime_worker());
|
||||
assert!(ProcessRole::All.runs_http());
|
||||
assert!(ProcessRole::All.runs_external_generation_worker());
|
||||
assert!(!ProcessRole::All.runs_external_generation_controller());
|
||||
assert!(ProcessRole::All.runs_web_project_runtime_worker());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -1587,6 +1699,23 @@ mod tests {
|
||||
assert!(!ExternalGenerationMode::Queue.is_inline());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn web_project_runtime_worker_dry_run_result_parses_aliases() {
|
||||
assert_eq!(
|
||||
parse_web_project_runtime_worker_dry_run_result("\"success\""),
|
||||
Some(WebProjectRuntimeWorkerDryRunResult::Succeed)
|
||||
);
|
||||
assert_eq!(
|
||||
parse_web_project_runtime_worker_dry_run_result("'failed'"),
|
||||
Some(WebProjectRuntimeWorkerDryRunResult::Fail)
|
||||
);
|
||||
assert_eq!(
|
||||
parse_web_project_runtime_worker_dry_run_result("unknown"),
|
||||
None
|
||||
);
|
||||
assert_eq!(WebProjectRuntimeWorkerDryRunResult::Fail.as_str(), "fail");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_env_reads_external_generation_mode() {
|
||||
let _guard = ENV_LOCK
|
||||
@@ -1752,6 +1881,11 @@ mod tests {
|
||||
std::env::remove_var("GENARRATIVE_API_DETAIL_MAX_CONCURRENT_REQUESTS");
|
||||
std::env::remove_var("GENARRATIVE_API_ADMIN_MAX_CONCURRENT_REQUESTS");
|
||||
std::env::remove_var("GENARRATIVE_WEB_PROJECT_PREVIEW_BUILD_MAX_CONCURRENT_TASKS");
|
||||
std::env::remove_var("GENARRATIVE_WEB_PROJECT_RUNTIME_WORKER_ID");
|
||||
std::env::remove_var("GENARRATIVE_WEB_PROJECT_RUNTIME_WORKER_CONCURRENCY");
|
||||
std::env::remove_var("GENARRATIVE_WEB_PROJECT_RUNTIME_WORKER_POLL_INTERVAL_MS");
|
||||
std::env::remove_var("GENARRATIVE_WEB_PROJECT_RUNTIME_WORKER_LEASE_SECONDS");
|
||||
std::env::remove_var("GENARRATIVE_WEB_PROJECT_RUNTIME_WORKER_DRY_RUN_RESULT");
|
||||
std::env::remove_var("GENARRATIVE_API_SHUTDOWN_OUTBOX_FLUSH_TIMEOUT_MS");
|
||||
std::env::remove_var("GENARRATIVE_TRACKING_OUTBOX_ENABLED");
|
||||
std::env::remove_var("GENARRATIVE_TRACKING_OUTBOX_DIR");
|
||||
@@ -1774,6 +1908,20 @@ mod tests {
|
||||
"GENARRATIVE_WEB_PROJECT_PREVIEW_BUILD_MAX_CONCURRENT_TASKS",
|
||||
"3",
|
||||
);
|
||||
std::env::set_var(
|
||||
"GENARRATIVE_WEB_PROJECT_RUNTIME_WORKER_ID",
|
||||
"web-worker-test",
|
||||
);
|
||||
std::env::set_var("GENARRATIVE_WEB_PROJECT_RUNTIME_WORKER_CONCURRENCY", "4");
|
||||
std::env::set_var(
|
||||
"GENARRATIVE_WEB_PROJECT_RUNTIME_WORKER_POLL_INTERVAL_MS",
|
||||
"1500",
|
||||
);
|
||||
std::env::set_var("GENARRATIVE_WEB_PROJECT_RUNTIME_WORKER_LEASE_SECONDS", "90");
|
||||
std::env::set_var(
|
||||
"GENARRATIVE_WEB_PROJECT_RUNTIME_WORKER_DRY_RUN_RESULT",
|
||||
"success",
|
||||
);
|
||||
std::env::set_var("GENARRATIVE_API_SHUTDOWN_OUTBOX_FLUSH_TIMEOUT_MS", "3000");
|
||||
std::env::set_var("GENARRATIVE_TRACKING_OUTBOX_ENABLED", "false");
|
||||
std::env::set_var(
|
||||
@@ -1802,6 +1950,20 @@ mod tests {
|
||||
assert_eq!(config.detail_max_concurrent_requests, Some(32));
|
||||
assert_eq!(config.admin_max_concurrent_requests, Some(16));
|
||||
assert_eq!(config.web_project_preview_build_max_concurrent_tasks, 3);
|
||||
assert_eq!(config.web_project_runtime_worker_id, "web-worker-test");
|
||||
assert_eq!(config.web_project_runtime_worker_concurrency, 4);
|
||||
assert_eq!(
|
||||
config.web_project_runtime_worker_poll_interval,
|
||||
std::time::Duration::from_millis(1_500)
|
||||
);
|
||||
assert_eq!(
|
||||
config.web_project_runtime_worker_lease,
|
||||
std::time::Duration::from_secs(90)
|
||||
);
|
||||
assert_eq!(
|
||||
config.web_project_runtime_worker_dry_run_result,
|
||||
WebProjectRuntimeWorkerDryRunResult::Succeed
|
||||
);
|
||||
assert_eq!(
|
||||
config.shutdown_outbox_flush_timeout,
|
||||
std::time::Duration::from_millis(3_000)
|
||||
@@ -1838,6 +2000,11 @@ mod tests {
|
||||
std::env::remove_var("GENARRATIVE_API_DETAIL_MAX_CONCURRENT_REQUESTS");
|
||||
std::env::remove_var("GENARRATIVE_API_ADMIN_MAX_CONCURRENT_REQUESTS");
|
||||
std::env::remove_var("GENARRATIVE_WEB_PROJECT_PREVIEW_BUILD_MAX_CONCURRENT_TASKS");
|
||||
std::env::remove_var("GENARRATIVE_WEB_PROJECT_RUNTIME_WORKER_ID");
|
||||
std::env::remove_var("GENARRATIVE_WEB_PROJECT_RUNTIME_WORKER_CONCURRENCY");
|
||||
std::env::remove_var("GENARRATIVE_WEB_PROJECT_RUNTIME_WORKER_POLL_INTERVAL_MS");
|
||||
std::env::remove_var("GENARRATIVE_WEB_PROJECT_RUNTIME_WORKER_LEASE_SECONDS");
|
||||
std::env::remove_var("GENARRATIVE_WEB_PROJECT_RUNTIME_WORKER_DRY_RUN_RESULT");
|
||||
std::env::remove_var("GENARRATIVE_API_SHUTDOWN_OUTBOX_FLUSH_TIMEOUT_MS");
|
||||
std::env::remove_var("GENARRATIVE_TRACKING_OUTBOX_ENABLED");
|
||||
std::env::remove_var("GENARRATIVE_TRACKING_OUTBOX_DIR");
|
||||
|
||||
@@ -97,6 +97,8 @@ mod wallet_refund_outbox;
|
||||
mod web_project;
|
||||
mod web_project_mock_agent;
|
||||
mod web_project_preview_gateway;
|
||||
mod web_project_preview_runtime;
|
||||
mod web_project_runtime_worker;
|
||||
mod wechat;
|
||||
mod wooden_fish;
|
||||
mod work_author;
|
||||
@@ -126,6 +128,7 @@ use crate::{
|
||||
state::{AppState, AppStateInitError},
|
||||
tracking_outbox::TrackingOutbox,
|
||||
wallet_refund_outbox::WalletRefundOutbox,
|
||||
web_project_runtime_worker::run_web_project_runtime_worker,
|
||||
};
|
||||
|
||||
const API_SERVER_STARTUP_STACK_SIZE_BYTES: usize = 32 * 1024 * 1024;
|
||||
@@ -140,6 +143,20 @@ struct ShutdownContext {
|
||||
outbox_flush_timeout: Duration,
|
||||
}
|
||||
|
||||
enum HttpRoleWorkerState {
|
||||
ExternalGeneration(AppState),
|
||||
WebProjectRuntime(AppState),
|
||||
}
|
||||
|
||||
impl HttpRoleWorkerState {
|
||||
async fn run(self) -> Result<(), io::Error> {
|
||||
match self {
|
||||
Self::ExternalGeneration(state) => run_external_generation_worker(state).await,
|
||||
Self::WebProjectRuntime(state) => run_web_project_runtime_worker(state).await,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() -> Result<(), io::Error> {
|
||||
// Windows 本地调试下 Axum 路由树和启动恢复链较重,显式放大启动线程栈,避免 debug 构建在进入监听前栈溢出。
|
||||
let server_thread = thread::Builder::new()
|
||||
@@ -187,11 +204,7 @@ async fn run_worker_only(config: AppConfig) -> Result<(), io::Error> {
|
||||
let process_role = config.process_role;
|
||||
let state = restore_app_state_for_startup(config)
|
||||
.await
|
||||
.map_err(|error| {
|
||||
io::Error::other(format!(
|
||||
"初始化 external generation worker 状态失败:{error}"
|
||||
))
|
||||
})?;
|
||||
.map_err(|error| io::Error::other(format!("初始化非 HTTP 进程角色状态失败:{error}")))?;
|
||||
spawn_app_state_background_workers(&state);
|
||||
info!(
|
||||
process_role = process_role.as_str(),
|
||||
@@ -201,6 +214,8 @@ async fn run_worker_only(config: AppConfig) -> Result<(), io::Error> {
|
||||
run_external_generation_worker(state).await
|
||||
} else if process_role.runs_external_generation_controller() {
|
||||
run_external_generation_worker_controller(state).await
|
||||
} else if process_role.runs_web_project_runtime_worker() {
|
||||
run_web_project_runtime_worker(state).await
|
||||
} else {
|
||||
Err(io::Error::other(format!(
|
||||
"不支持的非 HTTP 进程角色:{}",
|
||||
@@ -218,44 +233,48 @@ async fn run_http_role(config: AppConfig) -> Result<(), io::Error> {
|
||||
let outbox_flush_timeout = config.shutdown_outbox_flush_timeout;
|
||||
let listener = build_tcp_listener(bind_address, listen_backlog)?;
|
||||
|
||||
let (router, shutdown_context, worker_state) = match restore_app_state_for_startup(config).await
|
||||
{
|
||||
Ok(state) => {
|
||||
spawn_app_state_background_workers(&state);
|
||||
let preview_shutdown = shutdown_signal_for_preview(state.clone());
|
||||
spawn_web_project_preview_gateway(&state, preview_shutdown).await?;
|
||||
let tracking_outbox = state.tracking_outbox();
|
||||
let wallet_refund_outbox = state.wallet_refund_outbox();
|
||||
let worker_state = process_role
|
||||
.runs_external_generation_worker()
|
||||
.then(|| state.clone());
|
||||
(
|
||||
build_router(state.clone()),
|
||||
let (router, shutdown_context, worker_states) =
|
||||
match restore_app_state_for_startup(config).await {
|
||||
Ok(state) => {
|
||||
spawn_app_state_background_workers(&state);
|
||||
let preview_shutdown = shutdown_signal_for_preview(state.clone());
|
||||
spawn_web_project_preview_gateway(&state, preview_shutdown).await?;
|
||||
let tracking_outbox = state.tracking_outbox();
|
||||
let wallet_refund_outbox = state.wallet_refund_outbox();
|
||||
let mut worker_states = Vec::new();
|
||||
if process_role.runs_external_generation_worker() {
|
||||
worker_states.push(HttpRoleWorkerState::ExternalGeneration(state.clone()));
|
||||
}
|
||||
if process_role.runs_web_project_runtime_worker() {
|
||||
worker_states.push(HttpRoleWorkerState::WebProjectRuntime(state.clone()));
|
||||
}
|
||||
(
|
||||
build_router(state.clone()),
|
||||
ShutdownContext {
|
||||
app_state: Some(state),
|
||||
tracking_outbox,
|
||||
wallet_refund_outbox,
|
||||
outbox_flush_timeout,
|
||||
},
|
||||
worker_states,
|
||||
)
|
||||
}
|
||||
Err(AppStateInitError::DependencyUnavailable(message)) => (
|
||||
build_spacetime_unavailable_router(message),
|
||||
ShutdownContext {
|
||||
app_state: Some(state),
|
||||
tracking_outbox,
|
||||
wallet_refund_outbox,
|
||||
app_state: None,
|
||||
tracking_outbox: None,
|
||||
wallet_refund_outbox: None,
|
||||
outbox_flush_timeout,
|
||||
},
|
||||
worker_state,
|
||||
)
|
||||
}
|
||||
Err(AppStateInitError::DependencyUnavailable(message)) => (
|
||||
build_spacetime_unavailable_router(message),
|
||||
ShutdownContext {
|
||||
app_state: None,
|
||||
tracking_outbox: None,
|
||||
wallet_refund_outbox: None,
|
||||
outbox_flush_timeout,
|
||||
},
|
||||
None,
|
||||
),
|
||||
Err(error) => {
|
||||
return Err(std::io::Error::other(format!(
|
||||
"初始化应用状态失败:{error}"
|
||||
)));
|
||||
}
|
||||
};
|
||||
Vec::new(),
|
||||
),
|
||||
Err(error) => {
|
||||
return Err(std::io::Error::other(format!(
|
||||
"初始化应用状态失败:{error}"
|
||||
)));
|
||||
}
|
||||
};
|
||||
|
||||
info!(
|
||||
%bind_address,
|
||||
@@ -268,13 +287,23 @@ async fn run_http_role(config: AppConfig) -> Result<(), io::Error> {
|
||||
|
||||
let http_server = axum::serve(listener, router)
|
||||
.with_graceful_shutdown(shutdown_signal(shutdown_context.clone()));
|
||||
let result = if let Some(worker_state) = worker_state {
|
||||
let result = if worker_states.is_empty() {
|
||||
http_server.await
|
||||
} else {
|
||||
let mut worker_tasks = tokio::task::JoinSet::new();
|
||||
for worker_state in worker_states {
|
||||
worker_tasks.spawn(async move { worker_state.run().await });
|
||||
}
|
||||
tokio::select! {
|
||||
result = http_server => result,
|
||||
result = run_external_generation_worker(worker_state) => result,
|
||||
result = worker_tasks.join_next() => match result {
|
||||
Some(Ok(result)) => result,
|
||||
Some(Err(error)) => Err(io::Error::other(format!(
|
||||
"api-server HTTP 角色后台 worker panic:{error}"
|
||||
))),
|
||||
None => Ok(()),
|
||||
},
|
||||
}
|
||||
} else {
|
||||
http_server.await
|
||||
};
|
||||
finalize_shutdown(shutdown_context).await;
|
||||
result
|
||||
|
||||
@@ -7,8 +7,10 @@ use crate::{
|
||||
auth::require_bearer_auth,
|
||||
state::AppState,
|
||||
web_project::{
|
||||
create_mock_agent_turn, create_web_project, create_web_project_preview_build,
|
||||
get_web_project, get_web_project_preview_build, get_web_project_snapshot,
|
||||
cancel_web_project_runtime_job, create_mock_agent_turn, create_web_project,
|
||||
create_web_project_preview_build, create_web_project_runtime_job, get_web_project,
|
||||
get_web_project_preview_build, get_web_project_runtime_job, get_web_project_snapshot,
|
||||
list_open_web_project_runtime_jobs, list_web_project_runtime_job_logs,
|
||||
patch_web_project_files, stream_web_project_preview_build_events,
|
||||
},
|
||||
};
|
||||
@@ -57,6 +59,15 @@ pub fn router(state: AppState) -> Router<AppState> {
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/web-project/projects/{project_id}/runtime-jobs",
|
||||
post(create_web_project_runtime_job)
|
||||
.get(list_open_web_project_runtime_jobs)
|
||||
.route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/web-project/preview-builds/{job_id}",
|
||||
get(get_web_project_preview_build).route_layer(middleware::from_fn_with_state(
|
||||
@@ -64,6 +75,27 @@ pub fn router(state: AppState) -> Router<AppState> {
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/web-project/runtime-jobs/{job_id}",
|
||||
get(get_web_project_runtime_job).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/web-project/runtime-jobs/{job_id}/cancel",
|
||||
post(cancel_web_project_runtime_job).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/web-project/runtime-jobs/{job_id}/logs",
|
||||
get(list_web_project_runtime_job_logs).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/web-project/preview-builds/{job_id}/events",
|
||||
get(stream_web_project_preview_build_events)
|
||||
|
||||
@@ -273,7 +273,9 @@ pub struct AppStateInner {
|
||||
creative_agent_sessions: Arc<Mutex<HashMap<String, CreativeAgentSessionRuntimeRecord>>>,
|
||||
profile_recharge_order_updates: broadcast::Sender<String>,
|
||||
web_project_build_updates: broadcast::Sender<String>,
|
||||
#[allow(dead_code)]
|
||||
web_project_preview_build_limiter: Arc<Semaphore>,
|
||||
#[allow(dead_code)]
|
||||
web_project_preview_active_projects: Arc<Mutex<HashSet<String>>>,
|
||||
#[cfg(test)]
|
||||
// 测试环境允许在未启动 SpacetimeDB 时,用内存快照兜底当前 runtime story 回归链。
|
||||
@@ -287,12 +289,14 @@ struct CreativeAgentSessionRuntimeRecord {
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[allow(dead_code)]
|
||||
pub enum WebProjectPreviewBuildSlotError {
|
||||
GlobalLimit,
|
||||
ProjectAlreadyRunning,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[allow(dead_code)]
|
||||
pub struct WebProjectPreviewBuildSlot {
|
||||
project_key: String,
|
||||
active_projects: Arc<Mutex<HashSet<String>>>,
|
||||
@@ -955,6 +959,7 @@ impl AppState {
|
||||
self.web_project_build_updates.clone()
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn try_acquire_web_project_preview_build_slot(
|
||||
&self,
|
||||
project_id: &str,
|
||||
|
||||
@@ -9,7 +9,7 @@ use std::{
|
||||
use async_stream::stream;
|
||||
use axum::{
|
||||
Json,
|
||||
extract::{Extension, Path, State},
|
||||
extract::{Extension, Path, Query, State},
|
||||
http::StatusCode,
|
||||
response::{
|
||||
IntoResponse, Response,
|
||||
@@ -22,14 +22,21 @@ use shared_contracts::web_project::{
|
||||
MockAgentTurnRequest, MockAgentTurnResponse, WebProjectFile, WebProjectPatch,
|
||||
WebProjectPatchOperation, WebProjectPreviewBuild, WebProjectPreviewBuildEvent,
|
||||
WebProjectPreviewBuildResponse, WebProjectPreviewBuildStatus, WebProjectResponse,
|
||||
WebProjectSnapshot, WebProjectSnapshotResponse,
|
||||
WebProjectRuntimeJob, WebProjectRuntimeJobCreateRequest, WebProjectRuntimeJobKind,
|
||||
WebProjectRuntimeJobListResponse, WebProjectRuntimeJobLog, WebProjectRuntimeJobLogListResponse,
|
||||
WebProjectRuntimeJobResponse, WebProjectRuntimeJobStatus, WebProjectSnapshot,
|
||||
WebProjectSnapshotResponse,
|
||||
};
|
||||
use shared_kernel::{build_prefixed_uuid_id, new_uuid_simple_string};
|
||||
use spacetime_client::{
|
||||
SpacetimeClientError, WebProjectCreateRecordInput, WebProjectFileRecord,
|
||||
WebProjectGetRecordInput, WebProjectPreviewBuildCreateRecordInput,
|
||||
WebProjectPreviewBuildGetRecordInput, WebProjectPreviewBuildRecord, WebProjectRecord,
|
||||
WebProjectSnapshotGetRecordInput, WebProjectSnapshotRecord, WebProjectSnapshotSaveRecordInput,
|
||||
WebProjectRuntimeJobCancelRecordInput, WebProjectRuntimeJobCreateRecordInput,
|
||||
WebProjectRuntimeJobGetRecordInput, WebProjectRuntimeJobListLogsRecordInput,
|
||||
WebProjectRuntimeJobListOpenRecordInput, WebProjectRuntimeJobLogRecord,
|
||||
WebProjectRuntimeJobRecord, WebProjectSnapshotGetRecordInput, WebProjectSnapshotRecord,
|
||||
WebProjectSnapshotSaveRecordInput,
|
||||
};
|
||||
use tokio::{
|
||||
io::{AsyncReadExt, AsyncWriteExt},
|
||||
@@ -47,16 +54,22 @@ use crate::{
|
||||
request_context::RequestContext,
|
||||
state::{AppState, WebProjectPreviewBuildSlot, WebProjectPreviewBuildSlotError},
|
||||
web_project_mock_agent::build_mock_agent_patch,
|
||||
web_project_preview_runtime,
|
||||
};
|
||||
|
||||
const WEB_PROJECT_ID_PREFIX: &str = "web-project-";
|
||||
const WEB_PROJECT_SNAPSHOT_ID_PREFIX: &str = "web-snapshot-";
|
||||
const WEB_PROJECT_BUILD_ID_PREFIX: &str = "web-build-";
|
||||
const WEB_PROJECT_RUNTIME_JOB_ID_PREFIX: &str = "web-runtime-job-";
|
||||
const WEB_PROJECT_DEFAULT_TITLE: &str = "未命名 Web 工程";
|
||||
const WEB_PROJECT_MAX_PATH_DEPTH: usize = 8;
|
||||
const WEB_PROJECT_MAX_FILE_COUNT: usize = 80;
|
||||
const WEB_PROJECT_MAX_FILE_BYTES: usize = 128 * 1024;
|
||||
const WEB_PROJECT_MAX_SNAPSHOT_BYTES: usize = 512 * 1024;
|
||||
const WEB_PROJECT_RUNTIME_JOB_DEFAULT_LIST_LIMIT: u32 = 20;
|
||||
const WEB_PROJECT_RUNTIME_JOB_DEFAULT_LOG_LIMIT: u32 = 100;
|
||||
const WEB_PROJECT_RUNTIME_JOB_MAX_LOG_LIMIT: u32 = 100;
|
||||
#[allow(dead_code)]
|
||||
const WEB_PROJECT_RUNNER_TIMEOUT: Duration = Duration::from_secs(300);
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
@@ -79,6 +92,19 @@ pub struct WebProjectPreviewBuildCreateRequest {
|
||||
snapshot_id: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct WebProjectRuntimeJobListQuery {
|
||||
limit: Option<u32>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct WebProjectRuntimeJobLogsQuery {
|
||||
after_sequence: Option<u64>,
|
||||
limit: Option<u32>,
|
||||
}
|
||||
|
||||
pub async fn create_web_project(
|
||||
State(state): State<AppState>,
|
||||
Extension(request_context): Extension<RequestContext>,
|
||||
@@ -276,32 +302,53 @@ pub async fn create_web_project_preview_build(
|
||||
.active_snapshot_id
|
||||
}
|
||||
};
|
||||
let build_slot = state
|
||||
.try_acquire_web_project_preview_build_slot(&project_id)
|
||||
.map_err(|error| map_preview_build_slot_error(error, project_id.as_str()))?;
|
||||
let now_micros = current_utc_micros();
|
||||
let mutation = state
|
||||
.spacetime_client()
|
||||
.create_web_project_preview_build(WebProjectPreviewBuildCreateRecordInput {
|
||||
job_id: build_prefixed_uuid_id(WEB_PROJECT_BUILD_ID_PREFIX),
|
||||
project_id,
|
||||
snapshot_id,
|
||||
owner_user_id,
|
||||
now_micros: current_utc_micros(),
|
||||
project_id: project_id.clone(),
|
||||
snapshot_id: snapshot_id.clone(),
|
||||
owner_user_id: owner_user_id.clone(),
|
||||
now_micros,
|
||||
})
|
||||
.await
|
||||
.map_err(map_web_project_client_error)?;
|
||||
let mut build = build_from_record(mutation.build);
|
||||
build.logs.push("构建任务已进入队列".to_string());
|
||||
let runtime_job = match state
|
||||
.spacetime_client()
|
||||
.create_web_project_runtime_job(WebProjectRuntimeJobCreateRecordInput {
|
||||
job_id: build_prefixed_uuid_id(WEB_PROJECT_RUNTIME_JOB_ID_PREFIX),
|
||||
project_id,
|
||||
snapshot_id,
|
||||
owner_user_id: owner_user_id.clone(),
|
||||
job_kind: runtime_job_kind_to_record(WebProjectRuntimeJobKind::PreviewBuild),
|
||||
preview_build_id: Some(build.job_id.clone()),
|
||||
now_micros,
|
||||
})
|
||||
.await
|
||||
{
|
||||
Ok(runtime_job) => runtime_job,
|
||||
Err(error) => {
|
||||
let failed = mark_preview_build_queue_failed(
|
||||
&state,
|
||||
&owner_user_id,
|
||||
build,
|
||||
format!("runtime job 入队失败:{error}"),
|
||||
)
|
||||
.await;
|
||||
publish_build_event(&state, &failed, failed.error_summary.as_deref());
|
||||
return Err(map_web_project_client_error(error));
|
||||
}
|
||||
};
|
||||
publish_build_event(&state, &build, Some("构建任务已进入队列"));
|
||||
spawn_preview_build_task(
|
||||
state.clone(),
|
||||
authenticated.claims().user_id().to_string(),
|
||||
build.clone(),
|
||||
build_slot,
|
||||
);
|
||||
Ok(json_success_body(
|
||||
Some(&request_context),
|
||||
WebProjectPreviewBuildResponse { build },
|
||||
WebProjectPreviewBuildResponse {
|
||||
build,
|
||||
runtime_job: Some(runtime_job_from_record(runtime_job)),
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
@@ -323,6 +370,173 @@ pub async fn get_web_project_preview_build(
|
||||
Some(&request_context),
|
||||
WebProjectPreviewBuildResponse {
|
||||
build: build_from_record(mutation.build),
|
||||
runtime_job: None,
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
pub async fn create_web_project_runtime_job(
|
||||
State(state): State<AppState>,
|
||||
Path(project_id): Path<String>,
|
||||
Extension(request_context): Extension<RequestContext>,
|
||||
Extension(authenticated): Extension<AuthenticatedAccessToken>,
|
||||
Json(payload): Json<WebProjectRuntimeJobCreateRequest>,
|
||||
) -> Result<Json<Value>, AppError> {
|
||||
let owner_user_id = authenticated.claims().user_id().to_string();
|
||||
let snapshot_id = match payload.snapshot_id {
|
||||
Some(snapshot_id) if !snapshot_id.trim().is_empty() => snapshot_id,
|
||||
_ => {
|
||||
state
|
||||
.spacetime_client()
|
||||
.get_web_project(WebProjectGetRecordInput {
|
||||
project_id: project_id.clone(),
|
||||
owner_user_id: owner_user_id.clone(),
|
||||
})
|
||||
.await
|
||||
.map_err(map_web_project_client_error)?
|
||||
.active_snapshot_id
|
||||
}
|
||||
};
|
||||
let job = state
|
||||
.spacetime_client()
|
||||
.create_web_project_runtime_job(WebProjectRuntimeJobCreateRecordInput {
|
||||
job_id: build_prefixed_uuid_id(WEB_PROJECT_RUNTIME_JOB_ID_PREFIX),
|
||||
project_id,
|
||||
snapshot_id,
|
||||
owner_user_id,
|
||||
job_kind: runtime_job_kind_to_record(payload.job_kind),
|
||||
preview_build_id: payload.preview_build_id,
|
||||
now_micros: current_utc_micros(),
|
||||
})
|
||||
.await
|
||||
.map_err(map_web_project_client_error)?;
|
||||
|
||||
Ok(json_success_body(
|
||||
Some(&request_context),
|
||||
WebProjectRuntimeJobResponse {
|
||||
job: runtime_job_from_record(job),
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
pub async fn get_web_project_runtime_job(
|
||||
State(state): State<AppState>,
|
||||
Path(job_id): Path<String>,
|
||||
Extension(request_context): Extension<RequestContext>,
|
||||
Extension(authenticated): Extension<AuthenticatedAccessToken>,
|
||||
) -> Result<Json<Value>, AppError> {
|
||||
let job = state
|
||||
.spacetime_client()
|
||||
.get_web_project_runtime_job(WebProjectRuntimeJobGetRecordInput {
|
||||
job_id,
|
||||
owner_user_id: authenticated.claims().user_id().to_string(),
|
||||
})
|
||||
.await
|
||||
.map_err(map_web_project_client_error)?;
|
||||
|
||||
Ok(json_success_body(
|
||||
Some(&request_context),
|
||||
WebProjectRuntimeJobResponse {
|
||||
job: runtime_job_from_record(job),
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
pub async fn list_open_web_project_runtime_jobs(
|
||||
State(state): State<AppState>,
|
||||
Path(project_id): Path<String>,
|
||||
Query(query): Query<WebProjectRuntimeJobListQuery>,
|
||||
Extension(request_context): Extension<RequestContext>,
|
||||
Extension(authenticated): Extension<AuthenticatedAccessToken>,
|
||||
) -> Result<Json<Value>, AppError> {
|
||||
let jobs = state
|
||||
.spacetime_client()
|
||||
.list_open_web_project_runtime_jobs(WebProjectRuntimeJobListOpenRecordInput {
|
||||
project_id,
|
||||
owner_user_id: authenticated.claims().user_id().to_string(),
|
||||
limit: query
|
||||
.limit
|
||||
.unwrap_or(WEB_PROJECT_RUNTIME_JOB_DEFAULT_LIST_LIMIT),
|
||||
})
|
||||
.await
|
||||
.map_err(map_web_project_client_error)?;
|
||||
|
||||
Ok(json_success_body(
|
||||
Some(&request_context),
|
||||
WebProjectRuntimeJobListResponse {
|
||||
jobs: jobs.into_iter().map(runtime_job_from_record).collect(),
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
pub async fn cancel_web_project_runtime_job(
|
||||
State(state): State<AppState>,
|
||||
Path(job_id): Path<String>,
|
||||
Extension(request_context): Extension<RequestContext>,
|
||||
Extension(authenticated): Extension<AuthenticatedAccessToken>,
|
||||
) -> Result<Json<Value>, AppError> {
|
||||
let job = state
|
||||
.spacetime_client()
|
||||
.cancel_web_project_runtime_job(WebProjectRuntimeJobCancelRecordInput {
|
||||
job_id,
|
||||
owner_user_id: authenticated.claims().user_id().to_string(),
|
||||
cancelled_at_micros: current_utc_micros(),
|
||||
})
|
||||
.await
|
||||
.map_err(map_web_project_client_error)?;
|
||||
if job.status == "cancelled"
|
||||
&& let Some(preview_build_id) = job.preview_build_id.as_deref()
|
||||
{
|
||||
web_project_preview_runtime::cancel_preview_build_for_runtime_worker(
|
||||
&state,
|
||||
&job.owner_user_id,
|
||||
preview_build_id,
|
||||
)
|
||||
.await
|
||||
.map_err(|error| {
|
||||
AppError::from_status(StatusCode::INTERNAL_SERVER_ERROR)
|
||||
.with_message(format!("取消 Web 工程预览构建状态写回失败:{error}"))
|
||||
})?;
|
||||
}
|
||||
|
||||
Ok(json_success_body(
|
||||
Some(&request_context),
|
||||
WebProjectRuntimeJobResponse {
|
||||
job: runtime_job_from_record(job),
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
pub async fn list_web_project_runtime_job_logs(
|
||||
State(state): State<AppState>,
|
||||
Path(job_id): Path<String>,
|
||||
Query(query): Query<WebProjectRuntimeJobLogsQuery>,
|
||||
Extension(request_context): Extension<RequestContext>,
|
||||
Extension(authenticated): Extension<AuthenticatedAccessToken>,
|
||||
) -> Result<Json<Value>, AppError> {
|
||||
let requested_limit = query
|
||||
.limit
|
||||
.unwrap_or(WEB_PROJECT_RUNTIME_JOB_DEFAULT_LOG_LIMIT)
|
||||
.clamp(1, WEB_PROJECT_RUNTIME_JOB_MAX_LOG_LIMIT);
|
||||
let logs = state
|
||||
.spacetime_client()
|
||||
.list_web_project_runtime_job_logs(WebProjectRuntimeJobListLogsRecordInput {
|
||||
job_id,
|
||||
owner_user_id: authenticated.claims().user_id().to_string(),
|
||||
after_sequence: query.after_sequence,
|
||||
limit: requested_limit.saturating_add(1),
|
||||
})
|
||||
.await
|
||||
.map_err(map_web_project_client_error)?;
|
||||
let (logs, next_after_sequence, has_more) =
|
||||
paginate_runtime_job_log_records(logs, requested_limit);
|
||||
|
||||
Ok(json_success_body(
|
||||
Some(&request_context),
|
||||
WebProjectRuntimeJobLogListResponse {
|
||||
logs,
|
||||
next_after_sequence,
|
||||
has_more,
|
||||
},
|
||||
))
|
||||
}
|
||||
@@ -676,7 +890,7 @@ fn snapshot_from_record(record: WebProjectSnapshotRecord) -> WebProjectSnapshot
|
||||
}
|
||||
}
|
||||
|
||||
fn build_from_record(record: WebProjectPreviewBuildRecord) -> WebProjectPreviewBuild {
|
||||
pub(crate) fn build_from_record(record: WebProjectPreviewBuildRecord) -> WebProjectPreviewBuild {
|
||||
WebProjectPreviewBuild {
|
||||
job_id: record.job_id,
|
||||
project_id: record.project_id,
|
||||
@@ -695,6 +909,56 @@ fn build_from_record(record: WebProjectPreviewBuildRecord) -> WebProjectPreviewB
|
||||
}
|
||||
}
|
||||
|
||||
fn runtime_job_from_record(record: WebProjectRuntimeJobRecord) -> WebProjectRuntimeJob {
|
||||
WebProjectRuntimeJob {
|
||||
job_id: record.job_id,
|
||||
project_id: record.project_id,
|
||||
snapshot_id: record.snapshot_id,
|
||||
owner_user_id: record.owner_user_id,
|
||||
job_kind: runtime_job_kind_from_record(record.job_kind.as_str()),
|
||||
status: runtime_job_status_from_record(record.status.as_str()),
|
||||
attempt: record.attempt,
|
||||
worker_id: record.worker_id,
|
||||
lease_expires_at: record.lease_expires_at,
|
||||
cancel_requested_at: record.cancel_requested_at,
|
||||
stale_reason: record.stale_reason,
|
||||
artifact_id: record.artifact_id,
|
||||
preview_build_id: record.preview_build_id,
|
||||
error_summary: record.error_summary,
|
||||
created_at: record.created_at,
|
||||
started_at: record.started_at,
|
||||
finished_at: record.finished_at,
|
||||
updated_at: record.updated_at,
|
||||
}
|
||||
}
|
||||
|
||||
fn runtime_job_log_from_record(record: WebProjectRuntimeJobLogRecord) -> WebProjectRuntimeJobLog {
|
||||
WebProjectRuntimeJobLog {
|
||||
log_id: record.log_id,
|
||||
job_id: record.job_id,
|
||||
project_id: record.project_id,
|
||||
owner_user_id: record.owner_user_id,
|
||||
sequence: record.sequence,
|
||||
level: record.level,
|
||||
message: record.message,
|
||||
created_at: record.created_at,
|
||||
}
|
||||
}
|
||||
|
||||
fn paginate_runtime_job_log_records(
|
||||
mut logs: Vec<WebProjectRuntimeJobLogRecord>,
|
||||
requested_limit: u32,
|
||||
) -> (Vec<WebProjectRuntimeJobLog>, Option<u64>, bool) {
|
||||
let has_more = logs.len() > requested_limit as usize;
|
||||
logs.truncate(requested_limit as usize);
|
||||
let next_after_sequence = logs.last().map(|log| log.sequence);
|
||||
(
|
||||
logs.into_iter().map(runtime_job_log_from_record).collect(),
|
||||
next_after_sequence,
|
||||
has_more,
|
||||
)
|
||||
}
|
||||
|
||||
fn web_project_file_to_record(file: WebProjectFile) -> WebProjectFileRecord {
|
||||
WebProjectFileRecord {
|
||||
path: file.path,
|
||||
@@ -727,6 +991,32 @@ fn build_status_from_record(status: &str) -> WebProjectPreviewBuildStatus {
|
||||
}
|
||||
}
|
||||
|
||||
fn runtime_job_kind_to_record(kind: WebProjectRuntimeJobKind) -> String {
|
||||
match kind {
|
||||
WebProjectRuntimeJobKind::PreviewBuild => "preview_build".to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
fn runtime_job_kind_from_record(kind: &str) -> WebProjectRuntimeJobKind {
|
||||
match kind {
|
||||
"preview_build" => WebProjectRuntimeJobKind::PreviewBuild,
|
||||
_ => WebProjectRuntimeJobKind::PreviewBuild,
|
||||
}
|
||||
}
|
||||
|
||||
fn runtime_job_status_from_record(status: &str) -> WebProjectRuntimeJobStatus {
|
||||
match status {
|
||||
"running" => WebProjectRuntimeJobStatus::Running,
|
||||
"succeeded" => WebProjectRuntimeJobStatus::Succeeded,
|
||||
"failed" => WebProjectRuntimeJobStatus::Failed,
|
||||
"cancelled" => WebProjectRuntimeJobStatus::Cancelled,
|
||||
"expired" => WebProjectRuntimeJobStatus::Expired,
|
||||
"stale" => WebProjectRuntimeJobStatus::Stale,
|
||||
_ => WebProjectRuntimeJobStatus::Queued,
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn spawn_preview_build_task(
|
||||
state: AppState,
|
||||
owner_user_id: String,
|
||||
@@ -744,6 +1034,7 @@ fn spawn_preview_build_task(
|
||||
});
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
async fn run_preview_build_task(
|
||||
state: AppState,
|
||||
owner_user_id: String,
|
||||
@@ -827,6 +1118,7 @@ async fn run_preview_build_task(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
async fn mark_preview_build_failed(
|
||||
state: &AppState,
|
||||
owner_user_id: &str,
|
||||
@@ -873,6 +1165,98 @@ async fn mark_preview_build_failed(
|
||||
}
|
||||
}
|
||||
|
||||
async fn mark_preview_build_queue_failed(
|
||||
state: &AppState,
|
||||
owner_user_id: &str,
|
||||
build: WebProjectPreviewBuild,
|
||||
error: String,
|
||||
) -> WebProjectPreviewBuild {
|
||||
let now = current_utc_micros();
|
||||
let mut logs = build.logs.clone();
|
||||
logs.push("构建任务入队失败".to_string());
|
||||
logs.push(error.clone());
|
||||
match state
|
||||
.spacetime_client()
|
||||
.update_web_project_preview_build(
|
||||
spacetime_client::WebProjectPreviewBuildUpdateRecordInput {
|
||||
job_id: build.job_id.clone(),
|
||||
owner_user_id: owner_user_id.to_string(),
|
||||
status: "failed".to_string(),
|
||||
logs,
|
||||
artifact_id: None,
|
||||
preview_token_id: None,
|
||||
preview_url: None,
|
||||
error_summary: Some(error.clone()),
|
||||
started_at_micros: None,
|
||||
finished_at_micros: Some(now),
|
||||
updated_at_micros: now,
|
||||
},
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(updated) => build_from_record(updated.build),
|
||||
Err(update_error) => {
|
||||
let mut logs = build.logs.clone();
|
||||
logs.push("构建任务入队失败".to_string());
|
||||
logs.push(error.clone());
|
||||
logs.push(format!("入队失败状态写回失败:{update_error}"));
|
||||
WebProjectPreviewBuild {
|
||||
status: WebProjectPreviewBuildStatus::Failed,
|
||||
logs,
|
||||
error_summary: Some(error),
|
||||
finished_at: Some(shared_kernel::format_timestamp_micros(now)),
|
||||
updated_at: shared_kernel::format_timestamp_micros(now),
|
||||
..build
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate) async fn fail_preview_build_for_runtime_worker(
|
||||
state: &AppState,
|
||||
owner_user_id: &str,
|
||||
preview_build_id: &str,
|
||||
error: &str,
|
||||
) -> Result<WebProjectPreviewBuild, String> {
|
||||
let mutation = state
|
||||
.spacetime_client()
|
||||
.get_web_project_preview_build(WebProjectPreviewBuildGetRecordInput {
|
||||
job_id: preview_build_id.to_string(),
|
||||
owner_user_id: owner_user_id.to_string(),
|
||||
})
|
||||
.await
|
||||
.map_err(|error| error.to_string())?;
|
||||
let build = build_from_record(mutation.build);
|
||||
let now = current_utc_micros();
|
||||
let mut logs = build.logs.clone();
|
||||
logs.push("runtime worker: 构建任务失败".to_string());
|
||||
logs.push(format!("runtime worker: {error}"));
|
||||
let updated = state
|
||||
.spacetime_client()
|
||||
.update_web_project_preview_build(
|
||||
spacetime_client::WebProjectPreviewBuildUpdateRecordInput {
|
||||
job_id: build.job_id.clone(),
|
||||
owner_user_id: owner_user_id.to_string(),
|
||||
status: "failed".to_string(),
|
||||
logs,
|
||||
artifact_id: None,
|
||||
preview_token_id: None,
|
||||
preview_url: None,
|
||||
error_summary: Some(error.to_string()),
|
||||
started_at_micros: None,
|
||||
finished_at_micros: Some(now),
|
||||
updated_at_micros: now,
|
||||
},
|
||||
)
|
||||
.await
|
||||
.map_err(|error| error.to_string())?;
|
||||
let failed = build_from_record(updated.build);
|
||||
publish_build_event(state, &failed, failed.error_summary.as_deref());
|
||||
Ok(failed)
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
async fn invoke_runner_process(
|
||||
state: &AppState,
|
||||
build: &WebProjectPreviewBuild,
|
||||
@@ -968,6 +1352,7 @@ async fn invoke_runner_process(
|
||||
.map_err(|error| format!("runner 输出不是合法 JSON:{error}"))
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn resolve_runner_binary(state: &AppState) -> Result<PathBuf, String> {
|
||||
if let Some(path) = state.config.web_project_runner_bin.as_ref() {
|
||||
return Ok(path.clone());
|
||||
@@ -984,15 +1369,21 @@ fn resolve_runner_binary(state: &AppState) -> Result<PathBuf, String> {
|
||||
.unwrap_or_else(|| PathBuf::from(exe_name)))
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn build_preview_token_id(issued_at_micros: i64) -> String {
|
||||
format!("wpt_{}_{}", issued_at_micros, new_uuid_simple_string())
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn build_preview_url(base_url: &str, preview_token_id: &str) -> String {
|
||||
format!("{}/p/{preview_token_id}/", base_url.trim_end_matches('/'))
|
||||
}
|
||||
|
||||
fn publish_build_event(state: &AppState, build: &WebProjectPreviewBuild, message: Option<&str>) {
|
||||
pub(crate) fn publish_build_event(
|
||||
state: &AppState,
|
||||
build: &WebProjectPreviewBuild,
|
||||
message: Option<&str>,
|
||||
) {
|
||||
let event = WebProjectPreviewBuildEvent {
|
||||
job_id: build.job_id.clone(),
|
||||
status: build.status.clone(),
|
||||
@@ -1012,6 +1403,7 @@ fn web_project_bad_request(message: &str, path: Option<&str>) -> AppError {
|
||||
}))
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn map_preview_build_slot_error(
|
||||
error: WebProjectPreviewBuildSlotError,
|
||||
project_id: &str,
|
||||
@@ -1088,4 +1480,139 @@ mod tests {
|
||||
assert_eq!(error.status_code(), StatusCode::BAD_REQUEST);
|
||||
assert!(error.body_text().contains("目标文件已存在"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn web_project_runtime_job_status_from_record_maps_terminal_states() {
|
||||
assert_eq!(
|
||||
runtime_job_status_from_record("succeeded"),
|
||||
WebProjectRuntimeJobStatus::Succeeded
|
||||
);
|
||||
assert_eq!(
|
||||
runtime_job_status_from_record("stale"),
|
||||
WebProjectRuntimeJobStatus::Stale
|
||||
);
|
||||
assert_eq!(
|
||||
runtime_job_status_from_record("unexpected"),
|
||||
WebProjectRuntimeJobStatus::Queued
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn web_project_runtime_job_response_does_not_expose_lease_token() {
|
||||
let job = runtime_job_from_record(WebProjectRuntimeJobRecord {
|
||||
job_id: "job-1".to_string(),
|
||||
project_id: "project-1".to_string(),
|
||||
snapshot_id: "snapshot-1".to_string(),
|
||||
owner_user_id: "user-1".to_string(),
|
||||
job_kind: "preview_build".to_string(),
|
||||
status: "running".to_string(),
|
||||
attempt: 1,
|
||||
worker_id: Some("worker-1".to_string()),
|
||||
lease_token: Some("secret-lease".to_string()),
|
||||
lease_expires_at: Some("2026-06-17T00:00:00Z".to_string()),
|
||||
cancel_requested_at: None,
|
||||
stale_reason: None,
|
||||
artifact_id: None,
|
||||
preview_build_id: None,
|
||||
error_summary: None,
|
||||
created_at: "2026-06-17T00:00:00Z".to_string(),
|
||||
started_at: Some("2026-06-17T00:00:00Z".to_string()),
|
||||
finished_at: None,
|
||||
updated_at: "2026-06-17T00:00:00Z".to_string(),
|
||||
});
|
||||
|
||||
let value = serde_json::to_value(WebProjectRuntimeJobResponse { job })
|
||||
.expect("runtime job response should serialize");
|
||||
|
||||
assert!(value["job"].get("leaseToken").is_none());
|
||||
assert_eq!(value["job"]["status"], "running");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn web_project_runtime_logs_paginates_by_sequence() {
|
||||
let records = vec![
|
||||
runtime_log_record(1, "hydrate snapshot"),
|
||||
runtime_log_record(2, "run build"),
|
||||
runtime_log_record(3, "write artifact"),
|
||||
];
|
||||
|
||||
let (logs, next_after_sequence, has_more) =
|
||||
paginate_runtime_job_log_records(records, 2);
|
||||
|
||||
assert_eq!(
|
||||
logs.iter().map(|log| log.sequence).collect::<Vec<_>>(),
|
||||
vec![1, 2]
|
||||
);
|
||||
assert_eq!(
|
||||
logs.iter().map(|log| log.message.as_str()).collect::<Vec<_>>(),
|
||||
vec!["hydrate snapshot", "run build"]
|
||||
);
|
||||
assert_eq!(next_after_sequence, Some(2));
|
||||
assert!(has_more);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn preview_build_response_can_include_runtime_job() {
|
||||
let build = WebProjectPreviewBuild {
|
||||
job_id: "web-build-1".to_string(),
|
||||
project_id: "web-project-1".to_string(),
|
||||
snapshot_id: "web-snapshot-1".to_string(),
|
||||
owner_user_id: "user-1".to_string(),
|
||||
status: WebProjectPreviewBuildStatus::Queued,
|
||||
logs: vec!["构建任务已进入队列".to_string()],
|
||||
artifact_id: None,
|
||||
preview_token_id: None,
|
||||
preview_url: None,
|
||||
error_summary: None,
|
||||
created_at: "2026-06-17T00:00:00Z".to_string(),
|
||||
started_at: None,
|
||||
finished_at: None,
|
||||
updated_at: "2026-06-17T00:00:00Z".to_string(),
|
||||
};
|
||||
let runtime_job = runtime_job_from_record(WebProjectRuntimeJobRecord {
|
||||
job_id: "web-runtime-job-1".to_string(),
|
||||
project_id: "web-project-1".to_string(),
|
||||
snapshot_id: "web-snapshot-1".to_string(),
|
||||
owner_user_id: "user-1".to_string(),
|
||||
job_kind: "preview_build".to_string(),
|
||||
status: "queued".to_string(),
|
||||
attempt: 0,
|
||||
worker_id: None,
|
||||
lease_token: Some("secret-lease".to_string()),
|
||||
lease_expires_at: None,
|
||||
cancel_requested_at: None,
|
||||
stale_reason: None,
|
||||
artifact_id: None,
|
||||
preview_build_id: Some("web-build-1".to_string()),
|
||||
error_summary: None,
|
||||
created_at: "2026-06-17T00:00:00Z".to_string(),
|
||||
started_at: None,
|
||||
finished_at: None,
|
||||
updated_at: "2026-06-17T00:00:00Z".to_string(),
|
||||
});
|
||||
|
||||
let value = serde_json::to_value(WebProjectPreviewBuildResponse {
|
||||
build,
|
||||
runtime_job: Some(runtime_job),
|
||||
})
|
||||
.expect("preview build response should serialize");
|
||||
|
||||
assert_eq!(value["build"]["jobId"], "web-build-1");
|
||||
assert_eq!(value["runtimeJob"]["jobId"], "web-runtime-job-1");
|
||||
assert_eq!(value["runtimeJob"]["previewBuildId"], "web-build-1");
|
||||
assert!(value["runtimeJob"].get("leaseToken").is_none());
|
||||
}
|
||||
|
||||
fn runtime_log_record(sequence: u64, message: &str) -> WebProjectRuntimeJobLogRecord {
|
||||
WebProjectRuntimeJobLogRecord {
|
||||
log_id: format!("runtime-log-{sequence}"),
|
||||
job_id: "web-runtime-job-1".to_string(),
|
||||
project_id: "web-project-1".to_string(),
|
||||
owner_user_id: "user-1".to_string(),
|
||||
sequence,
|
||||
level: "info".to_string(),
|
||||
message: message.to_string(),
|
||||
created_at: format!("2026-06-17T00:00:0{sequence}.000Z"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
472
server-rs/crates/api-server/src/web_project_preview_runtime.rs
Normal file
472
server-rs/crates/api-server/src/web_project_preview_runtime.rs
Normal file
@@ -0,0 +1,472 @@
|
||||
use std::{
|
||||
future::Future,
|
||||
path::PathBuf,
|
||||
pin::Pin,
|
||||
process::Stdio,
|
||||
time::{Duration, SystemTime, UNIX_EPOCH},
|
||||
};
|
||||
|
||||
use shared_contracts::web_project::{WebProjectPreviewBuild, WebProjectPreviewBuildStatus};
|
||||
use shared_kernel::new_uuid_simple_string;
|
||||
use spacetime_client::{
|
||||
WebProjectPreviewBuildGetRecordInput, WebProjectPreviewBuildUpdateRecordInput,
|
||||
WebProjectRuntimeJobRecord, WebProjectSnapshotGetRecordInput, WebProjectSnapshotRecord,
|
||||
};
|
||||
use tokio::{
|
||||
io::{AsyncReadExt, AsyncWriteExt},
|
||||
process::Command,
|
||||
};
|
||||
use web_project_runner::{
|
||||
WebProjectBuildInput, WebProjectBuildOutput, WebProjectBuildStatus, WebProjectRunnerFile,
|
||||
};
|
||||
|
||||
use crate::{state::AppState, web_project};
|
||||
|
||||
const WEB_PROJECT_RUNNER_TIMEOUT: Duration = Duration::from_secs(300);
|
||||
|
||||
// P2-06 先保留子进程 runner 边界;后续 Docker / gVisor / microVM 只替换 SandboxRuntime 实现。
|
||||
pub(crate) trait SandboxRuntime: Send + Sync {
|
||||
fn run_preview_build<'a>(
|
||||
&'a self,
|
||||
state: &'a AppState,
|
||||
build: &'a WebProjectPreviewBuild,
|
||||
snapshot: WebProjectSnapshotRecord,
|
||||
) -> Pin<Box<dyn Future<Output = Result<WebProjectBuildOutput, String>> + Send + 'a>>;
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Default)]
|
||||
pub(crate) struct TempDirBuildRuntime;
|
||||
|
||||
impl SandboxRuntime for TempDirBuildRuntime {
|
||||
fn run_preview_build<'a>(
|
||||
&'a self,
|
||||
state: &'a AppState,
|
||||
build: &'a WebProjectPreviewBuild,
|
||||
snapshot: WebProjectSnapshotRecord,
|
||||
) -> Pin<Box<dyn Future<Output = Result<WebProjectBuildOutput, String>> + Send + 'a>> {
|
||||
Box::pin(invoke_runner_process(state, build, snapshot))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct PreviewBuildRunOutput {
|
||||
pub build: WebProjectPreviewBuild,
|
||||
pub runner_output: WebProjectBuildOutput,
|
||||
pub started_at_micros: i64,
|
||||
pub finished_at_micros: i64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct PreviewBuildFinishPlan {
|
||||
pub succeeded: bool,
|
||||
pub logs: Vec<String>,
|
||||
pub artifact_id: Option<String>,
|
||||
pub preview_token_id: Option<String>,
|
||||
pub preview_url: Option<String>,
|
||||
pub error_summary: Option<String>,
|
||||
}
|
||||
|
||||
pub(crate) async fn run_preview_build_with_temp_dir_runtime(
|
||||
state: &AppState,
|
||||
job: &WebProjectRuntimeJobRecord,
|
||||
) -> Result<PreviewBuildRunOutput, String> {
|
||||
let runtime = TempDirBuildRuntime;
|
||||
run_preview_build_with_runtime(state, job, &runtime).await
|
||||
}
|
||||
|
||||
async fn run_preview_build_with_runtime<R: SandboxRuntime>(
|
||||
state: &AppState,
|
||||
job: &WebProjectRuntimeJobRecord,
|
||||
runtime: &R,
|
||||
) -> Result<PreviewBuildRunOutput, String> {
|
||||
let preview_build_id = job
|
||||
.preview_build_id
|
||||
.as_deref()
|
||||
.ok_or_else(|| "preview_build runtime job 缺少 preview_build_id".to_string())?;
|
||||
let build = get_preview_build(state, &job.owner_user_id, preview_build_id).await?;
|
||||
validate_runtime_job_preview_build(job, &build)?;
|
||||
if is_terminal_preview_build_status(&build.status) {
|
||||
return Err(format!(
|
||||
"preview build {preview_build_id} 已终态,不能重复执行"
|
||||
));
|
||||
}
|
||||
|
||||
let started_at_micros = current_utc_micros();
|
||||
let running_build = mark_preview_build_running(state, &job.owner_user_id, &build).await?;
|
||||
let snapshot = state
|
||||
.spacetime_client()
|
||||
.get_web_project_snapshot(WebProjectSnapshotGetRecordInput {
|
||||
project_id: job.project_id.clone(),
|
||||
snapshot_id: Some(job.snapshot_id.clone()),
|
||||
owner_user_id: job.owner_user_id.clone(),
|
||||
})
|
||||
.await
|
||||
.map_err(|error| format!("hydrate snapshot 失败:{error}"))?
|
||||
.snapshot;
|
||||
let runner_output = runtime
|
||||
.run_preview_build(state, &running_build, snapshot)
|
||||
.await?;
|
||||
let finished_at_micros = current_utc_micros();
|
||||
|
||||
Ok(PreviewBuildRunOutput {
|
||||
build: running_build,
|
||||
runner_output,
|
||||
started_at_micros,
|
||||
finished_at_micros,
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) async fn finish_preview_build_from_runner_output(
|
||||
state: &AppState,
|
||||
owner_user_id: &str,
|
||||
running_build: &WebProjectPreviewBuild,
|
||||
started_at_micros: i64,
|
||||
finished_at_micros: i64,
|
||||
runner_output: &WebProjectBuildOutput,
|
||||
) -> Result<Option<String>, String> {
|
||||
let finish_plan = plan_preview_build_finish_from_runner_output(
|
||||
state,
|
||||
running_build,
|
||||
finished_at_micros,
|
||||
runner_output,
|
||||
);
|
||||
let updated = state
|
||||
.spacetime_client()
|
||||
.update_web_project_preview_build(WebProjectPreviewBuildUpdateRecordInput {
|
||||
job_id: running_build.job_id.clone(),
|
||||
owner_user_id: owner_user_id.to_string(),
|
||||
status: if finish_plan.succeeded {
|
||||
"succeeded"
|
||||
} else {
|
||||
"failed"
|
||||
}
|
||||
.to_string(),
|
||||
logs: finish_plan.logs,
|
||||
artifact_id: finish_plan.artifact_id.clone(),
|
||||
preview_token_id: finish_plan.preview_token_id,
|
||||
preview_url: finish_plan.preview_url.clone(),
|
||||
error_summary: finish_plan.error_summary.clone(),
|
||||
started_at_micros: Some(started_at_micros),
|
||||
finished_at_micros: Some(finished_at_micros),
|
||||
updated_at_micros: finished_at_micros,
|
||||
})
|
||||
.await
|
||||
.map_err(|error| error.to_string())?;
|
||||
let build = web_project::build_from_record(updated.build);
|
||||
web_project::publish_build_event(
|
||||
state,
|
||||
&build,
|
||||
build
|
||||
.error_summary
|
||||
.as_deref()
|
||||
.or(Some(if finish_plan.succeeded {
|
||||
"构建完成"
|
||||
} else {
|
||||
"构建失败"
|
||||
})),
|
||||
);
|
||||
|
||||
Ok(finish_plan.error_summary)
|
||||
}
|
||||
|
||||
pub(crate) fn plan_preview_build_finish_from_runner_output(
|
||||
state: &AppState,
|
||||
running_build: &WebProjectPreviewBuild,
|
||||
finished_at_micros: i64,
|
||||
runner_output: &WebProjectBuildOutput,
|
||||
) -> PreviewBuildFinishPlan {
|
||||
let succeeded = runner_output.status == WebProjectBuildStatus::Succeeded
|
||||
&& runner_output.artifact_id.is_some();
|
||||
let missing_artifact_error = (runner_output.status == WebProjectBuildStatus::Succeeded
|
||||
&& runner_output.artifact_id.is_none())
|
||||
.then(|| "web-project-runner 成功但缺少 artifact_id".to_string());
|
||||
let preview_token_id = succeeded.then(|| build_preview_token_id(finished_at_micros));
|
||||
let preview_url = preview_token_id
|
||||
.as_ref()
|
||||
.map(|token| build_preview_url(&state.config.web_project_preview_public_base_url, token));
|
||||
let error_summary = missing_artifact_error.or_else(|| runner_output.error_summary.clone());
|
||||
let mut logs = running_build.logs.clone();
|
||||
logs.extend(runner_output.logs.clone());
|
||||
logs.push(if succeeded {
|
||||
"runtime worker: 构建完成,预览地址已生成".to_string()
|
||||
} else {
|
||||
"runtime worker: 构建失败".to_string()
|
||||
});
|
||||
|
||||
PreviewBuildFinishPlan {
|
||||
succeeded,
|
||||
logs,
|
||||
artifact_id: runner_output.artifact_id.clone().filter(|_| succeeded),
|
||||
preview_token_id,
|
||||
preview_url,
|
||||
error_summary,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) async fn fail_preview_build_for_runtime_worker(
|
||||
state: &AppState,
|
||||
owner_user_id: &str,
|
||||
preview_build_id: &str,
|
||||
error: &str,
|
||||
) -> Result<WebProjectPreviewBuild, String> {
|
||||
finish_preview_build_with_terminal_status(
|
||||
state,
|
||||
owner_user_id,
|
||||
preview_build_id,
|
||||
"failed",
|
||||
"runtime worker: 构建任务失败",
|
||||
error,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
pub(crate) async fn cancel_preview_build_for_runtime_worker(
|
||||
state: &AppState,
|
||||
owner_user_id: &str,
|
||||
preview_build_id: &str,
|
||||
) -> Result<WebProjectPreviewBuild, String> {
|
||||
finish_preview_build_with_terminal_status(
|
||||
state,
|
||||
owner_user_id,
|
||||
preview_build_id,
|
||||
"cancelled",
|
||||
"runtime worker: 构建任务已取消",
|
||||
"构建任务已取消",
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn finish_preview_build_with_terminal_status(
|
||||
state: &AppState,
|
||||
owner_user_id: &str,
|
||||
preview_build_id: &str,
|
||||
status: &str,
|
||||
log_message: &str,
|
||||
error: &str,
|
||||
) -> Result<WebProjectPreviewBuild, String> {
|
||||
let build = get_preview_build(state, owner_user_id, preview_build_id).await?;
|
||||
let now = current_utc_micros();
|
||||
let mut logs = build.logs.clone();
|
||||
logs.push(log_message.to_string());
|
||||
logs.push(format!("runtime worker: {error}"));
|
||||
let updated = state
|
||||
.spacetime_client()
|
||||
.update_web_project_preview_build(WebProjectPreviewBuildUpdateRecordInput {
|
||||
job_id: build.job_id.clone(),
|
||||
owner_user_id: owner_user_id.to_string(),
|
||||
status: status.to_string(),
|
||||
logs,
|
||||
artifact_id: None,
|
||||
preview_token_id: None,
|
||||
preview_url: None,
|
||||
error_summary: Some(error.to_string()),
|
||||
started_at_micros: None,
|
||||
finished_at_micros: Some(now),
|
||||
updated_at_micros: now,
|
||||
})
|
||||
.await
|
||||
.map_err(|error| error.to_string())?;
|
||||
let build = web_project::build_from_record(updated.build);
|
||||
web_project::publish_build_event(state, &build, build.error_summary.as_deref());
|
||||
Ok(build)
|
||||
}
|
||||
|
||||
async fn mark_preview_build_running(
|
||||
state: &AppState,
|
||||
owner_user_id: &str,
|
||||
build: &WebProjectPreviewBuild,
|
||||
) -> Result<WebProjectPreviewBuild, String> {
|
||||
let started_at_micros = current_utc_micros();
|
||||
let mut logs = build.logs.clone();
|
||||
logs.push("runtime worker: hydrate snapshot".to_string());
|
||||
logs.push("构建任务开始执行".to_string());
|
||||
let updated = state
|
||||
.spacetime_client()
|
||||
.update_web_project_preview_build(WebProjectPreviewBuildUpdateRecordInput {
|
||||
job_id: build.job_id.clone(),
|
||||
owner_user_id: owner_user_id.to_string(),
|
||||
status: "running".to_string(),
|
||||
logs,
|
||||
artifact_id: None,
|
||||
preview_token_id: None,
|
||||
preview_url: None,
|
||||
error_summary: None,
|
||||
started_at_micros: Some(started_at_micros),
|
||||
finished_at_micros: None,
|
||||
updated_at_micros: started_at_micros,
|
||||
})
|
||||
.await
|
||||
.map_err(|error| error.to_string())?;
|
||||
let running_build = web_project::build_from_record(updated.build);
|
||||
web_project::publish_build_event(state, &running_build, Some("构建任务开始执行"));
|
||||
Ok(running_build)
|
||||
}
|
||||
|
||||
async fn get_preview_build(
|
||||
state: &AppState,
|
||||
owner_user_id: &str,
|
||||
preview_build_id: &str,
|
||||
) -> Result<WebProjectPreviewBuild, String> {
|
||||
let mutation = state
|
||||
.spacetime_client()
|
||||
.get_web_project_preview_build(WebProjectPreviewBuildGetRecordInput {
|
||||
job_id: preview_build_id.to_string(),
|
||||
owner_user_id: owner_user_id.to_string(),
|
||||
})
|
||||
.await
|
||||
.map_err(|error| error.to_string())?;
|
||||
Ok(web_project::build_from_record(mutation.build))
|
||||
}
|
||||
|
||||
fn validate_runtime_job_preview_build(
|
||||
job: &WebProjectRuntimeJobRecord,
|
||||
build: &WebProjectPreviewBuild,
|
||||
) -> Result<(), String> {
|
||||
if build.project_id != job.project_id
|
||||
|| build.snapshot_id != job.snapshot_id
|
||||
|| build.owner_user_id != job.owner_user_id
|
||||
{
|
||||
return Err(format!(
|
||||
"runtime job {} 与 preview build {} 绑定信息不一致",
|
||||
job.job_id, build.job_id
|
||||
));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn is_terminal_preview_build_status(status: &WebProjectPreviewBuildStatus) -> bool {
|
||||
matches!(
|
||||
status,
|
||||
WebProjectPreviewBuildStatus::Succeeded
|
||||
| WebProjectPreviewBuildStatus::Failed
|
||||
| WebProjectPreviewBuildStatus::Cancelled
|
||||
| WebProjectPreviewBuildStatus::Expired
|
||||
| WebProjectPreviewBuildStatus::Stale
|
||||
)
|
||||
}
|
||||
|
||||
async fn invoke_runner_process(
|
||||
state: &AppState,
|
||||
build: &WebProjectPreviewBuild,
|
||||
snapshot: WebProjectSnapshotRecord,
|
||||
) -> Result<WebProjectBuildOutput, String> {
|
||||
let runner_bin = resolve_runner_binary(state)?;
|
||||
let input = WebProjectBuildInput {
|
||||
job_id: build.job_id.clone(),
|
||||
project_id: build.project_id.clone(),
|
||||
snapshot_id: build.snapshot_id.clone(),
|
||||
files: snapshot
|
||||
.files
|
||||
.into_iter()
|
||||
.map(|file| WebProjectRunnerFile {
|
||||
path: file.path,
|
||||
content: file.content,
|
||||
})
|
||||
.collect(),
|
||||
artifact_root: state.config.web_project_artifact_root.clone(),
|
||||
};
|
||||
let input_json = serde_json::to_vec(&input).map_err(|error| error.to_string())?;
|
||||
let mut command = Command::new(&runner_bin);
|
||||
command
|
||||
.stdin(Stdio::piped())
|
||||
.stdout(Stdio::piped())
|
||||
.stderr(Stdio::piped())
|
||||
.kill_on_drop(true);
|
||||
let mut child = command
|
||||
.spawn()
|
||||
.map_err(|error| format!("启动 web-project-runner 失败:{error}"))?;
|
||||
if let Some(mut stdin) = child.stdin.take() {
|
||||
stdin
|
||||
.write_all(&input_json)
|
||||
.await
|
||||
.map_err(|error| format!("写入 runner 输入失败:{error}"))?;
|
||||
}
|
||||
let mut stdout = child
|
||||
.stdout
|
||||
.take()
|
||||
.ok_or_else(|| "web-project-runner stdout 未打开".to_string())?;
|
||||
let mut stderr = child
|
||||
.stderr
|
||||
.take()
|
||||
.ok_or_else(|| "web-project-runner stderr 未打开".to_string())?;
|
||||
let stdout_task = tokio::spawn(async move {
|
||||
let mut bytes = Vec::new();
|
||||
stdout
|
||||
.read_to_end(&mut bytes)
|
||||
.await
|
||||
.map(|_| bytes)
|
||||
.map_err(|error| error.to_string())
|
||||
});
|
||||
let stderr_task = tokio::spawn(async move {
|
||||
let mut bytes = Vec::new();
|
||||
stderr
|
||||
.read_to_end(&mut bytes)
|
||||
.await
|
||||
.map(|_| bytes)
|
||||
.map_err(|error| error.to_string())
|
||||
});
|
||||
let status = match tokio::time::timeout(WEB_PROJECT_RUNNER_TIMEOUT, child.wait()).await {
|
||||
Ok(result) => result.map_err(|error| format!("等待 runner 退出失败:{error}"))?,
|
||||
Err(_) => {
|
||||
let _ = child.kill().await;
|
||||
let _ = child.wait().await;
|
||||
let _ = stdout_task.await;
|
||||
let _ = stderr_task.await;
|
||||
return Err("web-project-runner 执行超时".to_string());
|
||||
}
|
||||
};
|
||||
let stdout = stdout_task
|
||||
.await
|
||||
.map_err(|error| format!("读取 runner stdout 任务失败:{error}"))?
|
||||
.map_err(|error| format!("读取 runner stdout 失败:{error}"))?;
|
||||
let stderr = stderr_task
|
||||
.await
|
||||
.map_err(|error| format!("读取 runner stderr 任务失败:{error}"))?
|
||||
.map_err(|error| format!("读取 runner stderr 失败:{error}"))?;
|
||||
if !status.success() {
|
||||
let stderr = String::from_utf8_lossy(&stderr);
|
||||
return Ok(WebProjectBuildOutput {
|
||||
job_id: build.job_id.clone(),
|
||||
project_id: build.project_id.clone(),
|
||||
snapshot_id: build.snapshot_id.clone(),
|
||||
status: WebProjectBuildStatus::Failed,
|
||||
artifact_id: None,
|
||||
artifact_path: None,
|
||||
error_summary: Some(format!("web-project-runner 退出失败:{}", stderr.trim())),
|
||||
logs: vec![stderr.to_string()],
|
||||
});
|
||||
}
|
||||
serde_json::from_slice::<WebProjectBuildOutput>(&stdout)
|
||||
.map_err(|error| format!("runner 输出不是合法 JSON:{error}"))
|
||||
}
|
||||
|
||||
fn resolve_runner_binary(state: &AppState) -> Result<PathBuf, String> {
|
||||
if let Some(path) = state.config.web_project_runner_bin.as_ref() {
|
||||
return Ok(path.clone());
|
||||
}
|
||||
let current_exe = std::env::current_exe().map_err(|error| error.to_string())?;
|
||||
let exe_name = if cfg!(windows) {
|
||||
"web-project-runner.exe"
|
||||
} else {
|
||||
"web-project-runner"
|
||||
};
|
||||
Ok(current_exe
|
||||
.parent()
|
||||
.map(|parent| parent.join(exe_name))
|
||||
.unwrap_or_else(|| PathBuf::from(exe_name)))
|
||||
}
|
||||
|
||||
fn build_preview_token_id(issued_at_micros: i64) -> String {
|
||||
format!("wpt_{}_{}", issued_at_micros, new_uuid_simple_string())
|
||||
}
|
||||
|
||||
fn build_preview_url(base_url: &str, preview_token_id: &str) -> String {
|
||||
format!("{}/p/{preview_token_id}/", base_url.trim_end_matches('/'))
|
||||
}
|
||||
|
||||
fn current_utc_micros() -> i64 {
|
||||
let duration = SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.expect("system clock should be after unix epoch");
|
||||
i64::try_from(duration.as_micros()).expect("current unix micros should fit in i64")
|
||||
}
|
||||
920
server-rs/crates/api-server/src/web_project_runtime_worker.rs
Normal file
920
server-rs/crates/api-server/src/web_project_runtime_worker.rs
Normal file
@@ -0,0 +1,920 @@
|
||||
use std::{future::Future, io, pin::Pin, time::Duration};
|
||||
|
||||
use shared_kernel::{build_prefixed_uuid_id, offset_datetime_to_unix_micros};
|
||||
use spacetime_client::{
|
||||
WebProjectRuntimeJobAppendLogRecordInput, WebProjectRuntimeJobClaimRecordInput,
|
||||
WebProjectRuntimeJobCompletePreviewBuildRecordInput, WebProjectRuntimeJobCompleteRecordInput,
|
||||
WebProjectRuntimeJobFailRecordInput, WebProjectRuntimeJobListLogsRecordInput,
|
||||
WebProjectRuntimeJobLogRecord, WebProjectRuntimeJobRecord,
|
||||
WebProjectRuntimeJobRenewLeaseRecordInput,
|
||||
};
|
||||
use tokio::{
|
||||
task::JoinSet,
|
||||
time::{Instant, sleep},
|
||||
};
|
||||
use tracing::{error, info, warn};
|
||||
|
||||
use web_project_runner::WebProjectBuildStatus;
|
||||
|
||||
use crate::{
|
||||
config::WebProjectRuntimeWorkerDryRunResult, state::AppState, web_project,
|
||||
web_project_preview_runtime,
|
||||
};
|
||||
|
||||
const WEB_PROJECT_RUNTIME_JOB_KIND_PREVIEW_BUILD: &str = "preview_build";
|
||||
const WEB_PROJECT_RUNTIME_JOB_LOG_ID_PREFIX: &str = "web-runtime-log-";
|
||||
const WEB_PROJECT_RUNTIME_JOB_LOG_PAGE_SIZE: u32 = 200;
|
||||
|
||||
pub(crate) async fn run_web_project_runtime_worker(state: AppState) -> Result<(), io::Error> {
|
||||
let worker_id = state.config.web_project_runtime_worker_id.clone();
|
||||
let concurrency = state.config.web_project_runtime_worker_concurrency.max(1);
|
||||
let poll_interval = state.config.web_project_runtime_worker_poll_interval;
|
||||
let lease = state.config.web_project_runtime_worker_lease;
|
||||
let dry_run_result = state.config.web_project_runtime_worker_dry_run_result;
|
||||
let mut tasks = JoinSet::new();
|
||||
let mut shutdown = web_project_runtime_worker_shutdown_signal();
|
||||
|
||||
info!(
|
||||
worker_id,
|
||||
concurrency,
|
||||
poll_interval_ms = poll_interval.as_millis(),
|
||||
lease_seconds = lease.as_secs(),
|
||||
dry_run_result = dry_run_result.as_str(),
|
||||
"Web Project runtime worker 已启动"
|
||||
);
|
||||
|
||||
loop {
|
||||
while tasks.len() >= concurrency {
|
||||
if await_worker_task_or_shutdown(&mut tasks, &mut shutdown).await {
|
||||
drain_web_project_runtime_worker_tasks(&mut tasks).await;
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
let available = concurrency.saturating_sub(tasks.len()).max(1);
|
||||
let now_micros = current_utc_micros();
|
||||
let lease_expires_at_micros = now_micros.saturating_add(duration_micros_i64(lease));
|
||||
|
||||
let claim_jobs = state.spacetime_client().claim_web_project_runtime_jobs(
|
||||
WebProjectRuntimeJobClaimRecordInput {
|
||||
worker_id: worker_id.clone(),
|
||||
limit: available.min(u32::MAX as usize) as u32,
|
||||
lease_expires_at_micros,
|
||||
claimed_at_micros: now_micros,
|
||||
},
|
||||
);
|
||||
tokio::pin!(claim_jobs);
|
||||
let jobs = match tokio::select! {
|
||||
_ = shutdown.as_mut() => {
|
||||
drain_web_project_runtime_worker_tasks(&mut tasks).await;
|
||||
return Ok(());
|
||||
}
|
||||
result = &mut claim_jobs => result,
|
||||
} {
|
||||
Ok(jobs) => jobs,
|
||||
Err(error) => {
|
||||
error!(error = %error, "领取 Web Project runtime job 失败,等待下一轮重试");
|
||||
if await_one_task_or_sleep_or_shutdown(
|
||||
&mut tasks,
|
||||
sleep(poll_interval),
|
||||
&mut shutdown,
|
||||
)
|
||||
.await
|
||||
{
|
||||
drain_web_project_runtime_worker_tasks(&mut tasks).await;
|
||||
return Ok(());
|
||||
}
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
if jobs.is_empty() {
|
||||
if await_one_task_or_sleep_or_shutdown(&mut tasks, sleep(poll_interval), &mut shutdown)
|
||||
.await
|
||||
{
|
||||
drain_web_project_runtime_worker_tasks(&mut tasks).await;
|
||||
return Ok(());
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
for job in jobs {
|
||||
let state = state.clone();
|
||||
let worker_id = worker_id.clone();
|
||||
tasks.spawn(async move {
|
||||
if let Err(error) =
|
||||
process_web_project_runtime_job(state, worker_id, lease, dry_run_result, job)
|
||||
.await
|
||||
{
|
||||
error!(error = %error, "Web Project runtime worker 执行任务失败");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type WebProjectRuntimeWorkerShutdownSignal = Pin<Box<dyn Future<Output = ()> + Send>>;
|
||||
|
||||
fn web_project_runtime_worker_shutdown_signal() -> WebProjectRuntimeWorkerShutdownSignal {
|
||||
Box::pin(async {
|
||||
wait_for_web_project_runtime_worker_shutdown_signal().await;
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
async fn wait_for_web_project_runtime_worker_shutdown_signal() {
|
||||
use tokio::signal::unix::{SignalKind, signal};
|
||||
|
||||
let mut sigterm = signal(SignalKind::terminate()).ok();
|
||||
tokio::select! {
|
||||
result = tokio::signal::ctrl_c() => {
|
||||
if let Err(error) = result {
|
||||
warn!(error = %error, "Web Project runtime worker 监听 SIGINT 失败");
|
||||
}
|
||||
}
|
||||
_ = async {
|
||||
if let Some(sigterm) = sigterm.as_mut() {
|
||||
sigterm.recv().await;
|
||||
} else {
|
||||
std::future::pending::<()>().await;
|
||||
}
|
||||
} => {}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(unix))]
|
||||
async fn wait_for_web_project_runtime_worker_shutdown_signal() {
|
||||
if let Err(error) = tokio::signal::ctrl_c().await {
|
||||
warn!(error = %error, "Web Project runtime worker 监听 Ctrl-C 失败");
|
||||
}
|
||||
}
|
||||
|
||||
async fn await_worker_task(tasks: &mut JoinSet<()>) {
|
||||
if let Some(result) = tasks.join_next().await
|
||||
&& let Err(error) = result
|
||||
{
|
||||
error!(error = %error, "Web Project runtime worker 子任务 panic");
|
||||
}
|
||||
}
|
||||
|
||||
async fn await_worker_task_or_shutdown(
|
||||
tasks: &mut JoinSet<()>,
|
||||
shutdown: &mut WebProjectRuntimeWorkerShutdownSignal,
|
||||
) -> bool {
|
||||
tokio::select! {
|
||||
_ = shutdown.as_mut() => true,
|
||||
_ = await_worker_task(tasks) => false,
|
||||
}
|
||||
}
|
||||
|
||||
async fn await_one_task_or_sleep_or_shutdown(
|
||||
tasks: &mut JoinSet<()>,
|
||||
sleeper: impl Future<Output = ()>,
|
||||
shutdown: &mut WebProjectRuntimeWorkerShutdownSignal,
|
||||
) -> bool {
|
||||
tokio::pin!(sleeper);
|
||||
if tasks.is_empty() {
|
||||
tokio::select! {
|
||||
_ = shutdown.as_mut() => true,
|
||||
_ = &mut sleeper => false,
|
||||
}
|
||||
} else {
|
||||
tokio::select! {
|
||||
_ = shutdown.as_mut() => true,
|
||||
_ = &mut sleeper => false,
|
||||
result = tasks.join_next() => {
|
||||
if let Some(Err(error)) = result {
|
||||
error!(error = %error, "Web Project runtime worker 子任务 panic");
|
||||
}
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn drain_web_project_runtime_worker_tasks(tasks: &mut JoinSet<()>) {
|
||||
info!(
|
||||
in_flight_jobs = tasks.len(),
|
||||
"Web Project runtime worker 收到停机信号,停止领取新任务并等待当前任务完成"
|
||||
);
|
||||
while !tasks.is_empty() {
|
||||
await_worker_task(tasks).await;
|
||||
}
|
||||
info!("Web Project runtime worker 已完成优雅停机");
|
||||
}
|
||||
|
||||
async fn process_web_project_runtime_job(
|
||||
state: AppState,
|
||||
worker_id: String,
|
||||
lease: Duration,
|
||||
dry_run_result: WebProjectRuntimeWorkerDryRunResult,
|
||||
job: WebProjectRuntimeJobRecord,
|
||||
) -> Result<(), String> {
|
||||
let terminal_update = process_web_project_runtime_job_until_terminal_update(
|
||||
state.clone(),
|
||||
worker_id.clone(),
|
||||
dry_run_result,
|
||||
job.clone(),
|
||||
lease,
|
||||
)
|
||||
.await?;
|
||||
finish_web_project_runtime_job_terminal_update(state, worker_id, job, terminal_update).await
|
||||
}
|
||||
|
||||
async fn process_web_project_runtime_job_until_terminal_update(
|
||||
state: AppState,
|
||||
worker_id: String,
|
||||
dry_run_result: WebProjectRuntimeWorkerDryRunResult,
|
||||
job: WebProjectRuntimeJobRecord,
|
||||
lease: Duration,
|
||||
) -> Result<WebProjectRuntimeWorkerTerminalUpdate, String> {
|
||||
let heartbeat_interval = web_project_runtime_worker_heartbeat_interval(lease);
|
||||
let work = plan_web_project_runtime_job_terminal_update(
|
||||
state.clone(),
|
||||
worker_id.clone(),
|
||||
dry_run_result,
|
||||
job.clone(),
|
||||
);
|
||||
tokio::pin!(work);
|
||||
let heartbeat = sleep(heartbeat_interval);
|
||||
tokio::pin!(heartbeat);
|
||||
|
||||
loop {
|
||||
tokio::select! {
|
||||
biased;
|
||||
result = &mut work => {
|
||||
let terminal_update = result?;
|
||||
let renewed_job = renew_job_lease(&state, &worker_id, &job, lease).await?;
|
||||
if runtime_job_has_cancel_request(&renewed_job) {
|
||||
return Ok(WebProjectRuntimeWorkerTerminalUpdate::CancelRequested);
|
||||
}
|
||||
return Ok(terminal_update);
|
||||
}
|
||||
_ = &mut heartbeat => {
|
||||
let renewed_job = renew_job_lease(&state, &worker_id, &job, lease).await?;
|
||||
if runtime_job_has_cancel_request(&renewed_job) {
|
||||
return Ok(WebProjectRuntimeWorkerTerminalUpdate::CancelRequested);
|
||||
}
|
||||
heartbeat.as_mut().reset(Instant::now() + heartbeat_interval);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn finish_web_project_runtime_job_terminal_update(
|
||||
state: AppState,
|
||||
worker_id: String,
|
||||
job: WebProjectRuntimeJobRecord,
|
||||
terminal_update: WebProjectRuntimeWorkerTerminalUpdate,
|
||||
) -> Result<(), String> {
|
||||
match terminal_update {
|
||||
WebProjectRuntimeWorkerTerminalUpdate::CompleteDryRun { log_message } => {
|
||||
append_job_log(&state, &worker_id, &job, "info", log_message).await?;
|
||||
let updated_job = complete_job(&state, &worker_id, &job, None, None).await?;
|
||||
if updated_job.status == "cancelled" {
|
||||
return Err("构建任务已取消".to_string());
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
WebProjectRuntimeWorkerTerminalUpdate::Fail {
|
||||
error_summary,
|
||||
fail_preview_build,
|
||||
} => {
|
||||
append_job_log(&state, &worker_id, &job, "error", error_summary.clone()).await?;
|
||||
let updated_job = fail_job(&state, &worker_id, &job, error_summary.clone()).await?;
|
||||
if updated_job.status == "cancelled" {
|
||||
cancel_linked_preview_build(&state, &job).await;
|
||||
return Err("构建任务已取消".to_string());
|
||||
}
|
||||
if fail_preview_build {
|
||||
fail_linked_preview_build(&state, &job, &error_summary).await;
|
||||
}
|
||||
Err(error_summary)
|
||||
}
|
||||
WebProjectRuntimeWorkerTerminalUpdate::FinishPreviewBuild {
|
||||
run_output,
|
||||
artifact_id,
|
||||
} => {
|
||||
append_job_log(
|
||||
&state,
|
||||
&worker_id,
|
||||
&job,
|
||||
"info",
|
||||
format!("artifact: runner 已产出 artifact {artifact_id}"),
|
||||
)
|
||||
.await?;
|
||||
append_job_log(
|
||||
&state,
|
||||
&worker_id,
|
||||
&job,
|
||||
"info",
|
||||
"preview: runtime job 完成校验通过后写入 preview token 与 URL".to_string(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
let finish_plan =
|
||||
web_project_preview_runtime::plan_preview_build_finish_from_runner_output(
|
||||
&state,
|
||||
&run_output.build,
|
||||
run_output.finished_at_micros,
|
||||
&run_output.runner_output,
|
||||
);
|
||||
let finish_result =
|
||||
complete_preview_build_job(&state, &worker_id, &job, &run_output, finish_plan)
|
||||
.await?;
|
||||
let build = web_project::build_from_record(finish_result.build.clone());
|
||||
let event_message = finish_result
|
||||
.job
|
||||
.stale_reason
|
||||
.as_deref()
|
||||
.or(build.error_summary.as_deref())
|
||||
.or(Some("构建完成"));
|
||||
web_project::publish_build_event(&state, &build, event_message);
|
||||
if finish_result.job.status == "stale" {
|
||||
let stale_reason = finish_result
|
||||
.job
|
||||
.stale_reason
|
||||
.unwrap_or_else(|| "job snapshot 已不是项目 active snapshot".to_string());
|
||||
return Err(stale_reason);
|
||||
}
|
||||
if finish_result.job.status == "cancelled" {
|
||||
return Err("构建任务已取消".to_string());
|
||||
}
|
||||
info!(
|
||||
job_id = job.job_id,
|
||||
preview_build_id = build.job_id,
|
||||
artifact_id,
|
||||
preview_url = build.preview_url.as_deref().unwrap_or(""),
|
||||
"Web Project runtime job 已完成预览构建"
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
WebProjectRuntimeWorkerTerminalUpdate::FailFinishedPreviewBuild {
|
||||
run_output,
|
||||
error_summary,
|
||||
} => {
|
||||
append_job_log(
|
||||
&state,
|
||||
&worker_id,
|
||||
&job,
|
||||
"error",
|
||||
"artifact: runner 未产出可用 artifact".to_string(),
|
||||
)
|
||||
.await?;
|
||||
let updated_job = fail_job(&state, &worker_id, &job, error_summary.clone()).await?;
|
||||
if updated_job.status == "cancelled" {
|
||||
cancel_linked_preview_build(&state, &job).await;
|
||||
return Err("构建任务已取消".to_string());
|
||||
}
|
||||
let finish_error_summary =
|
||||
web_project_preview_runtime::finish_preview_build_from_runner_output(
|
||||
&state,
|
||||
&job.owner_user_id,
|
||||
&run_output.build,
|
||||
run_output.started_at_micros,
|
||||
run_output.finished_at_micros,
|
||||
&run_output.runner_output,
|
||||
)
|
||||
.await?;
|
||||
let error_summary = finish_error_summary.unwrap_or(error_summary);
|
||||
Err(error_summary)
|
||||
}
|
||||
WebProjectRuntimeWorkerTerminalUpdate::CancelRequested => {
|
||||
append_job_log(
|
||||
&state,
|
||||
&worker_id,
|
||||
&job,
|
||||
"info",
|
||||
"cancel: 收到取消请求,停止当前 runtime job".to_string(),
|
||||
)
|
||||
.await?;
|
||||
fail_job(
|
||||
&state,
|
||||
&worker_id,
|
||||
&job,
|
||||
"构建任务已取消".to_string(),
|
||||
)
|
||||
.await?;
|
||||
cancel_linked_preview_build(&state, &job).await;
|
||||
Err("构建任务已取消".to_string())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn plan_web_project_runtime_job_terminal_update(
|
||||
state: AppState,
|
||||
worker_id: String,
|
||||
dry_run_result: WebProjectRuntimeWorkerDryRunResult,
|
||||
job: WebProjectRuntimeJobRecord,
|
||||
) -> Result<WebProjectRuntimeWorkerTerminalUpdate, String> {
|
||||
append_job_log(
|
||||
&state,
|
||||
&worker_id,
|
||||
&job,
|
||||
"info",
|
||||
format!(
|
||||
"runtime worker 已领取任务:{},attempt={}",
|
||||
job.job_kind, job.attempt
|
||||
),
|
||||
)
|
||||
.await?;
|
||||
|
||||
match plan_web_project_runtime_job(&job, dry_run_result) {
|
||||
WebProjectRuntimeWorkerAction::ExecutePreviewBuild => {
|
||||
plan_preview_build_runtime_job_terminal_update(&state, &worker_id, &job).await
|
||||
}
|
||||
WebProjectRuntimeWorkerAction::Complete { log_message } => {
|
||||
Ok(WebProjectRuntimeWorkerTerminalUpdate::CompleteDryRun { log_message })
|
||||
}
|
||||
WebProjectRuntimeWorkerAction::Fail { error_summary } => {
|
||||
Ok(WebProjectRuntimeWorkerTerminalUpdate::Fail {
|
||||
error_summary,
|
||||
fail_preview_build: job.preview_build_id.is_some(),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
enum WebProjectRuntimeWorkerAction {
|
||||
ExecutePreviewBuild,
|
||||
Complete { log_message: String },
|
||||
Fail { error_summary: String },
|
||||
}
|
||||
|
||||
enum WebProjectRuntimeWorkerTerminalUpdate {
|
||||
CompleteDryRun {
|
||||
log_message: String,
|
||||
},
|
||||
Fail {
|
||||
error_summary: String,
|
||||
fail_preview_build: bool,
|
||||
},
|
||||
FinishPreviewBuild {
|
||||
run_output: web_project_preview_runtime::PreviewBuildRunOutput,
|
||||
artifact_id: String,
|
||||
},
|
||||
FailFinishedPreviewBuild {
|
||||
run_output: web_project_preview_runtime::PreviewBuildRunOutput,
|
||||
error_summary: String,
|
||||
},
|
||||
CancelRequested,
|
||||
}
|
||||
|
||||
fn plan_web_project_runtime_job(
|
||||
job: &WebProjectRuntimeJobRecord,
|
||||
dry_run_result: WebProjectRuntimeWorkerDryRunResult,
|
||||
) -> WebProjectRuntimeWorkerAction {
|
||||
if job.job_kind != WEB_PROJECT_RUNTIME_JOB_KIND_PREVIEW_BUILD {
|
||||
return WebProjectRuntimeWorkerAction::Fail {
|
||||
error_summary: format!("暂不支持的 Web Project runtime job 类型:{}", job.job_kind),
|
||||
};
|
||||
}
|
||||
if job.preview_build_id.is_some() {
|
||||
return WebProjectRuntimeWorkerAction::ExecutePreviewBuild;
|
||||
}
|
||||
|
||||
match dry_run_result {
|
||||
WebProjectRuntimeWorkerDryRunResult::Succeed if job.preview_build_id.is_none() => {
|
||||
WebProjectRuntimeWorkerAction::Complete {
|
||||
log_message: "P2-05 dry-run worker 已完成无预览构建绑定的 runtime job".to_string(),
|
||||
}
|
||||
}
|
||||
WebProjectRuntimeWorkerDryRunResult::Succeed => WebProjectRuntimeWorkerAction::Fail {
|
||||
error_summary: "P2-05 dry-run worker 不生成预览产物,不能完成 preview build 任务"
|
||||
.to_string(),
|
||||
},
|
||||
WebProjectRuntimeWorkerDryRunResult::Fail => WebProjectRuntimeWorkerAction::Fail {
|
||||
error_summary: "P2-05 dry-run worker 尚未接入 SandboxRuntime,任务已按预期失败"
|
||||
.to_string(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
async fn plan_preview_build_runtime_job_terminal_update(
|
||||
state: &AppState,
|
||||
worker_id: &str,
|
||||
job: &WebProjectRuntimeJobRecord,
|
||||
) -> Result<WebProjectRuntimeWorkerTerminalUpdate, String> {
|
||||
append_job_log(
|
||||
state,
|
||||
worker_id,
|
||||
job,
|
||||
"info",
|
||||
"hydrate: 开始读取 Web Project snapshot".to_string(),
|
||||
)
|
||||
.await?;
|
||||
append_job_log(
|
||||
state,
|
||||
worker_id,
|
||||
job,
|
||||
"info",
|
||||
"build: 开始调用 TempDirBuildRuntime".to_string(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
let run_output = match web_project_preview_runtime::run_preview_build_with_temp_dir_runtime(
|
||||
state, job,
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(output) => output,
|
||||
Err(error) => {
|
||||
return Ok(WebProjectRuntimeWorkerTerminalUpdate::Fail {
|
||||
error_summary: error,
|
||||
fail_preview_build: job.preview_build_id.is_some(),
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
if run_output.runner_output.status != WebProjectBuildStatus::Succeeded
|
||||
|| run_output.runner_output.artifact_id.is_none()
|
||||
{
|
||||
let error_summary = run_output
|
||||
.runner_output
|
||||
.error_summary
|
||||
.clone()
|
||||
.unwrap_or_else(|| "web-project-runner 构建失败,但未返回错误摘要".to_string());
|
||||
return Ok(
|
||||
WebProjectRuntimeWorkerTerminalUpdate::FailFinishedPreviewBuild {
|
||||
run_output,
|
||||
error_summary,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
let artifact_id = run_output
|
||||
.runner_output
|
||||
.artifact_id
|
||||
.clone()
|
||||
.expect("artifact_id was checked before success path");
|
||||
Ok(WebProjectRuntimeWorkerTerminalUpdate::FinishPreviewBuild {
|
||||
run_output,
|
||||
artifact_id,
|
||||
})
|
||||
}
|
||||
|
||||
async fn fail_linked_preview_build(
|
||||
state: &AppState,
|
||||
job: &WebProjectRuntimeJobRecord,
|
||||
error_summary: &str,
|
||||
) {
|
||||
if let Some(preview_build_id) = job.preview_build_id.as_deref()
|
||||
&& let Err(error) = web_project_preview_runtime::fail_preview_build_for_runtime_worker(
|
||||
state,
|
||||
&job.owner_user_id,
|
||||
preview_build_id,
|
||||
error_summary,
|
||||
)
|
||||
.await
|
||||
{
|
||||
warn!(
|
||||
job_id = job.job_id,
|
||||
preview_build_id,
|
||||
error = %error,
|
||||
"runtime job 已失败,但 linked preview build 失败状态写回失败"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async fn cancel_linked_preview_build(state: &AppState, job: &WebProjectRuntimeJobRecord) {
|
||||
if let Some(preview_build_id) = job.preview_build_id.as_deref()
|
||||
&& let Err(error) = web_project_preview_runtime::cancel_preview_build_for_runtime_worker(
|
||||
state,
|
||||
&job.owner_user_id,
|
||||
preview_build_id,
|
||||
)
|
||||
.await
|
||||
{
|
||||
warn!(
|
||||
job_id = job.job_id,
|
||||
preview_build_id,
|
||||
error = %error,
|
||||
"runtime job 已取消,但 linked preview build 取消状态写回失败"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async fn complete_job(
|
||||
state: &AppState,
|
||||
worker_id: &str,
|
||||
job: &WebProjectRuntimeJobRecord,
|
||||
artifact_id: Option<String>,
|
||||
preview_build_id: Option<String>,
|
||||
) -> Result<WebProjectRuntimeJobRecord, String> {
|
||||
state
|
||||
.spacetime_client()
|
||||
.complete_web_project_runtime_job(WebProjectRuntimeJobCompleteRecordInput {
|
||||
job_id: job.job_id.clone(),
|
||||
worker_id: worker_id.to_string(),
|
||||
lease_token: require_job_lease_token(job)?,
|
||||
artifact_id,
|
||||
preview_build_id,
|
||||
completed_at_micros: current_utc_micros(),
|
||||
})
|
||||
.await
|
||||
.map_err(|error| error.to_string())
|
||||
}
|
||||
|
||||
async fn complete_preview_build_job(
|
||||
state: &AppState,
|
||||
worker_id: &str,
|
||||
job: &WebProjectRuntimeJobRecord,
|
||||
run_output: &web_project_preview_runtime::PreviewBuildRunOutput,
|
||||
finish_plan: web_project_preview_runtime::PreviewBuildFinishPlan,
|
||||
) -> Result<spacetime_client::WebProjectRuntimeJobPreviewBuildMutationRecord, String> {
|
||||
if !finish_plan.succeeded {
|
||||
return Err("preview build finish plan 不是 succeeded 状态".to_string());
|
||||
}
|
||||
let preview_build_id = job
|
||||
.preview_build_id
|
||||
.as_deref()
|
||||
.ok_or_else(|| "preview_build runtime job 缺少 preview_build_id".to_string())?;
|
||||
state
|
||||
.spacetime_client()
|
||||
.complete_web_project_preview_build_runtime_job(
|
||||
WebProjectRuntimeJobCompletePreviewBuildRecordInput {
|
||||
job_id: job.job_id.clone(),
|
||||
worker_id: worker_id.to_string(),
|
||||
lease_token: require_job_lease_token(job)?,
|
||||
preview_build_id: preview_build_id.to_string(),
|
||||
artifact_id: finish_plan
|
||||
.artifact_id
|
||||
.ok_or_else(|| "preview build 成功结果缺少 artifact_id".to_string())?,
|
||||
preview_token_id: finish_plan
|
||||
.preview_token_id
|
||||
.ok_or_else(|| "preview build 成功结果缺少 preview_token_id".to_string())?,
|
||||
preview_url: finish_plan
|
||||
.preview_url
|
||||
.ok_or_else(|| "preview build 成功结果缺少 preview_url".to_string())?,
|
||||
logs: finish_plan.logs,
|
||||
started_at_micros: Some(run_output.started_at_micros),
|
||||
finished_at_micros: run_output.finished_at_micros,
|
||||
},
|
||||
)
|
||||
.await
|
||||
.map_err(|error| error.to_string())
|
||||
}
|
||||
|
||||
async fn fail_job(
|
||||
state: &AppState,
|
||||
worker_id: &str,
|
||||
job: &WebProjectRuntimeJobRecord,
|
||||
error_summary: String,
|
||||
) -> Result<WebProjectRuntimeJobRecord, String> {
|
||||
state
|
||||
.spacetime_client()
|
||||
.fail_web_project_runtime_job(WebProjectRuntimeJobFailRecordInput {
|
||||
job_id: job.job_id.clone(),
|
||||
worker_id: worker_id.to_string(),
|
||||
lease_token: require_job_lease_token(job)?,
|
||||
error_summary,
|
||||
failed_at_micros: current_utc_micros(),
|
||||
})
|
||||
.await
|
||||
.map_err(|error| error.to_string())
|
||||
}
|
||||
|
||||
async fn renew_job_lease(
|
||||
state: &AppState,
|
||||
worker_id: &str,
|
||||
job: &WebProjectRuntimeJobRecord,
|
||||
lease: Duration,
|
||||
) -> Result<WebProjectRuntimeJobRecord, String> {
|
||||
let now_micros = current_utc_micros();
|
||||
state
|
||||
.spacetime_client()
|
||||
.renew_web_project_runtime_job_lease(WebProjectRuntimeJobRenewLeaseRecordInput {
|
||||
job_id: job.job_id.clone(),
|
||||
worker_id: worker_id.to_string(),
|
||||
lease_token: require_job_lease_token(job)?,
|
||||
lease_expires_at_micros: now_micros.saturating_add(duration_micros_i64(lease)),
|
||||
renewed_at_micros: now_micros,
|
||||
})
|
||||
.await
|
||||
.map_err(|error| error.to_string())
|
||||
}
|
||||
|
||||
async fn append_job_log(
|
||||
state: &AppState,
|
||||
worker_id: &str,
|
||||
job: &WebProjectRuntimeJobRecord,
|
||||
level: &str,
|
||||
message: String,
|
||||
) -> Result<WebProjectRuntimeJobLogRecord, String> {
|
||||
let lease_token = require_job_lease_token(job)?;
|
||||
let sequence = next_job_log_sequence(state, job).await?;
|
||||
state
|
||||
.spacetime_client()
|
||||
.append_web_project_runtime_job_log(WebProjectRuntimeJobAppendLogRecordInput {
|
||||
log_id: build_prefixed_uuid_id(WEB_PROJECT_RUNTIME_JOB_LOG_ID_PREFIX),
|
||||
job_id: job.job_id.clone(),
|
||||
owner_user_id: job.owner_user_id.clone(),
|
||||
sequence,
|
||||
level: level.to_string(),
|
||||
message,
|
||||
worker_id: Some(worker_id.to_string()),
|
||||
lease_token: Some(lease_token),
|
||||
created_at_micros: current_utc_micros(),
|
||||
})
|
||||
.await
|
||||
.map_err(|error| error.to_string())
|
||||
}
|
||||
|
||||
async fn next_job_log_sequence(
|
||||
state: &AppState,
|
||||
job: &WebProjectRuntimeJobRecord,
|
||||
) -> Result<u64, String> {
|
||||
let mut after_sequence = None;
|
||||
let mut max_sequence = 0_u64;
|
||||
|
||||
loop {
|
||||
let logs = state
|
||||
.spacetime_client()
|
||||
.list_web_project_runtime_job_logs(WebProjectRuntimeJobListLogsRecordInput {
|
||||
job_id: job.job_id.clone(),
|
||||
owner_user_id: job.owner_user_id.clone(),
|
||||
after_sequence,
|
||||
limit: WEB_PROJECT_RUNTIME_JOB_LOG_PAGE_SIZE,
|
||||
})
|
||||
.await
|
||||
.map_err(|error| error.to_string())?;
|
||||
if logs.is_empty() {
|
||||
break;
|
||||
}
|
||||
if let Some(last_sequence) = max_log_sequence(&logs) {
|
||||
max_sequence = max_sequence.max(last_sequence);
|
||||
}
|
||||
if logs.len() < WEB_PROJECT_RUNTIME_JOB_LOG_PAGE_SIZE as usize {
|
||||
break;
|
||||
}
|
||||
after_sequence = Some(max_sequence);
|
||||
}
|
||||
|
||||
Ok(max_sequence.saturating_add(1))
|
||||
}
|
||||
|
||||
fn max_log_sequence(logs: &[WebProjectRuntimeJobLogRecord]) -> Option<u64> {
|
||||
logs.iter().map(|log| log.sequence).max()
|
||||
}
|
||||
|
||||
fn require_job_lease_token(job: &WebProjectRuntimeJobRecord) -> Result<String, String> {
|
||||
job.lease_token
|
||||
.as_deref()
|
||||
.map(str::trim)
|
||||
.filter(|value| !value.is_empty())
|
||||
.map(ToOwned::to_owned)
|
||||
.ok_or_else(|| format!("web_project_runtime_job {} 缺少 lease token", job.job_id))
|
||||
}
|
||||
|
||||
fn runtime_job_has_cancel_request(job: &WebProjectRuntimeJobRecord) -> bool {
|
||||
job.status == "cancelled" || job.cancel_requested_at.is_some()
|
||||
}
|
||||
|
||||
fn web_project_runtime_worker_heartbeat_interval(lease: Duration) -> Duration {
|
||||
let heartbeat_millis = (lease.as_millis() / 3).clamp(250, 30_000) as u64;
|
||||
Duration::from_millis(heartbeat_millis)
|
||||
}
|
||||
|
||||
fn duration_micros_i64(duration: Duration) -> i64 {
|
||||
duration.as_micros().min(i64::MAX as u128) as i64
|
||||
}
|
||||
|
||||
fn current_utc_micros() -> i64 {
|
||||
offset_datetime_to_unix_micros(time::OffsetDateTime::now_utc())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn web_project_runtime_worker_heartbeat_interval_is_bounded() {
|
||||
assert_eq!(
|
||||
web_project_runtime_worker_heartbeat_interval(Duration::from_millis(300)),
|
||||
Duration::from_millis(250)
|
||||
);
|
||||
assert_eq!(
|
||||
web_project_runtime_worker_heartbeat_interval(Duration::from_secs(9)),
|
||||
Duration::from_secs(3)
|
||||
);
|
||||
assert_eq!(
|
||||
web_project_runtime_worker_heartbeat_interval(Duration::from_secs(300)),
|
||||
Duration::from_secs(30)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn web_project_runtime_worker_requires_claimed_job_lease_token() {
|
||||
let job = runtime_job_fixture(None, None);
|
||||
|
||||
let error = require_job_lease_token(&job).expect_err("missing token should fail");
|
||||
|
||||
assert!(error.contains("缺少 lease token"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn web_project_runtime_worker_plans_success_for_unlinked_dry_run_job() {
|
||||
let job = runtime_job_fixture(Some("lease-1"), None);
|
||||
|
||||
let action =
|
||||
plan_web_project_runtime_job(&job, WebProjectRuntimeWorkerDryRunResult::Succeed);
|
||||
|
||||
assert!(matches!(
|
||||
action,
|
||||
WebProjectRuntimeWorkerAction::Complete { .. }
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn web_project_runtime_worker_routes_linked_preview_build_to_runner() {
|
||||
let job = runtime_job_fixture(Some("lease-1"), Some("web-build-1"));
|
||||
|
||||
let action =
|
||||
plan_web_project_runtime_job(&job, WebProjectRuntimeWorkerDryRunResult::Succeed);
|
||||
|
||||
assert_eq!(action, WebProjectRuntimeWorkerAction::ExecutePreviewBuild);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn web_project_runtime_worker_plans_configured_dry_run_failure() {
|
||||
let job = runtime_job_fixture(Some("lease-1"), None);
|
||||
|
||||
let action = plan_web_project_runtime_job(&job, WebProjectRuntimeWorkerDryRunResult::Fail);
|
||||
|
||||
assert_eq!(
|
||||
action,
|
||||
WebProjectRuntimeWorkerAction::Fail {
|
||||
error_summary: "P2-05 dry-run worker 尚未接入 SandboxRuntime,任务已按预期失败"
|
||||
.to_string()
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn web_project_runtime_worker_rejects_unknown_job_kind() {
|
||||
let mut job = runtime_job_fixture(Some("lease-1"), None);
|
||||
job.job_kind = "unknown".to_string();
|
||||
|
||||
let action =
|
||||
plan_web_project_runtime_job(&job, WebProjectRuntimeWorkerDryRunResult::Succeed);
|
||||
|
||||
assert_eq!(
|
||||
action,
|
||||
WebProjectRuntimeWorkerAction::Fail {
|
||||
error_summary: "暂不支持的 Web Project runtime job 类型:unknown".to_string()
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn web_project_runtime_worker_uses_next_log_sequence_after_existing_logs() {
|
||||
let logs = vec![
|
||||
runtime_job_log_fixture(1),
|
||||
runtime_job_log_fixture(4),
|
||||
runtime_job_log_fixture(2),
|
||||
];
|
||||
|
||||
assert_eq!(max_log_sequence(&logs).unwrap_or_default() + 1, 5);
|
||||
}
|
||||
|
||||
fn runtime_job_fixture(
|
||||
lease_token: Option<&str>,
|
||||
preview_build_id: Option<&str>,
|
||||
) -> WebProjectRuntimeJobRecord {
|
||||
WebProjectRuntimeJobRecord {
|
||||
job_id: "web-runtime-job-1".to_string(),
|
||||
project_id: "web-project-1".to_string(),
|
||||
snapshot_id: "web-snapshot-1".to_string(),
|
||||
owner_user_id: "user-1".to_string(),
|
||||
job_kind: WEB_PROJECT_RUNTIME_JOB_KIND_PREVIEW_BUILD.to_string(),
|
||||
status: "running".to_string(),
|
||||
attempt: 1,
|
||||
worker_id: Some("worker-a".to_string()),
|
||||
lease_token: lease_token.map(ToOwned::to_owned),
|
||||
lease_expires_at: Some("2026-06-17T00:00:00Z".to_string()),
|
||||
cancel_requested_at: None,
|
||||
stale_reason: None,
|
||||
artifact_id: None,
|
||||
preview_build_id: preview_build_id.map(ToOwned::to_owned),
|
||||
error_summary: None,
|
||||
created_at: "2026-06-17T00:00:00Z".to_string(),
|
||||
started_at: Some("2026-06-17T00:00:00Z".to_string()),
|
||||
finished_at: None,
|
||||
updated_at: "2026-06-17T00:00:00Z".to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
fn runtime_job_log_fixture(sequence: u64) -> WebProjectRuntimeJobLogRecord {
|
||||
WebProjectRuntimeJobLogRecord {
|
||||
log_id: format!("log-{sequence}"),
|
||||
job_id: "web-runtime-job-1".to_string(),
|
||||
project_id: "web-project-1".to_string(),
|
||||
owner_user_id: "user-1".to_string(),
|
||||
sequence,
|
||||
level: "info".to_string(),
|
||||
message: "log".to_string(),
|
||||
created_at: "2026-06-17T00:00:00Z".to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,24 @@ pub enum WebProjectPreviewBuildStatus {
|
||||
Stale,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum WebProjectRuntimeJobKind {
|
||||
PreviewBuild,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub enum WebProjectRuntimeJobStatus {
|
||||
Queued,
|
||||
Running,
|
||||
Succeeded,
|
||||
Failed,
|
||||
Cancelled,
|
||||
Expired,
|
||||
Stale,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct WebProject {
|
||||
@@ -96,6 +114,42 @@ pub struct WebProjectPreviewBuild {
|
||||
pub updated_at: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct WebProjectRuntimeJob {
|
||||
pub job_id: String,
|
||||
pub project_id: String,
|
||||
pub snapshot_id: String,
|
||||
pub owner_user_id: String,
|
||||
pub job_kind: WebProjectRuntimeJobKind,
|
||||
pub status: WebProjectRuntimeJobStatus,
|
||||
pub attempt: u32,
|
||||
pub worker_id: Option<String>,
|
||||
pub lease_expires_at: Option<String>,
|
||||
pub cancel_requested_at: Option<String>,
|
||||
pub stale_reason: Option<String>,
|
||||
pub artifact_id: Option<String>,
|
||||
pub preview_build_id: Option<String>,
|
||||
pub error_summary: Option<String>,
|
||||
pub created_at: String,
|
||||
pub started_at: Option<String>,
|
||||
pub finished_at: Option<String>,
|
||||
pub updated_at: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct WebProjectRuntimeJobLog {
|
||||
pub log_id: String,
|
||||
pub job_id: String,
|
||||
pub project_id: String,
|
||||
pub owner_user_id: String,
|
||||
pub sequence: u64,
|
||||
pub level: String,
|
||||
pub message: String,
|
||||
pub created_at: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct WebProjectPreviewBuildEvent {
|
||||
@@ -136,4 +190,33 @@ pub struct WebProjectSnapshotResponse {
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct WebProjectPreviewBuildResponse {
|
||||
pub build: WebProjectPreviewBuild,
|
||||
pub runtime_job: Option<WebProjectRuntimeJob>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct WebProjectRuntimeJobCreateRequest {
|
||||
pub snapshot_id: Option<String>,
|
||||
pub job_kind: WebProjectRuntimeJobKind,
|
||||
pub preview_build_id: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct WebProjectRuntimeJobResponse {
|
||||
pub job: WebProjectRuntimeJob,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct WebProjectRuntimeJobListResponse {
|
||||
pub jobs: Vec<WebProjectRuntimeJob>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct WebProjectRuntimeJobLogListResponse {
|
||||
pub logs: Vec<WebProjectRuntimeJobLog>,
|
||||
pub next_after_sequence: Option<u64>,
|
||||
pub has_more: bool,
|
||||
}
|
||||
|
||||
@@ -105,9 +105,17 @@ pub use mapper::{
|
||||
WebProjectFileRecord, WebProjectGetRecordInput, WebProjectPreviewBuildCreateRecordInput,
|
||||
WebProjectPreviewBuildGetRecordInput, WebProjectPreviewBuildMutationRecord,
|
||||
WebProjectPreviewBuildRecord, WebProjectPreviewBuildTokenGetRecordInput,
|
||||
WebProjectPreviewBuildUpdateRecordInput, WebProjectRecord, WebProjectSnapshotGetRecordInput,
|
||||
WebProjectSnapshotMutationRecord, WebProjectSnapshotRecord, WebProjectSnapshotSaveRecordInput,
|
||||
WoodenFishActionRequest, WoodenFishActionResponse,
|
||||
WebProjectPreviewBuildUpdateRecordInput, WebProjectRecord,
|
||||
WebProjectRuntimeJobAppendLogRecordInput, WebProjectRuntimeJobCancelRecordInput,
|
||||
WebProjectRuntimeJobClaimRecordInput, WebProjectRuntimeJobCompletePreviewBuildRecordInput,
|
||||
WebProjectRuntimeJobCompleteRecordInput, WebProjectRuntimeJobCreateRecordInput,
|
||||
WebProjectRuntimeJobExpireRecordInput, WebProjectRuntimeJobFailRecordInput,
|
||||
WebProjectRuntimeJobGetRecordInput, WebProjectRuntimeJobListLogsRecordInput,
|
||||
WebProjectRuntimeJobListOpenRecordInput, WebProjectRuntimeJobLogRecord,
|
||||
WebProjectRuntimeJobPreviewBuildMutationRecord, WebProjectRuntimeJobRecord,
|
||||
WebProjectRuntimeJobRenewLeaseRecordInput, WebProjectRuntimeJobStaleRecordInput,
|
||||
WebProjectSnapshotGetRecordInput, WebProjectSnapshotMutationRecord, WebProjectSnapshotRecord,
|
||||
WebProjectSnapshotSaveRecordInput, WoodenFishActionRequest, WoodenFishActionResponse,
|
||||
WoodenFishActionType, WoodenFishAudioAsset, WoodenFishCheckpointRunRequest,
|
||||
WoodenFishDraftResponse, WoodenFishFinishRunRequest, WoodenFishGalleryCardResponse,
|
||||
WoodenFishGalleryDetailResponse, WoodenFishGalleryResponse, WoodenFishGenerationStatus,
|
||||
|
||||
@@ -159,8 +159,16 @@ pub use self::web_project::{
|
||||
WebProjectPreviewBuildCreateRecordInput, WebProjectPreviewBuildGetRecordInput,
|
||||
WebProjectPreviewBuildMutationRecord, WebProjectPreviewBuildRecord,
|
||||
WebProjectPreviewBuildTokenGetRecordInput, WebProjectPreviewBuildUpdateRecordInput,
|
||||
WebProjectRecord, WebProjectSnapshotGetRecordInput, WebProjectSnapshotMutationRecord,
|
||||
WebProjectSnapshotRecord, WebProjectSnapshotSaveRecordInput,
|
||||
WebProjectRecord, WebProjectRuntimeJobAppendLogRecordInput,
|
||||
WebProjectRuntimeJobCancelRecordInput, WebProjectRuntimeJobClaimRecordInput,
|
||||
WebProjectRuntimeJobCompletePreviewBuildRecordInput, WebProjectRuntimeJobCompleteRecordInput,
|
||||
WebProjectRuntimeJobCreateRecordInput, WebProjectRuntimeJobExpireRecordInput,
|
||||
WebProjectRuntimeJobFailRecordInput, WebProjectRuntimeJobGetRecordInput,
|
||||
WebProjectRuntimeJobListLogsRecordInput, WebProjectRuntimeJobListOpenRecordInput,
|
||||
WebProjectRuntimeJobLogRecord, WebProjectRuntimeJobPreviewBuildMutationRecord,
|
||||
WebProjectRuntimeJobRecord, WebProjectRuntimeJobRenewLeaseRecordInput,
|
||||
WebProjectRuntimeJobStaleRecordInput, WebProjectSnapshotGetRecordInput,
|
||||
WebProjectSnapshotMutationRecord, WebProjectSnapshotRecord, WebProjectSnapshotSaveRecordInput,
|
||||
};
|
||||
pub use self::wooden_fish::{
|
||||
WoodenFishActionRequest, WoodenFishActionResponse, WoodenFishActionType, WoodenFishAudioAsset,
|
||||
@@ -300,7 +308,10 @@ pub(crate) use self::visual_novel::{
|
||||
};
|
||||
pub(crate) use self::web_project::{
|
||||
map_web_project_preview_build_procedure_result, map_web_project_procedure_result,
|
||||
map_web_project_snapshot_procedure_result,
|
||||
map_web_project_runtime_job_list_result, map_web_project_runtime_job_log_list_result,
|
||||
map_web_project_runtime_job_log_procedure_result,
|
||||
map_web_project_runtime_job_preview_build_procedure_result,
|
||||
map_web_project_runtime_job_procedure_result, map_web_project_snapshot_procedure_result,
|
||||
};
|
||||
pub(crate) use self::wooden_fish::{
|
||||
map_wooden_fish_agent_session_procedure_result, map_wooden_fish_gallery_card_view_row,
|
||||
|
||||
@@ -52,6 +52,41 @@ pub struct WebProjectPreviewBuildRecord {
|
||||
pub updated_at: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
|
||||
pub struct WebProjectRuntimeJobRecord {
|
||||
pub job_id: String,
|
||||
pub project_id: String,
|
||||
pub snapshot_id: String,
|
||||
pub owner_user_id: String,
|
||||
pub job_kind: String,
|
||||
pub status: String,
|
||||
pub attempt: u32,
|
||||
pub worker_id: Option<String>,
|
||||
pub lease_token: Option<String>,
|
||||
pub lease_expires_at: Option<String>,
|
||||
pub cancel_requested_at: Option<String>,
|
||||
pub stale_reason: Option<String>,
|
||||
pub artifact_id: Option<String>,
|
||||
pub preview_build_id: Option<String>,
|
||||
pub error_summary: Option<String>,
|
||||
pub created_at: String,
|
||||
pub started_at: Option<String>,
|
||||
pub finished_at: Option<String>,
|
||||
pub updated_at: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
|
||||
pub struct WebProjectRuntimeJobLogRecord {
|
||||
pub log_id: String,
|
||||
pub job_id: String,
|
||||
pub project_id: String,
|
||||
pub owner_user_id: String,
|
||||
pub sequence: u64,
|
||||
pub level: String,
|
||||
pub message: String,
|
||||
pub created_at: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct WebProjectCreateRecordInput {
|
||||
pub project_id: String,
|
||||
@@ -122,6 +157,123 @@ pub struct WebProjectPreviewBuildUpdateRecordInput {
|
||||
pub updated_at_micros: i64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct WebProjectRuntimeJobCreateRecordInput {
|
||||
pub job_id: String,
|
||||
pub project_id: String,
|
||||
pub snapshot_id: String,
|
||||
pub owner_user_id: String,
|
||||
pub job_kind: String,
|
||||
pub preview_build_id: Option<String>,
|
||||
pub now_micros: i64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct WebProjectRuntimeJobGetRecordInput {
|
||||
pub job_id: String,
|
||||
pub owner_user_id: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct WebProjectRuntimeJobListOpenRecordInput {
|
||||
pub project_id: String,
|
||||
pub owner_user_id: String,
|
||||
pub limit: u32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct WebProjectRuntimeJobClaimRecordInput {
|
||||
pub worker_id: String,
|
||||
pub limit: u32,
|
||||
pub lease_expires_at_micros: i64,
|
||||
pub claimed_at_micros: i64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct WebProjectRuntimeJobRenewLeaseRecordInput {
|
||||
pub job_id: String,
|
||||
pub worker_id: String,
|
||||
pub lease_token: String,
|
||||
pub lease_expires_at_micros: i64,
|
||||
pub renewed_at_micros: i64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct WebProjectRuntimeJobCompleteRecordInput {
|
||||
pub job_id: String,
|
||||
pub worker_id: String,
|
||||
pub lease_token: String,
|
||||
pub artifact_id: Option<String>,
|
||||
pub preview_build_id: Option<String>,
|
||||
pub completed_at_micros: i64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct WebProjectRuntimeJobCompletePreviewBuildRecordInput {
|
||||
pub job_id: String,
|
||||
pub worker_id: String,
|
||||
pub lease_token: String,
|
||||
pub preview_build_id: String,
|
||||
pub artifact_id: String,
|
||||
pub preview_token_id: String,
|
||||
pub preview_url: String,
|
||||
pub logs: Vec<String>,
|
||||
pub started_at_micros: Option<i64>,
|
||||
pub finished_at_micros: i64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct WebProjectRuntimeJobFailRecordInput {
|
||||
pub job_id: String,
|
||||
pub worker_id: String,
|
||||
pub lease_token: String,
|
||||
pub error_summary: String,
|
||||
pub failed_at_micros: i64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct WebProjectRuntimeJobCancelRecordInput {
|
||||
pub job_id: String,
|
||||
pub owner_user_id: String,
|
||||
pub cancelled_at_micros: i64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct WebProjectRuntimeJobStaleRecordInput {
|
||||
pub job_id: String,
|
||||
pub owner_user_id: String,
|
||||
pub stale_reason: String,
|
||||
pub stale_at_micros: i64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct WebProjectRuntimeJobExpireRecordInput {
|
||||
pub job_id: String,
|
||||
pub owner_user_id: String,
|
||||
pub expired_at_micros: i64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct WebProjectRuntimeJobAppendLogRecordInput {
|
||||
pub log_id: String,
|
||||
pub job_id: String,
|
||||
pub owner_user_id: String,
|
||||
pub sequence: u64,
|
||||
pub level: String,
|
||||
pub message: String,
|
||||
pub worker_id: Option<String>,
|
||||
pub lease_token: Option<String>,
|
||||
pub created_at_micros: i64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct WebProjectRuntimeJobListLogsRecordInput {
|
||||
pub job_id: String,
|
||||
pub owner_user_id: String,
|
||||
pub after_sequence: Option<u64>,
|
||||
pub limit: u32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
|
||||
pub struct WebProjectSnapshotMutationRecord {
|
||||
pub project: WebProjectRecord,
|
||||
@@ -134,6 +286,13 @@ pub struct WebProjectPreviewBuildMutationRecord {
|
||||
pub build: WebProjectPreviewBuildRecord,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
|
||||
pub struct WebProjectRuntimeJobPreviewBuildMutationRecord {
|
||||
pub project: WebProjectRecord,
|
||||
pub build: WebProjectPreviewBuildRecord,
|
||||
pub job: WebProjectRuntimeJobRecord,
|
||||
}
|
||||
|
||||
impl From<WebProjectFileRecord> for crate::module_bindings::WebProjectFileSnapshot {
|
||||
fn from(input: WebProjectFileRecord) -> Self {
|
||||
Self {
|
||||
@@ -262,6 +421,188 @@ impl From<WebProjectPreviewBuildUpdateRecordInput>
|
||||
}
|
||||
}
|
||||
|
||||
impl From<WebProjectRuntimeJobCreateRecordInput>
|
||||
for crate::module_bindings::WebProjectRuntimeJobCreateInput
|
||||
{
|
||||
fn from(input: WebProjectRuntimeJobCreateRecordInput) -> Self {
|
||||
Self {
|
||||
job_id: input.job_id,
|
||||
project_id: input.project_id,
|
||||
snapshot_id: input.snapshot_id,
|
||||
owner_user_id: input.owner_user_id,
|
||||
job_kind: input.job_kind,
|
||||
preview_build_id: input.preview_build_id,
|
||||
now_micros: input.now_micros,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<WebProjectRuntimeJobGetRecordInput>
|
||||
for crate::module_bindings::WebProjectRuntimeJobGetInput
|
||||
{
|
||||
fn from(input: WebProjectRuntimeJobGetRecordInput) -> Self {
|
||||
Self {
|
||||
job_id: input.job_id,
|
||||
owner_user_id: input.owner_user_id,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<WebProjectRuntimeJobListOpenRecordInput>
|
||||
for crate::module_bindings::WebProjectRuntimeJobListOpenInput
|
||||
{
|
||||
fn from(input: WebProjectRuntimeJobListOpenRecordInput) -> Self {
|
||||
Self {
|
||||
project_id: input.project_id,
|
||||
owner_user_id: input.owner_user_id,
|
||||
limit: input.limit,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<WebProjectRuntimeJobClaimRecordInput>
|
||||
for crate::module_bindings::WebProjectRuntimeJobClaimInput
|
||||
{
|
||||
fn from(input: WebProjectRuntimeJobClaimRecordInput) -> Self {
|
||||
Self {
|
||||
worker_id: input.worker_id,
|
||||
limit: input.limit,
|
||||
lease_expires_at_micros: input.lease_expires_at_micros,
|
||||
claimed_at_micros: input.claimed_at_micros,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<WebProjectRuntimeJobRenewLeaseRecordInput>
|
||||
for crate::module_bindings::WebProjectRuntimeJobRenewLeaseInput
|
||||
{
|
||||
fn from(input: WebProjectRuntimeJobRenewLeaseRecordInput) -> Self {
|
||||
Self {
|
||||
job_id: input.job_id,
|
||||
worker_id: input.worker_id,
|
||||
lease_token: input.lease_token,
|
||||
lease_expires_at_micros: input.lease_expires_at_micros,
|
||||
renewed_at_micros: input.renewed_at_micros,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<WebProjectRuntimeJobCompleteRecordInput>
|
||||
for crate::module_bindings::WebProjectRuntimeJobCompleteInput
|
||||
{
|
||||
fn from(input: WebProjectRuntimeJobCompleteRecordInput) -> Self {
|
||||
Self {
|
||||
job_id: input.job_id,
|
||||
worker_id: input.worker_id,
|
||||
lease_token: input.lease_token,
|
||||
artifact_id: input.artifact_id,
|
||||
preview_build_id: input.preview_build_id,
|
||||
completed_at_micros: input.completed_at_micros,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<WebProjectRuntimeJobCompletePreviewBuildRecordInput>
|
||||
for crate::module_bindings::WebProjectRuntimeJobCompletePreviewBuildInput
|
||||
{
|
||||
fn from(input: WebProjectRuntimeJobCompletePreviewBuildRecordInput) -> Self {
|
||||
Self {
|
||||
job_id: input.job_id,
|
||||
worker_id: input.worker_id,
|
||||
lease_token: input.lease_token,
|
||||
preview_build_id: input.preview_build_id,
|
||||
artifact_id: input.artifact_id,
|
||||
preview_token_id: input.preview_token_id,
|
||||
preview_url: input.preview_url,
|
||||
logs: input.logs,
|
||||
started_at_micros: input.started_at_micros,
|
||||
finished_at_micros: input.finished_at_micros,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<WebProjectRuntimeJobFailRecordInput>
|
||||
for crate::module_bindings::WebProjectRuntimeJobFailInput
|
||||
{
|
||||
fn from(input: WebProjectRuntimeJobFailRecordInput) -> Self {
|
||||
Self {
|
||||
job_id: input.job_id,
|
||||
worker_id: input.worker_id,
|
||||
lease_token: input.lease_token,
|
||||
error_summary: input.error_summary,
|
||||
failed_at_micros: input.failed_at_micros,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<WebProjectRuntimeJobCancelRecordInput>
|
||||
for crate::module_bindings::WebProjectRuntimeJobCancelInput
|
||||
{
|
||||
fn from(input: WebProjectRuntimeJobCancelRecordInput) -> Self {
|
||||
Self {
|
||||
job_id: input.job_id,
|
||||
owner_user_id: input.owner_user_id,
|
||||
cancelled_at_micros: input.cancelled_at_micros,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<WebProjectRuntimeJobStaleRecordInput>
|
||||
for crate::module_bindings::WebProjectRuntimeJobStaleInput
|
||||
{
|
||||
fn from(input: WebProjectRuntimeJobStaleRecordInput) -> Self {
|
||||
Self {
|
||||
job_id: input.job_id,
|
||||
owner_user_id: input.owner_user_id,
|
||||
stale_reason: input.stale_reason,
|
||||
stale_at_micros: input.stale_at_micros,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<WebProjectRuntimeJobExpireRecordInput>
|
||||
for crate::module_bindings::WebProjectRuntimeJobExpireInput
|
||||
{
|
||||
fn from(input: WebProjectRuntimeJobExpireRecordInput) -> Self {
|
||||
Self {
|
||||
job_id: input.job_id,
|
||||
owner_user_id: input.owner_user_id,
|
||||
expired_at_micros: input.expired_at_micros,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<WebProjectRuntimeJobAppendLogRecordInput>
|
||||
for crate::module_bindings::WebProjectRuntimeJobAppendLogInput
|
||||
{
|
||||
fn from(input: WebProjectRuntimeJobAppendLogRecordInput) -> Self {
|
||||
Self {
|
||||
log_id: input.log_id,
|
||||
job_id: input.job_id,
|
||||
owner_user_id: input.owner_user_id,
|
||||
sequence: input.sequence,
|
||||
level: input.level,
|
||||
message: input.message,
|
||||
worker_id: input.worker_id,
|
||||
lease_token: input.lease_token,
|
||||
created_at_micros: input.created_at_micros,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<WebProjectRuntimeJobListLogsRecordInput>
|
||||
for crate::module_bindings::WebProjectRuntimeJobListLogsInput
|
||||
{
|
||||
fn from(input: WebProjectRuntimeJobListLogsRecordInput) -> Self {
|
||||
Self {
|
||||
job_id: input.job_id,
|
||||
owner_user_id: input.owner_user_id,
|
||||
after_sequence: input.after_sequence,
|
||||
limit: input.limit,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn map_web_project_procedure_result(
|
||||
result: WebProjectProcedureResult,
|
||||
) -> Result<WebProjectRecord, SpacetimeClientError> {
|
||||
@@ -313,6 +654,87 @@ pub(crate) fn map_web_project_preview_build_procedure_result(
|
||||
Ok(WebProjectPreviewBuildMutationRecord { project, build })
|
||||
}
|
||||
|
||||
pub(crate) fn map_web_project_runtime_job_procedure_result(
|
||||
result: WebProjectRuntimeJobProcedureResult,
|
||||
) -> Result<WebProjectRuntimeJobRecord, SpacetimeClientError> {
|
||||
if !result.ok {
|
||||
return Err(SpacetimeClientError::procedure_failed(result.error_message));
|
||||
}
|
||||
|
||||
result
|
||||
.job
|
||||
.map(map_web_project_runtime_job_snapshot)
|
||||
.ok_or_else(|| SpacetimeClientError::missing_snapshot("Web Project runtime job"))
|
||||
}
|
||||
|
||||
pub(crate) fn map_web_project_runtime_job_preview_build_procedure_result(
|
||||
result: WebProjectRuntimeJobPreviewBuildProcedureResult,
|
||||
) -> Result<WebProjectRuntimeJobPreviewBuildMutationRecord, SpacetimeClientError> {
|
||||
if !result.ok {
|
||||
return Err(SpacetimeClientError::procedure_failed(result.error_message));
|
||||
}
|
||||
|
||||
let project = result
|
||||
.project
|
||||
.map(map_web_project_snapshot)
|
||||
.ok_or_else(|| SpacetimeClientError::missing_snapshot("Web 工程"))?;
|
||||
let build = result
|
||||
.build
|
||||
.map(map_web_project_preview_build_snapshot)
|
||||
.ok_or_else(|| SpacetimeClientError::missing_snapshot("Web 工程预览构建"))?;
|
||||
let job = result
|
||||
.job
|
||||
.map(map_web_project_runtime_job_snapshot)
|
||||
.ok_or_else(|| SpacetimeClientError::missing_snapshot("Web Project runtime job"))?;
|
||||
|
||||
Ok(WebProjectRuntimeJobPreviewBuildMutationRecord {
|
||||
project,
|
||||
build,
|
||||
job,
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn map_web_project_runtime_job_list_result(
|
||||
result: WebProjectRuntimeJobProcedureResult,
|
||||
) -> Result<Vec<WebProjectRuntimeJobRecord>, SpacetimeClientError> {
|
||||
if !result.ok {
|
||||
return Err(SpacetimeClientError::procedure_failed(result.error_message));
|
||||
}
|
||||
|
||||
Ok(result
|
||||
.jobs
|
||||
.into_iter()
|
||||
.map(map_web_project_runtime_job_snapshot)
|
||||
.collect())
|
||||
}
|
||||
|
||||
pub(crate) fn map_web_project_runtime_job_log_procedure_result(
|
||||
result: WebProjectRuntimeJobProcedureResult,
|
||||
) -> Result<WebProjectRuntimeJobLogRecord, SpacetimeClientError> {
|
||||
if !result.ok {
|
||||
return Err(SpacetimeClientError::procedure_failed(result.error_message));
|
||||
}
|
||||
|
||||
result
|
||||
.log
|
||||
.map(map_web_project_runtime_job_log_snapshot)
|
||||
.ok_or_else(|| SpacetimeClientError::missing_snapshot("Web Project runtime job 日志"))
|
||||
}
|
||||
|
||||
pub(crate) fn map_web_project_runtime_job_log_list_result(
|
||||
result: WebProjectRuntimeJobProcedureResult,
|
||||
) -> Result<Vec<WebProjectRuntimeJobLogRecord>, SpacetimeClientError> {
|
||||
if !result.ok {
|
||||
return Err(SpacetimeClientError::procedure_failed(result.error_message));
|
||||
}
|
||||
|
||||
Ok(result
|
||||
.logs
|
||||
.into_iter()
|
||||
.map(map_web_project_runtime_job_log_snapshot)
|
||||
.collect())
|
||||
}
|
||||
|
||||
fn map_web_project_snapshot(snapshot: WebProjectProjectSnapshot) -> WebProjectRecord {
|
||||
WebProjectRecord {
|
||||
project_id: snapshot.project_id,
|
||||
@@ -361,6 +783,51 @@ fn map_web_project_preview_build_snapshot(
|
||||
}
|
||||
}
|
||||
|
||||
fn map_web_project_runtime_job_snapshot(
|
||||
snapshot: WebProjectRuntimeJobSnapshot,
|
||||
) -> WebProjectRuntimeJobRecord {
|
||||
WebProjectRuntimeJobRecord {
|
||||
job_id: snapshot.job_id,
|
||||
project_id: snapshot.project_id,
|
||||
snapshot_id: snapshot.snapshot_id,
|
||||
owner_user_id: snapshot.owner_user_id,
|
||||
job_kind: snapshot.job_kind,
|
||||
status: snapshot.status,
|
||||
attempt: snapshot.attempt,
|
||||
worker_id: snapshot.worker_id,
|
||||
lease_token: snapshot.lease_token,
|
||||
lease_expires_at: snapshot
|
||||
.lease_expires_at_micros
|
||||
.map(format_timestamp_micros),
|
||||
cancel_requested_at: snapshot
|
||||
.cancel_requested_at_micros
|
||||
.map(format_timestamp_micros),
|
||||
stale_reason: snapshot.stale_reason,
|
||||
artifact_id: snapshot.artifact_id,
|
||||
preview_build_id: snapshot.preview_build_id,
|
||||
error_summary: snapshot.error_summary,
|
||||
created_at: format_timestamp_micros(snapshot.created_at_micros),
|
||||
started_at: snapshot.started_at_micros.map(format_timestamp_micros),
|
||||
finished_at: snapshot.finished_at_micros.map(format_timestamp_micros),
|
||||
updated_at: format_timestamp_micros(snapshot.updated_at_micros),
|
||||
}
|
||||
}
|
||||
|
||||
fn map_web_project_runtime_job_log_snapshot(
|
||||
snapshot: WebProjectRuntimeJobLogSnapshot,
|
||||
) -> WebProjectRuntimeJobLogRecord {
|
||||
WebProjectRuntimeJobLogRecord {
|
||||
log_id: snapshot.log_id,
|
||||
job_id: snapshot.job_id,
|
||||
project_id: snapshot.project_id,
|
||||
owner_user_id: snapshot.owner_user_id,
|
||||
sequence: snapshot.sequence,
|
||||
level: snapshot.level,
|
||||
message: snapshot.message,
|
||||
created_at: format_timestamp_micros(snapshot.created_at_micros),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
@@ -380,4 +847,102 @@ mod tests {
|
||||
"无权访问该 Web 工程"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn maps_runtime_job_log_list_in_sequence_order_from_module_result() {
|
||||
let result = WebProjectRuntimeJobProcedureResult {
|
||||
ok: true,
|
||||
job: None,
|
||||
jobs: Vec::new(),
|
||||
log: None,
|
||||
logs: vec![WebProjectRuntimeJobLogSnapshot {
|
||||
log_id: "log-1".to_string(),
|
||||
job_id: "job-1".to_string(),
|
||||
project_id: "project-1".to_string(),
|
||||
owner_user_id: "user-1".to_string(),
|
||||
sequence: 2,
|
||||
level: "info".to_string(),
|
||||
message: "构建完成".to_string(),
|
||||
created_at_micros: 1_700_000_000_000_000,
|
||||
}],
|
||||
error_message: None,
|
||||
};
|
||||
|
||||
let logs = map_web_project_runtime_job_log_list_result(result)
|
||||
.expect("runtime job logs should map");
|
||||
|
||||
assert_eq!(logs.len(), 1);
|
||||
assert_eq!(logs[0].sequence, 2);
|
||||
assert_eq!(logs[0].message, "构建完成");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn maps_runtime_job_preview_build_combo_result() {
|
||||
let result = WebProjectRuntimeJobPreviewBuildProcedureResult {
|
||||
ok: true,
|
||||
project: Some(WebProjectProjectSnapshot {
|
||||
project_id: "project-1".to_string(),
|
||||
owner_user_id: "user-1".to_string(),
|
||||
title: "测试工程".to_string(),
|
||||
template_key: "react-vite-ts-static".to_string(),
|
||||
active_snapshot_id: "snapshot-2".to_string(),
|
||||
active_preview_build_id: Some("build-2".to_string()),
|
||||
created_at_micros: 1_700_000_000_000_000,
|
||||
updated_at_micros: 1_700_000_010_000_000,
|
||||
}),
|
||||
build: Some(WebProjectPreviewBuildSnapshot {
|
||||
job_id: "build-1".to_string(),
|
||||
project_id: "project-1".to_string(),
|
||||
snapshot_id: "snapshot-1".to_string(),
|
||||
owner_user_id: "user-1".to_string(),
|
||||
status: "stale".to_string(),
|
||||
logs: vec!["runtime worker: 构建完成,预览地址已生成".to_string()],
|
||||
artifact_id: None,
|
||||
preview_token_id: None,
|
||||
preview_url: None,
|
||||
error_summary: Some("job snapshot 已不是项目 active snapshot".to_string()),
|
||||
created_at_micros: 1_700_000_000_000_000,
|
||||
started_at_micros: Some(1_700_000_005_000_000),
|
||||
finished_at_micros: Some(1_700_000_010_000_000),
|
||||
updated_at_micros: 1_700_000_010_000_000,
|
||||
}),
|
||||
job: Some(WebProjectRuntimeJobSnapshot {
|
||||
job_id: "job-1".to_string(),
|
||||
project_id: "project-1".to_string(),
|
||||
snapshot_id: "snapshot-1".to_string(),
|
||||
owner_user_id: "user-1".to_string(),
|
||||
job_kind: "preview_build".to_string(),
|
||||
status: "stale".to_string(),
|
||||
attempt: 1,
|
||||
worker_id: None,
|
||||
lease_token: None,
|
||||
lease_expires_at_micros: None,
|
||||
cancel_requested_at_micros: None,
|
||||
stale_reason: Some("job snapshot 已不是项目 active snapshot".to_string()),
|
||||
artifact_id: None,
|
||||
preview_build_id: Some("build-1".to_string()),
|
||||
error_summary: None,
|
||||
created_at_micros: 1_700_000_000_000_000,
|
||||
started_at_micros: Some(1_700_000_005_000_000),
|
||||
finished_at_micros: Some(1_700_000_010_000_000),
|
||||
updated_at_micros: 1_700_000_010_000_000,
|
||||
}),
|
||||
error_message: None,
|
||||
};
|
||||
|
||||
let mapped = map_web_project_runtime_job_preview_build_procedure_result(result)
|
||||
.expect("combo result should map");
|
||||
|
||||
assert_eq!(
|
||||
mapped.project.active_preview_build_id.as_deref(),
|
||||
Some("build-2")
|
||||
);
|
||||
assert_eq!(mapped.build.status, "stale");
|
||||
assert_eq!(mapped.build.preview_url, None);
|
||||
assert_eq!(mapped.job.status, "stale");
|
||||
assert_eq!(
|
||||
mapped.job.stale_reason.as_deref(),
|
||||
Some("job snapshot 已不是项目 active snapshot")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
|
||||
// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.
|
||||
|
||||
// This was generated using spacetimedb cli version 2.4.1 (commit 07b52763c9da8d7cf79780db222fec1ffcb84070).
|
||||
// This was generated using spacetimedb cli version 2.5.0 (commit 19cbf2b219ac9fd7fdca6c5e2c61a3a2f0319515).
|
||||
|
||||
#![allow(unused, clippy::all)]
|
||||
use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws};
|
||||
@@ -68,6 +68,7 @@ pub mod analytics_metric_query_input_type;
|
||||
pub mod analytics_metric_query_procedure_result_type;
|
||||
pub mod append_ai_text_chunk_and_return_procedure;
|
||||
pub mod append_visual_novel_runtime_history_entry_procedure;
|
||||
pub mod append_web_project_runtime_job_log_and_return_procedure;
|
||||
pub mod apply_chapter_progression_ledger_entry_and_return_procedure;
|
||||
pub mod apply_chapter_progression_ledger_entry_reducer;
|
||||
pub mod apply_inventory_mutation_reducer;
|
||||
@@ -195,6 +196,7 @@ pub mod big_fish_works_procedure_result_type;
|
||||
pub mod bind_asset_object_to_entity_and_return_procedure;
|
||||
pub mod bind_asset_object_to_entity_reducer;
|
||||
pub mod cancel_ai_task_and_return_procedure;
|
||||
pub mod cancel_web_project_runtime_job_and_return_procedure;
|
||||
pub mod chapter_pace_band_type;
|
||||
pub mod chapter_progression_get_input_type;
|
||||
pub mod chapter_progression_input_type;
|
||||
@@ -208,6 +210,7 @@ pub mod claim_external_generation_jobs_and_return_procedure;
|
||||
pub mod claim_profile_task_reward_and_return_procedure;
|
||||
pub mod claim_puzzle_background_compile_task_procedure;
|
||||
pub mod claim_puzzle_work_point_incentive_procedure;
|
||||
pub mod claim_web_project_runtime_jobs_and_return_procedure;
|
||||
pub mod clear_database_migration_import_chunks_procedure;
|
||||
pub mod clear_platform_browse_history_and_return_procedure;
|
||||
pub mod click_match_3_d_item_procedure;
|
||||
@@ -224,6 +227,8 @@ pub mod compile_wooden_fish_draft_procedure;
|
||||
pub mod complete_ai_stage_and_return_procedure;
|
||||
pub mod complete_ai_task_and_return_procedure;
|
||||
pub mod complete_external_generation_job_and_return_procedure;
|
||||
pub mod complete_web_project_preview_build_runtime_job_and_return_procedure;
|
||||
pub mod complete_web_project_runtime_job_and_return_procedure;
|
||||
pub mod confirm_asset_object_and_return_procedure;
|
||||
pub mod confirm_asset_object_reducer;
|
||||
pub mod consume_inventory_item_input_type;
|
||||
@@ -250,6 +255,7 @@ pub mod create_square_hole_agent_session_procedure;
|
||||
pub mod create_visual_novel_agent_session_procedure;
|
||||
pub mod create_web_project_and_return_procedure;
|
||||
pub mod create_web_project_preview_build_and_return_procedure;
|
||||
pub mod create_web_project_runtime_job_and_return_procedure;
|
||||
pub mod create_wooden_fish_agent_session_procedure;
|
||||
pub mod creation_entry_config_procedure_result_type;
|
||||
pub mod creation_entry_config_snapshot_type;
|
||||
@@ -398,6 +404,7 @@ pub mod enqueue_external_generation_job_and_return_procedure;
|
||||
pub mod ensure_analytics_date_dimension_for_date_reducer;
|
||||
pub mod equip_inventory_item_input_type;
|
||||
pub mod execute_custom_world_agent_action_procedure;
|
||||
pub mod expire_web_project_runtime_job_and_return_procedure;
|
||||
pub mod export_auth_store_snapshot_from_tables_procedure;
|
||||
pub mod export_database_migration_to_file_procedure;
|
||||
pub mod external_generation_job_claim_input_type;
|
||||
@@ -414,6 +421,7 @@ pub mod external_generation_queue_stats_procedure_result_type;
|
||||
pub mod external_generation_queue_stats_snapshot_type;
|
||||
pub mod fail_ai_task_and_return_procedure;
|
||||
pub mod fail_external_generation_job_and_return_procedure;
|
||||
pub mod fail_web_project_runtime_job_and_return_procedure;
|
||||
pub mod finalize_big_fish_agent_message_turn_procedure;
|
||||
pub mod finalize_custom_world_agent_message_turn_procedure;
|
||||
pub mod finalize_match_3_d_agent_message_turn_procedure;
|
||||
@@ -477,6 +485,7 @@ pub mod get_visual_novel_work_detail_procedure;
|
||||
pub mod get_web_project_and_return_procedure;
|
||||
pub mod get_web_project_preview_build_and_return_procedure;
|
||||
pub mod get_web_project_preview_build_by_token_and_return_procedure;
|
||||
pub mod get_web_project_runtime_job_and_return_procedure;
|
||||
pub mod get_web_project_snapshot_and_return_procedure;
|
||||
pub mod get_wooden_fish_agent_session_procedure;
|
||||
pub mod get_wooden_fish_run_procedure;
|
||||
@@ -559,6 +568,7 @@ pub mod list_custom_world_works_procedure;
|
||||
pub mod list_editor_projects_and_return_procedure;
|
||||
pub mod list_jump_hop_works_procedure;
|
||||
pub mod list_match_3_d_works_procedure;
|
||||
pub mod list_open_web_project_runtime_jobs_and_return_procedure;
|
||||
pub mod list_platform_browse_history_procedure;
|
||||
pub mod list_profile_save_archives_procedure;
|
||||
pub mod list_profile_wallet_ledger_procedure;
|
||||
@@ -568,11 +578,13 @@ pub mod list_puzzle_works_procedure;
|
||||
pub mod list_square_hole_works_procedure;
|
||||
pub mod list_visual_novel_runtime_history_procedure;
|
||||
pub mod list_visual_novel_works_procedure;
|
||||
pub mod list_web_project_runtime_job_logs_and_return_procedure;
|
||||
pub mod list_wooden_fish_works_procedure;
|
||||
pub mod mark_profile_recharge_order_paid_and_return_procedure;
|
||||
pub mod mark_puzzle_clear_level_time_up_procedure;
|
||||
pub mod mark_puzzle_draft_generation_failed_procedure;
|
||||
pub mod mark_puzzle_level_generation_failed_procedure;
|
||||
pub mod mark_web_project_runtime_job_stale_and_return_procedure;
|
||||
pub mod match_3_d_agent_message_finalize_input_type;
|
||||
pub mod match_3_d_agent_message_row_type;
|
||||
pub mod match_3_d_agent_message_snapshot_type;
|
||||
@@ -855,6 +867,7 @@ pub mod remix_custom_world_profile_procedure;
|
||||
pub mod remix_puzzle_work_procedure;
|
||||
pub mod rename_editor_project_and_return_procedure;
|
||||
pub mod renew_external_generation_job_lease_and_return_procedure;
|
||||
pub mod renew_web_project_runtime_job_lease_and_return_procedure;
|
||||
pub mod resolve_combat_action_and_return_procedure;
|
||||
pub mod resolve_combat_action_input_type;
|
||||
pub mod resolve_combat_action_procedure_result_type;
|
||||
@@ -1181,6 +1194,27 @@ pub mod web_project_preview_build_token_get_input_type;
|
||||
pub mod web_project_preview_build_update_input_type;
|
||||
pub mod web_project_procedure_result_type;
|
||||
pub mod web_project_project_snapshot_type;
|
||||
pub mod web_project_runtime_job_append_log_input_type;
|
||||
pub mod web_project_runtime_job_cancel_input_type;
|
||||
pub mod web_project_runtime_job_claim_input_type;
|
||||
pub mod web_project_runtime_job_complete_input_type;
|
||||
pub mod web_project_runtime_job_complete_preview_build_input_type;
|
||||
pub mod web_project_runtime_job_create_input_type;
|
||||
pub mod web_project_runtime_job_expire_input_type;
|
||||
pub mod web_project_runtime_job_fail_input_type;
|
||||
pub mod web_project_runtime_job_get_input_type;
|
||||
pub mod web_project_runtime_job_list_logs_input_type;
|
||||
pub mod web_project_runtime_job_list_open_input_type;
|
||||
pub mod web_project_runtime_job_log_row_type;
|
||||
pub mod web_project_runtime_job_log_snapshot_type;
|
||||
pub mod web_project_runtime_job_log_table;
|
||||
pub mod web_project_runtime_job_preview_build_procedure_result_type;
|
||||
pub mod web_project_runtime_job_procedure_result_type;
|
||||
pub mod web_project_runtime_job_renew_lease_input_type;
|
||||
pub mod web_project_runtime_job_row_type;
|
||||
pub mod web_project_runtime_job_snapshot_type;
|
||||
pub mod web_project_runtime_job_stale_input_type;
|
||||
pub mod web_project_runtime_job_table;
|
||||
pub mod web_project_service_identity_authorize_input_type;
|
||||
pub mod web_project_service_identity_procedure_result_type;
|
||||
pub mod web_project_service_identity_revoke_input_type;
|
||||
@@ -1294,6 +1328,7 @@ pub use analytics_metric_query_input_type::AnalyticsMetricQueryInput;
|
||||
pub use analytics_metric_query_procedure_result_type::AnalyticsMetricQueryProcedureResult;
|
||||
pub use append_ai_text_chunk_and_return_procedure::append_ai_text_chunk_and_return;
|
||||
pub use append_visual_novel_runtime_history_entry_procedure::append_visual_novel_runtime_history_entry;
|
||||
pub use append_web_project_runtime_job_log_and_return_procedure::append_web_project_runtime_job_log_and_return;
|
||||
pub use apply_chapter_progression_ledger_entry_and_return_procedure::apply_chapter_progression_ledger_entry_and_return;
|
||||
pub use apply_chapter_progression_ledger_entry_reducer::apply_chapter_progression_ledger_entry;
|
||||
pub use apply_inventory_mutation_reducer::apply_inventory_mutation;
|
||||
@@ -1421,6 +1456,7 @@ pub use big_fish_works_procedure_result_type::BigFishWorksProcedureResult;
|
||||
pub use bind_asset_object_to_entity_and_return_procedure::bind_asset_object_to_entity_and_return;
|
||||
pub use bind_asset_object_to_entity_reducer::bind_asset_object_to_entity;
|
||||
pub use cancel_ai_task_and_return_procedure::cancel_ai_task_and_return;
|
||||
pub use cancel_web_project_runtime_job_and_return_procedure::cancel_web_project_runtime_job_and_return;
|
||||
pub use chapter_pace_band_type::ChapterPaceBand;
|
||||
pub use chapter_progression_get_input_type::ChapterProgressionGetInput;
|
||||
pub use chapter_progression_input_type::ChapterProgressionInput;
|
||||
@@ -1434,6 +1470,7 @@ pub use claim_external_generation_jobs_and_return_procedure::claim_external_gene
|
||||
pub use claim_profile_task_reward_and_return_procedure::claim_profile_task_reward_and_return;
|
||||
pub use claim_puzzle_background_compile_task_procedure::claim_puzzle_background_compile_task;
|
||||
pub use claim_puzzle_work_point_incentive_procedure::claim_puzzle_work_point_incentive;
|
||||
pub use claim_web_project_runtime_jobs_and_return_procedure::claim_web_project_runtime_jobs_and_return;
|
||||
pub use clear_database_migration_import_chunks_procedure::clear_database_migration_import_chunks;
|
||||
pub use clear_platform_browse_history_and_return_procedure::clear_platform_browse_history_and_return;
|
||||
pub use click_match_3_d_item_procedure::click_match_3_d_item;
|
||||
@@ -1450,6 +1487,8 @@ pub use compile_wooden_fish_draft_procedure::compile_wooden_fish_draft;
|
||||
pub use complete_ai_stage_and_return_procedure::complete_ai_stage_and_return;
|
||||
pub use complete_ai_task_and_return_procedure::complete_ai_task_and_return;
|
||||
pub use complete_external_generation_job_and_return_procedure::complete_external_generation_job_and_return;
|
||||
pub use complete_web_project_preview_build_runtime_job_and_return_procedure::complete_web_project_preview_build_runtime_job_and_return;
|
||||
pub use complete_web_project_runtime_job_and_return_procedure::complete_web_project_runtime_job_and_return;
|
||||
pub use confirm_asset_object_and_return_procedure::confirm_asset_object_and_return;
|
||||
pub use confirm_asset_object_reducer::confirm_asset_object;
|
||||
pub use consume_inventory_item_input_type::ConsumeInventoryItemInput;
|
||||
@@ -1476,6 +1515,7 @@ pub use create_square_hole_agent_session_procedure::create_square_hole_agent_ses
|
||||
pub use create_visual_novel_agent_session_procedure::create_visual_novel_agent_session;
|
||||
pub use create_web_project_and_return_procedure::create_web_project_and_return;
|
||||
pub use create_web_project_preview_build_and_return_procedure::create_web_project_preview_build_and_return;
|
||||
pub use create_web_project_runtime_job_and_return_procedure::create_web_project_runtime_job_and_return;
|
||||
pub use create_wooden_fish_agent_session_procedure::create_wooden_fish_agent_session;
|
||||
pub use creation_entry_config_procedure_result_type::CreationEntryConfigProcedureResult;
|
||||
pub use creation_entry_config_snapshot_type::CreationEntryConfigSnapshot;
|
||||
@@ -1624,6 +1664,7 @@ pub use enqueue_external_generation_job_and_return_procedure::enqueue_external_g
|
||||
pub use ensure_analytics_date_dimension_for_date_reducer::ensure_analytics_date_dimension_for_date;
|
||||
pub use equip_inventory_item_input_type::EquipInventoryItemInput;
|
||||
pub use execute_custom_world_agent_action_procedure::execute_custom_world_agent_action;
|
||||
pub use expire_web_project_runtime_job_and_return_procedure::expire_web_project_runtime_job_and_return;
|
||||
pub use export_auth_store_snapshot_from_tables_procedure::export_auth_store_snapshot_from_tables;
|
||||
pub use export_database_migration_to_file_procedure::export_database_migration_to_file;
|
||||
pub use external_generation_job_claim_input_type::ExternalGenerationJobClaimInput;
|
||||
@@ -1640,6 +1681,7 @@ pub use external_generation_queue_stats_procedure_result_type::ExternalGeneratio
|
||||
pub use external_generation_queue_stats_snapshot_type::ExternalGenerationQueueStatsSnapshot;
|
||||
pub use fail_ai_task_and_return_procedure::fail_ai_task_and_return;
|
||||
pub use fail_external_generation_job_and_return_procedure::fail_external_generation_job_and_return;
|
||||
pub use fail_web_project_runtime_job_and_return_procedure::fail_web_project_runtime_job_and_return;
|
||||
pub use finalize_big_fish_agent_message_turn_procedure::finalize_big_fish_agent_message_turn;
|
||||
pub use finalize_custom_world_agent_message_turn_procedure::finalize_custom_world_agent_message_turn;
|
||||
pub use finalize_match_3_d_agent_message_turn_procedure::finalize_match_3_d_agent_message_turn;
|
||||
@@ -1703,6 +1745,7 @@ pub use get_visual_novel_work_detail_procedure::get_visual_novel_work_detail;
|
||||
pub use get_web_project_and_return_procedure::get_web_project_and_return;
|
||||
pub use get_web_project_preview_build_and_return_procedure::get_web_project_preview_build_and_return;
|
||||
pub use get_web_project_preview_build_by_token_and_return_procedure::get_web_project_preview_build_by_token_and_return;
|
||||
pub use get_web_project_runtime_job_and_return_procedure::get_web_project_runtime_job_and_return;
|
||||
pub use get_web_project_snapshot_and_return_procedure::get_web_project_snapshot_and_return;
|
||||
pub use get_wooden_fish_agent_session_procedure::get_wooden_fish_agent_session;
|
||||
pub use get_wooden_fish_run_procedure::get_wooden_fish_run;
|
||||
@@ -1785,6 +1828,7 @@ pub use list_custom_world_works_procedure::list_custom_world_works;
|
||||
pub use list_editor_projects_and_return_procedure::list_editor_projects_and_return;
|
||||
pub use list_jump_hop_works_procedure::list_jump_hop_works;
|
||||
pub use list_match_3_d_works_procedure::list_match_3_d_works;
|
||||
pub use list_open_web_project_runtime_jobs_and_return_procedure::list_open_web_project_runtime_jobs_and_return;
|
||||
pub use list_platform_browse_history_procedure::list_platform_browse_history;
|
||||
pub use list_profile_save_archives_procedure::list_profile_save_archives;
|
||||
pub use list_profile_wallet_ledger_procedure::list_profile_wallet_ledger;
|
||||
@@ -1794,11 +1838,13 @@ pub use list_puzzle_works_procedure::list_puzzle_works;
|
||||
pub use list_square_hole_works_procedure::list_square_hole_works;
|
||||
pub use list_visual_novel_runtime_history_procedure::list_visual_novel_runtime_history;
|
||||
pub use list_visual_novel_works_procedure::list_visual_novel_works;
|
||||
pub use list_web_project_runtime_job_logs_and_return_procedure::list_web_project_runtime_job_logs_and_return;
|
||||
pub use list_wooden_fish_works_procedure::list_wooden_fish_works;
|
||||
pub use mark_profile_recharge_order_paid_and_return_procedure::mark_profile_recharge_order_paid_and_return;
|
||||
pub use mark_puzzle_clear_level_time_up_procedure::mark_puzzle_clear_level_time_up;
|
||||
pub use mark_puzzle_draft_generation_failed_procedure::mark_puzzle_draft_generation_failed;
|
||||
pub use mark_puzzle_level_generation_failed_procedure::mark_puzzle_level_generation_failed;
|
||||
pub use mark_web_project_runtime_job_stale_and_return_procedure::mark_web_project_runtime_job_stale_and_return;
|
||||
pub use match_3_d_agent_message_finalize_input_type::Match3DAgentMessageFinalizeInput;
|
||||
pub use match_3_d_agent_message_row_type::Match3DAgentMessageRow;
|
||||
pub use match_3_d_agent_message_snapshot_type::Match3DAgentMessageSnapshot;
|
||||
@@ -2081,6 +2127,7 @@ pub use remix_custom_world_profile_procedure::remix_custom_world_profile;
|
||||
pub use remix_puzzle_work_procedure::remix_puzzle_work;
|
||||
pub use rename_editor_project_and_return_procedure::rename_editor_project_and_return;
|
||||
pub use renew_external_generation_job_lease_and_return_procedure::renew_external_generation_job_lease_and_return;
|
||||
pub use renew_web_project_runtime_job_lease_and_return_procedure::renew_web_project_runtime_job_lease_and_return;
|
||||
pub use resolve_combat_action_and_return_procedure::resolve_combat_action_and_return;
|
||||
pub use resolve_combat_action_input_type::ResolveCombatActionInput;
|
||||
pub use resolve_combat_action_procedure_result_type::ResolveCombatActionProcedureResult;
|
||||
@@ -2407,6 +2454,27 @@ pub use web_project_preview_build_token_get_input_type::WebProjectPreviewBuildTo
|
||||
pub use web_project_preview_build_update_input_type::WebProjectPreviewBuildUpdateInput;
|
||||
pub use web_project_procedure_result_type::WebProjectProcedureResult;
|
||||
pub use web_project_project_snapshot_type::WebProjectProjectSnapshot;
|
||||
pub use web_project_runtime_job_append_log_input_type::WebProjectRuntimeJobAppendLogInput;
|
||||
pub use web_project_runtime_job_cancel_input_type::WebProjectRuntimeJobCancelInput;
|
||||
pub use web_project_runtime_job_claim_input_type::WebProjectRuntimeJobClaimInput;
|
||||
pub use web_project_runtime_job_complete_input_type::WebProjectRuntimeJobCompleteInput;
|
||||
pub use web_project_runtime_job_complete_preview_build_input_type::WebProjectRuntimeJobCompletePreviewBuildInput;
|
||||
pub use web_project_runtime_job_create_input_type::WebProjectRuntimeJobCreateInput;
|
||||
pub use web_project_runtime_job_expire_input_type::WebProjectRuntimeJobExpireInput;
|
||||
pub use web_project_runtime_job_fail_input_type::WebProjectRuntimeJobFailInput;
|
||||
pub use web_project_runtime_job_get_input_type::WebProjectRuntimeJobGetInput;
|
||||
pub use web_project_runtime_job_list_logs_input_type::WebProjectRuntimeJobListLogsInput;
|
||||
pub use web_project_runtime_job_list_open_input_type::WebProjectRuntimeJobListOpenInput;
|
||||
pub use web_project_runtime_job_log_row_type::WebProjectRuntimeJobLogRow;
|
||||
pub use web_project_runtime_job_log_snapshot_type::WebProjectRuntimeJobLogSnapshot;
|
||||
pub use web_project_runtime_job_log_table::*;
|
||||
pub use web_project_runtime_job_preview_build_procedure_result_type::WebProjectRuntimeJobPreviewBuildProcedureResult;
|
||||
pub use web_project_runtime_job_procedure_result_type::WebProjectRuntimeJobProcedureResult;
|
||||
pub use web_project_runtime_job_renew_lease_input_type::WebProjectRuntimeJobRenewLeaseInput;
|
||||
pub use web_project_runtime_job_row_type::WebProjectRuntimeJobRow;
|
||||
pub use web_project_runtime_job_snapshot_type::WebProjectRuntimeJobSnapshot;
|
||||
pub use web_project_runtime_job_stale_input_type::WebProjectRuntimeJobStaleInput;
|
||||
pub use web_project_runtime_job_table::*;
|
||||
pub use web_project_service_identity_authorize_input_type::WebProjectServiceIdentityAuthorizeInput;
|
||||
pub use web_project_service_identity_procedure_result_type::WebProjectServiceIdentityProcedureResult;
|
||||
pub use web_project_service_identity_revoke_input_type::WebProjectServiceIdentityRevokeInput;
|
||||
@@ -2850,6 +2918,8 @@ pub struct DbUpdate {
|
||||
visual_novel_work_profile: __sdk::TableUpdate<VisualNovelWorkProfileRow>,
|
||||
web_project: __sdk::TableUpdate<WebProject>,
|
||||
web_project_preview_build: __sdk::TableUpdate<WebProjectPreviewBuildRow>,
|
||||
web_project_runtime_job: __sdk::TableUpdate<WebProjectRuntimeJobRow>,
|
||||
web_project_runtime_job_log: __sdk::TableUpdate<WebProjectRuntimeJobLogRow>,
|
||||
web_project_service_identity: __sdk::TableUpdate<WebProjectServiceIdentity>,
|
||||
web_project_snapshot: __sdk::TableUpdate<WebProjectSnapshotRow>,
|
||||
wooden_fish_agent_session: __sdk::TableUpdate<WoodenFishAgentSessionRow>,
|
||||
@@ -3242,6 +3312,12 @@ impl TryFrom<__ws::v2::TransactionUpdate> for DbUpdate {
|
||||
"web_project_preview_build" => db_update.web_project_preview_build.append(
|
||||
web_project_preview_build_table::parse_table_update(table_update)?,
|
||||
),
|
||||
"web_project_runtime_job" => db_update.web_project_runtime_job.append(
|
||||
web_project_runtime_job_table::parse_table_update(table_update)?,
|
||||
),
|
||||
"web_project_runtime_job_log" => db_update.web_project_runtime_job_log.append(
|
||||
web_project_runtime_job_log_table::parse_table_update(table_update)?,
|
||||
),
|
||||
"web_project_service_identity" => db_update.web_project_service_identity.append(
|
||||
web_project_service_identity_table::parse_table_update(table_update)?,
|
||||
),
|
||||
@@ -3837,6 +3913,18 @@ impl __sdk::DbUpdate for DbUpdate {
|
||||
&self.web_project_preview_build,
|
||||
)
|
||||
.with_updates_by_pk(|row| &row.job_id);
|
||||
diff.web_project_runtime_job = cache
|
||||
.apply_diff_to_table::<WebProjectRuntimeJobRow>(
|
||||
"web_project_runtime_job",
|
||||
&self.web_project_runtime_job,
|
||||
)
|
||||
.with_updates_by_pk(|row| &row.job_id);
|
||||
diff.web_project_runtime_job_log = cache
|
||||
.apply_diff_to_table::<WebProjectRuntimeJobLogRow>(
|
||||
"web_project_runtime_job_log",
|
||||
&self.web_project_runtime_job_log,
|
||||
)
|
||||
.with_updates_by_pk(|row| &row.log_id);
|
||||
diff.web_project_service_identity = cache
|
||||
.apply_diff_to_table::<WebProjectServiceIdentity>(
|
||||
"web_project_service_identity",
|
||||
@@ -4299,6 +4387,12 @@ impl __sdk::DbUpdate for DbUpdate {
|
||||
"web_project_preview_build" => db_update
|
||||
.web_project_preview_build
|
||||
.append(__sdk::parse_row_list_as_inserts(table_rows.rows)?),
|
||||
"web_project_runtime_job" => db_update
|
||||
.web_project_runtime_job
|
||||
.append(__sdk::parse_row_list_as_inserts(table_rows.rows)?),
|
||||
"web_project_runtime_job_log" => db_update
|
||||
.web_project_runtime_job_log
|
||||
.append(__sdk::parse_row_list_as_inserts(table_rows.rows)?),
|
||||
"web_project_service_identity" => db_update
|
||||
.web_project_service_identity
|
||||
.append(__sdk::parse_row_list_as_inserts(table_rows.rows)?),
|
||||
@@ -4696,6 +4790,12 @@ impl __sdk::DbUpdate for DbUpdate {
|
||||
"web_project_preview_build" => db_update
|
||||
.web_project_preview_build
|
||||
.append(__sdk::parse_row_list_as_deletes(table_rows.rows)?),
|
||||
"web_project_runtime_job" => db_update
|
||||
.web_project_runtime_job
|
||||
.append(__sdk::parse_row_list_as_deletes(table_rows.rows)?),
|
||||
"web_project_runtime_job_log" => db_update
|
||||
.web_project_runtime_job_log
|
||||
.append(__sdk::parse_row_list_as_deletes(table_rows.rows)?),
|
||||
"web_project_service_identity" => db_update
|
||||
.web_project_service_identity
|
||||
.append(__sdk::parse_row_list_as_deletes(table_rows.rows)?),
|
||||
@@ -4858,6 +4958,8 @@ pub struct AppliedDiff<'r> {
|
||||
visual_novel_work_profile: __sdk::TableAppliedDiff<'r, VisualNovelWorkProfileRow>,
|
||||
web_project: __sdk::TableAppliedDiff<'r, WebProject>,
|
||||
web_project_preview_build: __sdk::TableAppliedDiff<'r, WebProjectPreviewBuildRow>,
|
||||
web_project_runtime_job: __sdk::TableAppliedDiff<'r, WebProjectRuntimeJobRow>,
|
||||
web_project_runtime_job_log: __sdk::TableAppliedDiff<'r, WebProjectRuntimeJobLogRow>,
|
||||
web_project_service_identity: __sdk::TableAppliedDiff<'r, WebProjectServiceIdentity>,
|
||||
web_project_snapshot: __sdk::TableAppliedDiff<'r, WebProjectSnapshotRow>,
|
||||
wooden_fish_agent_session: __sdk::TableAppliedDiff<'r, WoodenFishAgentSessionRow>,
|
||||
@@ -5455,6 +5557,16 @@ impl<'r> __sdk::AppliedDiff<'r> for AppliedDiff<'r> {
|
||||
&self.web_project_preview_build,
|
||||
event,
|
||||
);
|
||||
callbacks.invoke_table_row_callbacks::<WebProjectRuntimeJobRow>(
|
||||
"web_project_runtime_job",
|
||||
&self.web_project_runtime_job,
|
||||
event,
|
||||
);
|
||||
callbacks.invoke_table_row_callbacks::<WebProjectRuntimeJobLogRow>(
|
||||
"web_project_runtime_job_log",
|
||||
&self.web_project_runtime_job_log,
|
||||
event,
|
||||
);
|
||||
callbacks.invoke_table_row_callbacks::<WebProjectServiceIdentity>(
|
||||
"web_project_service_identity",
|
||||
&self.web_project_service_identity,
|
||||
@@ -6275,6 +6387,8 @@ impl __sdk::SpacetimeModule for RemoteModule {
|
||||
visual_novel_work_profile_table::register_table(client_cache);
|
||||
web_project_table::register_table(client_cache);
|
||||
web_project_preview_build_table::register_table(client_cache);
|
||||
web_project_runtime_job_table::register_table(client_cache);
|
||||
web_project_runtime_job_log_table::register_table(client_cache);
|
||||
web_project_service_identity_table::register_table(client_cache);
|
||||
web_project_snapshot_table::register_table(client_cache);
|
||||
wooden_fish_agent_session_table::register_table(client_cache);
|
||||
@@ -6405,6 +6519,8 @@ impl __sdk::SpacetimeModule for RemoteModule {
|
||||
"visual_novel_work_profile",
|
||||
"web_project",
|
||||
"web_project_preview_build",
|
||||
"web_project_runtime_job",
|
||||
"web_project_runtime_job_log",
|
||||
"web_project_service_identity",
|
||||
"web_project_snapshot",
|
||||
"wooden_fish_agent_session",
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
|
||||
// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.
|
||||
|
||||
#![allow(unused, clippy::all)]
|
||||
use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws};
|
||||
|
||||
use super::web_project_runtime_job_append_log_input_type::WebProjectRuntimeJobAppendLogInput;
|
||||
use super::web_project_runtime_job_procedure_result_type::WebProjectRuntimeJobProcedureResult;
|
||||
|
||||
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
|
||||
#[sats(crate = __lib)]
|
||||
struct AppendWebProjectRuntimeJobLogAndReturnArgs {
|
||||
pub input: WebProjectRuntimeJobAppendLogInput,
|
||||
}
|
||||
|
||||
impl __sdk::InModule for AppendWebProjectRuntimeJobLogAndReturnArgs {
|
||||
type Module = super::RemoteModule;
|
||||
}
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
/// Extension trait for access to the procedure `append_web_project_runtime_job_log_and_return`.
|
||||
///
|
||||
/// Implemented for [`super::RemoteProcedures`].
|
||||
pub trait append_web_project_runtime_job_log_and_return {
|
||||
fn append_web_project_runtime_job_log_and_return(
|
||||
&self,
|
||||
input: WebProjectRuntimeJobAppendLogInput,
|
||||
) {
|
||||
self.append_web_project_runtime_job_log_and_return_then(input, |_, _| {});
|
||||
}
|
||||
|
||||
fn append_web_project_runtime_job_log_and_return_then(
|
||||
&self,
|
||||
input: WebProjectRuntimeJobAppendLogInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<WebProjectRuntimeJobProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
);
|
||||
}
|
||||
|
||||
impl append_web_project_runtime_job_log_and_return for super::RemoteProcedures {
|
||||
fn append_web_project_runtime_job_log_and_return_then(
|
||||
&self,
|
||||
input: WebProjectRuntimeJobAppendLogInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<WebProjectRuntimeJobProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) {
|
||||
self.imp
|
||||
.invoke_procedure_with_callback::<_, WebProjectRuntimeJobProcedureResult>(
|
||||
"append_web_project_runtime_job_log_and_return",
|
||||
AppendWebProjectRuntimeJobLogAndReturnArgs { input },
|
||||
__callback,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
|
||||
// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.
|
||||
|
||||
#![allow(unused, clippy::all)]
|
||||
use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws};
|
||||
|
||||
use super::web_project_runtime_job_cancel_input_type::WebProjectRuntimeJobCancelInput;
|
||||
use super::web_project_runtime_job_procedure_result_type::WebProjectRuntimeJobProcedureResult;
|
||||
|
||||
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
|
||||
#[sats(crate = __lib)]
|
||||
struct CancelWebProjectRuntimeJobAndReturnArgs {
|
||||
pub input: WebProjectRuntimeJobCancelInput,
|
||||
}
|
||||
|
||||
impl __sdk::InModule for CancelWebProjectRuntimeJobAndReturnArgs {
|
||||
type Module = super::RemoteModule;
|
||||
}
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
/// Extension trait for access to the procedure `cancel_web_project_runtime_job_and_return`.
|
||||
///
|
||||
/// Implemented for [`super::RemoteProcedures`].
|
||||
pub trait cancel_web_project_runtime_job_and_return {
|
||||
fn cancel_web_project_runtime_job_and_return(&self, input: WebProjectRuntimeJobCancelInput) {
|
||||
self.cancel_web_project_runtime_job_and_return_then(input, |_, _| {});
|
||||
}
|
||||
|
||||
fn cancel_web_project_runtime_job_and_return_then(
|
||||
&self,
|
||||
input: WebProjectRuntimeJobCancelInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<WebProjectRuntimeJobProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
);
|
||||
}
|
||||
|
||||
impl cancel_web_project_runtime_job_and_return for super::RemoteProcedures {
|
||||
fn cancel_web_project_runtime_job_and_return_then(
|
||||
&self,
|
||||
input: WebProjectRuntimeJobCancelInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<WebProjectRuntimeJobProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) {
|
||||
self.imp
|
||||
.invoke_procedure_with_callback::<_, WebProjectRuntimeJobProcedureResult>(
|
||||
"cancel_web_project_runtime_job_and_return",
|
||||
CancelWebProjectRuntimeJobAndReturnArgs { input },
|
||||
__callback,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
|
||||
// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.
|
||||
|
||||
#![allow(unused, clippy::all)]
|
||||
use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws};
|
||||
|
||||
use super::web_project_runtime_job_claim_input_type::WebProjectRuntimeJobClaimInput;
|
||||
use super::web_project_runtime_job_procedure_result_type::WebProjectRuntimeJobProcedureResult;
|
||||
|
||||
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
|
||||
#[sats(crate = __lib)]
|
||||
struct ClaimWebProjectRuntimeJobsAndReturnArgs {
|
||||
pub input: WebProjectRuntimeJobClaimInput,
|
||||
}
|
||||
|
||||
impl __sdk::InModule for ClaimWebProjectRuntimeJobsAndReturnArgs {
|
||||
type Module = super::RemoteModule;
|
||||
}
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
/// Extension trait for access to the procedure `claim_web_project_runtime_jobs_and_return`.
|
||||
///
|
||||
/// Implemented for [`super::RemoteProcedures`].
|
||||
pub trait claim_web_project_runtime_jobs_and_return {
|
||||
fn claim_web_project_runtime_jobs_and_return(&self, input: WebProjectRuntimeJobClaimInput) {
|
||||
self.claim_web_project_runtime_jobs_and_return_then(input, |_, _| {});
|
||||
}
|
||||
|
||||
fn claim_web_project_runtime_jobs_and_return_then(
|
||||
&self,
|
||||
input: WebProjectRuntimeJobClaimInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<WebProjectRuntimeJobProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
);
|
||||
}
|
||||
|
||||
impl claim_web_project_runtime_jobs_and_return for super::RemoteProcedures {
|
||||
fn claim_web_project_runtime_jobs_and_return_then(
|
||||
&self,
|
||||
input: WebProjectRuntimeJobClaimInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<WebProjectRuntimeJobProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) {
|
||||
self.imp
|
||||
.invoke_procedure_with_callback::<_, WebProjectRuntimeJobProcedureResult>(
|
||||
"claim_web_project_runtime_jobs_and_return",
|
||||
ClaimWebProjectRuntimeJobsAndReturnArgs { input },
|
||||
__callback,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
|
||||
// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.
|
||||
|
||||
#![allow(unused, clippy::all)]
|
||||
use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws};
|
||||
|
||||
use super::web_project_runtime_job_complete_preview_build_input_type::WebProjectRuntimeJobCompletePreviewBuildInput;
|
||||
use super::web_project_runtime_job_preview_build_procedure_result_type::WebProjectRuntimeJobPreviewBuildProcedureResult;
|
||||
|
||||
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
|
||||
#[sats(crate = __lib)]
|
||||
struct CompleteWebProjectPreviewBuildRuntimeJobAndReturnArgs {
|
||||
pub input: WebProjectRuntimeJobCompletePreviewBuildInput,
|
||||
}
|
||||
|
||||
impl __sdk::InModule for CompleteWebProjectPreviewBuildRuntimeJobAndReturnArgs {
|
||||
type Module = super::RemoteModule;
|
||||
}
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
/// Extension trait for access to the procedure `complete_web_project_preview_build_runtime_job_and_return`.
|
||||
///
|
||||
/// Implemented for [`super::RemoteProcedures`].
|
||||
pub trait complete_web_project_preview_build_runtime_job_and_return {
|
||||
fn complete_web_project_preview_build_runtime_job_and_return(
|
||||
&self,
|
||||
input: WebProjectRuntimeJobCompletePreviewBuildInput,
|
||||
) {
|
||||
self.complete_web_project_preview_build_runtime_job_and_return_then(input, |_, _| {});
|
||||
}
|
||||
|
||||
fn complete_web_project_preview_build_runtime_job_and_return_then(
|
||||
&self,
|
||||
input: WebProjectRuntimeJobCompletePreviewBuildInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<WebProjectRuntimeJobPreviewBuildProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
);
|
||||
}
|
||||
|
||||
impl complete_web_project_preview_build_runtime_job_and_return for super::RemoteProcedures {
|
||||
fn complete_web_project_preview_build_runtime_job_and_return_then(
|
||||
&self,
|
||||
input: WebProjectRuntimeJobCompletePreviewBuildInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<WebProjectRuntimeJobPreviewBuildProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) {
|
||||
self.imp
|
||||
.invoke_procedure_with_callback::<_, WebProjectRuntimeJobPreviewBuildProcedureResult>(
|
||||
"complete_web_project_preview_build_runtime_job_and_return",
|
||||
CompleteWebProjectPreviewBuildRuntimeJobAndReturnArgs { input },
|
||||
__callback,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
|
||||
// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.
|
||||
|
||||
#![allow(unused, clippy::all)]
|
||||
use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws};
|
||||
|
||||
use super::web_project_runtime_job_complete_input_type::WebProjectRuntimeJobCompleteInput;
|
||||
use super::web_project_runtime_job_procedure_result_type::WebProjectRuntimeJobProcedureResult;
|
||||
|
||||
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
|
||||
#[sats(crate = __lib)]
|
||||
struct CompleteWebProjectRuntimeJobAndReturnArgs {
|
||||
pub input: WebProjectRuntimeJobCompleteInput,
|
||||
}
|
||||
|
||||
impl __sdk::InModule for CompleteWebProjectRuntimeJobAndReturnArgs {
|
||||
type Module = super::RemoteModule;
|
||||
}
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
/// Extension trait for access to the procedure `complete_web_project_runtime_job_and_return`.
|
||||
///
|
||||
/// Implemented for [`super::RemoteProcedures`].
|
||||
pub trait complete_web_project_runtime_job_and_return {
|
||||
fn complete_web_project_runtime_job_and_return(
|
||||
&self,
|
||||
input: WebProjectRuntimeJobCompleteInput,
|
||||
) {
|
||||
self.complete_web_project_runtime_job_and_return_then(input, |_, _| {});
|
||||
}
|
||||
|
||||
fn complete_web_project_runtime_job_and_return_then(
|
||||
&self,
|
||||
input: WebProjectRuntimeJobCompleteInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<WebProjectRuntimeJobProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
);
|
||||
}
|
||||
|
||||
impl complete_web_project_runtime_job_and_return for super::RemoteProcedures {
|
||||
fn complete_web_project_runtime_job_and_return_then(
|
||||
&self,
|
||||
input: WebProjectRuntimeJobCompleteInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<WebProjectRuntimeJobProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) {
|
||||
self.imp
|
||||
.invoke_procedure_with_callback::<_, WebProjectRuntimeJobProcedureResult>(
|
||||
"complete_web_project_runtime_job_and_return",
|
||||
CompleteWebProjectRuntimeJobAndReturnArgs { input },
|
||||
__callback,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
|
||||
// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.
|
||||
|
||||
#![allow(unused, clippy::all)]
|
||||
use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws};
|
||||
|
||||
use super::web_project_runtime_job_create_input_type::WebProjectRuntimeJobCreateInput;
|
||||
use super::web_project_runtime_job_procedure_result_type::WebProjectRuntimeJobProcedureResult;
|
||||
|
||||
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
|
||||
#[sats(crate = __lib)]
|
||||
struct CreateWebProjectRuntimeJobAndReturnArgs {
|
||||
pub input: WebProjectRuntimeJobCreateInput,
|
||||
}
|
||||
|
||||
impl __sdk::InModule for CreateWebProjectRuntimeJobAndReturnArgs {
|
||||
type Module = super::RemoteModule;
|
||||
}
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
/// Extension trait for access to the procedure `create_web_project_runtime_job_and_return`.
|
||||
///
|
||||
/// Implemented for [`super::RemoteProcedures`].
|
||||
pub trait create_web_project_runtime_job_and_return {
|
||||
fn create_web_project_runtime_job_and_return(&self, input: WebProjectRuntimeJobCreateInput) {
|
||||
self.create_web_project_runtime_job_and_return_then(input, |_, _| {});
|
||||
}
|
||||
|
||||
fn create_web_project_runtime_job_and_return_then(
|
||||
&self,
|
||||
input: WebProjectRuntimeJobCreateInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<WebProjectRuntimeJobProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
);
|
||||
}
|
||||
|
||||
impl create_web_project_runtime_job_and_return for super::RemoteProcedures {
|
||||
fn create_web_project_runtime_job_and_return_then(
|
||||
&self,
|
||||
input: WebProjectRuntimeJobCreateInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<WebProjectRuntimeJobProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) {
|
||||
self.imp
|
||||
.invoke_procedure_with_callback::<_, WebProjectRuntimeJobProcedureResult>(
|
||||
"create_web_project_runtime_job_and_return",
|
||||
CreateWebProjectRuntimeJobAndReturnArgs { input },
|
||||
__callback,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
|
||||
// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.
|
||||
|
||||
#![allow(unused, clippy::all)]
|
||||
use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws};
|
||||
|
||||
use super::web_project_runtime_job_expire_input_type::WebProjectRuntimeJobExpireInput;
|
||||
use super::web_project_runtime_job_procedure_result_type::WebProjectRuntimeJobProcedureResult;
|
||||
|
||||
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
|
||||
#[sats(crate = __lib)]
|
||||
struct ExpireWebProjectRuntimeJobAndReturnArgs {
|
||||
pub input: WebProjectRuntimeJobExpireInput,
|
||||
}
|
||||
|
||||
impl __sdk::InModule for ExpireWebProjectRuntimeJobAndReturnArgs {
|
||||
type Module = super::RemoteModule;
|
||||
}
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
/// Extension trait for access to the procedure `expire_web_project_runtime_job_and_return`.
|
||||
///
|
||||
/// Implemented for [`super::RemoteProcedures`].
|
||||
pub trait expire_web_project_runtime_job_and_return {
|
||||
fn expire_web_project_runtime_job_and_return(&self, input: WebProjectRuntimeJobExpireInput) {
|
||||
self.expire_web_project_runtime_job_and_return_then(input, |_, _| {});
|
||||
}
|
||||
|
||||
fn expire_web_project_runtime_job_and_return_then(
|
||||
&self,
|
||||
input: WebProjectRuntimeJobExpireInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<WebProjectRuntimeJobProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
);
|
||||
}
|
||||
|
||||
impl expire_web_project_runtime_job_and_return for super::RemoteProcedures {
|
||||
fn expire_web_project_runtime_job_and_return_then(
|
||||
&self,
|
||||
input: WebProjectRuntimeJobExpireInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<WebProjectRuntimeJobProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) {
|
||||
self.imp
|
||||
.invoke_procedure_with_callback::<_, WebProjectRuntimeJobProcedureResult>(
|
||||
"expire_web_project_runtime_job_and_return",
|
||||
ExpireWebProjectRuntimeJobAndReturnArgs { input },
|
||||
__callback,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
|
||||
// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.
|
||||
|
||||
#![allow(unused, clippy::all)]
|
||||
use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws};
|
||||
|
||||
use super::web_project_runtime_job_fail_input_type::WebProjectRuntimeJobFailInput;
|
||||
use super::web_project_runtime_job_procedure_result_type::WebProjectRuntimeJobProcedureResult;
|
||||
|
||||
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
|
||||
#[sats(crate = __lib)]
|
||||
struct FailWebProjectRuntimeJobAndReturnArgs {
|
||||
pub input: WebProjectRuntimeJobFailInput,
|
||||
}
|
||||
|
||||
impl __sdk::InModule for FailWebProjectRuntimeJobAndReturnArgs {
|
||||
type Module = super::RemoteModule;
|
||||
}
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
/// Extension trait for access to the procedure `fail_web_project_runtime_job_and_return`.
|
||||
///
|
||||
/// Implemented for [`super::RemoteProcedures`].
|
||||
pub trait fail_web_project_runtime_job_and_return {
|
||||
fn fail_web_project_runtime_job_and_return(&self, input: WebProjectRuntimeJobFailInput) {
|
||||
self.fail_web_project_runtime_job_and_return_then(input, |_, _| {});
|
||||
}
|
||||
|
||||
fn fail_web_project_runtime_job_and_return_then(
|
||||
&self,
|
||||
input: WebProjectRuntimeJobFailInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<WebProjectRuntimeJobProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
);
|
||||
}
|
||||
|
||||
impl fail_web_project_runtime_job_and_return for super::RemoteProcedures {
|
||||
fn fail_web_project_runtime_job_and_return_then(
|
||||
&self,
|
||||
input: WebProjectRuntimeJobFailInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<WebProjectRuntimeJobProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) {
|
||||
self.imp
|
||||
.invoke_procedure_with_callback::<_, WebProjectRuntimeJobProcedureResult>(
|
||||
"fail_web_project_runtime_job_and_return",
|
||||
FailWebProjectRuntimeJobAndReturnArgs { input },
|
||||
__callback,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
|
||||
// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.
|
||||
|
||||
#![allow(unused, clippy::all)]
|
||||
use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws};
|
||||
|
||||
use super::web_project_runtime_job_get_input_type::WebProjectRuntimeJobGetInput;
|
||||
use super::web_project_runtime_job_procedure_result_type::WebProjectRuntimeJobProcedureResult;
|
||||
|
||||
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
|
||||
#[sats(crate = __lib)]
|
||||
struct GetWebProjectRuntimeJobAndReturnArgs {
|
||||
pub input: WebProjectRuntimeJobGetInput,
|
||||
}
|
||||
|
||||
impl __sdk::InModule for GetWebProjectRuntimeJobAndReturnArgs {
|
||||
type Module = super::RemoteModule;
|
||||
}
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
/// Extension trait for access to the procedure `get_web_project_runtime_job_and_return`.
|
||||
///
|
||||
/// Implemented for [`super::RemoteProcedures`].
|
||||
pub trait get_web_project_runtime_job_and_return {
|
||||
fn get_web_project_runtime_job_and_return(&self, input: WebProjectRuntimeJobGetInput) {
|
||||
self.get_web_project_runtime_job_and_return_then(input, |_, _| {});
|
||||
}
|
||||
|
||||
fn get_web_project_runtime_job_and_return_then(
|
||||
&self,
|
||||
input: WebProjectRuntimeJobGetInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<WebProjectRuntimeJobProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
);
|
||||
}
|
||||
|
||||
impl get_web_project_runtime_job_and_return for super::RemoteProcedures {
|
||||
fn get_web_project_runtime_job_and_return_then(
|
||||
&self,
|
||||
input: WebProjectRuntimeJobGetInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<WebProjectRuntimeJobProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) {
|
||||
self.imp
|
||||
.invoke_procedure_with_callback::<_, WebProjectRuntimeJobProcedureResult>(
|
||||
"get_web_project_runtime_job_and_return",
|
||||
GetWebProjectRuntimeJobAndReturnArgs { input },
|
||||
__callback,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
|
||||
// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.
|
||||
|
||||
#![allow(unused, clippy::all)]
|
||||
use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws};
|
||||
|
||||
use super::web_project_runtime_job_list_open_input_type::WebProjectRuntimeJobListOpenInput;
|
||||
use super::web_project_runtime_job_procedure_result_type::WebProjectRuntimeJobProcedureResult;
|
||||
|
||||
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
|
||||
#[sats(crate = __lib)]
|
||||
struct ListOpenWebProjectRuntimeJobsAndReturnArgs {
|
||||
pub input: WebProjectRuntimeJobListOpenInput,
|
||||
}
|
||||
|
||||
impl __sdk::InModule for ListOpenWebProjectRuntimeJobsAndReturnArgs {
|
||||
type Module = super::RemoteModule;
|
||||
}
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
/// Extension trait for access to the procedure `list_open_web_project_runtime_jobs_and_return`.
|
||||
///
|
||||
/// Implemented for [`super::RemoteProcedures`].
|
||||
pub trait list_open_web_project_runtime_jobs_and_return {
|
||||
fn list_open_web_project_runtime_jobs_and_return(
|
||||
&self,
|
||||
input: WebProjectRuntimeJobListOpenInput,
|
||||
) {
|
||||
self.list_open_web_project_runtime_jobs_and_return_then(input, |_, _| {});
|
||||
}
|
||||
|
||||
fn list_open_web_project_runtime_jobs_and_return_then(
|
||||
&self,
|
||||
input: WebProjectRuntimeJobListOpenInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<WebProjectRuntimeJobProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
);
|
||||
}
|
||||
|
||||
impl list_open_web_project_runtime_jobs_and_return for super::RemoteProcedures {
|
||||
fn list_open_web_project_runtime_jobs_and_return_then(
|
||||
&self,
|
||||
input: WebProjectRuntimeJobListOpenInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<WebProjectRuntimeJobProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) {
|
||||
self.imp
|
||||
.invoke_procedure_with_callback::<_, WebProjectRuntimeJobProcedureResult>(
|
||||
"list_open_web_project_runtime_jobs_and_return",
|
||||
ListOpenWebProjectRuntimeJobsAndReturnArgs { input },
|
||||
__callback,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
|
||||
// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.
|
||||
|
||||
#![allow(unused, clippy::all)]
|
||||
use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws};
|
||||
|
||||
use super::web_project_runtime_job_list_logs_input_type::WebProjectRuntimeJobListLogsInput;
|
||||
use super::web_project_runtime_job_procedure_result_type::WebProjectRuntimeJobProcedureResult;
|
||||
|
||||
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
|
||||
#[sats(crate = __lib)]
|
||||
struct ListWebProjectRuntimeJobLogsAndReturnArgs {
|
||||
pub input: WebProjectRuntimeJobListLogsInput,
|
||||
}
|
||||
|
||||
impl __sdk::InModule for ListWebProjectRuntimeJobLogsAndReturnArgs {
|
||||
type Module = super::RemoteModule;
|
||||
}
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
/// Extension trait for access to the procedure `list_web_project_runtime_job_logs_and_return`.
|
||||
///
|
||||
/// Implemented for [`super::RemoteProcedures`].
|
||||
pub trait list_web_project_runtime_job_logs_and_return {
|
||||
fn list_web_project_runtime_job_logs_and_return(
|
||||
&self,
|
||||
input: WebProjectRuntimeJobListLogsInput,
|
||||
) {
|
||||
self.list_web_project_runtime_job_logs_and_return_then(input, |_, _| {});
|
||||
}
|
||||
|
||||
fn list_web_project_runtime_job_logs_and_return_then(
|
||||
&self,
|
||||
input: WebProjectRuntimeJobListLogsInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<WebProjectRuntimeJobProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
);
|
||||
}
|
||||
|
||||
impl list_web_project_runtime_job_logs_and_return for super::RemoteProcedures {
|
||||
fn list_web_project_runtime_job_logs_and_return_then(
|
||||
&self,
|
||||
input: WebProjectRuntimeJobListLogsInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<WebProjectRuntimeJobProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) {
|
||||
self.imp
|
||||
.invoke_procedure_with_callback::<_, WebProjectRuntimeJobProcedureResult>(
|
||||
"list_web_project_runtime_job_logs_and_return",
|
||||
ListWebProjectRuntimeJobLogsAndReturnArgs { input },
|
||||
__callback,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
|
||||
// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.
|
||||
|
||||
#![allow(unused, clippy::all)]
|
||||
use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws};
|
||||
|
||||
use super::web_project_runtime_job_procedure_result_type::WebProjectRuntimeJobProcedureResult;
|
||||
use super::web_project_runtime_job_stale_input_type::WebProjectRuntimeJobStaleInput;
|
||||
|
||||
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
|
||||
#[sats(crate = __lib)]
|
||||
struct MarkWebProjectRuntimeJobStaleAndReturnArgs {
|
||||
pub input: WebProjectRuntimeJobStaleInput,
|
||||
}
|
||||
|
||||
impl __sdk::InModule for MarkWebProjectRuntimeJobStaleAndReturnArgs {
|
||||
type Module = super::RemoteModule;
|
||||
}
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
/// Extension trait for access to the procedure `mark_web_project_runtime_job_stale_and_return`.
|
||||
///
|
||||
/// Implemented for [`super::RemoteProcedures`].
|
||||
pub trait mark_web_project_runtime_job_stale_and_return {
|
||||
fn mark_web_project_runtime_job_stale_and_return(&self, input: WebProjectRuntimeJobStaleInput) {
|
||||
self.mark_web_project_runtime_job_stale_and_return_then(input, |_, _| {});
|
||||
}
|
||||
|
||||
fn mark_web_project_runtime_job_stale_and_return_then(
|
||||
&self,
|
||||
input: WebProjectRuntimeJobStaleInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<WebProjectRuntimeJobProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
);
|
||||
}
|
||||
|
||||
impl mark_web_project_runtime_job_stale_and_return for super::RemoteProcedures {
|
||||
fn mark_web_project_runtime_job_stale_and_return_then(
|
||||
&self,
|
||||
input: WebProjectRuntimeJobStaleInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<WebProjectRuntimeJobProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) {
|
||||
self.imp
|
||||
.invoke_procedure_with_callback::<_, WebProjectRuntimeJobProcedureResult>(
|
||||
"mark_web_project_runtime_job_stale_and_return",
|
||||
MarkWebProjectRuntimeJobStaleAndReturnArgs { input },
|
||||
__callback,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
|
||||
// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.
|
||||
|
||||
#![allow(unused, clippy::all)]
|
||||
use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws};
|
||||
|
||||
use super::web_project_runtime_job_procedure_result_type::WebProjectRuntimeJobProcedureResult;
|
||||
use super::web_project_runtime_job_renew_lease_input_type::WebProjectRuntimeJobRenewLeaseInput;
|
||||
|
||||
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
|
||||
#[sats(crate = __lib)]
|
||||
struct RenewWebProjectRuntimeJobLeaseAndReturnArgs {
|
||||
pub input: WebProjectRuntimeJobRenewLeaseInput,
|
||||
}
|
||||
|
||||
impl __sdk::InModule for RenewWebProjectRuntimeJobLeaseAndReturnArgs {
|
||||
type Module = super::RemoteModule;
|
||||
}
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
/// Extension trait for access to the procedure `renew_web_project_runtime_job_lease_and_return`.
|
||||
///
|
||||
/// Implemented for [`super::RemoteProcedures`].
|
||||
pub trait renew_web_project_runtime_job_lease_and_return {
|
||||
fn renew_web_project_runtime_job_lease_and_return(
|
||||
&self,
|
||||
input: WebProjectRuntimeJobRenewLeaseInput,
|
||||
) {
|
||||
self.renew_web_project_runtime_job_lease_and_return_then(input, |_, _| {});
|
||||
}
|
||||
|
||||
fn renew_web_project_runtime_job_lease_and_return_then(
|
||||
&self,
|
||||
input: WebProjectRuntimeJobRenewLeaseInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<WebProjectRuntimeJobProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
);
|
||||
}
|
||||
|
||||
impl renew_web_project_runtime_job_lease_and_return for super::RemoteProcedures {
|
||||
fn renew_web_project_runtime_job_lease_and_return_then(
|
||||
&self,
|
||||
input: WebProjectRuntimeJobRenewLeaseInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<WebProjectRuntimeJobProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) {
|
||||
self.imp
|
||||
.invoke_procedure_with_callback::<_, WebProjectRuntimeJobProcedureResult>(
|
||||
"renew_web_project_runtime_job_lease_and_return",
|
||||
RenewWebProjectRuntimeJobLeaseAndReturnArgs { input },
|
||||
__callback,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
|
||||
// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.
|
||||
|
||||
#![allow(unused, clippy::all)]
|
||||
use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws};
|
||||
|
||||
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
|
||||
#[sats(crate = __lib)]
|
||||
pub struct WebProjectRuntimeJobAppendLogInput {
|
||||
pub log_id: String,
|
||||
pub job_id: String,
|
||||
pub owner_user_id: String,
|
||||
pub sequence: u64,
|
||||
pub level: String,
|
||||
pub message: String,
|
||||
pub worker_id: Option<String>,
|
||||
pub lease_token: Option<String>,
|
||||
pub created_at_micros: i64,
|
||||
}
|
||||
|
||||
impl __sdk::InModule for WebProjectRuntimeJobAppendLogInput {
|
||||
type Module = super::RemoteModule;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
|
||||
// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.
|
||||
|
||||
#![allow(unused, clippy::all)]
|
||||
use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws};
|
||||
|
||||
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
|
||||
#[sats(crate = __lib)]
|
||||
pub struct WebProjectRuntimeJobCancelInput {
|
||||
pub job_id: String,
|
||||
pub owner_user_id: String,
|
||||
pub cancelled_at_micros: i64,
|
||||
}
|
||||
|
||||
impl __sdk::InModule for WebProjectRuntimeJobCancelInput {
|
||||
type Module = super::RemoteModule;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
|
||||
// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.
|
||||
|
||||
#![allow(unused, clippy::all)]
|
||||
use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws};
|
||||
|
||||
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
|
||||
#[sats(crate = __lib)]
|
||||
pub struct WebProjectRuntimeJobClaimInput {
|
||||
pub worker_id: String,
|
||||
pub limit: u32,
|
||||
pub lease_expires_at_micros: i64,
|
||||
pub claimed_at_micros: i64,
|
||||
}
|
||||
|
||||
impl __sdk::InModule for WebProjectRuntimeJobClaimInput {
|
||||
type Module = super::RemoteModule;
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
|
||||
// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.
|
||||
|
||||
#![allow(unused, clippy::all)]
|
||||
use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws};
|
||||
|
||||
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
|
||||
#[sats(crate = __lib)]
|
||||
pub struct WebProjectRuntimeJobCompleteInput {
|
||||
pub job_id: String,
|
||||
pub worker_id: String,
|
||||
pub lease_token: String,
|
||||
pub artifact_id: Option<String>,
|
||||
pub preview_build_id: Option<String>,
|
||||
pub completed_at_micros: i64,
|
||||
}
|
||||
|
||||
impl __sdk::InModule for WebProjectRuntimeJobCompleteInput {
|
||||
type Module = super::RemoteModule;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
|
||||
// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.
|
||||
|
||||
#![allow(unused, clippy::all)]
|
||||
use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws};
|
||||
|
||||
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
|
||||
#[sats(crate = __lib)]
|
||||
pub struct WebProjectRuntimeJobCompletePreviewBuildInput {
|
||||
pub job_id: String,
|
||||
pub worker_id: String,
|
||||
pub lease_token: String,
|
||||
pub preview_build_id: String,
|
||||
pub artifact_id: String,
|
||||
pub preview_token_id: String,
|
||||
pub preview_url: String,
|
||||
pub logs: Vec<String>,
|
||||
pub started_at_micros: Option<i64>,
|
||||
pub finished_at_micros: i64,
|
||||
}
|
||||
|
||||
impl __sdk::InModule for WebProjectRuntimeJobCompletePreviewBuildInput {
|
||||
type Module = super::RemoteModule;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
|
||||
// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.
|
||||
|
||||
#![allow(unused, clippy::all)]
|
||||
use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws};
|
||||
|
||||
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
|
||||
#[sats(crate = __lib)]
|
||||
pub struct WebProjectRuntimeJobCreateInput {
|
||||
pub job_id: String,
|
||||
pub project_id: String,
|
||||
pub snapshot_id: String,
|
||||
pub owner_user_id: String,
|
||||
pub job_kind: String,
|
||||
pub preview_build_id: Option<String>,
|
||||
pub now_micros: i64,
|
||||
}
|
||||
|
||||
impl __sdk::InModule for WebProjectRuntimeJobCreateInput {
|
||||
type Module = super::RemoteModule;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
|
||||
// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.
|
||||
|
||||
#![allow(unused, clippy::all)]
|
||||
use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws};
|
||||
|
||||
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
|
||||
#[sats(crate = __lib)]
|
||||
pub struct WebProjectRuntimeJobExpireInput {
|
||||
pub job_id: String,
|
||||
pub owner_user_id: String,
|
||||
pub expired_at_micros: i64,
|
||||
}
|
||||
|
||||
impl __sdk::InModule for WebProjectRuntimeJobExpireInput {
|
||||
type Module = super::RemoteModule;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
|
||||
// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.
|
||||
|
||||
#![allow(unused, clippy::all)]
|
||||
use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws};
|
||||
|
||||
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
|
||||
#[sats(crate = __lib)]
|
||||
pub struct WebProjectRuntimeJobFailInput {
|
||||
pub job_id: String,
|
||||
pub worker_id: String,
|
||||
pub lease_token: String,
|
||||
pub error_summary: String,
|
||||
pub failed_at_micros: i64,
|
||||
}
|
||||
|
||||
impl __sdk::InModule for WebProjectRuntimeJobFailInput {
|
||||
type Module = super::RemoteModule;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
|
||||
// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.
|
||||
|
||||
#![allow(unused, clippy::all)]
|
||||
use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws};
|
||||
|
||||
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
|
||||
#[sats(crate = __lib)]
|
||||
pub struct WebProjectRuntimeJobGetInput {
|
||||
pub job_id: String,
|
||||
pub owner_user_id: String,
|
||||
}
|
||||
|
||||
impl __sdk::InModule for WebProjectRuntimeJobGetInput {
|
||||
type Module = super::RemoteModule;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
|
||||
// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.
|
||||
|
||||
#![allow(unused, clippy::all)]
|
||||
use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws};
|
||||
|
||||
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
|
||||
#[sats(crate = __lib)]
|
||||
pub struct WebProjectRuntimeJobListLogsInput {
|
||||
pub job_id: String,
|
||||
pub owner_user_id: String,
|
||||
pub after_sequence: Option<u64>,
|
||||
pub limit: u32,
|
||||
}
|
||||
|
||||
impl __sdk::InModule for WebProjectRuntimeJobListLogsInput {
|
||||
type Module = super::RemoteModule;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
|
||||
// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.
|
||||
|
||||
#![allow(unused, clippy::all)]
|
||||
use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws};
|
||||
|
||||
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
|
||||
#[sats(crate = __lib)]
|
||||
pub struct WebProjectRuntimeJobListOpenInput {
|
||||
pub project_id: String,
|
||||
pub owner_user_id: String,
|
||||
pub limit: u32,
|
||||
}
|
||||
|
||||
impl __sdk::InModule for WebProjectRuntimeJobListOpenInput {
|
||||
type Module = super::RemoteModule;
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
|
||||
// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.
|
||||
|
||||
#![allow(unused, clippy::all)]
|
||||
use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws};
|
||||
|
||||
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
|
||||
#[sats(crate = __lib)]
|
||||
pub struct WebProjectRuntimeJobLogRow {
|
||||
pub log_id: String,
|
||||
pub job_id: String,
|
||||
pub project_id: String,
|
||||
pub owner_user_id: String,
|
||||
pub sequence: u64,
|
||||
pub level: String,
|
||||
pub message: String,
|
||||
pub created_at: __sdk::Timestamp,
|
||||
}
|
||||
|
||||
impl __sdk::InModule for WebProjectRuntimeJobLogRow {
|
||||
type Module = super::RemoteModule;
|
||||
}
|
||||
|
||||
/// Column accessor struct for the table `WebProjectRuntimeJobLogRow`.
|
||||
///
|
||||
/// Provides typed access to columns for query building.
|
||||
pub struct WebProjectRuntimeJobLogRowCols {
|
||||
pub log_id: __sdk::__query_builder::Col<WebProjectRuntimeJobLogRow, String>,
|
||||
pub job_id: __sdk::__query_builder::Col<WebProjectRuntimeJobLogRow, String>,
|
||||
pub project_id: __sdk::__query_builder::Col<WebProjectRuntimeJobLogRow, String>,
|
||||
pub owner_user_id: __sdk::__query_builder::Col<WebProjectRuntimeJobLogRow, String>,
|
||||
pub sequence: __sdk::__query_builder::Col<WebProjectRuntimeJobLogRow, u64>,
|
||||
pub level: __sdk::__query_builder::Col<WebProjectRuntimeJobLogRow, String>,
|
||||
pub message: __sdk::__query_builder::Col<WebProjectRuntimeJobLogRow, String>,
|
||||
pub created_at: __sdk::__query_builder::Col<WebProjectRuntimeJobLogRow, __sdk::Timestamp>,
|
||||
}
|
||||
|
||||
impl __sdk::__query_builder::HasCols for WebProjectRuntimeJobLogRow {
|
||||
type Cols = WebProjectRuntimeJobLogRowCols;
|
||||
fn cols(table_name: &'static str) -> Self::Cols {
|
||||
WebProjectRuntimeJobLogRowCols {
|
||||
log_id: __sdk::__query_builder::Col::new(table_name, "log_id"),
|
||||
job_id: __sdk::__query_builder::Col::new(table_name, "job_id"),
|
||||
project_id: __sdk::__query_builder::Col::new(table_name, "project_id"),
|
||||
owner_user_id: __sdk::__query_builder::Col::new(table_name, "owner_user_id"),
|
||||
sequence: __sdk::__query_builder::Col::new(table_name, "sequence"),
|
||||
level: __sdk::__query_builder::Col::new(table_name, "level"),
|
||||
message: __sdk::__query_builder::Col::new(table_name, "message"),
|
||||
created_at: __sdk::__query_builder::Col::new(table_name, "created_at"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Indexed column accessor struct for the table `WebProjectRuntimeJobLogRow`.
|
||||
///
|
||||
/// Provides typed access to indexed columns for query building.
|
||||
pub struct WebProjectRuntimeJobLogRowIxCols {
|
||||
pub job_id: __sdk::__query_builder::IxCol<WebProjectRuntimeJobLogRow, String>,
|
||||
pub log_id: __sdk::__query_builder::IxCol<WebProjectRuntimeJobLogRow, String>,
|
||||
pub owner_user_id: __sdk::__query_builder::IxCol<WebProjectRuntimeJobLogRow, String>,
|
||||
pub project_id: __sdk::__query_builder::IxCol<WebProjectRuntimeJobLogRow, String>,
|
||||
}
|
||||
|
||||
impl __sdk::__query_builder::HasIxCols for WebProjectRuntimeJobLogRow {
|
||||
type IxCols = WebProjectRuntimeJobLogRowIxCols;
|
||||
fn ix_cols(table_name: &'static str) -> Self::IxCols {
|
||||
WebProjectRuntimeJobLogRowIxCols {
|
||||
job_id: __sdk::__query_builder::IxCol::new(table_name, "job_id"),
|
||||
log_id: __sdk::__query_builder::IxCol::new(table_name, "log_id"),
|
||||
owner_user_id: __sdk::__query_builder::IxCol::new(table_name, "owner_user_id"),
|
||||
project_id: __sdk::__query_builder::IxCol::new(table_name, "project_id"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl __sdk::__query_builder::CanBeLookupTable for WebProjectRuntimeJobLogRow {}
|
||||
@@ -0,0 +1,22 @@
|
||||
// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
|
||||
// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.
|
||||
|
||||
#![allow(unused, clippy::all)]
|
||||
use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws};
|
||||
|
||||
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
|
||||
#[sats(crate = __lib)]
|
||||
pub struct WebProjectRuntimeJobLogSnapshot {
|
||||
pub log_id: String,
|
||||
pub job_id: String,
|
||||
pub project_id: String,
|
||||
pub owner_user_id: String,
|
||||
pub sequence: u64,
|
||||
pub level: String,
|
||||
pub message: String,
|
||||
pub created_at_micros: i64,
|
||||
}
|
||||
|
||||
impl __sdk::InModule for WebProjectRuntimeJobLogSnapshot {
|
||||
type Module = super::RemoteModule;
|
||||
}
|
||||
@@ -0,0 +1,166 @@
|
||||
// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
|
||||
// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.
|
||||
|
||||
#![allow(unused, clippy::all)]
|
||||
use super::web_project_runtime_job_log_row_type::WebProjectRuntimeJobLogRow;
|
||||
use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws};
|
||||
|
||||
/// Table handle for the table `web_project_runtime_job_log`.
|
||||
///
|
||||
/// Obtain a handle from the [`WebProjectRuntimeJobLogTableAccess::web_project_runtime_job_log`] method on [`super::RemoteTables`],
|
||||
/// like `ctx.db.web_project_runtime_job_log()`.
|
||||
///
|
||||
/// Users are encouraged not to explicitly reference this type,
|
||||
/// but to directly chain method calls,
|
||||
/// like `ctx.db.web_project_runtime_job_log().on_insert(...)`.
|
||||
pub struct WebProjectRuntimeJobLogTableHandle<'ctx> {
|
||||
imp: __sdk::TableHandle<WebProjectRuntimeJobLogRow>,
|
||||
ctx: std::marker::PhantomData<&'ctx super::RemoteTables>,
|
||||
}
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
/// Extension trait for access to the table `web_project_runtime_job_log`.
|
||||
///
|
||||
/// Implemented for [`super::RemoteTables`].
|
||||
pub trait WebProjectRuntimeJobLogTableAccess {
|
||||
#[allow(non_snake_case)]
|
||||
/// Obtain a [`WebProjectRuntimeJobLogTableHandle`], which mediates access to the table `web_project_runtime_job_log`.
|
||||
fn web_project_runtime_job_log(&self) -> WebProjectRuntimeJobLogTableHandle<'_>;
|
||||
}
|
||||
|
||||
impl WebProjectRuntimeJobLogTableAccess for super::RemoteTables {
|
||||
fn web_project_runtime_job_log(&self) -> WebProjectRuntimeJobLogTableHandle<'_> {
|
||||
WebProjectRuntimeJobLogTableHandle {
|
||||
imp: self
|
||||
.imp
|
||||
.get_table::<WebProjectRuntimeJobLogRow>("web_project_runtime_job_log"),
|
||||
ctx: std::marker::PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct WebProjectRuntimeJobLogInsertCallbackId(__sdk::CallbackId);
|
||||
pub struct WebProjectRuntimeJobLogDeleteCallbackId(__sdk::CallbackId);
|
||||
|
||||
impl<'ctx> __sdk::Table for WebProjectRuntimeJobLogTableHandle<'ctx> {
|
||||
type Row = WebProjectRuntimeJobLogRow;
|
||||
type EventContext = super::EventContext;
|
||||
|
||||
fn count(&self) -> u64 {
|
||||
self.imp.count()
|
||||
}
|
||||
fn iter(&self) -> impl Iterator<Item = WebProjectRuntimeJobLogRow> + '_ {
|
||||
self.imp.iter()
|
||||
}
|
||||
|
||||
type InsertCallbackId = WebProjectRuntimeJobLogInsertCallbackId;
|
||||
|
||||
fn on_insert(
|
||||
&self,
|
||||
callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static,
|
||||
) -> WebProjectRuntimeJobLogInsertCallbackId {
|
||||
WebProjectRuntimeJobLogInsertCallbackId(self.imp.on_insert(Box::new(callback)))
|
||||
}
|
||||
|
||||
fn remove_on_insert(&self, callback: WebProjectRuntimeJobLogInsertCallbackId) {
|
||||
self.imp.remove_on_insert(callback.0)
|
||||
}
|
||||
|
||||
type DeleteCallbackId = WebProjectRuntimeJobLogDeleteCallbackId;
|
||||
|
||||
fn on_delete(
|
||||
&self,
|
||||
callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static,
|
||||
) -> WebProjectRuntimeJobLogDeleteCallbackId {
|
||||
WebProjectRuntimeJobLogDeleteCallbackId(self.imp.on_delete(Box::new(callback)))
|
||||
}
|
||||
|
||||
fn remove_on_delete(&self, callback: WebProjectRuntimeJobLogDeleteCallbackId) {
|
||||
self.imp.remove_on_delete(callback.0)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct WebProjectRuntimeJobLogUpdateCallbackId(__sdk::CallbackId);
|
||||
|
||||
impl<'ctx> __sdk::TableWithPrimaryKey for WebProjectRuntimeJobLogTableHandle<'ctx> {
|
||||
type UpdateCallbackId = WebProjectRuntimeJobLogUpdateCallbackId;
|
||||
|
||||
fn on_update(
|
||||
&self,
|
||||
callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static,
|
||||
) -> WebProjectRuntimeJobLogUpdateCallbackId {
|
||||
WebProjectRuntimeJobLogUpdateCallbackId(self.imp.on_update(Box::new(callback)))
|
||||
}
|
||||
|
||||
fn remove_on_update(&self, callback: WebProjectRuntimeJobLogUpdateCallbackId) {
|
||||
self.imp.remove_on_update(callback.0)
|
||||
}
|
||||
}
|
||||
|
||||
/// Access to the `log_id` unique index on the table `web_project_runtime_job_log`,
|
||||
/// which allows point queries on the field of the same name
|
||||
/// via the [`WebProjectRuntimeJobLogLogIdUnique::find`] method.
|
||||
///
|
||||
/// Users are encouraged not to explicitly reference this type,
|
||||
/// but to directly chain method calls,
|
||||
/// like `ctx.db.web_project_runtime_job_log().log_id().find(...)`.
|
||||
pub struct WebProjectRuntimeJobLogLogIdUnique<'ctx> {
|
||||
imp: __sdk::UniqueConstraintHandle<WebProjectRuntimeJobLogRow, String>,
|
||||
phantom: std::marker::PhantomData<&'ctx super::RemoteTables>,
|
||||
}
|
||||
|
||||
impl<'ctx> WebProjectRuntimeJobLogTableHandle<'ctx> {
|
||||
/// Get a handle on the `log_id` unique index on the table `web_project_runtime_job_log`.
|
||||
pub fn log_id(&self) -> WebProjectRuntimeJobLogLogIdUnique<'ctx> {
|
||||
WebProjectRuntimeJobLogLogIdUnique {
|
||||
imp: self.imp.get_unique_constraint::<String>("log_id"),
|
||||
phantom: std::marker::PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ctx> WebProjectRuntimeJobLogLogIdUnique<'ctx> {
|
||||
/// Find the subscribed row whose `log_id` column value is equal to `col_val`,
|
||||
/// if such a row is present in the client cache.
|
||||
pub fn find(&self, col_val: &String) -> Option<WebProjectRuntimeJobLogRow> {
|
||||
self.imp.find(col_val)
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub(super) fn register_table(client_cache: &mut __sdk::ClientCache<super::RemoteModule>) {
|
||||
let _table =
|
||||
client_cache.get_or_make_table::<WebProjectRuntimeJobLogRow>("web_project_runtime_job_log");
|
||||
_table.add_unique_constraint::<String>("log_id", |row| &row.log_id);
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub(super) fn parse_table_update(
|
||||
raw_updates: __ws::v2::TableUpdate,
|
||||
) -> __sdk::Result<__sdk::TableUpdate<WebProjectRuntimeJobLogRow>> {
|
||||
__sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| {
|
||||
__sdk::InternalError::failed_parse("TableUpdate<WebProjectRuntimeJobLogRow>", "TableUpdate")
|
||||
.with_cause(e)
|
||||
.into()
|
||||
})
|
||||
}
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
/// Extension trait for query builder access to the table `WebProjectRuntimeJobLogRow`.
|
||||
///
|
||||
/// Implemented for [`__sdk::QueryTableAccessor`].
|
||||
pub trait web_project_runtime_job_logQueryTableAccess {
|
||||
#[allow(non_snake_case)]
|
||||
/// Get a query builder for the table `WebProjectRuntimeJobLogRow`.
|
||||
fn web_project_runtime_job_log(
|
||||
&self,
|
||||
) -> __sdk::__query_builder::Table<WebProjectRuntimeJobLogRow>;
|
||||
}
|
||||
|
||||
impl web_project_runtime_job_logQueryTableAccess for __sdk::QueryTableAccessor {
|
||||
fn web_project_runtime_job_log(
|
||||
&self,
|
||||
) -> __sdk::__query_builder::Table<WebProjectRuntimeJobLogRow> {
|
||||
__sdk::__query_builder::Table::new("web_project_runtime_job_log")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
|
||||
// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.
|
||||
|
||||
#![allow(unused, clippy::all)]
|
||||
use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws};
|
||||
|
||||
use super::web_project_preview_build_snapshot_type::WebProjectPreviewBuildSnapshot;
|
||||
use super::web_project_project_snapshot_type::WebProjectProjectSnapshot;
|
||||
use super::web_project_runtime_job_snapshot_type::WebProjectRuntimeJobSnapshot;
|
||||
|
||||
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
|
||||
#[sats(crate = __lib)]
|
||||
pub struct WebProjectRuntimeJobPreviewBuildProcedureResult {
|
||||
pub ok: bool,
|
||||
pub project: Option<WebProjectProjectSnapshot>,
|
||||
pub build: Option<WebProjectPreviewBuildSnapshot>,
|
||||
pub job: Option<WebProjectRuntimeJobSnapshot>,
|
||||
pub error_message: Option<String>,
|
||||
}
|
||||
|
||||
impl __sdk::InModule for WebProjectRuntimeJobPreviewBuildProcedureResult {
|
||||
type Module = super::RemoteModule;
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
|
||||
// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.
|
||||
|
||||
#![allow(unused, clippy::all)]
|
||||
use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws};
|
||||
|
||||
use super::web_project_runtime_job_log_snapshot_type::WebProjectRuntimeJobLogSnapshot;
|
||||
use super::web_project_runtime_job_snapshot_type::WebProjectRuntimeJobSnapshot;
|
||||
|
||||
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
|
||||
#[sats(crate = __lib)]
|
||||
pub struct WebProjectRuntimeJobProcedureResult {
|
||||
pub ok: bool,
|
||||
pub job: Option<WebProjectRuntimeJobSnapshot>,
|
||||
pub jobs: Vec<WebProjectRuntimeJobSnapshot>,
|
||||
pub log: Option<WebProjectRuntimeJobLogSnapshot>,
|
||||
pub logs: Vec<WebProjectRuntimeJobLogSnapshot>,
|
||||
pub error_message: Option<String>,
|
||||
}
|
||||
|
||||
impl __sdk::InModule for WebProjectRuntimeJobProcedureResult {
|
||||
type Module = super::RemoteModule;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
|
||||
// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.
|
||||
|
||||
#![allow(unused, clippy::all)]
|
||||
use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws};
|
||||
|
||||
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
|
||||
#[sats(crate = __lib)]
|
||||
pub struct WebProjectRuntimeJobRenewLeaseInput {
|
||||
pub job_id: String,
|
||||
pub worker_id: String,
|
||||
pub lease_token: String,
|
||||
pub lease_expires_at_micros: i64,
|
||||
pub renewed_at_micros: i64,
|
||||
}
|
||||
|
||||
impl __sdk::InModule for WebProjectRuntimeJobRenewLeaseInput {
|
||||
type Module = super::RemoteModule;
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
|
||||
// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.
|
||||
|
||||
#![allow(unused, clippy::all)]
|
||||
use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws};
|
||||
|
||||
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
|
||||
#[sats(crate = __lib)]
|
||||
pub struct WebProjectRuntimeJobRow {
|
||||
pub job_id: String,
|
||||
pub project_id: String,
|
||||
pub snapshot_id: String,
|
||||
pub owner_user_id: String,
|
||||
pub job_kind: String,
|
||||
pub status: String,
|
||||
pub attempt: u32,
|
||||
pub worker_id: Option<String>,
|
||||
pub lease_token: Option<String>,
|
||||
pub lease_expires_at: Option<__sdk::Timestamp>,
|
||||
pub cancel_requested_at: Option<__sdk::Timestamp>,
|
||||
pub stale_reason: Option<String>,
|
||||
pub artifact_id: Option<String>,
|
||||
pub preview_build_id: Option<String>,
|
||||
pub error_summary: Option<String>,
|
||||
pub created_at: __sdk::Timestamp,
|
||||
pub started_at: Option<__sdk::Timestamp>,
|
||||
pub finished_at: Option<__sdk::Timestamp>,
|
||||
pub updated_at: __sdk::Timestamp,
|
||||
}
|
||||
|
||||
impl __sdk::InModule for WebProjectRuntimeJobRow {
|
||||
type Module = super::RemoteModule;
|
||||
}
|
||||
|
||||
/// Column accessor struct for the table `WebProjectRuntimeJobRow`.
|
||||
///
|
||||
/// Provides typed access to columns for query building.
|
||||
pub struct WebProjectRuntimeJobRowCols {
|
||||
pub job_id: __sdk::__query_builder::Col<WebProjectRuntimeJobRow, String>,
|
||||
pub project_id: __sdk::__query_builder::Col<WebProjectRuntimeJobRow, String>,
|
||||
pub snapshot_id: __sdk::__query_builder::Col<WebProjectRuntimeJobRow, String>,
|
||||
pub owner_user_id: __sdk::__query_builder::Col<WebProjectRuntimeJobRow, String>,
|
||||
pub job_kind: __sdk::__query_builder::Col<WebProjectRuntimeJobRow, String>,
|
||||
pub status: __sdk::__query_builder::Col<WebProjectRuntimeJobRow, String>,
|
||||
pub attempt: __sdk::__query_builder::Col<WebProjectRuntimeJobRow, u32>,
|
||||
pub worker_id: __sdk::__query_builder::Col<WebProjectRuntimeJobRow, Option<String>>,
|
||||
pub lease_token: __sdk::__query_builder::Col<WebProjectRuntimeJobRow, Option<String>>,
|
||||
pub lease_expires_at:
|
||||
__sdk::__query_builder::Col<WebProjectRuntimeJobRow, Option<__sdk::Timestamp>>,
|
||||
pub cancel_requested_at:
|
||||
__sdk::__query_builder::Col<WebProjectRuntimeJobRow, Option<__sdk::Timestamp>>,
|
||||
pub stale_reason: __sdk::__query_builder::Col<WebProjectRuntimeJobRow, Option<String>>,
|
||||
pub artifact_id: __sdk::__query_builder::Col<WebProjectRuntimeJobRow, Option<String>>,
|
||||
pub preview_build_id: __sdk::__query_builder::Col<WebProjectRuntimeJobRow, Option<String>>,
|
||||
pub error_summary: __sdk::__query_builder::Col<WebProjectRuntimeJobRow, Option<String>>,
|
||||
pub created_at: __sdk::__query_builder::Col<WebProjectRuntimeJobRow, __sdk::Timestamp>,
|
||||
pub started_at: __sdk::__query_builder::Col<WebProjectRuntimeJobRow, Option<__sdk::Timestamp>>,
|
||||
pub finished_at: __sdk::__query_builder::Col<WebProjectRuntimeJobRow, Option<__sdk::Timestamp>>,
|
||||
pub updated_at: __sdk::__query_builder::Col<WebProjectRuntimeJobRow, __sdk::Timestamp>,
|
||||
}
|
||||
|
||||
impl __sdk::__query_builder::HasCols for WebProjectRuntimeJobRow {
|
||||
type Cols = WebProjectRuntimeJobRowCols;
|
||||
fn cols(table_name: &'static str) -> Self::Cols {
|
||||
WebProjectRuntimeJobRowCols {
|
||||
job_id: __sdk::__query_builder::Col::new(table_name, "job_id"),
|
||||
project_id: __sdk::__query_builder::Col::new(table_name, "project_id"),
|
||||
snapshot_id: __sdk::__query_builder::Col::new(table_name, "snapshot_id"),
|
||||
owner_user_id: __sdk::__query_builder::Col::new(table_name, "owner_user_id"),
|
||||
job_kind: __sdk::__query_builder::Col::new(table_name, "job_kind"),
|
||||
status: __sdk::__query_builder::Col::new(table_name, "status"),
|
||||
attempt: __sdk::__query_builder::Col::new(table_name, "attempt"),
|
||||
worker_id: __sdk::__query_builder::Col::new(table_name, "worker_id"),
|
||||
lease_token: __sdk::__query_builder::Col::new(table_name, "lease_token"),
|
||||
lease_expires_at: __sdk::__query_builder::Col::new(table_name, "lease_expires_at"),
|
||||
cancel_requested_at: __sdk::__query_builder::Col::new(
|
||||
table_name,
|
||||
"cancel_requested_at",
|
||||
),
|
||||
stale_reason: __sdk::__query_builder::Col::new(table_name, "stale_reason"),
|
||||
artifact_id: __sdk::__query_builder::Col::new(table_name, "artifact_id"),
|
||||
preview_build_id: __sdk::__query_builder::Col::new(table_name, "preview_build_id"),
|
||||
error_summary: __sdk::__query_builder::Col::new(table_name, "error_summary"),
|
||||
created_at: __sdk::__query_builder::Col::new(table_name, "created_at"),
|
||||
started_at: __sdk::__query_builder::Col::new(table_name, "started_at"),
|
||||
finished_at: __sdk::__query_builder::Col::new(table_name, "finished_at"),
|
||||
updated_at: __sdk::__query_builder::Col::new(table_name, "updated_at"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Indexed column accessor struct for the table `WebProjectRuntimeJobRow`.
|
||||
///
|
||||
/// Provides typed access to indexed columns for query building.
|
||||
pub struct WebProjectRuntimeJobRowIxCols {
|
||||
pub job_id: __sdk::__query_builder::IxCol<WebProjectRuntimeJobRow, String>,
|
||||
pub owner_user_id: __sdk::__query_builder::IxCol<WebProjectRuntimeJobRow, String>,
|
||||
pub project_id: __sdk::__query_builder::IxCol<WebProjectRuntimeJobRow, String>,
|
||||
pub snapshot_id: __sdk::__query_builder::IxCol<WebProjectRuntimeJobRow, String>,
|
||||
pub status: __sdk::__query_builder::IxCol<WebProjectRuntimeJobRow, String>,
|
||||
}
|
||||
|
||||
impl __sdk::__query_builder::HasIxCols for WebProjectRuntimeJobRow {
|
||||
type IxCols = WebProjectRuntimeJobRowIxCols;
|
||||
fn ix_cols(table_name: &'static str) -> Self::IxCols {
|
||||
WebProjectRuntimeJobRowIxCols {
|
||||
job_id: __sdk::__query_builder::IxCol::new(table_name, "job_id"),
|
||||
owner_user_id: __sdk::__query_builder::IxCol::new(table_name, "owner_user_id"),
|
||||
project_id: __sdk::__query_builder::IxCol::new(table_name, "project_id"),
|
||||
snapshot_id: __sdk::__query_builder::IxCol::new(table_name, "snapshot_id"),
|
||||
status: __sdk::__query_builder::IxCol::new(table_name, "status"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl __sdk::__query_builder::CanBeLookupTable for WebProjectRuntimeJobRow {}
|
||||
@@ -0,0 +1,33 @@
|
||||
// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
|
||||
// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.
|
||||
|
||||
#![allow(unused, clippy::all)]
|
||||
use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws};
|
||||
|
||||
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
|
||||
#[sats(crate = __lib)]
|
||||
pub struct WebProjectRuntimeJobSnapshot {
|
||||
pub job_id: String,
|
||||
pub project_id: String,
|
||||
pub snapshot_id: String,
|
||||
pub owner_user_id: String,
|
||||
pub job_kind: String,
|
||||
pub status: String,
|
||||
pub attempt: u32,
|
||||
pub worker_id: Option<String>,
|
||||
pub lease_token: Option<String>,
|
||||
pub lease_expires_at_micros: Option<i64>,
|
||||
pub cancel_requested_at_micros: Option<i64>,
|
||||
pub stale_reason: Option<String>,
|
||||
pub artifact_id: Option<String>,
|
||||
pub preview_build_id: Option<String>,
|
||||
pub error_summary: Option<String>,
|
||||
pub created_at_micros: i64,
|
||||
pub started_at_micros: Option<i64>,
|
||||
pub finished_at_micros: Option<i64>,
|
||||
pub updated_at_micros: i64,
|
||||
}
|
||||
|
||||
impl __sdk::InModule for WebProjectRuntimeJobSnapshot {
|
||||
type Module = super::RemoteModule;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
|
||||
// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.
|
||||
|
||||
#![allow(unused, clippy::all)]
|
||||
use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws};
|
||||
|
||||
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
|
||||
#[sats(crate = __lib)]
|
||||
pub struct WebProjectRuntimeJobStaleInput {
|
||||
pub job_id: String,
|
||||
pub owner_user_id: String,
|
||||
pub stale_reason: String,
|
||||
pub stale_at_micros: i64,
|
||||
}
|
||||
|
||||
impl __sdk::InModule for WebProjectRuntimeJobStaleInput {
|
||||
type Module = super::RemoteModule;
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
|
||||
// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.
|
||||
|
||||
#![allow(unused, clippy::all)]
|
||||
use super::web_project_runtime_job_row_type::WebProjectRuntimeJobRow;
|
||||
use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws};
|
||||
|
||||
/// Table handle for the table `web_project_runtime_job`.
|
||||
///
|
||||
/// Obtain a handle from the [`WebProjectRuntimeJobTableAccess::web_project_runtime_job`] method on [`super::RemoteTables`],
|
||||
/// like `ctx.db.web_project_runtime_job()`.
|
||||
///
|
||||
/// Users are encouraged not to explicitly reference this type,
|
||||
/// but to directly chain method calls,
|
||||
/// like `ctx.db.web_project_runtime_job().on_insert(...)`.
|
||||
pub struct WebProjectRuntimeJobTableHandle<'ctx> {
|
||||
imp: __sdk::TableHandle<WebProjectRuntimeJobRow>,
|
||||
ctx: std::marker::PhantomData<&'ctx super::RemoteTables>,
|
||||
}
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
/// Extension trait for access to the table `web_project_runtime_job`.
|
||||
///
|
||||
/// Implemented for [`super::RemoteTables`].
|
||||
pub trait WebProjectRuntimeJobTableAccess {
|
||||
#[allow(non_snake_case)]
|
||||
/// Obtain a [`WebProjectRuntimeJobTableHandle`], which mediates access to the table `web_project_runtime_job`.
|
||||
fn web_project_runtime_job(&self) -> WebProjectRuntimeJobTableHandle<'_>;
|
||||
}
|
||||
|
||||
impl WebProjectRuntimeJobTableAccess for super::RemoteTables {
|
||||
fn web_project_runtime_job(&self) -> WebProjectRuntimeJobTableHandle<'_> {
|
||||
WebProjectRuntimeJobTableHandle {
|
||||
imp: self
|
||||
.imp
|
||||
.get_table::<WebProjectRuntimeJobRow>("web_project_runtime_job"),
|
||||
ctx: std::marker::PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct WebProjectRuntimeJobInsertCallbackId(__sdk::CallbackId);
|
||||
pub struct WebProjectRuntimeJobDeleteCallbackId(__sdk::CallbackId);
|
||||
|
||||
impl<'ctx> __sdk::Table for WebProjectRuntimeJobTableHandle<'ctx> {
|
||||
type Row = WebProjectRuntimeJobRow;
|
||||
type EventContext = super::EventContext;
|
||||
|
||||
fn count(&self) -> u64 {
|
||||
self.imp.count()
|
||||
}
|
||||
fn iter(&self) -> impl Iterator<Item = WebProjectRuntimeJobRow> + '_ {
|
||||
self.imp.iter()
|
||||
}
|
||||
|
||||
type InsertCallbackId = WebProjectRuntimeJobInsertCallbackId;
|
||||
|
||||
fn on_insert(
|
||||
&self,
|
||||
callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static,
|
||||
) -> WebProjectRuntimeJobInsertCallbackId {
|
||||
WebProjectRuntimeJobInsertCallbackId(self.imp.on_insert(Box::new(callback)))
|
||||
}
|
||||
|
||||
fn remove_on_insert(&self, callback: WebProjectRuntimeJobInsertCallbackId) {
|
||||
self.imp.remove_on_insert(callback.0)
|
||||
}
|
||||
|
||||
type DeleteCallbackId = WebProjectRuntimeJobDeleteCallbackId;
|
||||
|
||||
fn on_delete(
|
||||
&self,
|
||||
callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static,
|
||||
) -> WebProjectRuntimeJobDeleteCallbackId {
|
||||
WebProjectRuntimeJobDeleteCallbackId(self.imp.on_delete(Box::new(callback)))
|
||||
}
|
||||
|
||||
fn remove_on_delete(&self, callback: WebProjectRuntimeJobDeleteCallbackId) {
|
||||
self.imp.remove_on_delete(callback.0)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct WebProjectRuntimeJobUpdateCallbackId(__sdk::CallbackId);
|
||||
|
||||
impl<'ctx> __sdk::TableWithPrimaryKey for WebProjectRuntimeJobTableHandle<'ctx> {
|
||||
type UpdateCallbackId = WebProjectRuntimeJobUpdateCallbackId;
|
||||
|
||||
fn on_update(
|
||||
&self,
|
||||
callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static,
|
||||
) -> WebProjectRuntimeJobUpdateCallbackId {
|
||||
WebProjectRuntimeJobUpdateCallbackId(self.imp.on_update(Box::new(callback)))
|
||||
}
|
||||
|
||||
fn remove_on_update(&self, callback: WebProjectRuntimeJobUpdateCallbackId) {
|
||||
self.imp.remove_on_update(callback.0)
|
||||
}
|
||||
}
|
||||
|
||||
/// Access to the `job_id` unique index on the table `web_project_runtime_job`,
|
||||
/// which allows point queries on the field of the same name
|
||||
/// via the [`WebProjectRuntimeJobJobIdUnique::find`] method.
|
||||
///
|
||||
/// Users are encouraged not to explicitly reference this type,
|
||||
/// but to directly chain method calls,
|
||||
/// like `ctx.db.web_project_runtime_job().job_id().find(...)`.
|
||||
pub struct WebProjectRuntimeJobJobIdUnique<'ctx> {
|
||||
imp: __sdk::UniqueConstraintHandle<WebProjectRuntimeJobRow, String>,
|
||||
phantom: std::marker::PhantomData<&'ctx super::RemoteTables>,
|
||||
}
|
||||
|
||||
impl<'ctx> WebProjectRuntimeJobTableHandle<'ctx> {
|
||||
/// Get a handle on the `job_id` unique index on the table `web_project_runtime_job`.
|
||||
pub fn job_id(&self) -> WebProjectRuntimeJobJobIdUnique<'ctx> {
|
||||
WebProjectRuntimeJobJobIdUnique {
|
||||
imp: self.imp.get_unique_constraint::<String>("job_id"),
|
||||
phantom: std::marker::PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ctx> WebProjectRuntimeJobJobIdUnique<'ctx> {
|
||||
/// Find the subscribed row whose `job_id` column value is equal to `col_val`,
|
||||
/// if such a row is present in the client cache.
|
||||
pub fn find(&self, col_val: &String) -> Option<WebProjectRuntimeJobRow> {
|
||||
self.imp.find(col_val)
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub(super) fn register_table(client_cache: &mut __sdk::ClientCache<super::RemoteModule>) {
|
||||
let _table =
|
||||
client_cache.get_or_make_table::<WebProjectRuntimeJobRow>("web_project_runtime_job");
|
||||
_table.add_unique_constraint::<String>("job_id", |row| &row.job_id);
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub(super) fn parse_table_update(
|
||||
raw_updates: __ws::v2::TableUpdate,
|
||||
) -> __sdk::Result<__sdk::TableUpdate<WebProjectRuntimeJobRow>> {
|
||||
__sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| {
|
||||
__sdk::InternalError::failed_parse("TableUpdate<WebProjectRuntimeJobRow>", "TableUpdate")
|
||||
.with_cause(e)
|
||||
.into()
|
||||
})
|
||||
}
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
/// Extension trait for query builder access to the table `WebProjectRuntimeJobRow`.
|
||||
///
|
||||
/// Implemented for [`__sdk::QueryTableAccessor`].
|
||||
pub trait web_project_runtime_jobQueryTableAccess {
|
||||
#[allow(non_snake_case)]
|
||||
/// Get a query builder for the table `WebProjectRuntimeJobRow`.
|
||||
fn web_project_runtime_job(&self) -> __sdk::__query_builder::Table<WebProjectRuntimeJobRow>;
|
||||
}
|
||||
|
||||
impl web_project_runtime_jobQueryTableAccess for __sdk::QueryTableAccessor {
|
||||
fn web_project_runtime_job(&self) -> __sdk::__query_builder::Table<WebProjectRuntimeJobRow> {
|
||||
__sdk::__query_builder::Table::new("web_project_runtime_job")
|
||||
}
|
||||
}
|
||||
@@ -190,4 +190,331 @@ impl SpacetimeClient {
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn create_web_project_runtime_job(
|
||||
&self,
|
||||
input: WebProjectRuntimeJobCreateRecordInput,
|
||||
) -> Result<WebProjectRuntimeJobRecord, SpacetimeClientError> {
|
||||
let procedure_input = input.into();
|
||||
|
||||
self.call_after_connect(
|
||||
"create_web_project_runtime_job_and_return",
|
||||
move |connection, sender| {
|
||||
connection
|
||||
.procedures()
|
||||
.create_web_project_runtime_job_and_return_then(
|
||||
procedure_input,
|
||||
move |_, result| {
|
||||
let mapped = result
|
||||
.map_err(SpacetimeClientError::from_sdk_error)
|
||||
.and_then(map_web_project_runtime_job_procedure_result);
|
||||
send_once(&sender, mapped);
|
||||
},
|
||||
);
|
||||
},
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn get_web_project_runtime_job(
|
||||
&self,
|
||||
input: WebProjectRuntimeJobGetRecordInput,
|
||||
) -> Result<WebProjectRuntimeJobRecord, SpacetimeClientError> {
|
||||
let procedure_input = input.into();
|
||||
|
||||
self.call_after_connect(
|
||||
"get_web_project_runtime_job_and_return",
|
||||
move |connection, sender| {
|
||||
connection
|
||||
.procedures()
|
||||
.get_web_project_runtime_job_and_return_then(
|
||||
procedure_input,
|
||||
move |_, result| {
|
||||
let mapped = result
|
||||
.map_err(SpacetimeClientError::from_sdk_error)
|
||||
.and_then(map_web_project_runtime_job_procedure_result);
|
||||
send_once(&sender, mapped);
|
||||
},
|
||||
);
|
||||
},
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn list_open_web_project_runtime_jobs(
|
||||
&self,
|
||||
input: WebProjectRuntimeJobListOpenRecordInput,
|
||||
) -> Result<Vec<WebProjectRuntimeJobRecord>, SpacetimeClientError> {
|
||||
let procedure_input = input.into();
|
||||
|
||||
self.call_after_connect(
|
||||
"list_open_web_project_runtime_jobs_and_return",
|
||||
move |connection, sender| {
|
||||
connection
|
||||
.procedures()
|
||||
.list_open_web_project_runtime_jobs_and_return_then(
|
||||
procedure_input,
|
||||
move |_, result| {
|
||||
let mapped = result
|
||||
.map_err(SpacetimeClientError::from_sdk_error)
|
||||
.and_then(map_web_project_runtime_job_list_result);
|
||||
send_once(&sender, mapped);
|
||||
},
|
||||
);
|
||||
},
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn claim_web_project_runtime_jobs(
|
||||
&self,
|
||||
input: WebProjectRuntimeJobClaimRecordInput,
|
||||
) -> Result<Vec<WebProjectRuntimeJobRecord>, SpacetimeClientError> {
|
||||
let procedure_input = input.into();
|
||||
|
||||
self.call_after_connect(
|
||||
"claim_web_project_runtime_jobs_and_return",
|
||||
move |connection, sender| {
|
||||
connection
|
||||
.procedures()
|
||||
.claim_web_project_runtime_jobs_and_return_then(
|
||||
procedure_input,
|
||||
move |_, result| {
|
||||
let mapped = result
|
||||
.map_err(SpacetimeClientError::from_sdk_error)
|
||||
.and_then(map_web_project_runtime_job_list_result);
|
||||
send_once(&sender, mapped);
|
||||
},
|
||||
);
|
||||
},
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn renew_web_project_runtime_job_lease(
|
||||
&self,
|
||||
input: WebProjectRuntimeJobRenewLeaseRecordInput,
|
||||
) -> Result<WebProjectRuntimeJobRecord, SpacetimeClientError> {
|
||||
let procedure_input = input.into();
|
||||
|
||||
self.call_after_connect(
|
||||
"renew_web_project_runtime_job_lease_and_return",
|
||||
move |connection, sender| {
|
||||
connection
|
||||
.procedures()
|
||||
.renew_web_project_runtime_job_lease_and_return_then(
|
||||
procedure_input,
|
||||
move |_, result| {
|
||||
let mapped = result
|
||||
.map_err(SpacetimeClientError::from_sdk_error)
|
||||
.and_then(map_web_project_runtime_job_procedure_result);
|
||||
send_once(&sender, mapped);
|
||||
},
|
||||
);
|
||||
},
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn complete_web_project_runtime_job(
|
||||
&self,
|
||||
input: WebProjectRuntimeJobCompleteRecordInput,
|
||||
) -> Result<WebProjectRuntimeJobRecord, SpacetimeClientError> {
|
||||
let procedure_input = input.into();
|
||||
|
||||
self.call_after_connect(
|
||||
"complete_web_project_runtime_job_and_return",
|
||||
move |connection, sender| {
|
||||
connection
|
||||
.procedures()
|
||||
.complete_web_project_runtime_job_and_return_then(
|
||||
procedure_input,
|
||||
move |_, result| {
|
||||
let mapped = result
|
||||
.map_err(SpacetimeClientError::from_sdk_error)
|
||||
.and_then(map_web_project_runtime_job_procedure_result);
|
||||
send_once(&sender, mapped);
|
||||
},
|
||||
);
|
||||
},
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn complete_web_project_preview_build_runtime_job(
|
||||
&self,
|
||||
input: WebProjectRuntimeJobCompletePreviewBuildRecordInput,
|
||||
) -> Result<WebProjectRuntimeJobPreviewBuildMutationRecord, SpacetimeClientError> {
|
||||
let procedure_input = input.into();
|
||||
|
||||
self.call_after_connect(
|
||||
"complete_web_project_preview_build_runtime_job_and_return",
|
||||
move |connection, sender| {
|
||||
connection
|
||||
.procedures()
|
||||
.complete_web_project_preview_build_runtime_job_and_return_then(
|
||||
procedure_input,
|
||||
move |_, result| {
|
||||
let mapped = result
|
||||
.map_err(SpacetimeClientError::from_sdk_error)
|
||||
.and_then(
|
||||
map_web_project_runtime_job_preview_build_procedure_result,
|
||||
);
|
||||
send_once(&sender, mapped);
|
||||
},
|
||||
);
|
||||
},
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn fail_web_project_runtime_job(
|
||||
&self,
|
||||
input: WebProjectRuntimeJobFailRecordInput,
|
||||
) -> Result<WebProjectRuntimeJobRecord, SpacetimeClientError> {
|
||||
let procedure_input = input.into();
|
||||
|
||||
self.call_after_connect(
|
||||
"fail_web_project_runtime_job_and_return",
|
||||
move |connection, sender| {
|
||||
connection
|
||||
.procedures()
|
||||
.fail_web_project_runtime_job_and_return_then(
|
||||
procedure_input,
|
||||
move |_, result| {
|
||||
let mapped = result
|
||||
.map_err(SpacetimeClientError::from_sdk_error)
|
||||
.and_then(map_web_project_runtime_job_procedure_result);
|
||||
send_once(&sender, mapped);
|
||||
},
|
||||
);
|
||||
},
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn cancel_web_project_runtime_job(
|
||||
&self,
|
||||
input: WebProjectRuntimeJobCancelRecordInput,
|
||||
) -> Result<WebProjectRuntimeJobRecord, SpacetimeClientError> {
|
||||
let procedure_input = input.into();
|
||||
|
||||
self.call_after_connect(
|
||||
"cancel_web_project_runtime_job_and_return",
|
||||
move |connection, sender| {
|
||||
connection
|
||||
.procedures()
|
||||
.cancel_web_project_runtime_job_and_return_then(
|
||||
procedure_input,
|
||||
move |_, result| {
|
||||
let mapped = result
|
||||
.map_err(SpacetimeClientError::from_sdk_error)
|
||||
.and_then(map_web_project_runtime_job_procedure_result);
|
||||
send_once(&sender, mapped);
|
||||
},
|
||||
);
|
||||
},
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn mark_web_project_runtime_job_stale(
|
||||
&self,
|
||||
input: WebProjectRuntimeJobStaleRecordInput,
|
||||
) -> Result<WebProjectRuntimeJobRecord, SpacetimeClientError> {
|
||||
let procedure_input = input.into();
|
||||
|
||||
self.call_after_connect(
|
||||
"mark_web_project_runtime_job_stale_and_return",
|
||||
move |connection, sender| {
|
||||
connection
|
||||
.procedures()
|
||||
.mark_web_project_runtime_job_stale_and_return_then(
|
||||
procedure_input,
|
||||
move |_, result| {
|
||||
let mapped = result
|
||||
.map_err(SpacetimeClientError::from_sdk_error)
|
||||
.and_then(map_web_project_runtime_job_procedure_result);
|
||||
send_once(&sender, mapped);
|
||||
},
|
||||
);
|
||||
},
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn expire_web_project_runtime_job(
|
||||
&self,
|
||||
input: WebProjectRuntimeJobExpireRecordInput,
|
||||
) -> Result<WebProjectRuntimeJobRecord, SpacetimeClientError> {
|
||||
let procedure_input = input.into();
|
||||
|
||||
self.call_after_connect(
|
||||
"expire_web_project_runtime_job_and_return",
|
||||
move |connection, sender| {
|
||||
connection
|
||||
.procedures()
|
||||
.expire_web_project_runtime_job_and_return_then(
|
||||
procedure_input,
|
||||
move |_, result| {
|
||||
let mapped = result
|
||||
.map_err(SpacetimeClientError::from_sdk_error)
|
||||
.and_then(map_web_project_runtime_job_procedure_result);
|
||||
send_once(&sender, mapped);
|
||||
},
|
||||
);
|
||||
},
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn append_web_project_runtime_job_log(
|
||||
&self,
|
||||
input: WebProjectRuntimeJobAppendLogRecordInput,
|
||||
) -> Result<WebProjectRuntimeJobLogRecord, SpacetimeClientError> {
|
||||
let procedure_input = input.into();
|
||||
|
||||
self.call_after_connect(
|
||||
"append_web_project_runtime_job_log_and_return",
|
||||
move |connection, sender| {
|
||||
connection
|
||||
.procedures()
|
||||
.append_web_project_runtime_job_log_and_return_then(
|
||||
procedure_input,
|
||||
move |_, result| {
|
||||
let mapped = result
|
||||
.map_err(SpacetimeClientError::from_sdk_error)
|
||||
.and_then(map_web_project_runtime_job_log_procedure_result);
|
||||
send_once(&sender, mapped);
|
||||
},
|
||||
);
|
||||
},
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn list_web_project_runtime_job_logs(
|
||||
&self,
|
||||
input: WebProjectRuntimeJobListLogsRecordInput,
|
||||
) -> Result<Vec<WebProjectRuntimeJobLogRecord>, SpacetimeClientError> {
|
||||
let procedure_input = input.into();
|
||||
|
||||
self.call_after_connect(
|
||||
"list_web_project_runtime_job_logs_and_return",
|
||||
move |connection, sender| {
|
||||
connection
|
||||
.procedures()
|
||||
.list_web_project_runtime_job_logs_and_return_then(
|
||||
procedure_input,
|
||||
move |_, result| {
|
||||
let mapped = result
|
||||
.map_err(SpacetimeClientError::from_sdk_error)
|
||||
.and_then(map_web_project_runtime_job_log_list_result);
|
||||
send_once(&sender, mapped);
|
||||
},
|
||||
);
|
||||
},
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,12 @@
|
||||
// 少数领域 helper 同名只影响 value namespace 导出,不影响 table / reducer 类型。
|
||||
#![allow(ambiguous_glob_reexports)]
|
||||
|
||||
// 原生 `cargo test` 时,spacetimedb-bindings-sys 的 WASM 宿主符号无法由链接器解析。
|
||||
// 仅在非 WASM 测试编译中引入桩实现,满足链接器需求。
|
||||
// 这些桩函数不会在实际测试中被调用(单元测试只验证纯逻辑,不操作 SpacetimeDB 表)。
|
||||
#[cfg(all(test, not(target_arch = "wasm32")))]
|
||||
mod test_stubs;
|
||||
|
||||
pub use module_ai::*;
|
||||
pub use module_assets::*;
|
||||
pub use module_big_fish::*;
|
||||
|
||||
@@ -31,7 +31,10 @@ use crate::square_hole::tables::{
|
||||
square_hole_agent_message, square_hole_agent_session, square_hole_runtime_run,
|
||||
square_hole_work_profile,
|
||||
};
|
||||
use crate::web_project_storage::{web_project, web_project_preview_build, web_project_snapshot};
|
||||
use crate::web_project_storage::{
|
||||
web_project, web_project_preview_build, web_project_runtime_job, web_project_runtime_job_log,
|
||||
web_project_snapshot,
|
||||
};
|
||||
use crate::wooden_fish::tables::{
|
||||
wooden_fish_agent_session, wooden_fish_event, wooden_fish_runtime_run, wooden_fish_work_profile,
|
||||
};
|
||||
@@ -238,6 +241,8 @@ macro_rules! migration_tables {
|
||||
web_project,
|
||||
web_project_snapshot,
|
||||
web_project_preview_build,
|
||||
web_project_runtime_job,
|
||||
web_project_runtime_job_log,
|
||||
// web_project_service_identity 是环境级服务授权表,不随业务迁移包导入导出。
|
||||
puzzle_agent_session,
|
||||
puzzle_background_compile_task,
|
||||
|
||||
265
server-rs/crates/spacetime-module/src/test_stubs.rs
Normal file
265
server-rs/crates/spacetime-module/src/test_stubs.rs
Normal file
@@ -0,0 +1,265 @@
|
||||
//! 原生(非 WASM)编译时的 SpacetimeDB ABI 桩实现。
|
||||
//!
|
||||
//! ## 背景
|
||||
//! `spacetimedb-bindings-sys` 通过 `#[link(wasm_import_module = "spacetime_10.X")]`
|
||||
//! 声明了所有宿主 ABI 符号。这些符号由 SpacetimeDB WASM 运行时在 WASM 环境中注入。
|
||||
//! 当 `cargo test` 编译原生测试二进制时,没有 WASM 宿主,链接器无法找到这些符号。
|
||||
//!
|
||||
//! ## 作用
|
||||
//! 本模块为全部 25 个 ABI 符号提供 `#[unsafe(no_mangle)] extern "C"` 桩实现,
|
||||
//! 仅满足链接器需求,不会在测试中被实际调用。
|
||||
//! (spacetime-module 的单元测试只测试纯逻辑函数,不访问 SpacetimeDB 表。)
|
||||
//!
|
||||
//! ## 类型说明
|
||||
//! spacetimedb_primitives 中:
|
||||
//! TableId = repr(transparent) struct over u32
|
||||
//! IndexId = repr(transparent) struct over u32
|
||||
//! ColId = repr(transparent) struct over u16
|
||||
//! spacetimedb_bindings_sys::raw 中:
|
||||
//! RowIter = repr(transparent) struct over u32
|
||||
//! BytesSource = repr(transparent) struct over u32
|
||||
//! BytesSink = repr(transparent) struct over u32
|
||||
|
||||
#![allow(unused_variables, non_snake_case)]
|
||||
|
||||
// ── 类型别名,与 spacetimedb ABI 签名对齐 ────────────────────────────────────
|
||||
|
||||
type TableId = u32;
|
||||
type IndexId = u32;
|
||||
/// ColId 在 spacetimedb_primitives 中为 u16
|
||||
type ColId = u16;
|
||||
type RowIter = u32;
|
||||
type BytesSource = u32;
|
||||
type BytesSink = u32;
|
||||
|
||||
// ── 表 / 索引查找 ─────────────────────────────────────────────────────────────
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn table_id_from_name(
|
||||
name_ptr: *const u8,
|
||||
name_len: usize,
|
||||
out: *mut TableId,
|
||||
) -> u16 {
|
||||
panic!("SpacetimeDB WASM ABI 'table_id_from_name' 不可在原生单元测试中调用")
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn index_id_from_name(
|
||||
name_ptr: *const u8,
|
||||
name_len: usize,
|
||||
out: *mut IndexId,
|
||||
) -> u16 {
|
||||
panic!("SpacetimeDB WASM ABI 'index_id_from_name' 不可在原生单元测试中调用")
|
||||
}
|
||||
|
||||
// ── 表行数 ────────────────────────────────────────────────────────────────────
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn datastore_table_row_count(table_id: TableId, out: *mut u64) -> u16 {
|
||||
panic!("SpacetimeDB WASM ABI 'datastore_table_row_count' 不可在原生单元测试中调用")
|
||||
}
|
||||
|
||||
// ── 全表 / 索引扫描 ───────────────────────────────────────────────────────────
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn datastore_table_scan_bsatn(
|
||||
table_id: TableId,
|
||||
out: *mut RowIter,
|
||||
) -> u16 {
|
||||
panic!("SpacetimeDB WASM ABI 'datastore_table_scan_bsatn' 不可在原生单元测试中调用")
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn datastore_index_scan_point_bsatn(
|
||||
index_id: IndexId,
|
||||
point_ptr: *const u8,
|
||||
point_len: usize,
|
||||
out: *mut RowIter,
|
||||
) -> u16 {
|
||||
panic!("SpacetimeDB WASM ABI 'datastore_index_scan_point_bsatn' 不可在原生单元测试中调用")
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn datastore_index_scan_range_bsatn(
|
||||
index_id: IndexId,
|
||||
prefix_ptr: *const u8,
|
||||
prefix_len: usize,
|
||||
prefix_elems: ColId,
|
||||
rstart_ptr: *const u8,
|
||||
rstart_len: usize,
|
||||
rend_ptr: *const u8,
|
||||
rend_len: usize,
|
||||
out: *mut RowIter,
|
||||
) -> u16 {
|
||||
panic!("SpacetimeDB WASM ABI 'datastore_index_scan_range_bsatn' 不可在原生单元测试中调用")
|
||||
}
|
||||
|
||||
// ── 按索引删除 ────────────────────────────────────────────────────────────────
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn datastore_delete_by_index_scan_point_bsatn(
|
||||
index_id: IndexId,
|
||||
point_ptr: *const u8,
|
||||
point_len: usize,
|
||||
out: *mut u32,
|
||||
) -> u16 {
|
||||
panic!(
|
||||
"SpacetimeDB WASM ABI 'datastore_delete_by_index_scan_point_bsatn' 不可在原生单元测试中调用"
|
||||
)
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn datastore_delete_by_index_scan_range_bsatn(
|
||||
index_id: IndexId,
|
||||
prefix_ptr: *const u8,
|
||||
prefix_len: usize,
|
||||
prefix_elems: ColId,
|
||||
rstart_ptr: *const u8,
|
||||
rstart_len: usize,
|
||||
rend_ptr: *const u8,
|
||||
rend_len: usize,
|
||||
out: *mut u32,
|
||||
) -> u16 {
|
||||
panic!(
|
||||
"SpacetimeDB WASM ABI 'datastore_delete_by_index_scan_range_bsatn' 不可在原生单元测试中调用"
|
||||
)
|
||||
}
|
||||
|
||||
// ── 行写入 / 删除 ─────────────────────────────────────────────────────────────
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn datastore_insert_bsatn(
|
||||
table_id: TableId,
|
||||
row_ptr: *mut u8,
|
||||
row_len_ptr: *mut usize,
|
||||
) -> u16 {
|
||||
panic!("SpacetimeDB WASM ABI 'datastore_insert_bsatn' 不可在原生单元测试中调用")
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn datastore_update_bsatn(
|
||||
table_id: TableId,
|
||||
index_id: IndexId,
|
||||
row_ptr: *mut u8,
|
||||
row_len_ptr: *mut usize,
|
||||
) -> u16 {
|
||||
panic!("SpacetimeDB WASM ABI 'datastore_update_bsatn' 不可在原生单元测试中调用")
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn datastore_delete_all_by_eq_bsatn(
|
||||
table_id: TableId,
|
||||
rel_ptr: *const u8,
|
||||
rel_len: usize,
|
||||
out: *mut u32,
|
||||
) -> u16 {
|
||||
panic!("SpacetimeDB WASM ABI 'datastore_delete_all_by_eq_bsatn' 不可在原生单元测试中调用")
|
||||
}
|
||||
|
||||
// ── 行迭代器 ──────────────────────────────────────────────────────────────────
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn row_iter_bsatn_advance(
|
||||
iter: RowIter,
|
||||
buffer_ptr: *mut u8,
|
||||
buffer_len_ptr: *mut usize,
|
||||
) -> i16 {
|
||||
panic!("SpacetimeDB WASM ABI 'row_iter_bsatn_advance' 不可在原生单元测试中调用")
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn row_iter_bsatn_close(iter: RowIter) -> u16 {
|
||||
panic!("SpacetimeDB WASM ABI 'row_iter_bsatn_close' 不可在原生单元测试中调用")
|
||||
}
|
||||
|
||||
// ── 字节流 ────────────────────────────────────────────────────────────────────
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn bytes_sink_write(
|
||||
sink: BytesSink,
|
||||
buffer_ptr: *const u8,
|
||||
buffer_len_ptr: *mut usize,
|
||||
) -> u16 {
|
||||
panic!("SpacetimeDB WASM ABI 'bytes_sink_write' 不可在原生单元测试中调用")
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn bytes_source_remaining_length(
|
||||
source: BytesSource,
|
||||
out: *mut u32,
|
||||
) -> i16 {
|
||||
panic!("SpacetimeDB WASM ABI 'bytes_source_remaining_length' 不可在原生单元测试中调用")
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn bytes_source_read(
|
||||
source: BytesSource,
|
||||
buffer_ptr: *mut u8,
|
||||
buffer_len_ptr: *mut usize,
|
||||
) -> i16 {
|
||||
panic!("SpacetimeDB WASM ABI 'bytes_source_read' 不可在原生单元测试中调用")
|
||||
}
|
||||
|
||||
// ── 日志 ──────────────────────────────────────────────────────────────────────
|
||||
|
||||
/// console_log 在测试中静默丢弃,不 panic——日志初始化可能在 crate 加载时触发。
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn console_log(
|
||||
level: u8,
|
||||
target_ptr: *const u8,
|
||||
target_len: usize,
|
||||
filename_ptr: *const u8,
|
||||
filename_len: usize,
|
||||
line_number: u32,
|
||||
message_ptr: *const u8,
|
||||
message_len: usize,
|
||||
) {
|
||||
// 原生测试中静默丢弃日志消息
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn console_timer_start(name_ptr: *const u8, name_len: usize) -> u32 {
|
||||
panic!("SpacetimeDB WASM ABI 'console_timer_start' 不可在原生单元测试中调用")
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn console_timer_end(timer_id: u32) -> u16 {
|
||||
panic!("SpacetimeDB WASM ABI 'console_timer_end' 不可在原生单元测试中调用")
|
||||
}
|
||||
|
||||
// ── 模块身份 / JWT ────────────────────────────────────────────────────────────
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn identity(out_ptr: *mut u8) {
|
||||
panic!("SpacetimeDB WASM ABI 'identity' 不可在原生单元测试中调用")
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn get_jwt(
|
||||
connection_id_ptr: *const u8,
|
||||
bytes_source_id: *mut BytesSource,
|
||||
) -> u16 {
|
||||
panic!("SpacetimeDB WASM ABI 'get_jwt' 不可在原生单元测试中调用")
|
||||
}
|
||||
|
||||
// ── Procedure(事务 / 睡眠)──────────────────────────────────────────────────
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn procedure_sleep_until(wake_at_micros_since_unix_epoch: i64) -> i64 {
|
||||
panic!("SpacetimeDB WASM ABI 'procedure_sleep_until' 不可在原生单元测试中调用")
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn procedure_start_mut_tx(out: *mut i64) -> u16 {
|
||||
panic!("SpacetimeDB WASM ABI 'procedure_start_mut_tx' 不可在原生单元测试中调用")
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn procedure_commit_mut_tx() -> u16 {
|
||||
panic!("SpacetimeDB WASM ABI 'procedure_commit_mut_tx' 不可在原生单元测试中调用")
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn procedure_abort_mut_tx() -> u16 {
|
||||
panic!("SpacetimeDB WASM ABI 'procedure_abort_mut_tx' 不可在原生单元测试中调用")
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user