Add support for incoming messages. This breaks NewChat() in previous versions
This commit is contained in:
55
chatIn.go
55
chatIn.go
@ -1,19 +1,17 @@
|
|||||||
package keybase
|
package keybase
|
||||||
|
|
||||||
import ()
|
import (
|
||||||
|
"bufio"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"os/exec"
|
||||||
|
)
|
||||||
|
|
||||||
type chatIn struct {
|
type ChatIn struct {
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
Source string `json:"source"`
|
Source string `json:"source"`
|
||||||
Msg chatInMsg `json:"msg"`
|
Msg chatInMsg `json:"msg"`
|
||||||
}
|
}
|
||||||
type chatInChannel struct {
|
|
||||||
Name string `json:"name"`
|
|
||||||
Public bool `json:"public"`
|
|
||||||
MembersType string `json:"members_type"`
|
|
||||||
TopicType string `json:"topic_type"`
|
|
||||||
TopicName string `json:"topic_name"`
|
|
||||||
}
|
|
||||||
type chatInSender struct {
|
type chatInSender struct {
|
||||||
UID string `json:"uid"`
|
UID string `json:"uid"`
|
||||||
Username string `json:"username"`
|
Username string `json:"username"`
|
||||||
@ -84,7 +82,7 @@ type chatInContent struct {
|
|||||||
}
|
}
|
||||||
type chatInMsg struct {
|
type chatInMsg struct {
|
||||||
ID int `json:"id"`
|
ID int `json:"id"`
|
||||||
Channel chatInChannel `json:"channel"`
|
Channel Channel `json:"channel"`
|
||||||
Sender chatInSender `json:"sender"`
|
Sender chatInSender `json:"sender"`
|
||||||
SentAt int `json:"sent_at"`
|
SentAt int `json:"sent_at"`
|
||||||
SentAtMs int64 `json:"sent_at_ms"`
|
SentAtMs int64 `json:"sent_at_ms"`
|
||||||
@ -96,3 +94,40 @@ type chatInMsg struct {
|
|||||||
HasPairwiseMacs bool `json:"has_pairwise_macs"`
|
HasPairwiseMacs bool `json:"has_pairwise_macs"`
|
||||||
ChannelMention string `json:"channel_mention"`
|
ChannelMention string `json:"channel_mention"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Creates a string of json-encoded channels to pass to keybase chat api-listen --filter-channels
|
||||||
|
func createFilterString(channelFilters ...Channel) string {
|
||||||
|
if len(channelFilters) == 0 {
|
||||||
|
return "[]"
|
||||||
|
}
|
||||||
|
|
||||||
|
jsonBytes, _ := json.Marshal(channelFilters)
|
||||||
|
return fmt.Sprintf("%s", string(jsonBytes))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get new messages coming into keybase and send them into the channel
|
||||||
|
func getNewMessages(k Keybase, c chan<- ChatIn, filterString string) {
|
||||||
|
keybaseListen := exec.Command(k.Path, "chat", "api-listen", "--filter-channels", filterString)
|
||||||
|
keybaseOutput, _ := keybaseListen.StdoutPipe()
|
||||||
|
keybaseListen.Start()
|
||||||
|
scanner := bufio.NewScanner(keybaseOutput)
|
||||||
|
var jsonData ChatIn
|
||||||
|
|
||||||
|
for scanner.Scan() {
|
||||||
|
json.Unmarshal([]byte(scanner.Text()), &jsonData)
|
||||||
|
c <- jsonData
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Runner() runs keybase chat api-listen, and passes incoming messages to the message handler func
|
||||||
|
func (k Keybase) Runner(handler func(ChatIn), channelFilters ...Channel) {
|
||||||
|
c := make(chan ChatIn, 10)
|
||||||
|
defer close(c)
|
||||||
|
go getNewMessages(k, c, createFilterString(channelFilters...))
|
||||||
|
for {
|
||||||
|
chat, ok := <-c
|
||||||
|
if ok {
|
||||||
|
go handler(chat)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
43
chatOut.go
43
chatOut.go
@ -7,21 +7,22 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// ---- Struct for sending to API
|
// ---- Struct for sending to API
|
||||||
type chatOut struct { // not exported
|
type chatOut struct {
|
||||||
Method string `json:"method"`
|
Method string `json:"method"`
|
||||||
Params chatOutParams `json:"params"`
|
Params chatOutParams `json:"params"`
|
||||||
}
|
}
|
||||||
type chatOutChannel struct {
|
type Channel struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Public bool `json:"public"`
|
Public bool `json:"public,omitempty"`
|
||||||
MembersType string `json:"members_type"`
|
MembersType string `json:"members_type,omitempty"`
|
||||||
TopicName string `json:"topic_name"`
|
TopicType string `json:"topic_type,omitempty"`
|
||||||
|
TopicName string `json:"topic_name,omitempty"`
|
||||||
}
|
}
|
||||||
type chatOutMessage struct {
|
type chatOutMessage struct {
|
||||||
Body string `json:"body"`
|
Body string `json:"body"`
|
||||||
}
|
}
|
||||||
type chatOutOptions struct {
|
type chatOutOptions struct {
|
||||||
Channel chatOutChannel `json:"channel"`
|
Channel Channel `json:"channel"`
|
||||||
MessageID int `json:"message_id"`
|
MessageID int `json:"message_id"`
|
||||||
Message chatOutMessage `json:"message"`
|
Message chatOutMessage `json:"message"`
|
||||||
}
|
}
|
||||||
@ -41,22 +42,15 @@ type chatOutResultRatelimits struct {
|
|||||||
Reset int `json:"reset,omitempty"`
|
Reset int `json:"reset,omitempty"`
|
||||||
Gas int `json:"gas,omitempty"`
|
Gas int `json:"gas,omitempty"`
|
||||||
}
|
}
|
||||||
type chatOutResultChannel struct {
|
|
||||||
Name string `json:"name"`
|
|
||||||
Public bool `json:"public"`
|
|
||||||
MembersType string `json:"members_type"`
|
|
||||||
TopicType string `json:"topic_type,omitempty"`
|
|
||||||
TopicName string `json:"topic_name,omitempty"`
|
|
||||||
}
|
|
||||||
type conversation struct {
|
type conversation struct {
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
Channel chatOutResultChannel `json:"channel"`
|
Channel Channel `json:"channel"`
|
||||||
Unread bool `json:"unread"`
|
Unread bool `json:"unread"`
|
||||||
ActiveAt int `json:"active_at"`
|
ActiveAt int `json:"active_at"`
|
||||||
ActiveAtMs int64 `json:"active_at_ms"`
|
ActiveAtMs int64 `json:"active_at_ms"`
|
||||||
MemberStatus string `json:"member_status"`
|
MemberStatus string `json:"member_status"`
|
||||||
}
|
}
|
||||||
type ChatOut struct { // exported
|
type ChatOut struct {
|
||||||
Message string `json:"message,omitempty"`
|
Message string `json:"message,omitempty"`
|
||||||
ID int `json:"id,omitempty"`
|
ID int `json:"id,omitempty"`
|
||||||
Ratelimits []chatOutResultRatelimits `json:"ratelimits,omitempty"`
|
Ratelimits []chatOutResultRatelimits `json:"ratelimits,omitempty"`
|
||||||
@ -86,10 +80,7 @@ func chatAPIOut(keybasePath string, c chatOut) (chatOutResult, error) {
|
|||||||
func (c Chat) Send(message ...string) (ChatOut, error) {
|
func (c Chat) Send(message ...string) (ChatOut, error) {
|
||||||
m := chatOut{}
|
m := chatOut{}
|
||||||
m.Method = "send"
|
m.Method = "send"
|
||||||
m.Params.Options.Channel.Name = c.Name
|
m.Params.Options.Channel = c.Channel
|
||||||
m.Params.Options.Channel.Public = c.Public
|
|
||||||
m.Params.Options.Channel.MembersType = c.MembersType
|
|
||||||
m.Params.Options.Channel.TopicName = c.TopicName
|
|
||||||
m.Params.Options.Message.Body = strings.Join(message, " ")
|
m.Params.Options.Message.Body = strings.Join(message, " ")
|
||||||
|
|
||||||
r, err := chatAPIOut(c.keybase.Path, m)
|
r, err := chatAPIOut(c.keybase.Path, m)
|
||||||
@ -103,10 +94,7 @@ func (c Chat) Send(message ...string) (ChatOut, error) {
|
|||||||
func (c Chat) Edit(messageId int, message ...string) (ChatOut, error) {
|
func (c Chat) Edit(messageId int, message ...string) (ChatOut, error) {
|
||||||
m := chatOut{}
|
m := chatOut{}
|
||||||
m.Method = "edit"
|
m.Method = "edit"
|
||||||
m.Params.Options.Channel.Name = c.Name
|
m.Params.Options.Channel = c.Channel
|
||||||
m.Params.Options.Channel.Public = c.Public
|
|
||||||
m.Params.Options.Channel.MembersType = c.MembersType
|
|
||||||
m.Params.Options.Channel.TopicName = c.TopicName
|
|
||||||
m.Params.Options.Message.Body = strings.Join(message, " ")
|
m.Params.Options.Message.Body = strings.Join(message, " ")
|
||||||
m.Params.Options.MessageID = messageId
|
m.Params.Options.MessageID = messageId
|
||||||
|
|
||||||
@ -121,9 +109,7 @@ func (c Chat) Edit(messageId int, message ...string) (ChatOut, error) {
|
|||||||
func (c Chat) React(messageId int, reaction string) (ChatOut, error) {
|
func (c Chat) React(messageId int, reaction string) (ChatOut, error) {
|
||||||
m := chatOut{}
|
m := chatOut{}
|
||||||
m.Method = "reaction"
|
m.Method = "reaction"
|
||||||
m.Params.Options.Channel.Name = c.Name
|
m.Params.Options.Channel = c.Channel
|
||||||
m.Params.Options.Channel.MembersType = c.MembersType
|
|
||||||
m.Params.Options.Channel.TopicName = c.TopicName
|
|
||||||
m.Params.Options.Message.Body = reaction
|
m.Params.Options.Message.Body = reaction
|
||||||
m.Params.Options.MessageID = messageId
|
m.Params.Options.MessageID = messageId
|
||||||
|
|
||||||
@ -138,10 +124,7 @@ func (c Chat) React(messageId int, reaction string) (ChatOut, error) {
|
|||||||
func (c Chat) Delete(messageId int) (ChatOut, error) {
|
func (c Chat) Delete(messageId int) (ChatOut, error) {
|
||||||
m := chatOut{}
|
m := chatOut{}
|
||||||
m.Method = "delete"
|
m.Method = "delete"
|
||||||
m.Params.Options.Channel.Name = c.Name
|
m.Params.Options.Channel = c.Channel
|
||||||
m.Params.Options.Channel.Public = c.Public
|
|
||||||
m.Params.Options.Channel.MembersType = c.MembersType
|
|
||||||
m.Params.Options.Channel.TopicName = c.TopicName
|
|
||||||
m.Params.Options.MessageID = messageId
|
m.Params.Options.MessageID = messageId
|
||||||
|
|
||||||
r, err := chatAPIOut(c.keybase.Path, m)
|
r, err := chatAPIOut(c.keybase.Path, m)
|
||||||
|
|||||||
44
keybase.go
44
keybase.go
@ -25,17 +25,10 @@ type Keybase struct {
|
|||||||
Version string
|
Version string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Channel is a map of options that can be passed to NewChat()
|
|
||||||
type Channel map[string]interface{}
|
|
||||||
|
|
||||||
// Chat holds basic information about a specific conversation
|
// Chat holds basic information about a specific conversation
|
||||||
type Chat struct {
|
type Chat struct {
|
||||||
keybase Keybase
|
keybase Keybase
|
||||||
Name string
|
Channel Channel
|
||||||
Public bool
|
|
||||||
MembersType string
|
|
||||||
TopicName string
|
|
||||||
TopicType string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type chat interface {
|
type chat interface {
|
||||||
@ -46,7 +39,8 @@ type chat interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type keybase interface {
|
type keybase interface {
|
||||||
NewChat(channel map[string]interface{}) Chat
|
NewChat(channel Channel) Chat
|
||||||
|
Runner(handler func(ChatIn), channelFilters ...Channel)
|
||||||
ChatList() ([]conversation, error)
|
ChatList() ([]conversation, error)
|
||||||
loggedIn() bool
|
loggedIn() bool
|
||||||
username() string
|
username() string
|
||||||
@ -75,35 +69,11 @@ func NewKeybase(path ...string) Keybase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Return a new Chat instance
|
// Return a new Chat instance
|
||||||
func (k Keybase) NewChat(channel map[string]interface{}) Chat {
|
func (k Keybase) NewChat(channel Channel) Chat {
|
||||||
var c Chat = Chat{}
|
return Chat{
|
||||||
c.keybase = k
|
keybase: k,
|
||||||
if value, ok := channel["Name"].(string); ok == true {
|
Channel: channel,
|
||||||
c.Name = value
|
|
||||||
}
|
}
|
||||||
if value, ok := channel["Public"].(bool); ok == true {
|
|
||||||
c.Public = value
|
|
||||||
} else {
|
|
||||||
c.Public = false
|
|
||||||
}
|
|
||||||
if value, ok := channel["MembersType"].(string); ok == true {
|
|
||||||
c.MembersType = value
|
|
||||||
} else {
|
|
||||||
c.MembersType = USER
|
|
||||||
}
|
|
||||||
if value, ok := channel["TopicName"].(string); ok == true {
|
|
||||||
c.TopicName = value
|
|
||||||
} else {
|
|
||||||
if c.MembersType == TEAM {
|
|
||||||
c.TopicName = "general"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if value, ok := channel["TopicType"].(string); ok == true {
|
|
||||||
c.TopicType = value
|
|
||||||
} else {
|
|
||||||
c.TopicType = CHAT
|
|
||||||
}
|
|
||||||
return c
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// username() returns the username of the currently logged-in Keybase user.
|
// username() returns the username of the currently logged-in Keybase user.
|
||||||
|
|||||||
Reference in New Issue
Block a user