Skip to content

Commit be4b848

Browse files
committed
feat: add node_status and list_indexed_models methods
1 parent 991d5ac commit be4b848

2 files changed

Lines changed: 223 additions & 0 deletions

File tree

src/api.rs

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,18 @@ pub struct IndexModelData {
175175
pub models: Vec<ModelData>,
176176
}
177177

178+
/// Request to list indexed models
179+
#[derive(Serialize)]
180+
pub struct ListIndexedModelsRequest {}
181+
182+
/// Response list of indexed models
183+
#[derive(Debug, Deserialize)]
184+
#[serde(rename_all = "camelCase")]
185+
pub struct ListIndexedModelsResponse {
186+
/// List of indexed models
187+
pub models: Vec<StreamId>,
188+
}
189+
178190
/// Response from call to admin api /getCode
179191
#[derive(Debug, Deserialize)]
180192
#[serde(rename_all = "camelCase")]
@@ -202,6 +214,13 @@ pub struct AdminApiRequest {
202214
jws: String,
203215
}
204216

217+
impl AdminApiRequest {
218+
/// JWS Compact Serialization string.
219+
pub fn jws(&self) -> &str {
220+
self.jws.as_ref()
221+
}
222+
}
223+
205224
impl TryFrom<Jws> for AdminApiRequest {
206225
type Error = anyhow::Error;
207226
fn try_from(value: Jws) -> Result<Self, Self::Error> {
@@ -333,6 +352,121 @@ pub struct TypedQueryResponse<T> {
333352
#[derive(Serialize)]
334353
pub struct HealthcheckRequest {}
335354

355+
/// Node status request for http api
356+
#[derive(Serialize)]
357+
pub struct NodeStatusRequest {}
358+
359+
/// Node status response for http api
360+
#[derive(Debug, Deserialize)]
361+
#[serde(rename_all = "camelCase")]
362+
pub struct NodeStatusResponse {
363+
/// A random UUID that is generated each time a node starts up.
364+
/// Can be used to detect when a node restarts.
365+
pub run_id: String,
366+
/// How long the node has been running.
367+
pub uptime_ms: i64,
368+
/// The Ceramic network the node is connected to.
369+
pub network: String,
370+
/// Information about the anchoring service.
371+
pub anchor: AnchorStatus,
372+
/// Information about the connected IPFS node.
373+
pub ipfs: IpfsStatus,
374+
/// Information about the ComposeDB operations.
375+
pub compose_db: Option<ComposeDBStatus>,
376+
}
377+
378+
/// Information about the anchoring service.
379+
#[derive(Debug, Deserialize)]
380+
#[serde(rename_all = "camelCase")]
381+
pub struct AnchorStatus {
382+
/// The URL of the Ceramic Anchor Service used to request anchors.
383+
pub anchor_service_url: String,
384+
/// The ethereum rpc endpoint used to validate anchor transactions. If null, likely means
385+
/// the node is using the default, rate-limited ethereum provider.
386+
pub ethereum_rpc_endpoint: Option<String>,
387+
/// The ethereum chainId used for anchors.
388+
pub chain_id: String,
389+
}
390+
391+
/// Information about the connected IPFS node.
392+
#[derive(Debug, Deserialize)]
393+
#[serde(rename_all = "camelCase")]
394+
pub struct IpfsStatus {
395+
/// PeerId of the connected ipfs node
396+
pub peer_id: String,
397+
/// IPFS Swarm multiaddrs of the connected ipfs node
398+
pub addresses: Vec<String>,
399+
}
400+
401+
/// Status about the ComposeDB specific operations of the node.
402+
#[derive(Debug, Deserialize)]
403+
#[serde(rename_all = "camelCase")]
404+
pub struct ComposeDBStatus {
405+
/// The list of models Ids that are being indexed.
406+
pub indexed_models: Vec<String>,
407+
/// The set of active sync operations.
408+
pub syncs: Option<SyncStatus>,
409+
}
410+
411+
/// Status of all sync operations.
412+
#[derive(Debug, Deserialize)]
413+
#[serde(rename_all = "camelCase")]
414+
pub struct SyncStatus {
415+
/// Status of currently active sync operations.
416+
pub active_syncs: Vec<ActiveSyncStatus>,
417+
/// Status of continuously running sync operations.
418+
pub continuous_sync: Vec<ContinuousSyncStatus>,
419+
/// Status of pending sync operations.
420+
pub pending_syncs: Vec<PendingSyncStatus>,
421+
}
422+
423+
/// Status of currently active sync operations.
424+
#[derive(Debug, Deserialize)]
425+
#[serde(rename_all = "camelCase")]
426+
pub struct ActiveSyncStatus {
427+
/// The block the sync starts at
428+
pub start_block: i32,
429+
/// The block the sync is currently processing
430+
pub current_block: i32,
431+
/// The block the sync will end on
432+
pub end_block: i32,
433+
/// Models that are being synced
434+
pub models: Vec<StreamId>,
435+
/// Date when the sync was requested
436+
pub created_at: String,
437+
/// Date when the sync started
438+
pub started_at: String,
439+
}
440+
441+
/// Status of continuously running sync operations.
442+
#[derive(Debug, Deserialize)]
443+
#[serde(rename_all = "camelCase")]
444+
pub struct ContinuousSyncStatus {
445+
/// The first block recevied form the chain on node startup
446+
pub start_block: i32,
447+
/// The latest block received from the chain
448+
pub latest_block: i32,
449+
/// The number of blocks we wait for before we process a block
450+
pub confirmations: i32,
451+
/// The block we are currently processing (should be latestBlock - confirmations)
452+
pub current_block: i32,
453+
/// Models that are being synced
454+
pub models: Vec<StreamId>,
455+
}
456+
/// Status of pending sync operations.
457+
#[derive(Debug, Deserialize)]
458+
#[serde(rename_all = "camelCase")]
459+
pub struct PendingSyncStatus {
460+
/// The block the sync starts at
461+
pub start_block: i32,
462+
/// The block the sync will end on
463+
pub end_block: i32,
464+
/// Models that are being synced
465+
pub models: Vec<StreamId>,
466+
/// Date when the sync was requested
467+
pub created_at: String,
468+
}
469+
336470
#[cfg(test)]
337471
mod tests {
338472
use super::*;

src/lib.rs

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,12 +65,21 @@ impl<S: Signer> CeramicHttpClient<S> {
6565
pub fn index_endpoint(&self) -> &'static str {
6666
"/api/v0/admin/modelData"
6767
}
68+
/// Get the models endpoint
69+
pub fn models_endpoint(&self) -> &'static str {
70+
"/api/v0/admin/models"
71+
}
6872

6973
/// Get the healthcheck endpoint
7074
pub fn healthcheck_endpoint(&self) -> &'static str {
7175
"/api/v0/node/healthcheck"
7276
}
7377

78+
/// Get the status endpoint
79+
pub fn node_status_endpoint(&self) -> &'static str {
80+
"/api/v0/admin/status"
81+
}
82+
7483
/// Create a serde compatible request for model creation
7584
pub async fn create_model_request(
7685
&self,
@@ -118,6 +127,21 @@ impl<S: Signer> CeramicHttpClient<S> {
118127
api::AdminApiRequest::try_from(jws)
119128
}
120129

130+
/// Create a serde compatible request for listing indexed models
131+
pub async fn create_list_indexed_models_request(
132+
&self,
133+
code: &str,
134+
) -> anyhow::Result<api::AdminApiRequest> {
135+
let data = api::ListIndexedModelsRequest {};
136+
let req = api::AdminApiPayload {
137+
code: code.to_string(),
138+
request_path: self.models_endpoint().to_string(),
139+
request_body: data,
140+
};
141+
let jws = Jws::for_data(&self.signer, &req).await?;
142+
api::AdminApiRequest::try_from(jws)
143+
}
144+
121145
/// Create a serde compatible request for a single instance per account creation of a model
122146
pub async fn create_single_instance_request(
123147
&self,
@@ -249,6 +273,20 @@ impl<S: Signer> CeramicHttpClient<S> {
249273
pub async fn create_healthcheck_request(&self) -> anyhow::Result<api::HealthcheckRequest> {
250274
Ok(api::HealthcheckRequest {})
251275
}
276+
/// Create a serde compatible request for the node status
277+
pub async fn create_node_status_request(
278+
&self,
279+
code: &str,
280+
) -> anyhow::Result<api::AdminApiRequest> {
281+
let data = api::NodeStatusRequest {};
282+
let req = api::AdminApiPayload {
283+
code: code.to_string(),
284+
request_path: self.node_status_endpoint().to_string(),
285+
request_body: data,
286+
};
287+
let jws = Jws::for_data(&self.signer, &req).await?;
288+
api::AdminApiRequest::try_from(jws)
289+
}
252290
}
253291

254292
/// Remote HTTP Functionality
@@ -329,6 +367,33 @@ pub mod remote {
329367
}
330368
}
331369

370+
/// List indexed models on the remote ceramic
371+
pub async fn list_indexed_models(&self) -> anyhow::Result<api::ListIndexedModelsResponse> {
372+
let resp: api::AdminCodeResponse = self
373+
.remote
374+
.get(self.url_for_path(self.cli.admin_code_endpoint())?)
375+
.send()
376+
.await?
377+
.json()
378+
.await?;
379+
let req = self
380+
.cli
381+
.create_list_indexed_models_request(&resp.code)
382+
.await?;
383+
let resp = self
384+
.remote
385+
.get(self.url_for_path(self.cli.models_endpoint())?)
386+
.header(
387+
reqwest::header::AUTHORIZATION,
388+
format!("Basic {}", req.jws()),
389+
)
390+
.send()
391+
.await?
392+
.json()
393+
.await?;
394+
Ok(resp)
395+
}
396+
332397
/// Create an instance of a model that allows a single instance on the remote ceramic
333398
pub async fn create_single_instance(
334399
&self,
@@ -487,6 +552,30 @@ pub mod remote {
487552
.await?;
488553
Ok(resp)
489554
}
555+
556+
/// Get the node status
557+
pub async fn node_status(&self) -> anyhow::Result<api::NodeStatusResponse> {
558+
let resp: api::AdminCodeResponse = self
559+
.remote
560+
.get(self.url_for_path(self.cli.admin_code_endpoint())?)
561+
.send()
562+
.await?
563+
.json()
564+
.await?;
565+
let req = self.cli.create_node_status_request(&resp.code).await?;
566+
let resp = self
567+
.remote
568+
.get(self.url_for_path(self.cli.node_status_endpoint())?)
569+
.header(
570+
reqwest::header::AUTHORIZATION,
571+
format!("Basic {}", req.jws()),
572+
)
573+
.send()
574+
.await?
575+
.json()
576+
.await?;
577+
Ok(resp)
578+
}
490579
}
491580
}
492581

0 commit comments

Comments
 (0)