package chatcore import ( "errors" "sync" "time" ) type SessionType string const ( SessionTypeGroup SessionType = "group" SessionTypeDM SessionType = "dm" ) type MessageType string const ( MessageTypeText MessageType = "text" MessageTypeImage MessageType = "image" MessageTypeSystem MessageType = "system" ) type Session struct { Id int64 `json:"id"` Type SessionType `json:"type"` Name string `json:"name"` CreatorId int64 `json:"creatorId"` Participants []int64 `json:"participants"` LastMessage string `json:"lastMessage"` LastMessageAt int64 `json:"lastMessageAt"` CreatedAt int64 `json:"createdAt"` UpdatedAt int64 `json:"updatedAt"` } type Message struct { Id int64 `json:"id"` SessionId int64 `json:"sessionId"` SenderId int64 `json:"senderId"` Type MessageType `json:"type"` Content string `json:"content"` CreatedAt int64 `json:"createdAt"` } type Store struct { mu sync.RWMutex nextSessionID int64 nextMessageID int64 Sessions map[int64]*Session Messages map[int64]*Message SessionMessages map[int64][]int64 // sessionId -> []messageId } func NewStore() *Store { return &Store{ nextSessionID: 1000, nextMessageID: 1000, Sessions: make(map[int64]*Session), Messages: make(map[int64]*Message), SessionMessages: make(map[int64][]int64), } } func (s *Store) CreateSession(typ SessionType, name string, creatorId int64, participants []int64) (*Session, error) { if creatorId <= 0 { return nil, errors.New("creatorId is required") } s.mu.Lock() defer s.mu.Unlock() now := time.Now().Unix() ps := append([]int64(nil), participants...) hasCreator := false for _, p := range ps { if p == creatorId { hasCreator = true break } } if !hasCreator { ps = append(ps, creatorId) } s.nextSessionID++ session := &Session{ Id: s.nextSessionID, Type: typ, Name: name, CreatorId: creatorId, Participants: ps, CreatedAt: now, UpdatedAt: now, } s.Sessions[session.Id] = session return session, nil } func (s *Store) GetSession(id int64) (*Session, error) { s.mu.RLock() defer s.mu.RUnlock() session, ok := s.Sessions[id] if !ok { return nil, errors.New("session not found") } return session, nil } func (s *Store) IsParticipant(sessionId, userId int64) bool { s.mu.RLock() defer s.mu.RUnlock() session, ok := s.Sessions[sessionId] if !ok { return false } for _, p := range session.Participants { if p == userId { return true } } return false } func (s *Store) ListUserSessions(userId int64, page, limit int) []*Session { s.mu.RLock() defer s.mu.RUnlock() var results []*Session for _, sess := range s.Sessions { for _, p := range sess.Participants { if p == userId { results = append(results, sess) break } } } offset := page * limit if offset >= len(results) { return nil } end := offset + limit if end > len(results) { end = len(results) } return results[offset:end] } func (s *Store) AddParticipant(sessionId, userId int64) error { s.mu.Lock() defer s.mu.Unlock() session, ok := s.Sessions[sessionId] if !ok { return errors.New("session not found") } for _, p := range session.Participants { if p == userId { return nil } } session.Participants = append(session.Participants, userId) session.UpdatedAt = time.Now().Unix() return nil } func (s *Store) RemoveParticipant(sessionId, userId int64) error { s.mu.Lock() defer s.mu.Unlock() session, ok := s.Sessions[sessionId] if !ok { return errors.New("session not found") } filtered := make([]int64, 0, len(session.Participants)) for _, p := range session.Participants { if p != userId { filtered = append(filtered, p) } } session.Participants = filtered session.UpdatedAt = time.Now().Unix() return nil } func (s *Store) AddMessage(sessionId, senderId int64, msgType MessageType, content string) (*Message, error) { if sessionId <= 0 { return nil, errors.New("sessionId is required") } if senderId <= 0 { return nil, errors.New("senderId is required") } if content == "" { return nil, errors.New("content is required") } s.mu.Lock() defer s.mu.Unlock() session, ok := s.Sessions[sessionId] if !ok { return nil, errors.New("session not found") } now := time.Now().Unix() if msgType == "" { msgType = MessageTypeText } s.nextMessageID++ msg := &Message{ Id: s.nextMessageID, SessionId: sessionId, SenderId: senderId, Type: msgType, Content: content, CreatedAt: now, } s.Messages[msg.Id] = msg s.SessionMessages[sessionId] = append(s.SessionMessages[sessionId], msg.Id) session.LastMessage = content session.LastMessageAt = now session.UpdatedAt = now return msg, nil } func (s *Store) GetMessages(sessionId int64, page, limit int) []*Message { s.mu.RLock() defer s.mu.RUnlock() msgIDs := s.SessionMessages[sessionId] var results []*Message for _, id := range msgIDs { if msg, ok := s.Messages[id]; ok { results = append(results, msg) } } if limit <= 0 { limit = 50 } offset := page * limit if offset >= len(results) { return nil } end := offset + limit if end > len(results) { end = len(results) } return results[offset:end] } func (s *Store) DeleteSession(id int64) { s.mu.Lock() defer s.mu.Unlock() delete(s.Sessions, id) for _, msgId := range s.SessionMessages[id] { delete(s.Messages, msgId) } delete(s.SessionMessages, id) }