Private
Public Access
1
0

Add 'mock/' from commit '2041d3ce6377da091eca17cf9d8ad176a3024616'

git-subtree-dir: mock
git-subtree-mainline: 8216d7c706
git-subtree-split: 2041d3ce63
This commit is contained in:
2025-09-06 19:35:49 -07:00
20 changed files with 2661 additions and 0 deletions

218
mock/prompt/prompt.go Normal file
View File

@@ -0,0 +1,218 @@
package prompt
import (
"fmt"
"io"
"strings"
"time"
"github.com/chzyer/readline"
"github.com/google/uuid"
"github.com/rs/zerolog/log"
"go.buzzert.net/kordophone-mock/model"
"go.buzzert.net/kordophone-mock/server"
)
type Prompt struct {
rl *readline.Instance
server *server.Server
}
func (p *Prompt) conversationForGUID(guid string) (*model.Conversation, error) {
if guid == "*" {
// This means any conversation: return the first one (that's not the special Attachments convo)
convo := p.server.SortedConversations()[0]
if convo.DisplayName != nil && *convo.DisplayName == server.ATTACHMENT_CONVO_DISP_NAME {
return &p.server.SortedConversations()[1], nil
}
return &convo, nil
}
return p.server.ConversationForGUID(guid)
}
func (p *Prompt) listConversations() {
conversations := p.server.SortedConversations()
for _, c := range conversations {
fmt.Printf("%s %s \t %s ", c.Guid, c.GetDisplayName(), c.Date.Format("2006-01-02 15:04:05"))
if c.UnreadCount > 0 {
fmt.Printf("(%d unread)", c.UnreadCount)
}
fmt.Println()
}
}
func (p *Prompt) listMessages(guid string) {
conversation, err := p.conversationForGUID(guid)
if err != nil {
log.Err(err).Msgf("Error listing messages for conversation %s", guid)
return
}
messages := p.server.MessagesForConversation(conversation)
for _, m := range messages {
var sender string
if m.Sender == nil {
sender = "(Me)"
} else {
sender = *m.Sender
}
fmt.Printf("%s %s From: %s\n", m.Guid, m.Date.Format("2006-01-02 15:04:05"), sender)
fmt.Printf("\t %s\n", m.Text)
}
}
func (p *Prompt) markConversation(guid string, read bool) {
conversation, err := p.conversationForGUID(guid)
if err != nil {
log.Err(err).Msgf("Error marking conversation %s as read", guid)
return
}
if read {
conversation.UnreadCount = 0
} else {
conversation.UnreadCount = 1
}
}
func (p *Prompt) receiveMessage(guid string, text string) {
conversation, err := p.conversationForGUID(guid)
if err != nil {
log.Err(err).Msgf("Error receiving message for conversation %s", guid)
return
}
message := model.Message{
Guid: uuid.New().String(),
Sender: &conversation.Participants[0],
Text: text,
Date: model.Date(time.Now()),
}
p.server.ReceiveMessage(conversation, message)
}
func NewPrompt(server *server.Server) *Prompt {
completer := readline.NewPrefixCompleter(
readline.PcItem("ls"),
readline.PcItem("mark",
readline.PcItem("-r"),
),
readline.PcItem("help"),
readline.PcItem("recv"),
readline.PcItem("exit"),
)
rl, err := readline.NewEx(&readline.Config{
Prompt: "\033[31m»\033[0m ",
HistoryFile: "/tmp/readline.tmp",
InterruptPrompt: "^C",
EOFPrompt: "exit",
AutoComplete: completer,
HistorySearchFold: true,
})
if err != nil {
panic(err)
}
return &Prompt{
rl: rl,
server: server,
}
}
func (p *Prompt) StartInteractive() error {
for {
line, err := p.rl.Readline()
if err == readline.ErrInterrupt {
if len(line) == 0 {
break
} else {
continue
}
} else if err == io.EOF {
break
}
line = strings.TrimSpace(line)
switch {
case strings.HasPrefix(line, "ls"): // List
args := strings.Split(line, " ")
if len(args) == 1 {
p.listConversations()
} else {
p.listMessages(args[1])
}
case strings.HasPrefix(line, "mark"): // Mark
args := strings.Split(line, " ")
if len(args) < 2 {
log.Info().Msgf("Usage: mark [-r] <guid>")
continue
}
read := false
if args[1] == "-r" {
read = true
args = args[1:]
}
p.markConversation(args[1], read)
case strings.HasPrefix(line, "recv"): // Receive
args := strings.Split(line, " ")
if len(args) < 3 {
log.Info().Msgf("Usage: recv <guid> <msg>")
continue
}
body := strings.Join(args[2:], " ")
// strip quotes
if strings.HasPrefix(body, "\"") && strings.HasSuffix(body, "\"") {
body = body[1 : len(body)-1]
}
p.receiveMessage(args[1], body)
case line == "version": // Version
fmt.Printf("Server version: %s\n", p.server.Version())
case line == "help": // Help
fmt.Println("Usage: <command> [args]")
fmt.Println("Where <guid> is specified, '*' can be provided as a wildcard.")
fmt.Println()
fmt.Println("Commands:")
fmt.Println("\tls list conversations")
fmt.Println("\tls <guid> list messages for conversation")
fmt.Println("\tmark [-r] <guid> mark conversation as unread/[r]ead")
fmt.Println("\trecv <guid> <msg> receive a message")
fmt.Println("\tversion print server version")
fmt.Println("\thelp show this help")
fmt.Println("\texit exits the program")
case line == "exit": // Exit
return nil
default:
if len(line) > 0 {
fmt.Printf("Unknown command: %s\n", line)
}
}
}
return nil
}
func (p *Prompt) CleanAndRefreshForLogging() {
p.rl.Clean()
// xxx: Lazy hack to make sure this runs _after_ the log is written.
go p.rl.Refresh()
}