Real-time index of opencode sessions
at main 157 lines 4.6 kB view raw
1use crate::id::{MessageId, PartId, SessionId}; 2use crate::storage::FileReader; 3use crate::types::message::FileDiff; 4use crate::types::{Message, Part, SessionInfo}; 5use crate::Result; 6 7pub struct SessionLoader { 8 reader: FileReader, 9} 10 11impl SessionLoader { 12 pub fn new() -> Result<Self> { 13 let reader = FileReader::new()?; 14 Ok(Self { reader }) 15 } 16 17 pub fn with_reader(reader: FileReader) -> Self { 18 Self { reader } 19 } 20 21 pub fn reader(&self) -> &FileReader { 22 &self.reader 23 } 24 25 pub fn load_session(&self, project_id: &str, session_id: &SessionId) -> Result<LoadedSession> { 26 let info = self.reader.read_session(project_id, session_id)?; 27 let diff = self.reader.read_diff(session_id).ok(); 28 Ok(LoadedSession { info, diff }) 29 } 30 31 pub fn load_message(&self, session_id: &SessionId, message_id: &MessageId) -> Result<Message> { 32 self.reader.read_message(session_id, message_id) 33 } 34 35 pub fn load_part(&self, message_id: &MessageId, part_id: &PartId) -> Result<Part> { 36 self.reader.read_part(message_id, part_id) 37 } 38 39 pub fn load_messages(&self, session_id: &SessionId) -> Result<Vec<Message>> { 40 let message_ids = self.reader.list_messages(session_id)?; 41 self.load_messages_by_ids(session_id, &message_ids) 42 } 43 44 pub fn load_messages_by_ids( 45 &self, 46 session_id: &SessionId, 47 message_ids: &[MessageId], 48 ) -> Result<Vec<Message>> { 49 let mut messages = Vec::with_capacity(message_ids.len()); 50 for msg_id in message_ids { 51 messages.push(self.load_message(session_id, msg_id)?); 52 } 53 Ok(messages) 54 } 55 56 pub fn load_parts(&self, message_id: &MessageId) -> Result<Vec<Part>> { 57 let part_ids = self.reader.list_parts(message_id)?; 58 self.load_parts_by_ids(message_id, &part_ids) 59 } 60 61 pub fn load_parts_by_ids( 62 &self, 63 message_id: &MessageId, 64 part_ids: &[PartId], 65 ) -> Result<Vec<Part>> { 66 let mut parts = Vec::with_capacity(part_ids.len()); 67 for part_id in part_ids { 68 parts.push(self.load_part(message_id, part_id)?); 69 } 70 Ok(parts) 71 } 72 73 pub fn load_message_with_parts( 74 &self, 75 session_id: &SessionId, 76 message_id: &MessageId, 77 ) -> Result<MessageWithParts> { 78 let message = self.load_message(session_id, message_id)?; 79 let part_ids = self.reader.list_parts(message_id)?; 80 let parts = self.load_parts_by_ids(message_id, &part_ids)?; 81 Ok(MessageWithParts { message, parts }) 82 } 83 84 pub fn load_messages_with_parts( 85 &self, 86 session_id: &SessionId, 87 message_ids: &[MessageId], 88 ) -> Result<Vec<MessageWithParts>> { 89 let mut messages = Vec::with_capacity(message_ids.len()); 90 for message_id in message_ids { 91 messages.push(self.load_message_with_parts(session_id, message_id)?); 92 } 93 Ok(messages) 94 } 95 96 pub fn load_session_tree( 97 &self, 98 project_id: &str, 99 session_id: &SessionId, 100 ) -> Result<SessionTree> { 101 let session = self.load_session(project_id, session_id)?; 102 let message_ids = self.reader.list_messages(session_id)?; 103 let messages = self.load_messages_with_parts(session_id, &message_ids)?; 104 105 Ok(SessionTree { session, messages }) 106 } 107 108 pub fn list_sessions(&self, project_id: &str) -> Result<Vec<SessionId>> { 109 self.reader.list_sessions(project_id) 110 } 111 112 pub fn list_messages(&self, session_id: &SessionId) -> Result<Vec<MessageId>> { 113 self.reader.list_messages(session_id) 114 } 115 116 pub fn list_parts(&self, message_id: &MessageId) -> Result<Vec<PartId>> { 117 self.reader.list_parts(message_id) 118 } 119 120 pub fn list_projects(&self) -> Result<Vec<String>> { 121 self.reader.paths().project_dirs() 122 } 123} 124 125#[derive(Debug, Clone)] 126pub struct LoadedSession { 127 pub info: SessionInfo, 128 pub diff: Option<Vec<FileDiff>>, 129} 130 131#[derive(Debug, Clone)] 132pub struct MessageWithParts { 133 pub message: Message, 134 pub parts: Vec<Part>, 135} 136 137#[derive(Debug, Clone)] 138pub struct SessionTree { 139 pub session: LoadedSession, 140 pub messages: Vec<MessageWithParts>, 141} 142 143#[cfg(test)] 144mod tests { 145 use super::*; 146 use crate::Error; 147 148 #[test] 149 fn test_loader_creation() { 150 let result = SessionLoader::new(); 151 match result { 152 Ok(_) => {} 153 Err(Error::StorageRootNotFound) => {} 154 Err(e) => panic!("unexpected error: {}", e), 155 } 156 } 157}