diff --git a/go.mod b/go.mod index cc2a624..0f663ad 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/mattn/go-sqlite3 v1.14.10 github.com/prometheus/client_golang v1.11.0 github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e - go.mau.fi/whatsmeow v0.0.0-20220124150706-afc33ee3c21a + go.mau.fi/whatsmeow v0.0.0-20220128124639-e64fb976bf15 golang.org/x/image v0.0.0-20211028202545-6944b10bf410 google.golang.org/protobuf v1.27.1 gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b diff --git a/go.sum b/go.sum index ac927ab..0bc53ee 100644 --- a/go.sum +++ b/go.sum @@ -140,8 +140,8 @@ github.com/tidwall/sjson v1.2.4 h1:cuiLzLnaMeBhRmEv00Lpk3tkYrcxpmbU81tAY4Dw0tc= github.com/tidwall/sjson v1.2.4/go.mod h1:098SZ494YoMWPmMO6ct4dcFnqxwj9r/gF0Etp19pSNM= go.mau.fi/libsignal v0.0.0-20211109153248-a67163214910 h1:9FFhG0OmkuMau5UEaTgiUQ+7cSbtbOQ7hiWKdN8OI3I= go.mau.fi/libsignal v0.0.0-20211109153248-a67163214910/go.mod h1:AufGrvVh+00Nc07Jm4hTquh7yleZyn20tKJI2wCPAKg= -go.mau.fi/whatsmeow v0.0.0-20220124150706-afc33ee3c21a h1:e8aExGixi/O+kveh6S3wgydk9ogU5+gx0NqOmqWMapM= -go.mau.fi/whatsmeow v0.0.0-20220124150706-afc33ee3c21a/go.mod h1:8jUjOAi3xtGubxcZgG8uSHpAdyQXBRbWAfxkctX/4y4= +go.mau.fi/whatsmeow v0.0.0-20220128124639-e64fb976bf15 h1:BmdZu7K6IHsb+sPxvzkEjAINKxTMNeSiJRe1cvfesIY= +go.mau.fi/whatsmeow v0.0.0-20220128124639-e64fb976bf15/go.mod h1:8jUjOAi3xtGubxcZgG8uSHpAdyQXBRbWAfxkctX/4y4= 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-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= diff --git a/metrics.go b/metrics.go index 73d9762..5613b50 100644 --- a/metrics.go +++ b/metrics.go @@ -20,6 +20,7 @@ import ( "context" "net/http" "runtime/debug" + "strconv" "sync" "time" @@ -50,6 +51,7 @@ type MetricsHandler struct { whatsappMessageHandling *prometheus.HistogramVec countCollection prometheus.Histogram disconnections *prometheus.CounterVec + incomingRetryReceipts *prometheus.CounterVec puppetCount prometheus.Gauge userCount prometheus.Gauge messageCount prometheus.Gauge @@ -99,6 +101,10 @@ func NewMetricsHandler(address string, log log.Logger, db *database.Database) *M Name: "whatsapp_disconnections", Help: "Number of times a Matrix user has been disconnected from WhatsApp", }, []string{"user_id"}), + incomingRetryReceipts: promauto.NewCounterVec(prometheus.CounterOpts{ + Name: "whatsapp_incoming_retry_receipts", + Help: "Number of times a remote WhatsApp user has requested a retry from the bridge. retry_count = 5 is usually the last attempt (and very likely means a failed message)", + }, []string{"retry_count", "message_found"}), puppetCount: promauto.NewGauge(prometheus.GaugeOpts{ Name: "whatsapp_puppets_total", Help: "Number of WhatsApp users bridged into Matrix", @@ -167,6 +173,16 @@ func (mh *MetricsHandler) TrackDisconnection(userID id.UserID) { mh.disconnections.With(prometheus.Labels{"user_id": string(userID)}).Inc() } +func (mh *MetricsHandler) TrackRetryReceipt(count int, found bool) { + if !mh.running { + return + } + mh.incomingRetryReceipts.With(prometheus.Labels{ + "retry_count": strconv.Itoa(count), + "message_found": strconv.FormatBool(found), + }).Inc() +} + func (mh *MetricsHandler) TrackLoginState(jid types.JID, loggedIn bool) { if !mh.running { return diff --git a/user.go b/user.go index 2a0deae..8cfcb7c 100644 --- a/user.go +++ b/user.go @@ -39,6 +39,7 @@ import ( "go.mau.fi/whatsmeow" "go.mau.fi/whatsmeow/appstate" + waProto "go.mau.fi/whatsmeow/binary/proto" "go.mau.fi/whatsmeow/store" "go.mau.fi/whatsmeow/types" "go.mau.fi/whatsmeow/types/events" @@ -318,6 +319,19 @@ func (w *waLogger) Sub(module string) waLog.Logger { return &waLogger{l: var ErrAlreadyLoggedIn = errors.New("already logged in") +func (user *User) createClient(sess *store.Device) { + user.Client = whatsmeow.NewClient(sess, &waLogger{user.log.Sub("Client")}) + user.Client.AddEventHandler(user.HandleEvent) + user.Client.GetMessageForRetry = func(to types.JID, id types.MessageID) *waProto.Message { + user.bridge.Metrics.TrackRetryReceipt(0, false) + return nil + } + user.Client.PreRetryCallback = func(receipt *events.Receipt, retryCount int, msg *waProto.Message) bool { + user.bridge.Metrics.TrackRetryReceipt(retryCount, true) + return true + } +} + func (user *User) Login(ctx context.Context) (<-chan whatsmeow.QRChannelItem, error) { user.connLock.Lock() defer user.connLock.Unlock() @@ -328,8 +342,7 @@ func (user *User) Login(ctx context.Context) (<-chan whatsmeow.QRChannelItem, er } newSession := user.bridge.WAContainer.NewDevice() newSession.Log = &waLogger{user.log.Sub("Session")} - user.Client = whatsmeow.NewClient(newSession, &waLogger{user.log.Sub("Client")}) - user.Client.AddEventHandler(user.HandleEvent) + user.createClient(newSession) qrChan, err := user.Client.GetQRChannel(ctx) if err != nil { return nil, fmt.Errorf("failed to get QR channel: %w", err) @@ -351,8 +364,7 @@ func (user *User) Connect() bool { } user.log.Debugln("Connecting to WhatsApp") user.sendBridgeState(BridgeState{StateEvent: StateConnecting, Error: WAConnecting}) - user.Client = whatsmeow.NewClient(user.Session, &waLogger{user.log.Sub("Client")}) - user.Client.AddEventHandler(user.HandleEvent) + user.createClient(user.Session) err := user.Client.Connect() if err != nil { user.log.Warnln("Error connecting to WhatsApp:", err)