package keybase import ( "encoding/json" "os/exec" "strings" ) // chatOut holds data to be sent to the Chat API type chatOut struct { Method string `json:"method"` Params chatOutParams `json:"params"` } type Channel struct { Name string `json:"name"` Public bool `json:"public,omitempty"` MembersType string `json:"members_type,omitempty"` TopicType string `json:"topic_type,omitempty"` TopicName string `json:"topic_name,omitempty"` } type chatOutMessage struct { Body string `json:"body"` } type chatOutOptions struct { Channel Channel `json:"channel"` MessageID int `json:"message_id"` Message chatOutMessage `json:"message"` } type chatOutParams struct { Options chatOutOptions `json:"options"` } // chatOutResult holds data received after sending to API type chatOutResult struct { Result ChatOut `json:"result"` } type chatOutResultRatelimits struct { Tank string `json:"tank,omitempty"` Capacity int `json:"capacity,omitempty"` Reset int `json:"reset,omitempty"` Gas int `json:"gas,omitempty"` } type conversation struct { ID string `json:"id"` Channel Channel `json:"channel"` Unread bool `json:"unread"` ActiveAt int `json:"active_at"` ActiveAtMs int64 `json:"active_at_ms"` MemberStatus string `json:"member_status"` } type ChatOut struct { Message string `json:"message,omitempty"` ID int `json:"id,omitempty"` Ratelimits []chatOutResultRatelimits `json:"ratelimits,omitempty"` Conversations []conversation `json:"conversations,omitempty"` Offline bool `json:"offline,omitempty"` } // chatAPIOut sends JSON requests to the chat API and returns its response. func chatAPIOut(keybasePath string, c chatOut) (chatOutResult, error) { jsonBytes, _ := json.Marshal(c) cmd := exec.Command(keybasePath, "chat", "api", "-m", string(jsonBytes)) cmdOut, err := cmd.Output() if err != nil { return chatOutResult{}, err } var r chatOutResult json.Unmarshal(cmdOut, &r) return r, nil } // Send sends a chat message func (c Chat) Send(message ...string) (ChatOut, error) { m := chatOut{} m.Method = "send" m.Params.Options.Channel = c.Channel m.Params.Options.Message.Body = strings.Join(message, " ") r, err := chatAPIOut(c.keybase.Path, m) if err != nil { return ChatOut{}, err } return r.Result, nil } // Edit edits a previously sent chat message func (c Chat) Edit(messageId int, message ...string) (ChatOut, error) { m := chatOut{} m.Method = "edit" m.Params.Options.Channel = c.Channel m.Params.Options.Message.Body = strings.Join(message, " ") m.Params.Options.MessageID = messageId r, err := chatAPIOut(c.keybase.Path, m) if err != nil { return ChatOut{}, err } return r.Result, nil } // React sends a reaction to a message. func (c Chat) React(messageId int, reaction string) (ChatOut, error) { m := chatOut{} m.Method = "reaction" m.Params.Options.Channel = c.Channel m.Params.Options.Message.Body = reaction m.Params.Options.MessageID = messageId r, err := chatAPIOut(c.keybase.Path, m) if err != nil { return ChatOut{}, err } return r.Result, nil } // Delete deletes a chat message func (c Chat) Delete(messageId int) (ChatOut, error) { m := chatOut{} m.Method = "delete" m.Params.Options.Channel = c.Channel m.Params.Options.MessageID = messageId r, err := chatAPIOut(c.keybase.Path, m) if err != nil { return ChatOut{}, err } return r.Result, nil } // ChatList returns a list of all conversations. func (k *Keybase) ChatList() ([]conversation, error) { m := chatOut{} m.Method = "list" r, err := chatAPIOut(k.Path, m) return r.Result.Conversations, err }