| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452 |
- package cmd
- import (
- "context"
- "encoding/json"
- "fmt"
- "os"
- "gogs.dmsc.dev/arp/arp_cli/client"
- "gogs.dmsc.dev/arp/arp_cli/config"
- "github.com/AlecAivazis/survey/v2"
- "github.com/olekukonko/tablewriter"
- "github.com/urfave/cli/v3"
- )
- // MessageCommand returns the message command
- func MessageCommand() *cli.Command {
- return &cli.Command{
- Name: "message",
- Usage: "Manage messages",
- Description: `Manage ARP messages. Messages are sent in channels between users/agents.
- Use this command to create, list, update, and delete messages. You can also watch for real-time message updates.`,
- Commands: []*cli.Command{
- {
- Name: "list",
- Aliases: []string{"ls"},
- Usage: "List all messages",
- Flags: []cli.Flag{
- &cli.BoolFlag{
- Name: "json",
- Aliases: []string{"j"},
- Usage: "Output as JSON",
- },
- },
- Action: messageList,
- },
- {
- Name: "get",
- Usage: "Get a message by ID",
- Flags: []cli.Flag{
- &cli.StringFlag{
- Name: "id",
- Aliases: []string{"i"},
- Usage: "Message ID",
- Required: true,
- },
- &cli.BoolFlag{
- Name: "json",
- Aliases: []string{"j"},
- Usage: "Output as JSON",
- },
- },
- Action: messageGet,
- },
- {
- Name: "create",
- Usage: "Create a new message",
- Action: messageCreate,
- Flags: []cli.Flag{
- &cli.StringFlag{
- Name: "conversation",
- Aliases: []string{"c"},
- Usage: "Conversation/Channel ID",
- },
- &cli.StringFlag{
- Name: "sender",
- Aliases: []string{"s"},
- Usage: "Sender user ID",
- },
- &cli.StringFlag{
- Name: "content",
- Aliases: []string{"m"},
- Usage: "Message content",
- },
- },
- },
- {
- Name: "update",
- Usage: "Update a message",
- Action: messageUpdate,
- Flags: []cli.Flag{
- &cli.StringFlag{
- Name: "id",
- Aliases: []string{"i"},
- Usage: "Message ID",
- Required: true,
- },
- &cli.StringFlag{
- Name: "content",
- Aliases: []string{"c"},
- Usage: "Message content",
- },
- },
- },
- {
- Name: "delete",
- Usage: "Delete a message",
- Action: messageDelete,
- Flags: []cli.Flag{
- &cli.StringFlag{
- Name: "id",
- Aliases: []string{"i"},
- Usage: "Message ID",
- Required: true,
- },
- &cli.BoolFlag{
- Name: "yes",
- Aliases: []string{"y"},
- Usage: "Skip confirmation",
- },
- },
- },
- {
- Name: "watch",
- Usage: "Watch for real-time message updates",
- Action: messageWatch,
- },
- },
- }
- }
- type Message struct {
- ID string `json:"id"`
- ConversationID string `json:"conversationId"`
- SenderID string `json:"senderId"`
- Sender *User `json:"sender"`
- Content string `json:"content"`
- SentAt string `json:"sentAt"`
- CreatedAt string `json:"createdAt"`
- UpdatedAt string `json:"updatedAt"`
- }
- func messageList(ctx context.Context, cmd *cli.Command) error {
- cfg, err := config.Load()
- if err != nil {
- return err
- }
- if err := RequireAuth(cfg); err != nil {
- return err
- }
- c := client.New(cfg.ServerURL)
- c.SetToken(cfg.Token)
- query := "query Messages { messages { id conversationId sender { id email } content sentAt createdAt } }"
- resp, err := c.Query(query, nil)
- if err != nil {
- return err
- }
- var result struct {
- Messages []Message `json:"messages"`
- }
- if err := json.Unmarshal(resp.Data, &result); err != nil {
- return err
- }
- if cmd.Bool("json") {
- enc := json.NewEncoder(os.Stdout)
- enc.SetIndent("", " ")
- return enc.Encode(result.Messages)
- }
- if len(result.Messages) == 0 {
- fmt.Println("No messages found.")
- return nil
- }
- table := tablewriter.NewWriter(os.Stdout)
- table.Header([]string{"ID", "Conversation", "Sender", "Content", "Sent At"})
-
- for _, m := range result.Messages {
- sender := ""
- if m.Sender != nil {
- sender = m.Sender.Email
- }
- content := m.Content
- if len(content) > 50 {
- content = content[:47] + "..."
- }
- table.Append([]string{m.ID, m.ConversationID, sender, content, m.SentAt})
- }
- table.Render()
- return nil
- }
- func messageGet(ctx context.Context, cmd *cli.Command) error {
- cfg, err := config.Load()
- if err != nil {
- return err
- }
- if err := RequireAuth(cfg); err != nil {
- return err
- }
- c := client.New(cfg.ServerURL)
- c.SetToken(cfg.Token)
- id := cmd.String("id")
- query := "query Message($id: ID!) { message(id: $id) { id conversationId sender { id email } content sentAt createdAt updatedAt } }"
- resp, err := c.Query(query, map[string]interface{}{"id": id})
- if err != nil {
- return err
- }
- var result struct {
- Message *Message `json:"message"`
- }
- if err := json.Unmarshal(resp.Data, &result); err != nil {
- return err
- }
- if result.Message == nil {
- return fmt.Errorf("message not found")
- }
- if cmd.Bool("json") {
- enc := json.NewEncoder(os.Stdout)
- enc.SetIndent("", " ")
- return enc.Encode(result.Message)
- }
- m := result.Message
- fmt.Printf("ID: %s\n", m.ID)
- fmt.Printf("Conversation ID: %s\n", m.ConversationID)
- if m.Sender != nil {
- fmt.Printf("Sender: %s (%s)\n", m.Sender.Email, m.SenderID)
- } else {
- fmt.Printf("Sender ID: %s\n", m.SenderID)
- }
- fmt.Printf("Content: %s\n", m.Content)
- fmt.Printf("Sent At: %s\n", m.SentAt)
- fmt.Printf("Created At: %s\n", m.CreatedAt)
- fmt.Printf("Updated At: %s\n", m.UpdatedAt)
- return nil
- }
- func messageCreate(ctx context.Context, cmd *cli.Command) error {
- cfg, err := config.Load()
- if err != nil {
- return err
- }
- if err := RequireAuth(cfg); err != nil {
- return err
- }
- conversationID := cmd.String("conversation")
- senderID := cmd.String("sender")
- content := cmd.String("content")
- if conversationID == "" {
- prompt := &survey.Input{Message: "Conversation ID:"}
- if err := survey.AskOne(prompt, &conversationID, survey.WithValidator(survey.Required)); err != nil {
- return err
- }
- }
- if senderID == "" {
- prompt := &survey.Input{Message: "Sender user ID:"}
- if err := survey.AskOne(prompt, &senderID, survey.WithValidator(survey.Required)); err != nil {
- return err
- }
- }
- if content == "" {
- prompt := &survey.Multiline{Message: "Message content:"}
- if err := survey.AskOne(prompt, &content, survey.WithValidator(survey.Required)); err != nil {
- return err
- }
- }
- c := client.New(cfg.ServerURL)
- c.SetToken(cfg.Token)
- mutation := `mutation CreateMessage($input: NewMessage!) { createMessage(input: $input) { id conversationId sender { id email } content sentAt createdAt } }`
- input := map[string]interface{}{
- "conversationId": conversationID,
- "senderId": senderID,
- "content": content,
- }
- resp, err := c.Mutation(mutation, map[string]interface{}{"input": input})
- if err != nil {
- return err
- }
- var result struct {
- CreateMessage *Message `json:"createMessage"`
- }
- if err := json.Unmarshal(resp.Data, &result); err != nil {
- return err
- }
- if result.CreateMessage == nil {
- return fmt.Errorf("failed to create message")
- }
- fmt.Printf("Message created successfully!\n")
- fmt.Printf("ID: %s\n", result.CreateMessage.ID)
- return nil
- }
- func messageUpdate(ctx context.Context, cmd *cli.Command) error {
- cfg, err := config.Load()
- if err != nil {
- return err
- }
- if err := RequireAuth(cfg); err != nil {
- return err
- }
- id := cmd.String("id")
- content := cmd.String("content")
- if content == "" {
- prompt := &survey.Multiline{Message: "New message content:"}
- if err := survey.AskOne(prompt, &content, survey.WithValidator(survey.Required)); err != nil {
- return err
- }
- }
- c := client.New(cfg.ServerURL)
- c.SetToken(cfg.Token)
- input := map[string]interface{}{
- "content": content,
- }
- mutation := `mutation UpdateMessage($id: ID!, $input: UpdateMessageInput!) { updateMessage(id: $id, input: $input) { id content updatedAt } }`
- resp, err := c.Mutation(mutation, map[string]interface{}{"id": id, "input": input})
- if err != nil {
- return err
- }
- var result struct {
- UpdateMessage *Message `json:"updateMessage"`
- }
- if err := json.Unmarshal(resp.Data, &result); err != nil {
- return err
- }
- if result.UpdateMessage == nil {
- return fmt.Errorf("message not found")
- }
- fmt.Printf("Message updated successfully!\n")
- fmt.Printf("ID: %s\n", result.UpdateMessage.ID)
- return nil
- }
- func messageDelete(ctx context.Context, cmd *cli.Command) error {
- cfg, err := config.Load()
- if err != nil {
- return err
- }
- if err := RequireAuth(cfg); err != nil {
- return err
- }
- id := cmd.String("id")
- skipConfirm := cmd.Bool("yes")
- if !skipConfirm {
- confirm := false
- prompt := &survey.Confirm{
- Message: fmt.Sprintf("Are you sure you want to delete message %s?", id),
- Default: false,
- }
- if err := survey.AskOne(prompt, &confirm); err != nil {
- return err
- }
- if !confirm {
- fmt.Println("Deletion cancelled.")
- return nil
- }
- }
- c := client.New(cfg.ServerURL)
- c.SetToken(cfg.Token)
- mutation := `mutation DeleteMessage($id: ID!) { deleteMessage(id: $id) }`
- resp, err := c.Mutation(mutation, map[string]interface{}{"id": id})
- if err != nil {
- return err
- }
- var result struct {
- DeleteMessage bool `json:"deleteMessage"`
- }
- if err := json.Unmarshal(resp.Data, &result); err != nil {
- return err
- }
- if result.DeleteMessage {
- fmt.Printf("Message %s deleted successfully.\n", id)
- } else {
- fmt.Printf("Failed to delete message %s.\n", id)
- }
- return nil
- }
- func messageWatch(ctx context.Context, cmd *cli.Command) error {
- cfg, err := config.Load()
- if err != nil {
- return err
- }
- if err := RequireAuth(cfg); err != nil {
- return err
- }
- wsClient := client.NewWebSocketClient(cfg.ServerURL, cfg.Token)
- if err := wsClient.Connect(); err != nil {
- return fmt.Errorf("failed to connect: %w", err)
- }
- defer wsClient.Close()
- fmt.Println("Watching for new messages...")
- fmt.Println("Press Ctrl+C to stop.")
- subscription := "subscription { messageAdded { id conversationId sender { id email } content sentAt } }"
- if err := wsClient.Subscribe("1", subscription, nil); err != nil {
- return fmt.Errorf("failed to subscribe: %w", err)
- }
- for {
- select {
- case msg := <-wsClient.Messages():
- fmt.Printf("New message: %s\n", string(msg))
- case err := <-wsClient.Errors():
- fmt.Fprintf(os.Stderr, "Error: %v\n", err)
- case <-wsClient.Done():
- return nil
- case <-ctx.Done():
- return nil
- }
- }
- }
|