1use tauri::{AppHandle, Emitter, Runtime, State};
13
14use crate::state::GraphPluginState;
15use crate::types::{
16 GetEntityResult, GetListResult, PatchEntityPayload, PersistSnapshotPayload, PlatformPing,
17 RemoveEntityPayload, RestoreSnapshotPayload, RestoreSnapshotResult, SetListPayload,
18 SnapshotPersistedEvent, SnapshotRestoredEvent, UpsertEntityPayload,
19};
20use crate::EntityGraphExt;
21
22#[tauri::command]
26#[cfg_attr(feature = "generate-bindings", specta::specta)]
27pub async fn graph_upsert_entity(
28 state: State<'_, GraphPluginState>,
29 payload: UpsertEntityPayload,
30) -> Result<(), String> {
31 state
32 .upsert_entity(&payload.entity_type, &payload.entity_id, payload.data)
33 .await;
34 Ok(())
35}
36
37#[tauri::command]
39#[cfg_attr(feature = "generate-bindings", specta::specta)]
40pub async fn graph_remove_entity(
41 state: State<'_, GraphPluginState>,
42 payload: RemoveEntityPayload,
43) -> Result<(), String> {
44 state
45 .remove_entity(&payload.entity_type, &payload.entity_id)
46 .await;
47 Ok(())
48}
49
50#[tauri::command]
52#[cfg_attr(feature = "generate-bindings", specta::specta)]
53pub async fn graph_patch_entity(
54 _state: State<'_, GraphPluginState>,
55 _payload: PatchEntityPayload,
56) -> Result<(), String> {
57 Ok(())
58}
59
60#[tauri::command]
62#[cfg_attr(feature = "generate-bindings", specta::specta)]
63pub async fn graph_set_list(
64 state: State<'_, GraphPluginState>,
65 payload: SetListPayload,
66) -> Result<(), String> {
67 state
68 .set_list(&payload.query_key, payload.ids, payload.total)
69 .await;
70 Ok(())
71}
72
73#[tauri::command]
75#[cfg_attr(feature = "generate-bindings", specta::specta)]
76pub async fn graph_get_entity(
77 state: State<'_, GraphPluginState>,
78 entity_type: String,
79 entity_id: String,
80) -> Result<GetEntityResult, String> {
81 let data = state.get_entity(&entity_type, &entity_id).await;
82 Ok(GetEntityResult { data })
83}
84
85#[tauri::command]
87#[cfg_attr(feature = "generate-bindings", specta::specta)]
88pub async fn graph_get_list(
89 state: State<'_, GraphPluginState>,
90 query_key: String,
91) -> Result<GetListResult, String> {
92 match state.get_list(&query_key).await {
93 Some(entry) => Ok(GetListResult {
94 ids: entry.ids,
95 total: entry.total,
96 }),
97 None => Ok(GetListResult {
98 ids: vec![],
99 total: None,
100 }),
101 }
102}
103
104#[tauri::command]
106#[cfg_attr(feature = "generate-bindings", specta::specta)]
107pub fn graph_platform_ping<R: Runtime>(app: AppHandle<R>) -> Result<PlatformPing, String> {
108 app.entity_graph().ping().map_err(|error| error.to_string())
109}
110
111#[tauri::command]
113#[cfg_attr(feature = "generate-bindings", specta::specta)]
114pub async fn graph_clear(state: State<'_, GraphPluginState>) -> Result<(), String> {
115 state.clear_entities().await;
116 state.clear_lists().await;
117 Ok(())
118}
119
120#[tauri::command]
126#[cfg_attr(feature = "generate-bindings", specta::specta)]
127pub async fn graph_persist_snapshot<R: Runtime>(
128 app: AppHandle<R>,
129 state: State<'_, GraphPluginState>,
130 payload: PersistSnapshotPayload,
131) -> Result<(), String> {
132 let key = payload
133 .storage_key
134 .unwrap_or_else(|| "entity-graph:snapshot".to_owned());
135
136 let byte_size = payload.snapshot.len();
137 state.set_snapshot(&key, payload.snapshot).await;
138
139 let now = monotonic_ts();
140 let _ = app.emit(
141 "plugin:entity-graph-tauri:snapshot-persisted",
142 SnapshotPersistedEvent {
143 storage_key: key,
144 persisted_at: now,
145 byte_size,
146 },
147 );
148
149 Ok(())
150}
151
152#[tauri::command]
156#[cfg_attr(feature = "generate-bindings", specta::specta)]
157pub async fn graph_restore_snapshot<R: Runtime>(
158 app: AppHandle<R>,
159 state: State<'_, GraphPluginState>,
160 payload: RestoreSnapshotPayload,
161) -> Result<RestoreSnapshotResult, String> {
162 let key = payload
163 .storage_key
164 .unwrap_or_else(|| "entity-graph:snapshot".to_owned());
165
166 let snapshot = state.get_snapshot(&key).await;
167
168 if snapshot.is_some() {
169 let now = monotonic_ts();
170 let _ = app.emit(
171 "plugin:entity-graph-tauri:snapshot-restored",
172 SnapshotRestoredEvent {
173 storage_key: key,
174 restored_at: now,
175 },
176 );
177 }
178
179 Ok(RestoreSnapshotResult { snapshot })
180}
181
182fn monotonic_ts() -> String {
185 use std::time::{SystemTime, UNIX_EPOCH};
186 let ms = SystemTime::now()
187 .duration_since(UNIX_EPOCH)
188 .unwrap_or_default()
189 .as_millis();
190 format!("{ms}")
191}