Update go-whatsapp to break everything and maybe improve things
This commit is contained in:
parent
ca118e8678
commit
7bd47fabb2
10 changed files with 173 additions and 153 deletions
47
commands.go
47
commands.go
|
@ -17,6 +17,7 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
|
@ -254,7 +255,7 @@ func (handler *CommandHandler) CommandJoin(ce *CommandEvent) {
|
||||||
handler.log.Debugln("%s successfully joined group %s", ce.User.MXID, jid)
|
handler.log.Debugln("%s successfully joined group %s", ce.User.MXID, jid)
|
||||||
portal := handler.bridge.GetPortalByJID(database.GroupPortalKey(jid))
|
portal := handler.bridge.GetPortalByJID(database.GroupPortalKey(jid))
|
||||||
if len(portal.MXID) > 0 {
|
if len(portal.MXID) > 0 {
|
||||||
portal.Sync(ce.User, whatsapp.Contact{Jid: portal.Key.JID})
|
portal.Sync(ce.User, whatsapp.Contact{JID: portal.Key.JID})
|
||||||
ce.Reply("Successfully joined group \"%s\" and synced portal room: [%s](https://matrix.to/#/%s)", portal.Name, portal.Name, portal.MXID)
|
ce.Reply("Successfully joined group \"%s\" and synced portal room: [%s](https://matrix.to/#/%s)", portal.Name, portal.Name, portal.MXID)
|
||||||
} else {
|
} else {
|
||||||
err = portal.CreateMatrixRoom(ce.User)
|
err = portal.CreateMatrixRoom(ce.User)
|
||||||
|
@ -411,11 +412,11 @@ func (handler *CommandHandler) CommandLogout(ce *CommandEvent) {
|
||||||
ce.Reply("Unknown error while logging out: %v", err)
|
ce.Reply("Unknown error while logging out: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ce.User.Disconnect()
|
|
||||||
ce.User.removeFromJIDMap()
|
ce.User.removeFromJIDMap()
|
||||||
// TODO this causes a foreign key violation, which should be fixed
|
// TODO this causes a foreign key violation, which should be fixed
|
||||||
//ce.User.JID = ""
|
//ce.User.JID = ""
|
||||||
ce.User.SetSession(nil)
|
ce.User.SetSession(nil)
|
||||||
|
ce.User.DeleteConnection()
|
||||||
ce.Reply("Logged out successfully.")
|
ce.Reply("Logged out successfully.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -469,9 +470,10 @@ func (handler *CommandHandler) CommandDeleteSession(ce *CommandEvent) {
|
||||||
ce.Reply("Nothing to purge: no session information stored and no active connection.")
|
ce.Reply("Nothing to purge: no session information stored and no active connection.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ce.User.Disconnect()
|
//ce.User.JID = ""
|
||||||
ce.User.removeFromJIDMap()
|
ce.User.removeFromJIDMap()
|
||||||
ce.User.SetSession(nil)
|
ce.User.SetSession(nil)
|
||||||
|
ce.User.DeleteConnection()
|
||||||
ce.Reply("Session information purged")
|
ce.Reply("Session information purged")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -489,24 +491,21 @@ func (handler *CommandHandler) CommandReconnect(ce *CommandEvent) {
|
||||||
}
|
}
|
||||||
|
|
||||||
wasConnected := true
|
wasConnected := true
|
||||||
sess, err := ce.User.Conn.Disconnect()
|
err := ce.User.Conn.Disconnect()
|
||||||
if err == whatsapp.ErrNotConnected {
|
if err == whatsapp.ErrNotConnected {
|
||||||
wasConnected = false
|
wasConnected = false
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
ce.User.log.Warnln("Error while disconnecting:", err)
|
ce.User.log.Warnln("Error while disconnecting:", err)
|
||||||
} else {
|
|
||||||
ce.User.SetSession(&sess)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
err = ce.User.Conn.Restore(true)
|
ctx := context.Background()
|
||||||
|
|
||||||
|
err = ce.User.Conn.Restore(true, ctx)
|
||||||
if err == whatsapp.ErrInvalidSession {
|
if err == whatsapp.ErrInvalidSession {
|
||||||
if ce.User.Session != nil {
|
if ce.User.Session != nil {
|
||||||
ce.User.log.Debugln("Got invalid session error when reconnecting, but user has session. Retrying using RestoreWithSession()...")
|
ce.User.log.Debugln("Got invalid session error when reconnecting, but user has session. Retrying using RestoreWithSession()...")
|
||||||
var sess whatsapp.Session
|
ce.User.Conn.SetSession(*ce.User.Session)
|
||||||
sess, err = ce.User.Conn.RestoreWithSession(*ce.User.Session)
|
err = ce.User.Conn.Restore(true, ctx)
|
||||||
if err == nil {
|
|
||||||
ce.User.SetSession(&sess)
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
ce.Reply("You are not logged in.")
|
ce.Reply("You are not logged in.")
|
||||||
return
|
return
|
||||||
|
@ -520,17 +519,11 @@ func (handler *CommandHandler) CommandReconnect(ce *CommandEvent) {
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ce.User.log.Warnln("Error while reconnecting:", err)
|
ce.User.log.Warnln("Error while reconnecting:", err)
|
||||||
if errors.Is(err, whatsapp.ErrRestoreSessionTimeout) {
|
|
||||||
ce.Reply("Reconnection timed out. Is WhatsApp on your phone reachable?")
|
|
||||||
} else {
|
|
||||||
ce.Reply("Unknown error while reconnecting: %v", err)
|
ce.Reply("Unknown error while reconnecting: %v", err)
|
||||||
}
|
|
||||||
ce.User.log.Debugln("Disconnecting due to failed session restore in reconnect command...")
|
ce.User.log.Debugln("Disconnecting due to failed session restore in reconnect command...")
|
||||||
sess, err = ce.User.Conn.Disconnect()
|
err = ce.User.Conn.Disconnect()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ce.User.log.Errorln("Failed to disconnect after failed session restore in reconnect command:", err)
|
ce.User.log.Errorln("Failed to disconnect after failed session restore in reconnect command:", err)
|
||||||
} else {
|
|
||||||
ce.User.SetSession(&sess)
|
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -553,7 +546,7 @@ func (handler *CommandHandler) CommandDeleteConnection(ce *CommandEvent) {
|
||||||
ce.Reply("You don't have a WhatsApp connection.")
|
ce.Reply("You don't have a WhatsApp connection.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ce.User.Disconnect()
|
ce.User.DeleteConnection()
|
||||||
ce.Reply("Successfully disconnected. Use the `reconnect` command to reconnect.")
|
ce.Reply("Successfully disconnected. Use the `reconnect` command to reconnect.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -564,7 +557,7 @@ func (handler *CommandHandler) CommandDisconnect(ce *CommandEvent) {
|
||||||
ce.Reply("You don't have a WhatsApp connection.")
|
ce.Reply("You don't have a WhatsApp connection.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
sess, err := ce.User.Conn.Disconnect()
|
err := ce.User.Conn.Disconnect()
|
||||||
if err == whatsapp.ErrNotConnected {
|
if err == whatsapp.ErrNotConnected {
|
||||||
ce.Reply("You were not connected.")
|
ce.Reply("You were not connected.")
|
||||||
return
|
return
|
||||||
|
@ -572,8 +565,6 @@ func (handler *CommandHandler) CommandDisconnect(ce *CommandEvent) {
|
||||||
ce.User.log.Warnln("Error while disconnecting:", err)
|
ce.User.log.Warnln("Error while disconnecting:", err)
|
||||||
ce.Reply("Unknown error while disconnecting: %v", err)
|
ce.Reply("Unknown error while disconnecting: %v", err)
|
||||||
return
|
return
|
||||||
} else {
|
|
||||||
ce.User.SetSession(&sess)
|
|
||||||
}
|
}
|
||||||
ce.User.bridge.Metrics.TrackConnectionState(ce.User.JID, false)
|
ce.User.bridge.Metrics.TrackConnectionState(ce.User.JID, false)
|
||||||
ce.Reply("Successfully disconnected. Use the `reconnect` command to reconnect.")
|
ce.Reply("Successfully disconnected. Use the `reconnect` command to reconnect.")
|
||||||
|
@ -741,9 +732,9 @@ func formatContacts(contacts bool, input map[string]whatsapp.Contact) (result []
|
||||||
}
|
}
|
||||||
|
|
||||||
if contacts {
|
if contacts {
|
||||||
result = append(result, fmt.Sprintf("* %s / %s - `%s`", contact.Name, contact.Notify, contact.Jid[:len(contact.Jid)-len(whatsapp.NewUserSuffix)]))
|
result = append(result, fmt.Sprintf("* %s / %s - `%s`", contact.Name, contact.Notify, contact.JID[:len(contact.JID)-len(whatsapp.NewUserSuffix)]))
|
||||||
} else {
|
} else {
|
||||||
result = append(result, fmt.Sprintf("* %s - `%s`", contact.Name, contact.Jid))
|
result = append(result, fmt.Sprintf("* %s - `%s`", contact.Name, contact.JID))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sort.Sort(sort.StringSlice(result))
|
sort.Sort(sort.StringSlice(result))
|
||||||
|
@ -875,11 +866,11 @@ func (handler *CommandHandler) CommandPM(ce *CommandEvent) {
|
||||||
"To create a portal anyway, use `pm --force <number>`.")
|
"To create a portal anyway, use `pm --force <number>`.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
contact = whatsapp.Contact{Jid: jid}
|
contact = whatsapp.Contact{JID: jid}
|
||||||
}
|
}
|
||||||
puppet := user.bridge.GetPuppetByJID(contact.Jid)
|
puppet := user.bridge.GetPuppetByJID(contact.JID)
|
||||||
puppet.Sync(user, contact)
|
puppet.Sync(user, contact)
|
||||||
portal := user.bridge.GetPortalByJID(database.NewPortalKey(contact.Jid, user.JID))
|
portal := user.bridge.GetPortalByJID(database.NewPortalKey(contact.JID, user.JID))
|
||||||
if len(portal.MXID) > 0 {
|
if len(portal.MXID) > 0 {
|
||||||
err := portal.MainIntent().EnsureInvited(portal.MXID, user.MXID)
|
err := portal.MainIntent().EnsureInvited(portal.MXID, user.MXID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -165,8 +165,8 @@ type UsernameTemplateArgs struct {
|
||||||
|
|
||||||
func (bc BridgeConfig) FormatDisplayname(contact whatsapp.Contact) (string, int8) {
|
func (bc BridgeConfig) FormatDisplayname(contact whatsapp.Contact) (string, int8) {
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
if index := strings.IndexRune(contact.Jid, '@'); index > 0 {
|
if index := strings.IndexRune(contact.JID, '@'); index > 0 {
|
||||||
contact.Jid = "+" + contact.Jid[:index]
|
contact.JID = "+" + contact.JID[:index]
|
||||||
}
|
}
|
||||||
bc.displaynameTemplate.Execute(&buf, contact)
|
bc.displaynameTemplate.Execute(&buf, contact)
|
||||||
var quality int8
|
var quality int8
|
||||||
|
@ -175,7 +175,7 @@ func (bc BridgeConfig) FormatDisplayname(contact whatsapp.Contact) (string, int8
|
||||||
quality = 3
|
quality = 3
|
||||||
case len(contact.Name) > 0 || len(contact.Short) > 0:
|
case len(contact.Name) > 0 || len(contact.Short) > 0:
|
||||||
quality = 2
|
quality = 2
|
||||||
case len(contact.Jid) > 0:
|
case len(contact.JID) > 0:
|
||||||
quality = 1
|
quality = 1
|
||||||
default:
|
default:
|
||||||
quality = 0
|
quality = 0
|
||||||
|
|
|
@ -93,7 +93,7 @@ func (user *User) Scan(row Scannable) *User {
|
||||||
if len(jid.String) > 0 && len(clientID.String) > 0 {
|
if len(jid.String) > 0 && len(clientID.String) > 0 {
|
||||||
user.JID = jid.String + whatsapp.NewUserSuffix
|
user.JID = jid.String + whatsapp.NewUserSuffix
|
||||||
user.Session = &whatsapp.Session{
|
user.Session = &whatsapp.Session{
|
||||||
ClientId: clientID.String,
|
ClientID: clientID.String,
|
||||||
ClientToken: clientToken.String,
|
ClientToken: clientToken.String,
|
||||||
ServerToken: serverToken.String,
|
ServerToken: serverToken.String,
|
||||||
EncKey: encKey,
|
EncKey: encKey,
|
||||||
|
@ -139,7 +139,7 @@ func (user *User) Insert() {
|
||||||
_, err := user.db.Exec(`INSERT INTO "user" (mxid, jid, management_room, last_connection, client_id, client_token, server_token, enc_key, mac_key) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)`,
|
_, err := user.db.Exec(`INSERT INTO "user" (mxid, jid, management_room, last_connection, client_id, client_token, server_token, enc_key, mac_key) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)`,
|
||||||
user.MXID, user.jidPtr(),
|
user.MXID, user.jidPtr(),
|
||||||
user.ManagementRoom, user.LastConnection,
|
user.ManagementRoom, user.LastConnection,
|
||||||
sess.ClientId, sess.ClientToken, sess.ServerToken, sess.EncKey, sess.MacKey)
|
sess.ClientID, sess.ClientToken, sess.ServerToken, sess.EncKey, sess.MacKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
user.log.Warnfln("Failed to insert %s: %v", user.MXID, err)
|
user.log.Warnfln("Failed to insert %s: %v", user.MXID, err)
|
||||||
}
|
}
|
||||||
|
@ -158,7 +158,7 @@ func (user *User) Update() {
|
||||||
sess := user.sessionUnptr()
|
sess := user.sessionUnptr()
|
||||||
_, err := user.db.Exec(`UPDATE "user" SET jid=$1, management_room=$2, last_connection=$3, client_id=$4, client_token=$5, server_token=$6, enc_key=$7, mac_key=$8 WHERE mxid=$9`,
|
_, err := user.db.Exec(`UPDATE "user" SET jid=$1, management_room=$2, last_connection=$3, client_id=$4, client_token=$5, server_token=$6, enc_key=$7, mac_key=$8 WHERE mxid=$9`,
|
||||||
user.jidPtr(), user.ManagementRoom, user.LastConnection,
|
user.jidPtr(), user.ManagementRoom, user.LastConnection,
|
||||||
sess.ClientId, sess.ClientToken, sess.ServerToken, sess.EncKey, sess.MacKey,
|
sess.ClientID, sess.ClientToken, sess.ServerToken, sess.EncKey, sess.MacKey,
|
||||||
user.MXID)
|
user.MXID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
user.log.Warnfln("Failed to update %s: %v", user.MXID, err)
|
user.log.Warnfln("Failed to update %s: %v", user.MXID, err)
|
||||||
|
|
4
go.mod
4
go.mod
|
@ -12,8 +12,8 @@ require (
|
||||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
|
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
|
||||||
gopkg.in/yaml.v2 v2.3.0
|
gopkg.in/yaml.v2 v2.3.0
|
||||||
maunium.net/go/mauflag v1.0.0
|
maunium.net/go/mauflag v1.0.0
|
||||||
maunium.net/go/maulogger/v2 v2.1.1
|
maunium.net/go/maulogger/v2 v2.2.2
|
||||||
maunium.net/go/mautrix v0.8.2
|
maunium.net/go/mautrix v0.8.2
|
||||||
)
|
)
|
||||||
|
|
||||||
replace github.com/Rhymen/go-whatsapp => github.com/tulir/go-whatsapp v0.3.21
|
replace github.com/Rhymen/go-whatsapp => github.com/tulir/go-whatsapp v0.3.22-0.20210218211744-b9f35ff6257a
|
||||||
|
|
6
go.sum
6
go.sum
|
@ -145,6 +145,8 @@ github.com/tulir/go-whatsapp v0.3.20 h1:nK92MgruqXwk+QlaAS39xhzHNbFvJIEgUIOUrN3i
|
||||||
github.com/tulir/go-whatsapp v0.3.20/go.mod h1:U5+sm33vrv3wz62YyRM/VS7q2ObXkxU4Xqj/3KOmN9o=
|
github.com/tulir/go-whatsapp v0.3.20/go.mod h1:U5+sm33vrv3wz62YyRM/VS7q2ObXkxU4Xqj/3KOmN9o=
|
||||||
github.com/tulir/go-whatsapp v0.3.21 h1:2m7gUw4oHX4kIpMmP9VwCR7KEUK/PHhXLygPFGF9XfI=
|
github.com/tulir/go-whatsapp v0.3.21 h1:2m7gUw4oHX4kIpMmP9VwCR7KEUK/PHhXLygPFGF9XfI=
|
||||||
github.com/tulir/go-whatsapp v0.3.21/go.mod h1:U5+sm33vrv3wz62YyRM/VS7q2ObXkxU4Xqj/3KOmN9o=
|
github.com/tulir/go-whatsapp v0.3.21/go.mod h1:U5+sm33vrv3wz62YyRM/VS7q2ObXkxU4Xqj/3KOmN9o=
|
||||||
|
github.com/tulir/go-whatsapp v0.3.22-0.20210218211744-b9f35ff6257a h1:8JSW6oIAgI1TtR7wkvhNpTYhjKWBxk/eFyB8qXeOfyg=
|
||||||
|
github.com/tulir/go-whatsapp v0.3.22-0.20210218211744-b9f35ff6257a/go.mod h1:rwwuTh1bKqhgrRvOBAr8hDqtuz8Cc1Quqw/0BeXb+/E=
|
||||||
golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
|
@ -232,6 +234,10 @@ maunium.net/go/mauflag v1.0.0 h1:YiaRc0tEI3toYtJMRIfjP+jklH45uDHtT80nUamyD4M=
|
||||||
maunium.net/go/mauflag v1.0.0/go.mod h1:nLivPOpTpHnpzEh8jEdSL9UqO9+/KBJFmNRlwKfkPeA=
|
maunium.net/go/mauflag v1.0.0/go.mod h1:nLivPOpTpHnpzEh8jEdSL9UqO9+/KBJFmNRlwKfkPeA=
|
||||||
maunium.net/go/maulogger/v2 v2.1.1 h1:NAZNc6XUFJzgzfewCzVoGkxNAsblLCSSEdtDuIjP0XA=
|
maunium.net/go/maulogger/v2 v2.1.1 h1:NAZNc6XUFJzgzfewCzVoGkxNAsblLCSSEdtDuIjP0XA=
|
||||||
maunium.net/go/maulogger/v2 v2.1.1/go.mod h1:TYWy7wKwz/tIXTpsx8G3mZseIRiC5DoMxSZazOHy68A=
|
maunium.net/go/maulogger/v2 v2.1.1/go.mod h1:TYWy7wKwz/tIXTpsx8G3mZseIRiC5DoMxSZazOHy68A=
|
||||||
|
maunium.net/go/maulogger/v2 v2.2.1 h1:qwEDOdT7OhwqvFBXhSD0lqW2O2Oc/DbP/uv3zaai0W8=
|
||||||
|
maunium.net/go/maulogger/v2 v2.2.1/go.mod h1:TYWy7wKwz/tIXTpsx8G3mZseIRiC5DoMxSZazOHy68A=
|
||||||
|
maunium.net/go/maulogger/v2 v2.2.2 h1:NCw+7Be1GQFm8xXJ4M2C0Q8yLBTx3c5s7UZ4y1anZMU=
|
||||||
|
maunium.net/go/maulogger/v2 v2.2.2/go.mod h1:TYWy7wKwz/tIXTpsx8G3mZseIRiC5DoMxSZazOHy68A=
|
||||||
maunium.net/go/mautrix v0.8.0-rc.3 h1:bb18oNxHUmeiJ0V63YTRVGMjgoeLwu+G40l4n42Z5GI=
|
maunium.net/go/mautrix v0.8.0-rc.3 h1:bb18oNxHUmeiJ0V63YTRVGMjgoeLwu+G40l4n42Z5GI=
|
||||||
maunium.net/go/mautrix v0.8.0-rc.3/go.mod h1:TtVePxoEaw6+RZDKVajw66Yaj1lqLjH8l4FF3krsqWY=
|
maunium.net/go/mautrix v0.8.0-rc.3/go.mod h1:TtVePxoEaw6+RZDKVajw66Yaj1lqLjH8l4FF3krsqWY=
|
||||||
maunium.net/go/mautrix v0.8.0-rc.4 h1:3JXoL2JJPE5nh/YSw9sv9dQA9ulma9yHTMOBMBY1xdo=
|
maunium.net/go/mautrix v0.8.0-rc.4 h1:3JXoL2JJPE5nh/YSw9sv9dQA9ulma9yHTMOBMBY1xdo=
|
||||||
|
|
4
main.go
4
main.go
|
@ -384,11 +384,9 @@ func (bridge *Bridge) Stop() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
bridge.Log.Debugln("Disconnecting", user.MXID)
|
bridge.Log.Debugln("Disconnecting", user.MXID)
|
||||||
sess, err := user.Conn.Disconnect()
|
err := user.Conn.Disconnect()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
bridge.Log.Errorfln("Error while disconnecting %s: %v", user.MXID, err)
|
bridge.Log.Errorfln("Error while disconnecting %s: %v", user.MXID, err)
|
||||||
} else {
|
|
||||||
user.SetSession(&sess)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1771,7 +1771,7 @@ func (portal *Portal) convertGifToVideo(gif []byte) ([]byte, error) {
|
||||||
"-pix_fmt", "yuv420p", "-c:v", "libx264", "-movflags", "+faststart",
|
"-pix_fmt", "yuv420p", "-c:v", "libx264", "-movflags", "+faststart",
|
||||||
"-filter:v", "crop='floor(in_w/2)*2:floor(in_h/2)*2'",
|
"-filter:v", "crop='floor(in_w/2)*2:floor(in_h/2)*2'",
|
||||||
outputFileName)
|
outputFileName)
|
||||||
vcLog := portal.log.Sub("VideoConverter").WithDefaultLevel(log.LevelWarn)
|
vcLog := portal.log.Sub("VideoConverter").Writer(log.LevelWarn)
|
||||||
cmd.Stdout = vcLog
|
cmd.Stdout = vcLog
|
||||||
cmd.Stderr = vcLog
|
cmd.Stderr = vcLog
|
||||||
|
|
||||||
|
@ -2319,7 +2319,7 @@ func (portal *Portal) HandleMatrixMeta(sender *User, evt *event.Event) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
portal.Topic = content.Topic
|
portal.Topic = content.Topic
|
||||||
resp, err = sender.Conn.UpdateGroupDescription(portal.Key.JID, content.Topic)
|
resp, err = sender.Conn.UpdateGroupDescription(sender.JID, portal.Key.JID, content.Topic)
|
||||||
case *event.RoomAvatarEventContent:
|
case *event.RoomAvatarEventContent:
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -125,7 +125,7 @@ func (prov *ProvisioningAPI) DeleteSession(w http.ResponseWriter, r *http.Reques
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
user.Disconnect()
|
user.DeleteConnection()
|
||||||
user.SetSession(nil)
|
user.SetSession(nil)
|
||||||
jsonResponse(w, http.StatusOK, Response{true, "Session information purged"})
|
jsonResponse(w, http.StatusOK, Response{true, "Session information purged"})
|
||||||
}
|
}
|
||||||
|
@ -139,7 +139,7 @@ func (prov *ProvisioningAPI) DeleteConnection(w http.ResponseWriter, r *http.Req
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
user.Disconnect()
|
user.DeleteConnection()
|
||||||
jsonResponse(w, http.StatusOK, Response{true, "Disconnected from WhatsApp and connection deleted"})
|
jsonResponse(w, http.StatusOK, Response{true, "Disconnected from WhatsApp and connection deleted"})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,7 +152,7 @@ func (prov *ProvisioningAPI) Disconnect(w http.ResponseWriter, r *http.Request)
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
sess, err := user.Conn.Disconnect()
|
err := user.Conn.Disconnect()
|
||||||
if err == whatsapp.ErrNotConnected {
|
if err == whatsapp.ErrNotConnected {
|
||||||
jsonResponse(w, http.StatusNotFound, Error{
|
jsonResponse(w, http.StatusNotFound, Error{
|
||||||
Error: "You were not connected",
|
Error: "You were not connected",
|
||||||
|
@ -166,8 +166,6 @@ func (prov *ProvisioningAPI) Disconnect(w http.ResponseWriter, r *http.Request)
|
||||||
ErrCode: err.Error(),
|
ErrCode: err.Error(),
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
} else {
|
|
||||||
user.SetSession(&sess)
|
|
||||||
}
|
}
|
||||||
user.bridge.Metrics.TrackConnectionState(user.JID, false)
|
user.bridge.Metrics.TrackConnectionState(user.JID, false)
|
||||||
jsonResponse(w, http.StatusOK, Response{true, "Disconnected from WhatsApp"})
|
jsonResponse(w, http.StatusOK, Response{true, "Disconnected from WhatsApp"})
|
||||||
|
@ -190,25 +188,21 @@ func (prov *ProvisioningAPI) Reconnect(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
user.log.Debugln("Received /reconnect request, disconnecting")
|
user.log.Debugln("Received /reconnect request, disconnecting")
|
||||||
wasConnected := true
|
wasConnected := true
|
||||||
sess, err := user.Conn.Disconnect()
|
err := user.Conn.Disconnect()
|
||||||
if err == whatsapp.ErrNotConnected {
|
if err == whatsapp.ErrNotConnected {
|
||||||
wasConnected = false
|
wasConnected = false
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
user.log.Warnln("Error while disconnecting:", err)
|
user.log.Warnln("Error while disconnecting:", err)
|
||||||
} else {
|
|
||||||
user.SetSession(&sess)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
user.log.Debugln("Restoring session for /reconnect")
|
user.log.Debugln("Restoring session for /reconnect")
|
||||||
err = user.Conn.Restore(true)
|
err = user.Conn.Restore(true, r.Context())
|
||||||
user.log.Debugfln("Restore session for /reconnect responded with %v", err)
|
user.log.Debugfln("Restore session for /reconnect responded with %v", err)
|
||||||
if err == whatsapp.ErrInvalidSession {
|
if err == whatsapp.ErrInvalidSession {
|
||||||
if user.Session != nil {
|
if user.Session != nil {
|
||||||
user.log.Debugln("Got invalid session error when reconnecting, but user has session. Retrying using RestoreWithSession()...")
|
user.log.Debugln("Got invalid session error when reconnecting, but user has session. Retrying using RestoreWithSession()...")
|
||||||
sess, err = user.Conn.RestoreWithSession(*user.Session)
|
user.Conn.SetSession(*user.Session)
|
||||||
if err == nil {
|
err = user.Conn.Restore(true, r.Context())
|
||||||
user.SetSession(&sess)
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
jsonResponse(w, http.StatusForbidden, Error{
|
jsonResponse(w, http.StatusForbidden, Error{
|
||||||
Error: "You're not logged in",
|
Error: "You're not logged in",
|
||||||
|
@ -216,7 +210,8 @@ func (prov *ProvisioningAPI) Reconnect(w http.ResponseWriter, r *http.Request) {
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
} else if err == whatsapp.ErrLoginInProgress {
|
}
|
||||||
|
if err == whatsapp.ErrLoginInProgress {
|
||||||
jsonResponse(w, http.StatusConflict, Error{
|
jsonResponse(w, http.StatusConflict, Error{
|
||||||
Error: "A login or reconnection is already in progress.",
|
Error: "A login or reconnection is already in progress.",
|
||||||
ErrCode: "login in progress",
|
ErrCode: "login in progress",
|
||||||
|
@ -231,23 +226,14 @@ func (prov *ProvisioningAPI) Reconnect(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
user.log.Warnln("Error while reconnecting:", err)
|
user.log.Warnln("Error while reconnecting:", err)
|
||||||
if errors.Is(err, whatsapp.ErrRestoreSessionTimeout) {
|
jsonResponse(w, http.StatusInternalServerError, Error{
|
||||||
jsonResponse(w, http.StatusForbidden, Error{
|
|
||||||
Error: "Reconnection timed out. Is WhatsApp on your phone reachable?",
|
|
||||||
ErrCode: err.Error(),
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
jsonResponse(w, http.StatusForbidden, Error{
|
|
||||||
Error: fmt.Sprintf("Unknown error while reconnecting: %v", err),
|
Error: fmt.Sprintf("Unknown error while reconnecting: %v", err),
|
||||||
ErrCode: err.Error(),
|
ErrCode: err.Error(),
|
||||||
})
|
})
|
||||||
}
|
|
||||||
user.log.Debugln("Disconnecting due to failed session restore in reconnect command...")
|
user.log.Debugln("Disconnecting due to failed session restore in reconnect command...")
|
||||||
sess, err := user.Conn.Disconnect()
|
err = user.Conn.Disconnect()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
user.log.Errorln("Failed to disconnect after failed session restore in reconnect command:", err)
|
user.log.Errorln("Failed to disconnect after failed session restore in reconnect command:", err)
|
||||||
} else {
|
|
||||||
user.SetSession(&sess)
|
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -339,7 +325,7 @@ func (prov *ProvisioningAPI) Logout(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
user.Disconnect()
|
user.DeleteConnection()
|
||||||
}
|
}
|
||||||
|
|
||||||
user.bridge.Metrics.TrackConnectionState(user.JID, false)
|
user.bridge.Metrics.TrackConnectionState(user.JID, false)
|
||||||
|
@ -407,7 +393,7 @@ func (prov *ProvisioningAPI) Login(w http.ResponseWriter, r *http.Request) {
|
||||||
})
|
})
|
||||||
|
|
||||||
user.log.Debugln("Starting login via provisioning API")
|
user.log.Debugln("Starting login via provisioning API")
|
||||||
session, err := user.Conn.LoginWithRetry(qrChan, ctx, user.bridge.Config.Bridge.LoginQRRegenCount)
|
session, jid, err := user.Conn.Login(qrChan, ctx, user.bridge.Config.Bridge.LoginQRRegenCount)
|
||||||
qrChan <- "stop"
|
qrChan <- "stop"
|
||||||
if err != nil {
|
if err != nil {
|
||||||
var msg string
|
var msg string
|
||||||
|
@ -419,7 +405,7 @@ func (prov *ProvisioningAPI) Login(w http.ResponseWriter, r *http.Request) {
|
||||||
msg = "QR code scan timed out. Please try again."
|
msg = "QR code scan timed out. Please try again."
|
||||||
} else if errors.Is(err, whatsapp.ErrInvalidWebsocket) {
|
} else if errors.Is(err, whatsapp.ErrInvalidWebsocket) {
|
||||||
msg = "WhatsApp connection error. Please try again."
|
msg = "WhatsApp connection error. Please try again."
|
||||||
user.Disconnect()
|
// TODO might need to make sure it reconnects?
|
||||||
} else {
|
} else {
|
||||||
msg = fmt.Sprintf("Unknown error while logging in: %v", err)
|
msg = fmt.Sprintf("Unknown error while logging in: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -430,9 +416,9 @@ func (prov *ProvisioningAPI) Login(w http.ResponseWriter, r *http.Request) {
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
user.log.Debugln("Successful login via provisioning API")
|
user.log.Debugln("Successful login as", jid, "via provisioning API")
|
||||||
user.ConnectionErrors = 0
|
user.ConnectionErrors = 0
|
||||||
user.JID = strings.Replace(user.Conn.Info.Wid, whatsapp.OldUserSuffix, whatsapp.NewUserSuffix, 1)
|
user.JID = strings.Replace(jid, whatsapp.OldUserSuffix, whatsapp.NewUserSuffix, 1)
|
||||||
user.addToJIDMap()
|
user.addToJIDMap()
|
||||||
user.SetSession(&session)
|
user.SetSession(&session)
|
||||||
_ = c.WriteJSON(map[string]interface{}{
|
_ = c.WriteJSON(map[string]interface{}{
|
||||||
|
|
|
@ -291,8 +291,8 @@ func (puppet *Puppet) Sync(source *User, contact whatsapp.Contact) {
|
||||||
puppet.log.Errorln("Failed to ensure registered:", err)
|
puppet.log.Errorln("Failed to ensure registered:", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if contact.Jid == source.JID {
|
if contact.JID == source.JID {
|
||||||
contact.Notify = source.Conn.Info.Pushname
|
contact.Notify = source.pushName
|
||||||
}
|
}
|
||||||
|
|
||||||
update := false
|
update := false
|
||||||
|
|
171
user.go
171
user.go
|
@ -17,6 +17,7 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
@ -61,6 +62,7 @@ type User struct {
|
||||||
cleanDisconnection bool
|
cleanDisconnection bool
|
||||||
batteryWarningsSent int
|
batteryWarningsSent int
|
||||||
lastReconnection int64
|
lastReconnection int64
|
||||||
|
pushName string
|
||||||
|
|
||||||
chatListReceived chan struct{}
|
chatListReceived chan struct{}
|
||||||
syncPortalsDone chan struct{}
|
syncPortalsDone chan struct{}
|
||||||
|
@ -73,6 +75,7 @@ type User struct {
|
||||||
|
|
||||||
mgmtCreateLock sync.Mutex
|
mgmtCreateLock sync.Mutex
|
||||||
connLock sync.Mutex
|
connLock sync.Mutex
|
||||||
|
cancelReconnect func()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bridge *Bridge) GetUserByMXID(userID id.UserID) *User {
|
func (bridge *Bridge) GetUserByMXID(userID id.UserID) *User {
|
||||||
|
@ -234,55 +237,56 @@ func (user *User) SetSession(session *whatsapp.Session) {
|
||||||
|
|
||||||
func (user *User) Connect(evenIfNoSession bool) bool {
|
func (user *User) Connect(evenIfNoSession bool) bool {
|
||||||
user.connLock.Lock()
|
user.connLock.Lock()
|
||||||
if user.Conn != nil && user.Conn.IsConnected() {
|
if user.Conn != nil {
|
||||||
user.connLock.Unlock()
|
user.connLock.Unlock()
|
||||||
|
if user.Conn.IsConnected() {
|
||||||
return true
|
return true
|
||||||
|
} else {
|
||||||
|
return user.RestoreSession()
|
||||||
|
}
|
||||||
} else if !evenIfNoSession && user.Session == nil {
|
} else if !evenIfNoSession && user.Session == nil {
|
||||||
user.connLock.Unlock()
|
user.connLock.Unlock()
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if user.Conn != nil {
|
|
||||||
user.Disconnect()
|
|
||||||
}
|
|
||||||
user.log.Debugln("Connecting to WhatsApp")
|
user.log.Debugln("Connecting to WhatsApp")
|
||||||
timeout := time.Duration(user.bridge.Config.Bridge.ConnectionTimeout)
|
timeout := time.Duration(user.bridge.Config.Bridge.ConnectionTimeout)
|
||||||
if timeout == 0 {
|
if timeout == 0 {
|
||||||
timeout = 20
|
timeout = 20
|
||||||
}
|
}
|
||||||
conn, err := whatsapp.NewConnWithOptions(&whatsapp.Options{
|
user.Conn = whatsapp.NewConn(&whatsapp.Options{
|
||||||
Timeout: timeout * time.Second,
|
Timeout: timeout * time.Second,
|
||||||
LongClientName: user.bridge.Config.WhatsApp.OSName,
|
LongClientName: user.bridge.Config.WhatsApp.OSName,
|
||||||
ShortClientName: user.bridge.Config.WhatsApp.BrowserName,
|
ShortClientName: user.bridge.Config.WhatsApp.BrowserName,
|
||||||
ClientVersion: WAVersion,
|
ClientVersion: WAVersion,
|
||||||
|
Log: user.log.Sub("Conn"),
|
||||||
|
Handler: []whatsapp.Handler{user},
|
||||||
})
|
})
|
||||||
if err != nil {
|
|
||||||
user.log.Errorln("Failed to connect to WhatsApp:", err)
|
|
||||||
user.sendMarkdownBridgeAlert("\u26a0 Failed to connect to WhatsApp server. " +
|
|
||||||
"This indicates a network problem on the bridge server. See bridge logs for more info.")
|
|
||||||
user.connLock.Unlock()
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
user.Conn = conn
|
|
||||||
user.log.Debugln("WhatsApp connection successful")
|
|
||||||
user.Conn.AddHandler(user)
|
|
||||||
user.connLock.Unlock()
|
user.connLock.Unlock()
|
||||||
return user.RestoreSession()
|
return user.RestoreSession()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (user *User) Disconnect() {
|
func (user *User) DeleteConnection() {
|
||||||
sess, err := user.Conn.Disconnect()
|
user.connLock.Lock()
|
||||||
|
if user.Conn == nil {
|
||||||
|
user.connLock.Unlock()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err := user.Conn.Disconnect()
|
||||||
if err != nil && err != whatsapp.ErrNotConnected {
|
if err != nil && err != whatsapp.ErrNotConnected {
|
||||||
user.log.Warnln("Error disconnecting: %v", err)
|
user.log.Warnln("Error disconnecting: %v", err)
|
||||||
}
|
}
|
||||||
user.SetSession(&sess)
|
|
||||||
user.Conn.RemoveHandlers()
|
user.Conn.RemoveHandlers()
|
||||||
user.Conn = nil
|
user.Conn = nil
|
||||||
user.bridge.Metrics.TrackConnectionState(user.JID, false)
|
user.bridge.Metrics.TrackConnectionState(user.JID, false)
|
||||||
|
user.connLock.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (user *User) RestoreSession() bool {
|
func (user *User) RestoreSession() bool {
|
||||||
if user.Session != nil {
|
if user.Session != nil {
|
||||||
sess, err := user.Conn.RestoreWithSession(*user.Session)
|
user.Conn.SetSession(*user.Session)
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Minute)
|
||||||
|
defer cancel()
|
||||||
|
err := user.Conn.Restore(true, ctx)
|
||||||
if err == whatsapp.ErrAlreadyLoggedIn {
|
if err == whatsapp.ErrAlreadyLoggedIn {
|
||||||
return true
|
return true
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
|
@ -290,24 +294,23 @@ func (user *User) RestoreSession() bool {
|
||||||
if errors.Is(err, whatsapp.ErrUnpaired) {
|
if errors.Is(err, whatsapp.ErrUnpaired) {
|
||||||
user.sendMarkdownBridgeAlert("\u26a0 Failed to connect to WhatsApp: unpaired from phone. " +
|
user.sendMarkdownBridgeAlert("\u26a0 Failed to connect to WhatsApp: unpaired from phone. " +
|
||||||
"To re-pair your phone, log in again.")
|
"To re-pair your phone, log in again.")
|
||||||
user.Disconnect()
|
|
||||||
user.removeFromJIDMap()
|
user.removeFromJIDMap()
|
||||||
//user.JID = ""
|
//user.JID = ""
|
||||||
user.SetSession(nil)
|
user.SetSession(nil)
|
||||||
|
user.DeleteConnection()
|
||||||
return false
|
return false
|
||||||
} else {
|
} else {
|
||||||
user.sendMarkdownBridgeAlert("\u26a0 Failed to connect to WhatsApp. Make sure WhatsApp " +
|
user.sendMarkdownBridgeAlert("\u26a0 Failed to connect to WhatsApp. Make sure WhatsApp " +
|
||||||
"on your phone is reachable and use `reconnect` to try connecting again.")
|
"on your phone is reachable and use `reconnect` to try connecting again.")
|
||||||
}
|
}
|
||||||
user.log.Debugln("Disconnecting due to failed session restore...")
|
user.log.Debugln("Disconnecting due to failed session restore...")
|
||||||
_, err := user.Conn.Disconnect()
|
err = user.Conn.Disconnect()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
user.log.Errorln("Failed to disconnect after failed session restore:", err)
|
user.log.Errorln("Failed to disconnect after failed session restore:", err)
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
user.ConnectionErrors = 0
|
user.ConnectionErrors = 0
|
||||||
user.SetSession(&sess)
|
|
||||||
user.log.Debugln("Session restored successfully")
|
user.log.Debugln("Session restored successfully")
|
||||||
user.PostLogin()
|
user.PostLogin()
|
||||||
}
|
}
|
||||||
|
@ -382,7 +385,7 @@ func (user *User) Login(ce *CommandEvent) {
|
||||||
qrChan := make(chan string, 3)
|
qrChan := make(chan string, 3)
|
||||||
eventIDChan := make(chan id.EventID, 1)
|
eventIDChan := make(chan id.EventID, 1)
|
||||||
go user.loginQrChannel(ce, qrChan, eventIDChan)
|
go user.loginQrChannel(ce, qrChan, eventIDChan)
|
||||||
session, err := user.Conn.LoginWithRetry(qrChan, nil, user.bridge.Config.Bridge.LoginQRRegenCount)
|
session, jid, err := user.Conn.Login(qrChan, nil, user.bridge.Config.Bridge.LoginQRRegenCount)
|
||||||
qrChan <- "stop"
|
qrChan <- "stop"
|
||||||
if err != nil {
|
if err != nil {
|
||||||
var eventID id.EventID
|
var eventID id.EventID
|
||||||
|
@ -416,8 +419,9 @@ func (user *User) Login(ce *CommandEvent) {
|
||||||
}
|
}
|
||||||
// TODO there's a bit of duplication between this and the provisioning API login method
|
// TODO there's a bit of duplication between this and the provisioning API login method
|
||||||
// Also between the two logout methods (commands.go and provisioning.go)
|
// Also between the two logout methods (commands.go and provisioning.go)
|
||||||
|
user.log.Debugln("Successful login as", jid, "via command")
|
||||||
user.ConnectionErrors = 0
|
user.ConnectionErrors = 0
|
||||||
user.JID = strings.Replace(user.Conn.Info.Wid, whatsapp.OldUserSuffix, whatsapp.NewUserSuffix, 1)
|
user.JID = strings.Replace(jid, whatsapp.OldUserSuffix, whatsapp.NewUserSuffix, 1)
|
||||||
user.addToJIDMap()
|
user.addToJIDMap()
|
||||||
user.SetSession(&session)
|
user.SetSession(&session)
|
||||||
ce.Reply("Successfully logged in, synchronizing chats...")
|
ce.Reply("Successfully logged in, synchronizing chats...")
|
||||||
|
@ -499,20 +503,24 @@ func (user *User) sendMarkdownBridgeAlert(formatString string, args ...interface
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (user *User) postConnPing(conn *whatsapp.Conn) bool {
|
func (user *User) postConnPing() bool {
|
||||||
if user.Conn != conn {
|
|
||||||
user.log.Warnln("Connection changed before scheduled post-connection ping, canceling ping")
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
user.log.Debugln("Making post-connection ping")
|
user.log.Debugln("Making post-connection ping")
|
||||||
err := conn.AdminTest()
|
var err error
|
||||||
if err != nil {
|
for i := 0; ; i++ {
|
||||||
|
err = user.Conn.AdminTest()
|
||||||
|
if err == nil {
|
||||||
|
user.log.Debugln("Post-connection ping OK")
|
||||||
|
return true
|
||||||
|
} else if errors.Is(err, whatsapp.ErrConnectionTimeout) && i < 5 {
|
||||||
|
user.log.Warnfln("Post-connection ping timed out, sending new one")
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
user.log.Errorfln("Post-connection ping failed: %v. Disconnecting and then reconnecting after a second", err)
|
user.log.Errorfln("Post-connection ping failed: %v. Disconnecting and then reconnecting after a second", err)
|
||||||
sess, disconnectErr := conn.Disconnect()
|
disconnectErr := user.Conn.Disconnect()
|
||||||
if disconnectErr != nil {
|
if disconnectErr != nil {
|
||||||
user.log.Warnln("Error while disconnecting after failed post-connection ping:", disconnectErr)
|
user.log.Warnln("Error while disconnecting after failed post-connection ping:", disconnectErr)
|
||||||
} else {
|
|
||||||
user.Session = &sess
|
|
||||||
}
|
}
|
||||||
user.bridge.Metrics.TrackDisconnection(user.MXID)
|
user.bridge.Metrics.TrackDisconnection(user.MXID)
|
||||||
go func() {
|
go func() {
|
||||||
|
@ -520,10 +528,6 @@ func (user *User) postConnPing(conn *whatsapp.Conn) bool {
|
||||||
user.tryReconnect(fmt.Sprintf("Post-connection ping failed: %v", err))
|
user.tryReconnect(fmt.Sprintf("Post-connection ping failed: %v", err))
|
||||||
}()
|
}()
|
||||||
return false
|
return false
|
||||||
} else {
|
|
||||||
user.log.Debugln("Post-connection ping OK")
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (user *User) intPostLogin(conn *whatsapp.Conn) {
|
func (user *User) intPostLogin(conn *whatsapp.Conn) {
|
||||||
|
@ -538,11 +542,11 @@ func (user *User) intPostLogin(conn *whatsapp.Conn) {
|
||||||
user.log.Debugln("Chat list receive confirmation received in PostLogin")
|
user.log.Debugln("Chat list receive confirmation received in PostLogin")
|
||||||
case <-time.After(time.Duration(user.bridge.Config.Bridge.ChatListWait) * time.Second):
|
case <-time.After(time.Duration(user.bridge.Config.Bridge.ChatListWait) * time.Second):
|
||||||
user.log.Warnln("Timed out waiting for chat list to arrive!")
|
user.log.Warnln("Timed out waiting for chat list to arrive!")
|
||||||
user.postConnPing(conn)
|
user.postConnPing()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if !user.postConnPing(conn) {
|
if !user.postConnPing() {
|
||||||
user.log.Debugln("Post-connection ping failed, unlocking processing of incoming messages.")
|
user.log.Debugln("Post-connection ping failed, unlocking processing of incoming messages.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -557,16 +561,14 @@ func (user *User) intPostLogin(conn *whatsapp.Conn) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type InfoGetter interface {
|
type NormalMessage interface {
|
||||||
GetInfo() whatsapp.MessageInfo
|
GetInfo() whatsapp.MessageInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
func (user *User) HandleEvent(event interface{}) {
|
func (user *User) HandleEvent(event interface{}) {
|
||||||
switch v := event.(type) {
|
switch v := event.(type) {
|
||||||
case whatsapp.TextMessage, whatsapp.ImageMessage, whatsapp.StickerMessage, whatsapp.VideoMessage,
|
case NormalMessage:
|
||||||
whatsapp.AudioMessage, whatsapp.DocumentMessage, whatsapp.ContactMessage, whatsapp.StubMessage,
|
info := v.GetInfo()
|
||||||
whatsapp.LocationMessage:
|
|
||||||
info := v.(InfoGetter).GetInfo()
|
|
||||||
user.messageInput <- PortalMessage{info.RemoteJid, user, v, info.Timestamp}
|
user.messageInput <- PortalMessage{info.RemoteJid, user, v, info.Timestamp}
|
||||||
case whatsapp.MessageRevocation:
|
case whatsapp.MessageRevocation:
|
||||||
user.messageInput <- PortalMessage{v.RemoteJid, user, v, 0}
|
user.messageInput <- PortalMessage{v.RemoteJid, user, v, 0}
|
||||||
|
@ -596,6 +598,8 @@ func (user *User) HandleEvent(event interface{}) {
|
||||||
user.HandleCommand(v)
|
user.HandleCommand(v)
|
||||||
case whatsapp.ChatUpdate:
|
case whatsapp.ChatUpdate:
|
||||||
user.HandleChatUpdate(v)
|
user.HandleChatUpdate(v)
|
||||||
|
case whatsapp.ConnInfo:
|
||||||
|
user.HandleConnInfo(v)
|
||||||
case json.RawMessage:
|
case json.RawMessage:
|
||||||
user.HandleJSONMessage(v)
|
user.HandleJSONMessage(v)
|
||||||
case *waProto.WebMessageInfo:
|
case *waProto.WebMessageInfo:
|
||||||
|
@ -614,11 +618,11 @@ func (user *User) HandleStreamEvent(evt whatsapp.StreamEvent) {
|
||||||
if user.lastReconnection+60 > time.Now().Unix() {
|
if user.lastReconnection+60 > time.Now().Unix() {
|
||||||
user.lastReconnection = 0
|
user.lastReconnection = 0
|
||||||
user.log.Infoln("Stream went to sleep soon after reconnection, making new post-connection ping in 20 seconds")
|
user.log.Infoln("Stream went to sleep soon after reconnection, making new post-connection ping in 20 seconds")
|
||||||
conn := user.Conn
|
|
||||||
go func() {
|
go func() {
|
||||||
time.Sleep(20 * time.Second)
|
time.Sleep(20 * time.Second)
|
||||||
// TODO if this happens during the post-login sync, it can get stuck forever
|
// TODO if this happens during the post-login sync, it can get stuck forever
|
||||||
user.postConnPing(conn)
|
// TODO check if the above is still true
|
||||||
|
user.postConnPing()
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -630,10 +634,10 @@ func (user *User) HandleChatList(chats []whatsapp.Chat) {
|
||||||
user.log.Infoln("Chat list received")
|
user.log.Infoln("Chat list received")
|
||||||
chatMap := make(map[string]whatsapp.Chat)
|
chatMap := make(map[string]whatsapp.Chat)
|
||||||
for _, chat := range user.Conn.Store.Chats {
|
for _, chat := range user.Conn.Store.Chats {
|
||||||
chatMap[chat.Jid] = chat
|
chatMap[chat.JID] = chat
|
||||||
}
|
}
|
||||||
for _, chat := range chats {
|
for _, chat := range chats {
|
||||||
chatMap[chat.Jid] = chat
|
chatMap[chat.JID] = chat
|
||||||
}
|
}
|
||||||
select {
|
select {
|
||||||
case user.chatListReceived <- struct{}{}:
|
case user.chatListReceived <- struct{}{}:
|
||||||
|
@ -655,14 +659,14 @@ func (user *User) syncPortals(chatMap map[string]whatsapp.Chat, createAll bool)
|
||||||
for _, chat := range chatMap {
|
for _, chat := range chatMap {
|
||||||
ts, err := strconv.ParseUint(chat.LastMessageTime, 10, 64)
|
ts, err := strconv.ParseUint(chat.LastMessageTime, 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
user.log.Warnfln("Non-integer last message time in %s: %s", chat.Jid, chat.LastMessageTime)
|
user.log.Warnfln("Non-integer last message time in %s: %s", chat.JID, chat.LastMessageTime)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
portal := user.GetPortalByJID(chat.Jid)
|
portal := user.GetPortalByJID(chat.JID)
|
||||||
|
|
||||||
chats = append(chats, Chat{
|
chats = append(chats, Chat{
|
||||||
Portal: portal,
|
Portal: portal,
|
||||||
Contact: user.Conn.Store.Contacts[chat.Jid],
|
Contact: user.Conn.Store.Contacts[chat.JID],
|
||||||
LastMessageTime: ts,
|
LastMessageTime: ts,
|
||||||
})
|
})
|
||||||
var inCommunity, ok bool
|
var inCommunity, ok bool
|
||||||
|
@ -777,7 +781,7 @@ func (user *User) UpdateDirectChats(chats map[id.UserID][]id.RoomID) {
|
||||||
func (user *User) HandleContactList(contacts []whatsapp.Contact) {
|
func (user *User) HandleContactList(contacts []whatsapp.Contact) {
|
||||||
contactMap := make(map[string]whatsapp.Contact)
|
contactMap := make(map[string]whatsapp.Contact)
|
||||||
for _, contact := range contacts {
|
for _, contact := range contacts {
|
||||||
contactMap[contact.Jid] = contact
|
contactMap[contact.JID] = contact
|
||||||
}
|
}
|
||||||
go user.syncPuppets(contactMap)
|
go user.syncPuppets(contactMap)
|
||||||
}
|
}
|
||||||
|
@ -786,10 +790,20 @@ func (user *User) syncPuppets(contacts map[string]whatsapp.Contact) {
|
||||||
if contacts == nil {
|
if contacts == nil {
|
||||||
contacts = user.Conn.Store.Contacts
|
contacts = user.Conn.Store.Contacts
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_, hasSelf := contacts[user.JID]
|
||||||
|
if !hasSelf {
|
||||||
|
contacts[user.JID] = whatsapp.Contact{
|
||||||
|
Name: user.pushName,
|
||||||
|
Notify: user.pushName,
|
||||||
|
JID: user.JID,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
user.log.Infoln("Syncing puppet info from contacts")
|
user.log.Infoln("Syncing puppet info from contacts")
|
||||||
for jid, contact := range contacts {
|
for jid, contact := range contacts {
|
||||||
if strings.HasSuffix(jid, whatsapp.NewUserSuffix) {
|
if strings.HasSuffix(jid, whatsapp.NewUserSuffix) {
|
||||||
puppet := user.bridge.GetPuppetByJID(contact.Jid)
|
puppet := user.bridge.GetPuppetByJID(contact.JID)
|
||||||
puppet.Sync(user, contact)
|
puppet.Sync(user, contact)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -846,14 +860,18 @@ func (user *User) tryReconnect(msg string) {
|
||||||
baseDelay = -baseDelay + 1
|
baseDelay = -baseDelay + 1
|
||||||
}
|
}
|
||||||
delay := baseDelay
|
delay := baseDelay
|
||||||
conn := user.Conn
|
|
||||||
takeover := false
|
takeover := false
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
defer cancel()
|
||||||
|
user.cancelReconnect = cancel
|
||||||
for user.ConnectionErrors <= user.bridge.Config.Bridge.MaxConnectionAttempts {
|
for user.ConnectionErrors <= user.bridge.Config.Bridge.MaxConnectionAttempts {
|
||||||
if user.Conn != conn {
|
select {
|
||||||
user.log.Debugln("Connection was recreated, aborting reconnection attempts")
|
case <-ctx.Done():
|
||||||
|
user.log.Debugln("tryReconnect context cancelled, aborting reconnection attempts")
|
||||||
return
|
return
|
||||||
|
default:
|
||||||
}
|
}
|
||||||
err := conn.Restore(takeover)
|
err := user.Conn.Restore(takeover, ctx)
|
||||||
takeover = true
|
takeover = true
|
||||||
if err == nil {
|
if err == nil {
|
||||||
user.ConnectionErrors = 0
|
user.ConnectionErrors = 0
|
||||||
|
@ -863,14 +881,23 @@ func (user *User) tryReconnect(msg string) {
|
||||||
user.PostLogin()
|
user.PostLogin()
|
||||||
return
|
return
|
||||||
} else if errors.Is(err, whatsapp.ErrBadRequest) {
|
} else if errors.Is(err, whatsapp.ErrBadRequest) {
|
||||||
user.log.Infoln("Got init 400 error when trying to reconnect, resetting connection...")
|
user.log.Warnln("Got init 400 error when trying to reconnect, resetting connection...")
|
||||||
sess, err := conn.Disconnect()
|
err = user.Conn.Disconnect()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
user.log.Debugln("Error while disconnecting for connection reset:", err)
|
user.log.Debugln("Error while disconnecting for connection reset:", err)
|
||||||
}
|
}
|
||||||
user.SetSession(&sess)
|
} else if errors.Is(err, whatsapp.ErrUnpaired) {
|
||||||
}
|
user.log.Errorln("Got init 401 (unpaired) error when trying to reconnect, not retrying")
|
||||||
|
user.removeFromJIDMap()
|
||||||
|
//user.JID = ""
|
||||||
|
user.SetSession(nil)
|
||||||
|
user.DeleteConnection()
|
||||||
|
user.sendMarkdownBridgeAlert("\u26a0 Failed to reconnect to WhatsApp: unpaired from phone. " +
|
||||||
|
"To re-pair your phone, log in again.")
|
||||||
|
return
|
||||||
|
} else {
|
||||||
user.log.Errorln("Error while trying to reconnect after disconnection:", err)
|
user.log.Errorln("Error while trying to reconnect after disconnection:", err)
|
||||||
|
}
|
||||||
tries++
|
tries++
|
||||||
user.ConnectionErrors++
|
user.ConnectionErrors++
|
||||||
if user.ConnectionErrors <= user.bridge.Config.Bridge.MaxConnectionAttempts {
|
if user.ConnectionErrors <= user.bridge.Config.Bridge.MaxConnectionAttempts {
|
||||||
|
@ -930,10 +957,10 @@ func (user *User) handleMessageLoop() {
|
||||||
|
|
||||||
func (user *User) HandleNewContact(contact whatsapp.Contact) {
|
func (user *User) HandleNewContact(contact whatsapp.Contact) {
|
||||||
user.log.Debugfln("Contact message: %+v", contact)
|
user.log.Debugfln("Contact message: %+v", contact)
|
||||||
if strings.HasSuffix(contact.Jid, whatsapp.OldUserSuffix) {
|
if strings.HasSuffix(contact.JID, whatsapp.OldUserSuffix) {
|
||||||
contact.Jid = strings.Replace(contact.Jid, whatsapp.OldUserSuffix, whatsapp.NewUserSuffix, -1)
|
contact.JID = strings.Replace(contact.JID, whatsapp.OldUserSuffix, whatsapp.NewUserSuffix, -1)
|
||||||
}
|
}
|
||||||
puppet := user.bridge.GetPuppetByJID(contact.Jid)
|
puppet := user.bridge.GetPuppetByJID(contact.JID)
|
||||||
puppet.UpdateName(user, contact)
|
puppet.UpdateName(user, contact)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1176,11 +1203,23 @@ func (user *User) HandleChatUpdate(cmd whatsapp.ChatUpdate) {
|
||||||
go portal.HandleWhatsAppInvite(cmd.Data.SenderJID, nil, cmd.Data.UserChange.JIDs)
|
go portal.HandleWhatsAppInvite(cmd.Data.SenderJID, nil, cmd.Data.UserChange.JIDs)
|
||||||
case whatsapp.ChatActionIntroduce:
|
case whatsapp.ChatActionIntroduce:
|
||||||
if cmd.Data.SenderJID != "unknown" {
|
if cmd.Data.SenderJID != "unknown" {
|
||||||
go portal.Sync(user, whatsapp.Contact{Jid: portal.Key.JID})
|
go portal.Sync(user, whatsapp.Contact{JID: portal.Key.JID})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (user *User) HandleConnInfo(info whatsapp.ConnInfo) {
|
||||||
|
if user.Session != nil && info.Connected && len(info.ClientToken) > 0 {
|
||||||
|
user.log.Debugln("Received new tokens")
|
||||||
|
user.Session.ClientToken = info.ClientToken
|
||||||
|
user.Session.ServerToken = info.ServerToken
|
||||||
|
user.Session.Wid = info.WID
|
||||||
|
}
|
||||||
|
if len(info.PushName) > 0 {
|
||||||
|
user.pushName = info.PushName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (user *User) HandleJSONMessage(message json.RawMessage) {
|
func (user *User) HandleJSONMessage(message json.RawMessage) {
|
||||||
if !json.Valid(message) {
|
if !json.Valid(message) {
|
||||||
return
|
return
|
||||||
|
|
Loading…
Reference in a new issue