147 lines
3.3 KiB
Go
147 lines
3.3 KiB
Go
package main
|
|
|
|
import (
|
|
"bufio"
|
|
"flag"
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
"os/signal"
|
|
"strings"
|
|
"syscall"
|
|
"time"
|
|
)
|
|
|
|
var (
|
|
token = flag.String("token", "", "JWT token for authentication (get from browser DevTools)")
|
|
room = flag.String("room", "", "Room ID to join (e.g., @hyperspaceout)")
|
|
email = flag.String("email", "", "Email for login (requires --password, not yet implemented)")
|
|
password = flag.String("password", "", "Password for login (requires --email, not yet implemented)")
|
|
)
|
|
|
|
func main() {
|
|
flag.Parse()
|
|
|
|
// Validate required flags
|
|
if *room == "" {
|
|
log.Fatal("Error: --room is required")
|
|
}
|
|
|
|
// Get authentication token
|
|
authToken, err := GetToken(*token, *email, *password)
|
|
if err != nil {
|
|
log.Fatalf("Authentication error: %v", err)
|
|
}
|
|
|
|
// Create client
|
|
client := NewKosmiClient(authToken, *room)
|
|
|
|
// Set up message handler to print incoming messages
|
|
client.SetMessageHandler(func(msg Message) {
|
|
timestamp := formatTime(msg.Time)
|
|
fmt.Printf("\r[%s] %s: %s\n> ", timestamp, msg.DisplayName, msg.Body)
|
|
})
|
|
|
|
// Connect to Kosmi
|
|
if err := client.Connect(); err != nil {
|
|
log.Fatalf("Connection error: %v", err)
|
|
}
|
|
|
|
// Set up graceful shutdown
|
|
sigChan := make(chan os.Signal, 1)
|
|
signal.Notify(sigChan, os.Interrupt, syscall.SIGTERM)
|
|
|
|
// Start goroutine to handle shutdown signal
|
|
shutdownChan := make(chan struct{})
|
|
go func() {
|
|
<-sigChan
|
|
fmt.Println("\n\nReceived interrupt signal, shutting down gracefully...")
|
|
close(shutdownChan)
|
|
}()
|
|
|
|
// Print usage instructions
|
|
fmt.Println("\n" + strings.Repeat("=", 60))
|
|
fmt.Println("Connected! Type messages and press Enter to send.")
|
|
fmt.Println("Press Ctrl+C to exit.")
|
|
fmt.Println(strings.Repeat("=", 60) + "\n")
|
|
|
|
// Start interactive CLI loop
|
|
go func() {
|
|
scanner := bufio.NewScanner(os.Stdin)
|
|
fmt.Print("> ")
|
|
|
|
for scanner.Scan() {
|
|
select {
|
|
case <-shutdownChan:
|
|
return
|
|
default:
|
|
}
|
|
|
|
text := strings.TrimSpace(scanner.Text())
|
|
|
|
// Skip empty messages
|
|
if text == "" {
|
|
fmt.Print("> ")
|
|
continue
|
|
}
|
|
|
|
// Handle special commands
|
|
if text == "/quit" || text == "/exit" {
|
|
fmt.Println("Exiting...")
|
|
close(shutdownChan)
|
|
return
|
|
}
|
|
|
|
if text == "/help" {
|
|
printHelp()
|
|
fmt.Print("> ")
|
|
continue
|
|
}
|
|
|
|
// Send the message
|
|
if err := client.SendMessage(text); err != nil {
|
|
fmt.Printf("\rError sending message: %v\n> ", err)
|
|
} else {
|
|
// Clear the line and reprint prompt
|
|
fmt.Print("> ")
|
|
}
|
|
}
|
|
|
|
if err := scanner.Err(); err != nil {
|
|
log.Printf("Scanner error: %v", err)
|
|
}
|
|
}()
|
|
|
|
// Wait for shutdown signal
|
|
<-shutdownChan
|
|
|
|
// Close the client gracefully
|
|
if err := client.Close(); err != nil {
|
|
log.Printf("Error closing client: %v", err)
|
|
}
|
|
|
|
// Give a moment for cleanup
|
|
time.Sleep(200 * time.Millisecond)
|
|
|
|
fmt.Println("Goodbye!")
|
|
}
|
|
|
|
// formatTime converts ISO timestamp to readable format
|
|
func formatTime(isoTime string) string {
|
|
t, err := time.Parse(time.RFC3339, isoTime)
|
|
if err != nil {
|
|
return isoTime
|
|
}
|
|
return t.Format("15:04:05")
|
|
}
|
|
|
|
// printHelp displays available commands
|
|
func printHelp() {
|
|
fmt.Println("\nAvailable commands:")
|
|
fmt.Println(" /help - Show this help message")
|
|
fmt.Println(" /quit - Exit the client")
|
|
fmt.Println(" /exit - Exit the client")
|
|
fmt.Println("\nJust type any text and press Enter to send a message.")
|
|
}
|
|
|