huskies: merge 670_refactor_hoist_chat_history_persistence_into_a_shared_module_replaces_658
This commit is contained in:
@@ -1,40 +1,21 @@
|
||||
//! Discord conversation history persistence.
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::Mutex as TokioMutex;
|
||||
|
||||
use crate::chat::history::{load_chat_history, save_chat_history};
|
||||
use crate::chat::transport::matrix::RoomConversation;
|
||||
use crate::slog;
|
||||
|
||||
/// Per-channel conversation history, keyed by channel ID.
|
||||
pub type DiscordConversationHistory = Arc<TokioMutex<HashMap<String, RoomConversation>>>;
|
||||
|
||||
/// On-disk format for persisted Discord conversation history.
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct PersistedDiscordHistory {
|
||||
channels: HashMap<String, RoomConversation>,
|
||||
}
|
||||
|
||||
/// Path to the persisted Discord conversation history file.
|
||||
const DISCORD_HISTORY_FILE: &str = ".huskies/discord_history.json";
|
||||
|
||||
/// Load Discord conversation history from disk.
|
||||
pub fn load_discord_history(project_root: &std::path::Path) -> HashMap<String, RoomConversation> {
|
||||
let path = project_root.join(DISCORD_HISTORY_FILE);
|
||||
let data = match std::fs::read_to_string(&path) {
|
||||
Ok(d) => d,
|
||||
Err(_) => return HashMap::new(),
|
||||
};
|
||||
let persisted: PersistedDiscordHistory = match serde_json::from_str(&data) {
|
||||
Ok(p) => p,
|
||||
Err(e) => {
|
||||
slog!("[discord] Failed to parse history file: {e}");
|
||||
return HashMap::new();
|
||||
}
|
||||
};
|
||||
persisted.channels
|
||||
load_chat_history(project_root, DISCORD_HISTORY_FILE, "discord")
|
||||
}
|
||||
|
||||
/// Save Discord conversation history to disk.
|
||||
@@ -42,18 +23,7 @@ pub(super) fn save_discord_history(
|
||||
project_root: &std::path::Path,
|
||||
history: &HashMap<String, RoomConversation>,
|
||||
) {
|
||||
let persisted = PersistedDiscordHistory {
|
||||
channels: history.clone(),
|
||||
};
|
||||
let path = project_root.join(DISCORD_HISTORY_FILE);
|
||||
match serde_json::to_string_pretty(&persisted) {
|
||||
Ok(json) => {
|
||||
if let Err(e) = std::fs::write(&path, json) {
|
||||
slog!("[discord] Failed to write history file: {e}");
|
||||
}
|
||||
}
|
||||
Err(e) => slog!("[discord] Failed to serialise history: {e}"),
|
||||
}
|
||||
save_chat_history(project_root, DISCORD_HISTORY_FILE, "discord", history);
|
||||
}
|
||||
|
||||
// ── Tests ───────────────────────────────────────────────────────────────
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//! Matrix conversation history — per-room message history for LLM context.
|
||||
use crate::slog;
|
||||
use crate::chat::history::{load_chat_history, save_chat_history};
|
||||
use matrix_sdk::ruma::OwnedRoomId;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
@@ -44,32 +44,13 @@ pub struct RoomConversation {
|
||||
/// event-handler tasks without blocking the sync loop.
|
||||
pub type ConversationHistory = Arc<TokioMutex<HashMap<OwnedRoomId, RoomConversation>>>;
|
||||
|
||||
/// On-disk format for persisted conversation history. Room IDs are stored as
|
||||
/// strings because `OwnedRoomId` does not implement `Serialize` as a map key.
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub(super) struct PersistedHistory {
|
||||
pub rooms: HashMap<String, RoomConversation>,
|
||||
}
|
||||
|
||||
/// Path to the persisted conversation history file relative to project root.
|
||||
pub(super) const HISTORY_FILE: &str = ".huskies/matrix_history.json";
|
||||
|
||||
/// Load conversation history from disk, returning an empty map on any error.
|
||||
pub fn load_history(project_root: &std::path::Path) -> HashMap<OwnedRoomId, RoomConversation> {
|
||||
let path = project_root.join(HISTORY_FILE);
|
||||
let data = match std::fs::read_to_string(&path) {
|
||||
Ok(d) => d,
|
||||
Err(_) => return HashMap::new(),
|
||||
};
|
||||
let persisted: PersistedHistory = match serde_json::from_str(&data) {
|
||||
Ok(p) => p,
|
||||
Err(e) => {
|
||||
slog!("[matrix-bot] Failed to parse history file: {e}");
|
||||
return HashMap::new();
|
||||
}
|
||||
};
|
||||
persisted
|
||||
.rooms
|
||||
let string_map = load_chat_history(project_root, HISTORY_FILE, "matrix-bot");
|
||||
string_map
|
||||
.into_iter()
|
||||
.filter_map(|(k, v)| k.parse::<OwnedRoomId>().ok().map(|room_id| (room_id, v)))
|
||||
.collect()
|
||||
@@ -80,21 +61,11 @@ pub fn save_history(
|
||||
project_root: &std::path::Path,
|
||||
history: &HashMap<OwnedRoomId, RoomConversation>,
|
||||
) {
|
||||
let persisted = PersistedHistory {
|
||||
rooms: history
|
||||
.iter()
|
||||
.map(|(k, v)| (k.to_string(), v.clone()))
|
||||
.collect(),
|
||||
};
|
||||
let path = project_root.join(HISTORY_FILE);
|
||||
match serde_json::to_string_pretty(&persisted) {
|
||||
Ok(json) => {
|
||||
if let Err(e) = std::fs::write(&path, json) {
|
||||
slog!("[matrix-bot] Failed to write history file: {e}");
|
||||
}
|
||||
}
|
||||
Err(e) => slog!("[matrix-bot] Failed to serialise history: {e}"),
|
||||
}
|
||||
let string_map: HashMap<String, RoomConversation> = history
|
||||
.iter()
|
||||
.map(|(k, v)| (k.to_string(), v.clone()))
|
||||
.collect();
|
||||
save_chat_history(project_root, HISTORY_FILE, "matrix-bot", &string_map);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
@@ -1,40 +1,21 @@
|
||||
//! Slack conversation history persistence.
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::Mutex as TokioMutex;
|
||||
|
||||
use crate::chat::history::{load_chat_history, save_chat_history};
|
||||
use crate::chat::transport::matrix::RoomConversation;
|
||||
use crate::slog;
|
||||
|
||||
/// Per-channel conversation history, keyed by channel ID.
|
||||
pub type SlackConversationHistory = Arc<TokioMutex<HashMap<String, RoomConversation>>>;
|
||||
|
||||
/// On-disk format for persisted Slack conversation history.
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct PersistedSlackHistory {
|
||||
channels: HashMap<String, RoomConversation>,
|
||||
}
|
||||
|
||||
/// Path to the persisted Slack conversation history file.
|
||||
const SLACK_HISTORY_FILE: &str = ".huskies/slack_history.json";
|
||||
|
||||
/// Load Slack conversation history from disk.
|
||||
pub fn load_slack_history(project_root: &std::path::Path) -> HashMap<String, RoomConversation> {
|
||||
let path = project_root.join(SLACK_HISTORY_FILE);
|
||||
let data = match std::fs::read_to_string(&path) {
|
||||
Ok(d) => d,
|
||||
Err(_) => return HashMap::new(),
|
||||
};
|
||||
let persisted: PersistedSlackHistory = match serde_json::from_str(&data) {
|
||||
Ok(p) => p,
|
||||
Err(e) => {
|
||||
slog!("[slack] Failed to parse history file: {e}");
|
||||
return HashMap::new();
|
||||
}
|
||||
};
|
||||
persisted.channels
|
||||
load_chat_history(project_root, SLACK_HISTORY_FILE, "slack")
|
||||
}
|
||||
|
||||
/// Save Slack conversation history to disk.
|
||||
@@ -42,18 +23,7 @@ pub(super) fn save_slack_history(
|
||||
project_root: &std::path::Path,
|
||||
history: &HashMap<String, RoomConversation>,
|
||||
) {
|
||||
let persisted = PersistedSlackHistory {
|
||||
channels: history.clone(),
|
||||
};
|
||||
let path = project_root.join(SLACK_HISTORY_FILE);
|
||||
match serde_json::to_string_pretty(&persisted) {
|
||||
Ok(json) => {
|
||||
if let Err(e) = std::fs::write(&path, json) {
|
||||
slog!("[slack] Failed to write history file: {e}");
|
||||
}
|
||||
}
|
||||
Err(e) => slog!("[slack] Failed to serialise history: {e}"),
|
||||
}
|
||||
save_chat_history(project_root, SLACK_HISTORY_FILE, "slack", history);
|
||||
}
|
||||
|
||||
// ── Tests ───────────────────────────────────────────────────────────────
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
//! WhatsApp conversation history — per-number message history and messaging window tracking.
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::Mutex as TokioMutex;
|
||||
|
||||
use crate::chat::history::{load_chat_history, save_chat_history};
|
||||
use crate::chat::transport::matrix::RoomConversation;
|
||||
use crate::slog;
|
||||
|
||||
// ── Messaging window tracker ─────────────────────────────────────────────
|
||||
|
||||
@@ -73,30 +72,12 @@ impl MessagingWindowTracker {
|
||||
/// Per-sender conversation history, keyed by phone number.
|
||||
pub type WhatsAppConversationHistory = Arc<TokioMutex<HashMap<String, RoomConversation>>>;
|
||||
|
||||
/// On-disk format for persisted WhatsApp conversation history.
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct PersistedWhatsAppHistory {
|
||||
senders: HashMap<String, RoomConversation>,
|
||||
}
|
||||
|
||||
/// Path to the persisted WhatsApp conversation history file.
|
||||
const WHATSAPP_HISTORY_FILE: &str = ".huskies/whatsapp_history.json";
|
||||
|
||||
/// Load WhatsApp conversation history from disk.
|
||||
pub fn load_whatsapp_history(project_root: &std::path::Path) -> HashMap<String, RoomConversation> {
|
||||
let path = project_root.join(WHATSAPP_HISTORY_FILE);
|
||||
let data = match std::fs::read_to_string(&path) {
|
||||
Ok(d) => d,
|
||||
Err(_) => return HashMap::new(),
|
||||
};
|
||||
let persisted: PersistedWhatsAppHistory = match serde_json::from_str(&data) {
|
||||
Ok(p) => p,
|
||||
Err(e) => {
|
||||
slog!("[whatsapp] Failed to parse history file: {e}");
|
||||
return HashMap::new();
|
||||
}
|
||||
};
|
||||
persisted.senders
|
||||
load_chat_history(project_root, WHATSAPP_HISTORY_FILE, "whatsapp")
|
||||
}
|
||||
|
||||
/// Save WhatsApp conversation history to disk.
|
||||
@@ -104,18 +85,7 @@ pub(super) fn save_whatsapp_history(
|
||||
project_root: &std::path::Path,
|
||||
history: &HashMap<String, RoomConversation>,
|
||||
) {
|
||||
let persisted = PersistedWhatsAppHistory {
|
||||
senders: history.clone(),
|
||||
};
|
||||
let path = project_root.join(WHATSAPP_HISTORY_FILE);
|
||||
match serde_json::to_string_pretty(&persisted) {
|
||||
Ok(json) => {
|
||||
if let Err(e) = std::fs::write(&path, json) {
|
||||
slog!("[whatsapp] Failed to write history file: {e}");
|
||||
}
|
||||
}
|
||||
Err(e) => slog!("[whatsapp] Failed to serialise history: {e}"),
|
||||
}
|
||||
save_chat_history(project_root, WHATSAPP_HISTORY_FILE, "whatsapp", history);
|
||||
}
|
||||
|
||||
// ── Tests ───────────────────────────────────────────────────────────────
|
||||
|
||||
Reference in New Issue
Block a user