aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Auvolat <alex@adnab.me>2020-03-09 17:41:53 +0100
committerAlex Auvolat <alex@adnab.me>2020-03-09 17:41:53 +0100
commitf9e0c58f3c0e90b987b7763f020ea5dcbf366779 (patch)
treeda02fdd4d02ec2631736757e3fc2cf8dbbd3e2d5
parent0d6fa02a782a5679716a0244098697af756d0699 (diff)
downloadeasybridge-f9e0c58f3c0e90b987b7763f020ea5dcbf366779.tar.gz
easybridge-f9e0c58f3c0e90b987b7763f020ea5dcbf366779.zip
Fix revUserId (messenger) and implement search (messenger only for now)
-rw-r--r--connector/connector.go8
-rw-r--r--connector/external/external.go29
-rw-r--r--connector/irc/irc.go5
-rw-r--r--connector/mattermost/mattermost.go5
-rw-r--r--connector/xmpp/xmpp.go5
-rwxr-xr-xexternal/messenger.py29
-rw-r--r--server.go16
7 files changed, 86 insertions, 11 deletions
diff --git a/connector/connector.go b/connector/connector.go
index 48fc9e7..c2edda4 100644
--- a/connector/connector.go
+++ b/connector/connector.go
@@ -59,6 +59,9 @@ type Connector interface {
// Leave a channel
Leave(roomId RoomID)
+ // Search for users
+ SearchForUsers(query string) ([]UserSearchResult, error)
+
// Send an event. Returns the ID of the created remote message.
// This ID is used to deduplicate messages: if it comes back, it should have the same Id
// than the one returned here.
@@ -153,6 +156,11 @@ type RoomInfo struct {
Picture SMediaObject `json:"picture"`
}
+type UserSearchResult struct {
+ ID UserID `json:"id"`
+ DisplayName string `json:"display_name"`
+}
+
type MediaObject interface {
Filename() string
Size() int64
diff --git a/connector/external/external.go b/connector/external/external.go
index 637e69e..c40d55b 100644
--- a/connector/external/external.go
+++ b/connector/external/external.go
@@ -49,6 +49,7 @@ const (
JOIN = "join"
INVITE = "invite"
LEAVE = "leave"
+ SEARCH = "search"
SEND = "send"
CLOSE = "close"
@@ -64,8 +65,9 @@ const (
// reply messages
// ezbr -> external: all must wait for a reply!
// external -> ezbr: only CACHE_GET produces a reply
- REP_OK = "rep_ok"
- REP_ERROR = "rep_error"
+ REP_OK = "rep_ok"
+ REP_SEARCH_RESULTS = "rep_search_results"
+ REP_ERROR = "rep_error"
)
// ----
@@ -226,6 +228,16 @@ func (m *extMessageWithData) UnmarshalJSON(jj []byte) error {
}
m.Data = &ev.Data
return nil
+ case REP_SEARCH_RESULTS:
+ var ev struct {
+ Data []UserSearchResult `json:"data"`
+ }
+ err := json.Unmarshal(jj, &ev)
+ if err != nil {
+ return err
+ }
+ m.Data = ev.Data
+ return nil
case JOINED, LEFT, CACHE_PUT, CACHE_GET, REP_OK, REP_ERROR:
return nil
default:
@@ -428,6 +440,19 @@ func (ext *External) Leave(room RoomID) {
}
}
+func (ext *External) SearchForUsers(query string) ([]UserSearchResult, error) {
+ rep, err := ext.cmd(extMessage{
+ MsgType: SEARCH,
+ }, query)
+ if err != nil {
+ return nil, err
+ }
+ if rep.MsgType != REP_SEARCH_RESULTS {
+ return nil, fmt.Errorf("Invalid result type from external: %s", rep.MsgType)
+ }
+ return rep.Data.([]UserSearchResult), nil
+}
+
func (ext *External) Send(event *Event) (string, error) {
rep, err := ext.cmd(extMessage{
MsgType: SEND,
diff --git a/connector/irc/irc.go b/connector/irc/irc.go
index bf36dfe..cf93893 100644
--- a/connector/irc/irc.go
+++ b/connector/irc/irc.go
@@ -198,6 +198,11 @@ func (irc *IRC) Leave(roomId RoomID) {
irc.conn.Cmd.Part(ch)
}
+func (irc *IRC) SearchForUsers(query string) ([]UserSearchResult, error) {
+ // TODO
+ return nil, fmt.Errorf("Not implemented")
+}
+
func (irc *IRC) Send(event *Event) (string, error) {
if irc.conn == nil {
return "", fmt.Errorf("Not connected")
diff --git a/connector/mattermost/mattermost.go b/connector/mattermost/mattermost.go
index 9410126..4490f2a 100644
--- a/connector/mattermost/mattermost.go
+++ b/connector/mattermost/mattermost.go
@@ -253,6 +253,11 @@ func (mm *Mattermost) Leave(roomId RoomID) {
// Not supported? TODO
}
+func (mm *Mattermost) SearchForUsers(query string) ([]UserSearchResult, error) {
+ // TODO
+ return nil, fmt.Errorf("Not implemented")
+}
+
func (mm *Mattermost) Send(event *Event) (string, error) {
post := &model.Post{
Message: event.Text,
diff --git a/connector/xmpp/xmpp.go b/connector/xmpp/xmpp.go
index 1f77fdf..483c75e 100644
--- a/connector/xmpp/xmpp.go
+++ b/connector/xmpp/xmpp.go
@@ -306,6 +306,11 @@ func (xm *XMPP) Leave(roomId RoomID) {
xm.conn.LeaveMUC(string(roomId))
}
+func (xm *XMPP) SearchForUsers(query string) ([]UserSearchResult, error) {
+ // TODO: search roster
+ return nil, fmt.Errorf("Not implemented")
+}
+
func (xm *XMPP) Send(event *Event) (string, error) {
if event.Attachments != nil && len(event.Attachments) > 0 {
for _, at := range event.Attachments {
diff --git a/external/messenger.py b/external/messenger.py
index 9874b5b..6da4808 100755
--- a/external/messenger.py
+++ b/external/messenger.py
@@ -1,8 +1,6 @@
#!/usr/bin/env python3
-# @FIXME: make revUserId work correctly (e.g.: talking to a contact not in your top 20 recent threads will fail) - could we do this with a search request?
# @FIXME: store the client pickle in the config automatically
-# @FIXME: add a way to search for users and initiate a discussion
import sys
import json
@@ -31,6 +29,7 @@ SET_ROOM_INFO = "set_room_info"
JOIN = "join"
INVITE = "invite"
LEAVE = "leave"
+SEARCH = "search"
SEND = "send"
CLOSE = "close"
@@ -47,6 +46,7 @@ CACHE_GET = "cache_get"
# ezbr -> external: all must wait for a reply!
# external -> ezbr: only CACHE_GET produces a reply
REP_OK = "rep_ok"
+REP_SEARCH_RESULTS = "rep_search_results"
REP_ERROR = "rep_error"
# Event types
@@ -168,13 +168,14 @@ class MessengerBridge:
return self.getUserId(user)
def revUserId(self, user_id):
- if user_id in self.rev_uid:
- return self.rev_uid[user_id]
- else:
- # TODO this doesn't work always...
- # we should try to find the api endpoint that resolves usernames ?
- # or do a search request and try to find a user that has that username
- return user_id
+ if user_id not in self.rev_uid:
+ for user in self.client.searchForUsers(user_id):
+ self.getUserId(user)
+
+ if user_id not in self.rev_uid:
+ raise ValueError("User not found: {}".format(user_id))
+
+ return self.rev_uid[user_id]
def getUserShortName(self, user):
if user.first_name != None:
@@ -277,6 +278,16 @@ class MessengerBridge:
uid = self.revUserId(cmd["user"])
self.client.addUsersToGroup([uid], cmd["room"])
+ elif ty == SEARCH:
+ users = self.client.searchForUsers(cmd["data"])
+ rep = []
+ for user in users:
+ rep.append({
+ "id": self.getUserId(user),
+ "display_name": user.name,
+ })
+ return {"_type": REP_SEARCH_RESULTS, "data": rep}
+
elif ty == SEND:
event = cmd["data"]
if event["type"] in [EVENT_MESSAGE, EVENT_ACTION]:
diff --git a/server.go b/server.go
index 294ad7f..84b1893 100644
--- a/server.go
+++ b/server.go
@@ -228,6 +228,7 @@ func handleSystemMessage(mxid string, msg string) {
ezbrSystemSend(mxid, "- accounts: list accounts")
ezbrSystemSend(mxid, "- join <protocol or account> <room id>: join public chat room")
ezbrSystemSend(mxid, "- talk <protocol or account> <user id>: open private conversation to contact")
+ ezbrSystemSend(mxid, "- search <protocol or account> <name>: search for users by name")
case "list", "account", "accounts":
one := false
if accts, ok := registeredAccounts[mxid]; ok {
@@ -271,6 +272,21 @@ func handleSystemMessage(mxid string, msg string) {
} else {
ezbrSystemSendf(mxid, "No account with name or using protocol %s", cmd[1])
}
+ case "search":
+ account := findAccount(mxid, cmd[1])
+ if account != nil {
+ rep, err := account.Conn.SearchForUsers(cmd[2])
+ if err != nil {
+ ezbrSystemSendf(mxid, "Search error: %s", err)
+ } else {
+ ezbrSystemSendf(mxid, "%d users found", len(rep))
+ for i, user := range rep {
+ ezbrSystemSendf(mxid, "- %s (%s)", i+1, user.DisplayName, user.ID)
+ }
+ }
+ } else {
+ ezbrSystemSendf(mxid, "No account with name or using protocol %s", cmd[1])
+ }
default:
ezbrSystemSend(mxid, "Unrecognized command. Type `help` if you need some help!")
}