From 7c39436eda59efb033d172dfa03af3782f0acacf Mon Sep 17 00:00:00 2001 From: Alex Auvolat Date: Mon, 9 Mar 2020 18:02:13 +0100 Subject: [PATCH] Save client pickle automatically (messenger) --- account.go | 81 ++++++++++++++++++++-------------- connector/connector.go | 3 ++ connector/external/external.go | 19 ++++++-- external/messenger.py | 13 ++++-- 4 files changed, 76 insertions(+), 40 deletions(-) diff --git a/account.go b/account.go index da6e854..7071397 100644 --- a/account.go +++ b/account.go @@ -39,41 +39,40 @@ func SetAccount(mxid string, name string, protocol string, config map[string]str } accounts := registeredAccounts[mxid] - if prev_acct, ok := accounts[name]; ok { - if protocol != prev_acct.Protocol { - return fmt.Errorf("Wrong protocol") - } - if !reflect.DeepEqual(config, prev_acct.Config) { - go func() { - prev_acct.Conn.Close() - prev_acct.JoinedRooms = map[RoomID]bool{} - - prev_acct.Config = config - prev_acct.connect() - }() - } - } else { - proto, ok := Protocols[protocol] - if !ok { - return fmt.Errorf("Invalid protocol: %s", protocol) - } - conn := proto.NewConnector() - if conn == nil { - return fmt.Errorf("Could not create connector for protocol %s", protocol) - } - account := &Account{ - MatrixUser: mxid, - AccountName: name, - Protocol: protocol, - Config: config, - Conn: conn, - JoinedRooms: map[RoomID]bool{}, - } - conn.SetHandler(account) - - accounts[name] = account - go account.connect() + // Check we can create connector + proto, ok := Protocols[protocol] + if !ok { + return fmt.Errorf("Invalid protocol: %s", protocol) } + conn := proto.NewConnector() + if conn == nil { + return fmt.Errorf("Could not create connector for protocol %s", protocol) + } + + // If the account existed already, close and drop connector + if prev_acct, ok := accounts[name]; ok { + if prev_acct.Protocol == protocol && reflect.DeepEqual(config, prev_acct.Config) { + return nil + } + + go prev_acct.Conn.Close() + delete(accounts, name) + } + + // Configure and connect + account := &Account{ + MatrixUser: mxid, + AccountName: name, + Protocol: protocol, + Config: config, + Conn: conn, + JoinedRooms: map[RoomID]bool{}, + } + conn.SetHandler(account) + + accounts[name] = account + go account.connect() + return nil } @@ -232,6 +231,20 @@ func (a *Account) delAutojoin(roomId RoomID) { // ---- Begin event handlers ---- +func (a *Account) SaveConfig(config Configuration) { + a.Config = config + if key, ok := userKeys[a.MatrixUser]; ok { + var entry DbAccountConfig + db.Where(&DbAccountConfig{ + MxUserID: a.MatrixUser, + Name: a.AccountName, + }).Assign(&DbAccountConfig{ + Protocol: a.Protocol, + Config: encryptAccountConfig(a.Config, key), + }).FirstOrCreate(&entry) + } +} + func (a *Account) Joined(roomId RoomID) { err := a.joinedInternal(roomId) if err != nil { diff --git a/connector/connector.go b/connector/connector.go index c2edda4..fd49c7e 100644 --- a/connector/connector.go +++ b/connector/connector.go @@ -76,6 +76,9 @@ type Connector interface { } type Handler interface { + // Called to save updated configuration parameters + SaveConfig(config Configuration) + // Called when a room was joined (automatically or by call to Connector.Join) Joined(roomId RoomID) diff --git a/connector/external/external.go b/connector/external/external.go index c40d55b..9aae0f1 100644 --- a/connector/external/external.go +++ b/connector/external/external.go @@ -54,6 +54,7 @@ const ( CLOSE = "close" // external -> ezbr + SAVE_CONFIG = "save_config" JOINED = "joined" LEFT = "left" USER_INFO_UPDATED = "user_info_updated" @@ -198,6 +199,16 @@ func (m *extMessageWithData) UnmarshalJSON(jj []byte) error { } *m = extMessageWithData{extMessage: c} switch c.MsgType { + case SAVE_CONFIG: + var cf struct { + Data Configuration `json:"data"` + } + err := json.Unmarshal(jj, &cf) + if err != nil { + return err + } + m.Data = cf.Data + return nil case USER_INFO_UPDATED: var ui struct { Data UserInfo `json:"data"` @@ -229,14 +240,14 @@ func (m *extMessageWithData) UnmarshalJSON(jj []byte) error { m.Data = &ev.Data return nil case REP_SEARCH_RESULTS: - var ev struct { + var sr struct { Data []UserSearchResult `json:"data"` } - err := json.Unmarshal(jj, &ev) + err := json.Unmarshal(jj, &sr) if err != nil { return err } - m.Data = ev.Data + m.Data = sr.Data return nil case JOINED, LEFT, CACHE_PUT, CACHE_GET, REP_OK, REP_ERROR: return nil @@ -364,6 +375,8 @@ func (ext *External) Close() { func (ext *External) handleCmd(msg *extMessageWithData) { switch msg.MsgType { + case SAVE_CONFIG: + ext.handler.SaveConfig(msg.Data.(Configuration)) case JOINED: ext.handler.Joined(msg.Room) case LEFT: diff --git a/external/messenger.py b/external/messenger.py index 6da4808..e45a45e 100755 --- a/external/messenger.py +++ b/external/messenger.py @@ -1,7 +1,5 @@ #!/usr/bin/env python3 -# @FIXME: store the client pickle in the config automatically - import sys import json import signal @@ -34,6 +32,7 @@ SEND = "send" CLOSE = "close" # external -> ezbr +SAVE_CONFIG = "save_config" JOINED = "joined" LEFT = "left" USER_INFO_UPDATED = "user_info_updated" @@ -228,7 +227,8 @@ class MessengerBridge: if ty == CONFIGURE: self.init_backlog_length = int(cmd["data"]["initial_backlog"]) - if "client_pickle" in cmd["data"] and len(cmd["data"]["client_pickle"]) > 0: + has_pickle = "client_pickle" in cmd["data"] and len(cmd["data"]["client_pickle"]) > 0 + if has_pickle: data = base64.b64decode(cmd["data"]["client_pickle"]) data = zlib.decompress(data) self.client = pickle.loads(data) @@ -240,6 +240,13 @@ class MessengerBridge: if not self.client.isLoggedIn(): return {"_type": REP_ERROR, "error": "Unable to login (invalid pickle?)"} + if not has_pickle: + new_config = cmd["data"] + data = pickle.dumps(self.client) + data = zlib.compress(data) + new_config["client_pickle"] = base64.b64encode(data).decode('ascii') + self.write({"_type": SAVE_CONFIG, "data": new_config}) + self.client.setBridge(self) self.my_user_id = self.getUserIdFromUid(self.client.uid)