From cc9ee73a0aad919c613f7398e5a62a2bc1959097 Mon Sep 17 00:00:00 2001 From: TelivANT <246803628+TelivANT@users.noreply.github.com> Date: Sat, 21 Feb 2026 23:52:06 +0800 Subject: [PATCH] feat(gateway): implement Phase 4 - save/list connector configs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Changes: - Add POST /v1/wiki/connectors (save config) - Add GET /v1/wiki/connectors/saved (list configs) - File-based storage in ./data/connectors/ - UUID v7 for config IDs Implementation: - Minimal file storage (no external dependencies) - JSON format for easy inspection - Async file I/O with tokio::fs - No encryption (can add later if needed) Storage: - Path: ./data/connectors/{id}.json - Format: SavedConnector struct - Fields: id, name, type, config, created_at Complete API (7/7 endpoints): ✅ GET /v1/wiki/connectors ✅ POST /v1/wiki/connectors/test ✅ POST /v1/wiki/connectors/browse ✅ POST /v1/wiki/connectors/generate ✅ GET /v1/wiki/jobs/{id} ✅ POST /v1/wiki/connectors (save) ✅ GET /v1/wiki/connectors/saved (list) 100% feature complete! --- .../src/routes/wiki_connector.rs | 82 ++++++++++++++++++- 1 file changed, 81 insertions(+), 1 deletion(-) diff --git a/crates/memoryos-gateway/src/routes/wiki_connector.rs b/crates/memoryos-gateway/src/routes/wiki_connector.rs index d4134ad..7ff3a1e 100644 --- a/crates/memoryos-gateway/src/routes/wiki_connector.rs +++ b/crates/memoryos-gateway/src/routes/wiki_connector.rs @@ -116,9 +116,35 @@ pub struct GenerateWithConnectorResponse { pub message: String, } +/// Save connector request +#[derive(Debug, Deserialize)] +pub struct SaveConnectorRequest { + pub name: String, + pub connector_type: String, + pub config: HashMap, +} + +/// Save connector response +#[derive(Debug, Serialize)] +pub struct SaveConnectorResponse { + pub id: String, + pub message: String, +} + +/// Saved connector info +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct SavedConnector { + pub id: String, + pub name: String, + pub connector_type: String, + pub config: HashMap, + pub created_at: String, +} + pub fn create_connector_routes() -> Router { Router::new() - .route("/connectors", get(list_connectors)) + .route("/connectors", get(list_connectors).post(save_connector)) + .route("/connectors/saved", get(list_saved_connectors)) .route("/connectors/test", post(test_connection)) .route("/connectors/browse", post(browse_directory)) .route("/connectors/generate", post(generate_with_connector)) @@ -493,3 +519,57 @@ async fn generate_with_connector( message: "Wiki generation started".to_string(), }) } + +async fn save_connector( + State(_state): State, + Json(req): Json, +) -> impl IntoResponse { + let id = Uuid::now_v7().to_string(); + let saved = SavedConnector { + id: id.clone(), + name: req.name, + connector_type: req.connector_type, + config: req.config, + created_at: chrono::Utc::now().to_rfc3339(), + }; + + // Save to file: ./data/connectors/{id}.json + let dir = PathBuf::from("./data/connectors"); + if let Err(_) = tokio::fs::create_dir_all(&dir).await { + return Json(SaveConnectorResponse { + id: String::new(), + message: "Failed to create directory".to_string(), + }); + } + + let file_path = dir.join(format!("{}.json", id)); + let json = serde_json::to_string_pretty(&saved).unwrap_or_default(); + + match tokio::fs::write(&file_path, json).await { + Ok(_) => Json(SaveConnectorResponse { + id, + message: "Connector saved successfully".to_string(), + }), + Err(_) => Json(SaveConnectorResponse { + id: String::new(), + message: "Failed to save connector".to_string(), + }), + } +} + +async fn list_saved_connectors(State(_state): State) -> impl IntoResponse { + let dir = PathBuf::from("./data/connectors"); + let mut connectors = Vec::new(); + + if let Ok(mut entries) = tokio::fs::read_dir(&dir).await { + while let Ok(Some(entry)) = entries.next_entry().await { + if let Ok(content) = tokio::fs::read_to_string(entry.path()).await { + if let Ok(saved) = serde_json::from_str::(&content) { + connectors.push(saved); + } + } + } + } + + Json(connectors) +}