X-Git-Url: https://git.giacomolli.uk/onechat/blobdiff_plain/7b8d8e8f4b57bd51fd6d0f0d926b821f06b0e1f0..c781f79f3c8cb9a7577ee1574d196988da2719b3:/whatsapp.go diff --git a/whatsapp.go b/whatsapp.go index 4950d28..738ef8d 100644 --- a/whatsapp.go +++ b/whatsapp.go @@ -98,60 +98,6 @@ type WhatsAppClient interface { SendMessage(ctx context.Context, to types.JID, message *waE2E.Message, extra ...whatsmeow.SendRequestExtra) (whatsmeow.SendResponse, error) } -// openWhatsApp opens the WhatsApp session in the data directory dir. Without -// the session file, WhatsApp is not linked. The session gives full access to -// the account, so a file that another user can read is an error. The clock -// gives the times of the status, logger gets the failures, and newClient makes -// the client of a device with its event handler. -func openWhatsApp(ctx context.Context, dir string, clock func() time.Time, logger *slog.Logger, newClient func(device *store.Device, handle func(event any) bool) WhatsAppClient) (*WhatsApp, error) { - w := &WhatsApp{ - ctx: ctx, - dir: filepath.Join(dir, whatsappDirName), - clock: clock, - logger: logger, - newClient: newClient, - requests: make(chan WhatsAppRequest, whatsappRequests), - logouts: make(chan struct{}, 1), - groups: newWhatsAppGroups(logger), - } - - var err error - - w.state, err = openWhatsAppState(filepath.Join(w.dir, whatsappStateFileName)) - if err != nil { - return nil, err - } - - w.inbox = newWhatsAppInbox(w.state, clock, w.groups, &ImageStore{dir: filepath.Join(dir, imageDirName)}, logger) - - info, err := os.Stat(w.sessionPath()) - if errors.Is(err, os.ErrNotExist) { - return w, nil - } - - if err != nil { - return nil, fmt.Errorf("read WhatsApp session: %w", err) - } - - if info.Mode().Perm()&0o077 != 0 { - return nil, fmt.Errorf("%s holds the WhatsApp session, so its mode must be 0600", filepath.Join(whatsappDirName, whatsappSessionFileName)) - } - - err = w.openSession(ctx) - if err != nil { - return nil, err - } - - if w.device.ID != nil { - w.linked = true - w.inbox.waitForCatchup() - - w.own = whatsappOwnIDs(w.device.ID.User, w.device.LID.User) - } - - return w, nil -} - // WhatsApp is the link of the daemon to the WhatsApp account of the user, as a // linked device. The session database of the library in dir holds the keys of // the device. Run keeps a linked device connected, and the library connects @@ -212,6 +158,78 @@ type WhatsApp struct { closed bool } +// WhatsAppLink is a copy of the link of the device at one time, for the parts +// of WhatsApp that do not own it: the groups, the batches, find, and send. +type WhatsAppLink struct { + linked bool + device *store.Device + client WhatsAppClient + connected bool + own []string +} + +// WhatsAppRequest is a pair or unlink command for Run, with the function that +// gives its answers to the client that asked. A pairing has the phone number. +type WhatsAppRequest struct { + phone string + unlink bool + answer func(text string) +} + +// openWhatsApp opens the WhatsApp session in the data directory dir. Without +// the session file, WhatsApp is not linked. The session gives full access to +// the account, so a file that another user can read is an error. The clock +// gives the times of the status, logger gets the failures, and newClient makes +// the client of a device with its event handler. +func openWhatsApp(ctx context.Context, dir string, clock func() time.Time, logger *slog.Logger, newClient func(device *store.Device, handle func(event any) bool) WhatsAppClient) (*WhatsApp, error) { + w := &WhatsApp{ + ctx: ctx, + dir: filepath.Join(dir, whatsappDirName), + clock: clock, + logger: logger, + newClient: newClient, + requests: make(chan WhatsAppRequest, whatsappRequests), + logouts: make(chan struct{}, 1), + groups: newWhatsAppGroups(logger), + } + + var err error + + w.state, err = openWhatsAppState(filepath.Join(w.dir, whatsappStateFileName)) + if err != nil { + return nil, err + } + + w.inbox = newWhatsAppInbox(w.state, clock, w.groups, &ImageStore{dir: filepath.Join(dir, imageDirName)}, logger) + + info, err := os.Stat(w.sessionPath()) + if errors.Is(err, os.ErrNotExist) { + return w, nil + } + + if err != nil { + return nil, fmt.Errorf("read WhatsApp session: %w", err) + } + + if info.Mode().Perm()&0o077 != 0 { + return nil, fmt.Errorf("%s holds the WhatsApp session, so its mode must be 0600", filepath.Join(whatsappDirName, whatsappSessionFileName)) + } + + err = w.openSession(ctx) + if err != nil { + return nil, err + } + + if w.device.ID != nil { + w.linked = true + w.inbox.waitForCatchup() + + w.own = whatsappOwnIDs(w.device.ID.User, w.device.LID.User) + } + + return w, nil +} + // Run connects a linked device, logs the closed batches in l, runs the pair and // unlink commands, and handles a logout from the phone, until ctx ends. Its // notes go to the log of l, and notify gets the notices for all clients. A @@ -261,7 +279,8 @@ func (w *WhatsApp) Run(ctx context.Context, l *TurnLoop, notify func(Event)) err var pairing sync.WaitGroup - cancel := func() {} + cancel := func() { + } defer func() { cancel() pairing.Wait() @@ -298,7 +317,8 @@ func (w *WhatsApp) Run(ctx context.Context, l *TurnLoop, notify func(Event)) err cancel() pairing.Wait() - cancel = func() {} + cancel = func() { + } switch { case request.unlink: @@ -1047,24 +1067,6 @@ func (w *WhatsApp) redact(text string) string { return whatsappRedact(w.own, text) } -// WhatsAppLink is a copy of the link of the device at one time, for the parts -// of WhatsApp that do not own it: the groups, the batches, find, and send. -type WhatsAppLink struct { - linked bool - device *store.Device - client WhatsAppClient - connected bool - own []string -} - -// WhatsAppRequest is a pair or unlink command for Run, with the function that -// gives its answers to the client that asked. A pairing has the phone number. -type WhatsAppRequest struct { - phone string - unlink bool - 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