X-Git-Url: https://git.giacomolli.uk/onechat/blobdiff_plain/33aa709aa4e59e05ada6940a1c055f5e5646a418..d7a967f43fae27bcabc6072da3b5a2f923d47764:/whatsapp.go?ds=inline diff --git a/whatsapp.go b/whatsapp.go index b883496..40729d8 100644 --- a/whatsapp.go +++ b/whatsapp.go @@ -14,6 +14,7 @@ import ( "time" "go.mau.fi/whatsmeow" + "go.mau.fi/whatsmeow/proto/waCompanionReg" "go.mau.fi/whatsmeow/proto/waE2E" "go.mau.fi/whatsmeow/store" "go.mau.fi/whatsmeow/store/sqlstore" @@ -404,7 +405,7 @@ func (w *WhatsApp) connect(ctx context.Context) { err := client.ConnectContext(ctx) if err != nil { - w.logger.Printf("connect: %s", w.redact(err.Error())) + w.logger.Printf("connect failed, restart to retry: %s", w.redact(err.Error())) } } @@ -434,6 +435,7 @@ func (w *WhatsApp) loggedOut(ctx context.Context, l *TurnLoop) error { return nil } + w.logger.Print("logged out by the phone, run /whatsapp pair PHONE") err := w.inbox.deliver(ctx, l, w.link(), true) if err != nil { return err @@ -441,12 +443,12 @@ func (w *WhatsApp) loggedOut(ctx context.Context, l *TurnLoop) error { err = w.removeSession() if err != nil { - w.logger.Printf("delete the session after the logout: %v", err) + w.logger.Printf("session delete failed: %v", err) } err = l.note("WhatsApp was unlinked from the phone.") if err != nil { - w.logger.Printf("note the logout: %v", err) + w.logger.Printf("chat note failed: %v", err) } w.broadcast("WhatsApp was unlinked from the phone. Run /whatsapp pair PHONE to link it again.") @@ -489,9 +491,10 @@ func (w *WhatsApp) unlink(ctx context.Context, l *TurnLoop, answer func(text str return nil } + w.logger.Print("unlinked") err = l.note("WhatsApp is unlinked.") if err != nil { - w.logger.Printf("note the unlink: %v", err) + w.logger.Printf("chat note failed: %v", err) } if client == nil || logoutErr != nil { @@ -513,6 +516,7 @@ func (w *WhatsApp) removeSession() error { w.linked = false w.own = nil w.connected = false + w.disconnectedAt = time.Time{} if w.timer != nil { w.timer.Stop() } @@ -594,6 +598,8 @@ func (w *WhatsApp) pair(ctx, runCtx context.Context, l *TurnLoop, phone string, return } + // The server accepts only a display name of the form "Browser (OS)" + // with a common browser and OS, and refuses the pairing otherwise. code, err := client.PairPhone(ctx, phone, true, whatsmeow.PairClientChrome, "Chrome (Linux)") if err != nil { answer("WhatsApp refused the pairing: " + err.Error() + ". Check the phone number and run /whatsapp pair PHONE again.") @@ -625,10 +631,11 @@ func (w *WhatsApp) pair(ctx, runCtx context.Context, l *TurnLoop, phone string, case item.Event == whatsmeow.QRChannelSuccess.Event: linked = true w.linkedBy(client) + w.logger.Print("linked") err = l.note("WhatsApp is linked.") if err != nil { - w.logger.Printf("note the link: %v", err) + w.logger.Printf("chat note failed: %v", err) } answer("WhatsApp is linked to +" + phone + ".") @@ -691,6 +698,11 @@ func (w *WhatsApp) linkedBy(client WhatsAppClient) { // the library tries again. After noticeDelay of a disconnection, all clients // get one notice, and they get one more when the connection comes back. A // disconnection that the library does not try again gives a notice at once. +// +// The log of the daemon gets one line for each change of the connection of the +// linked device: connected, a failed first connection, a lost connection, and +// connected again with the length of the outage. The retries of the library +// between them log nothing. func (w *WhatsApp) handle(event any) bool { switch event := event.(type) { case *events.Message: @@ -711,12 +723,20 @@ func (w *WhatsApp) handle(event any) bool { w.inbox.startCatchup() } - var notice string + var notice, line string w.mutex.Lock() switch event := event.(type) { case *events.PairSuccess: w.own = whatsappOwnIDs(event.ID.User, event.LID.User) case *events.Connected: + switch { + case !w.linked || w.connected: + case w.disconnectedAt.IsZero(): + line = "connected" + default: + line = "connected again after " + durationText(w.clock().Sub(w.disconnectedAt)) + } + w.connected = true w.connectedAt = w.clock() if w.timer != nil { @@ -729,6 +749,11 @@ func (w *WhatsApp) handle(event any) bool { } case *events.Disconnected: if w.linked && (w.connected || w.disconnectedAt.IsZero()) { + line = "disconnected, retrying" + if !w.connected { + line = "first connect failed, retrying" + } + w.disconnectedAt = w.clock() w.disconnections++ disconnections := w.disconnections @@ -748,10 +773,20 @@ func (w *WhatsApp) handle(event any) bool { w.connected = false w.noticed = true notice = "WhatsApp is disconnected and does not connect again by itself: " + event.PermanentDisconnectDescription() + ". Restart the daemon to try again." + line = "disconnected for good, restart to retry: " + whatsappRedact(w.own, event.PermanentDisconnectDescription()) } } + + if w.closed { + line = "" + } + w.mutex.Unlock() + if line != "" { + w.logger.Print(line) + } + if notice != "" { w.broadcast(notice) } @@ -817,12 +852,20 @@ type WhatsAppRequest struct { answer func(text string) } +// whatsappSetDeviceProps sets the device properties that the library sends at +// the pairing. They are global values of the library, so the daemon sets them +// once before any client exists. The phone shows the linked device with the +// name OneChat and a desktop icon only when the platform type is known. +func whatsappSetDeviceProps() { + store.SetOSInfo("OneChat", [3]uint32{0, 1, 0}) + store.DeviceProps.PlatformType = waCompanionReg.DeviceProps_DESKTOP.Enum() +} + // whatsappNewClient returns the client of the library for device, with handle // as its event handler. The client tries again after a failed first connection, // acknowledges a message only after handle returns true, and downloads no old -// history. The phone shows the device with the name OneChat. +// history. func whatsappNewClient(device *store.Device, handle func(event any) bool) WhatsAppClient { - store.SetOSInfo("OneChat", [3]uint32{0, 1, 0}) client := whatsmeow.NewClient(device, waLog.Noop) client.InitialAutoReconnect = true client.SynchronousAck = true