package isphere import ( "context" "fmt" "strings" "isphere-ai-bridge/internal/isphere/logcodec" "isphere-ai-bridge/internal/isphere/packetlog" ) type Message struct { ID string ConversationID string ConversationType string SenderID string ReceiverID string Text string Timestamp string Subject string ReceiptID string Read bool } type ReceiveMessagesQuery struct { Limit int } type ReceiveMessagesResult struct { Messages []Message } type EncryptedPacketLogSource struct { Lines []string } func (s EncryptedPacketLogSource) ReceiveMessages(ctx context.Context, query ReceiveMessagesQuery) (ReceiveMessagesResult, error) { limit := query.Limit if limit <= 0 || limit > len(s.Lines) { limit = len(s.Lines) } messages := make([]Message, 0, limit) for index, line := range s.Lines { if len(messages) == limit { break } select { case <-ctx.Done(): return ReceiveMessagesResult{}, ctx.Err() default: } plaintext, err := logcodec.DecryptLine(line) if err != nil { return ReceiveMessagesResult{}, fmt.Errorf("decrypt packet log line %d: %w", index, err) } parsed, err := packetlog.ParseMessageLog(plaintext) if err != nil { return ReceiveMessagesResult{}, fmt.Errorf("parse packet log line %d: %w", index, err) } messages = append(messages, normalizePacketMessage(parsed)) } return ReceiveMessagesResult{Messages: messages}, nil } func normalizePacketMessage(msg packetlog.Message) Message { sender := bareJID(msg.From) receiver := bareJID(msg.To) return Message{ ID: msg.ID, ConversationID: conversationID(sender, receiver), ConversationType: msg.Type, SenderID: sender, ReceiverID: receiver, Text: msg.Body, Timestamp: msg.SendTime, Subject: msg.Subject, ReceiptID: msg.ReceiptID, Read: msg.Read, } } func bareJID(value string) string { beforeResource, _, _ := strings.Cut(value, "/") return beforeResource } func conversationID(sender string, receiver string) string { if sender == "" { return receiver } if receiver == "" { return sender } return sender + "|" + receiver }