2023-06-16 23:35:41 -07:00
|
|
|
package server
|
|
|
|
|
|
|
|
|
|
import (
|
2023-06-19 18:31:05 -07:00
|
|
|
"sort"
|
|
|
|
|
|
2023-06-16 23:35:41 -07:00
|
|
|
"code.severnaya.net/kordophone-mock/v2/data"
|
|
|
|
|
"code.severnaya.net/kordophone-mock/v2/model"
|
2023-06-23 00:44:25 -07:00
|
|
|
"github.com/rs/zerolog/log"
|
2023-06-16 23:35:41 -07:00
|
|
|
)
|
|
|
|
|
|
2023-06-16 23:38:48 -07:00
|
|
|
const VERSION = "Kordophone-2.0"
|
|
|
|
|
|
2023-06-18 13:11:51 -07:00
|
|
|
const (
|
|
|
|
|
AUTH_USERNAME = "test"
|
|
|
|
|
AUTH_PASSWORD = "test"
|
|
|
|
|
)
|
|
|
|
|
|
2023-06-16 23:35:41 -07:00
|
|
|
type Server struct {
|
|
|
|
|
version string
|
|
|
|
|
conversations []model.Conversation
|
2023-06-18 13:11:51 -07:00
|
|
|
authTokens []model.AuthToken
|
2023-06-19 18:31:05 -07:00
|
|
|
messageStore map[string][]model.Message
|
2023-06-18 13:11:51 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type AuthError struct {
|
|
|
|
|
message string
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (e *AuthError) Error() string {
|
|
|
|
|
return e.message
|
2023-06-16 23:35:41 -07:00
|
|
|
}
|
|
|
|
|
|
2023-06-19 18:31:05 -07:00
|
|
|
type DatabaseError struct {
|
|
|
|
|
message string
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (e *DatabaseError) Error() string {
|
|
|
|
|
return e.message
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-16 23:35:41 -07:00
|
|
|
func NewServer() *Server {
|
|
|
|
|
return &Server{
|
2023-06-16 23:38:48 -07:00
|
|
|
version: VERSION,
|
2023-06-16 23:35:41 -07:00
|
|
|
conversations: []model.Conversation{},
|
2023-06-19 18:31:05 -07:00
|
|
|
authTokens: []model.AuthToken{},
|
|
|
|
|
messageStore: make(map[string][]model.Message),
|
2023-06-16 23:35:41 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *Server) Version() string {
|
|
|
|
|
return s.version
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *Server) Conversations() []model.Conversation {
|
|
|
|
|
return s.conversations
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-23 00:32:17 -07:00
|
|
|
func (s *Server) SortedConversations() []model.Conversation {
|
|
|
|
|
conversations := s.Conversations()
|
|
|
|
|
sort.Slice(conversations, func(i, j int) bool {
|
|
|
|
|
return conversations[i].Date.After(conversations[j].Date)
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
return conversations
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-19 18:31:05 -07:00
|
|
|
func (s *Server) ConversationForGUID(guid string) (*model.Conversation, error) {
|
|
|
|
|
var conversation *model.Conversation = nil
|
2023-06-23 00:32:17 -07:00
|
|
|
for i := range s.conversations {
|
|
|
|
|
c := &s.conversations[i]
|
2023-06-19 18:31:05 -07:00
|
|
|
if c.Guid == guid {
|
2023-06-23 00:32:17 -07:00
|
|
|
conversation = c
|
2023-06-19 18:31:05 -07:00
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if conversation != nil {
|
|
|
|
|
return conversation, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nil, &DatabaseError{message: "Conversation not found"}
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-16 23:35:41 -07:00
|
|
|
func (s *Server) AddConversation(c model.Conversation) {
|
|
|
|
|
s.conversations = append(s.conversations, c)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *Server) PopulateWithTestData() {
|
|
|
|
|
numConversations := 100
|
|
|
|
|
cs := make([]model.Conversation, numConversations)
|
|
|
|
|
for i := 0; i < numConversations; i++ {
|
|
|
|
|
cs[i] = data.GenerateRandomConversation()
|
2023-06-19 18:31:05 -07:00
|
|
|
|
|
|
|
|
// Generate messages
|
|
|
|
|
convo := &cs[i]
|
|
|
|
|
var lastMessage model.Message
|
|
|
|
|
for i := 0; i < 100; i++ {
|
|
|
|
|
message := data.GenerateRandomMessage(convo.Participants)
|
|
|
|
|
s.AppendMessageToConversation(convo, message)
|
|
|
|
|
|
|
|
|
|
if lastMessage.Date.Before(message.Date) {
|
|
|
|
|
lastMessage = message
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Update last message preview
|
|
|
|
|
convo.LastMessagePreview = lastMessage.Text
|
2023-06-16 23:35:41 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
s.conversations = cs
|
|
|
|
|
}
|
2023-06-18 13:11:51 -07:00
|
|
|
|
|
|
|
|
func (s *Server) Authenticate(username string, password string) (*model.AuthToken, error) {
|
|
|
|
|
if username != AUTH_USERNAME || password != AUTH_PASSWORD {
|
|
|
|
|
return nil, &AuthError{"Invalid username or password"}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
token, err := model.NewAuthToken(username)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Register for future auth
|
|
|
|
|
s.registerAuthToken(token)
|
|
|
|
|
|
|
|
|
|
return token, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *Server) CheckBearerToken(token string) bool {
|
|
|
|
|
return s.authenticateToken(token)
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-23 00:32:17 -07:00
|
|
|
func (s *Server) MessagesForConversation(conversation *model.Conversation) []model.Message {
|
2023-06-19 18:31:05 -07:00
|
|
|
messages := s.messageStore[conversation.Guid]
|
|
|
|
|
sort.Slice(messages, func(i int, j int) bool {
|
|
|
|
|
return messages[i].Date.Before(messages[j].Date)
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
return messages
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *Server) AppendMessageToConversation(conversation *model.Conversation, message model.Message) {
|
|
|
|
|
s.messageStore[conversation.Guid] = append(s.messageStore[conversation.Guid], message)
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-23 00:44:25 -07:00
|
|
|
func (s *Server) SendMessage(conversation *model.Conversation, message model.Message) {
|
|
|
|
|
s.AppendMessageToConversation(conversation, message)
|
|
|
|
|
conversation.LastMessagePreview = message.Text
|
|
|
|
|
conversation.Date = message.Date
|
|
|
|
|
|
|
|
|
|
log.Info().EmbedObject(message).Msgf("Sent message to conversation %s", conversation.Guid)
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-18 13:11:51 -07:00
|
|
|
// Private
|
|
|
|
|
|
|
|
|
|
func (s *Server) registerAuthToken(token *model.AuthToken) {
|
|
|
|
|
s.authTokens = append(s.authTokens, *token)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *Server) authenticateToken(token string) bool {
|
|
|
|
|
for _, t := range s.authTokens {
|
|
|
|
|
if t.SignedToken == token {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false
|
|
|
|
|
}
|