Skip to main content

systemprompt_database/repository/service/
model.rs

1//! Data models for the [`super::ServiceRepository`].
2//!
3//! [`ServiceConfig`] is the typed registry row; `ServiceRow` is the raw
4//! decode target of the `services` queries, converted through
5//! `into_config` so a `module_name` or `status` no orchestrator writes surfaces
6//! as `RepositoryError::Decode` instead of a string nobody matches.
7//!
8//! Copyright (c) systemprompt.io — Business Source License 1.1.
9//! See <https://systemprompt.io> for licensing details.
10
11use serde::{Deserialize, Serialize};
12use systemprompt_identifiers::{InstanceId, ServiceName};
13use systemprompt_manifest::services::{ServiceModule, ServiceStatus};
14
15use crate::error::RepositoryError;
16
17#[derive(Debug, Clone, Serialize, Deserialize)]
18pub struct ServiceConfig {
19    pub instance_id: InstanceId,
20    pub name: ServiceName,
21    pub module_name: ServiceModule,
22    pub status: ServiceStatus,
23    pub pid: Option<i32>,
24    pub port: i32,
25    pub binary_mtime: Option<i64>,
26    pub heartbeat_at: String,
27    pub created_at: String,
28    pub updated_at: String,
29}
30
31#[derive(Debug)]
32pub(super) struct ServiceRow {
33    pub instance_id: InstanceId,
34    pub name: String,
35    pub module_name: String,
36    pub status: String,
37    pub pid: Option<i32>,
38    pub port: i32,
39    pub binary_mtime: Option<i64>,
40    pub heartbeat_at: String,
41    pub created_at: String,
42    pub updated_at: String,
43}
44
45impl ServiceRow {
46    pub(super) fn into_config(self) -> Result<ServiceConfig, RepositoryError> {
47        let module_name = self
48            .module_name
49            .parse::<ServiceModule>()
50            .map_err(|source| RepositoryError::Decode {
51                context: "services.module_name".to_owned(),
52                source: Box::new(source),
53            })?;
54        let status =
55            self.status
56                .parse::<ServiceStatus>()
57                .map_err(|source| RepositoryError::Decode {
58                    context: "services.status".to_owned(),
59                    source: Box::new(source),
60                })?;
61        Ok(ServiceConfig {
62            instance_id: self.instance_id,
63            name: ServiceName::new(self.name),
64            module_name,
65            status,
66            pid: self.pid,
67            port: self.port,
68            binary_mtime: self.binary_mtime,
69            heartbeat_at: self.heartbeat_at,
70            created_at: self.created_at,
71            updated_at: self.updated_at,
72        })
73    }
74}
75
76pub(super) fn into_configs(rows: Vec<ServiceRow>) -> Result<Vec<ServiceConfig>, RepositoryError> {
77    rows.into_iter().map(ServiceRow::into_config).collect()
78}
79
80#[derive(Debug)]
81pub struct CreateServiceInput<'a> {
82    pub name: &'a ServiceName,
83    pub module_name: ServiceModule,
84    pub status: ServiceStatus,
85    pub port: u16,
86    pub binary_mtime: Option<i64>,
87}
88
89#[derive(Debug)]
90pub struct UpsertServiceProcessInput<'a> {
91    pub name: &'a ServiceName,
92    pub module_name: ServiceModule,
93    pub pid: i32,
94    pub port: u16,
95    pub status: ServiceStatus,
96}