]> git.giacomolli.uk - onechat/blobdiff - whatsapp.go
Pass caller contexts through WhatsApp callbacks
[onechat] / whatsapp.go
index 851cfd1c348053a8dba203afc24a20e7e4a55ec3..be1acc65b8e763b131f107513b3efd9c2e71af0f 100644 (file)
@@ -95,6 +95,7 @@ type WhatsAppClient interface {
        PairPhone(ctx context.Context, phone string, showPushNotification bool, clientType whatsmeow.PairClientType, clientDisplayName string) (string, error)
        Logout(ctx context.Context) error
        GetJoinedGroups(ctx context.Context) ([]*types.GroupInfo, error)
        PairPhone(ctx context.Context, phone string, showPushNotification bool, clientType whatsmeow.PairClientType, clientDisplayName string) (string, error)
        Logout(ctx context.Context) error
        GetJoinedGroups(ctx context.Context) ([]*types.GroupInfo, error)
+       Download(ctx context.Context, message whatsmeow.DownloadableMessage) ([]byte, error)
        GenerateMessageID() types.MessageID
        SendMessage(ctx context.Context, to types.JID, message *waE2E.Message, extra ...whatsmeow.SendRequestExtra) (whatsmeow.SendResponse, error)
 }
        GenerateMessageID() types.MessageID
        SendMessage(ctx context.Context, to types.JID, message *waE2E.Message, extra ...whatsmeow.SendRequestExtra) (whatsmeow.SendResponse, error)
 }
@@ -106,6 +107,7 @@ type WhatsAppClient interface {
 // 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{
 // 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,
                dir:         filepath.Join(dir, whatsappDirName),
                clock:       clock,
                logger:      logger,
@@ -123,7 +125,7 @@ func openWhatsApp(ctx context.Context, dir string, clock func() time.Time, logge
                return nil, err
        }
 
                return nil, err
        }
 
-       w.inbox = newWhatsAppInbox(w.state, clock, w.groups)
+       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) {
 
        info, err := os.Stat(w.sessionPath())
        if errors.Is(err, os.ErrNotExist) {
@@ -168,9 +170,12 @@ func openWhatsApp(ctx context.Context, dir string, clock func() time.Time, logge
 // creation, close, removal, and snapshots. It is held before mutex, and stays
 // held when removal releases mutex for client callbacks.
 //
 // creation, close, removal, and snapshots. It is held before mutex, and stays
 // held when removal releases mutex for client callbacks.
 //
-// The inbox puts the text messages into batches and logs them, and groups
-// holds the names of the groups. Both get a WhatsAppLink from link for each
-// call, so they use the current device and client.
+// ctx is the caller context until Run sets its context for library callbacks.
+// The mutex protects it, so callbacks follow daemon cancellation.
+//
+// The inbox puts messages into batches and logs them, and groups holds the
+// names of the groups. Both get a WhatsAppLink from link for each call, so they
+// use the current device and client.
 //
 // The library logs nothing, because its log lines hold the ID of the own
 // account, which is the phone number of the user. The own number and the own
 //
 // The library logs nothing, because its log lines hold the ID of the own
 // account, which is the phone number of the user. The own number and the own
@@ -180,6 +185,7 @@ func openWhatsApp(ctx context.Context, dir string, clock func() time.Time, logge
 // log, and those of private chats hold phone numbers, because the agent needs
 // them to send.
 type WhatsApp struct {
 // log, and those of private chats hold phone numbers, because the agent needs
 // them to send.
 type WhatsApp struct {
+       ctx         context.Context
        dir         string
        clock       func() time.Time
        logger      *slog.Logger
        dir         string
        clock       func() time.Time
        logger      *slog.Logger
@@ -223,6 +229,7 @@ type WhatsApp struct {
 func (w *WhatsApp) Run(ctx context.Context, l *TurnLoop, notify func(Event)) error {
        w.mutex.Lock()
 
 func (w *WhatsApp) Run(ctx context.Context, l *TurnLoop, notify func(Event)) error {
        w.mutex.Lock()
 
+       w.ctx = ctx
        w.notify = notify
        linked := w.linked
        w.retrying = linked
        w.notify = notify
        linked := w.linked
        w.retrying = linked
@@ -899,9 +906,14 @@ func (w *WhatsApp) linkedBy(client WhatsAppClient) {
 // connected again with the length of the outage. The retries of the library and
 // Run between them log nothing.
 func (w *WhatsApp) handle(event any) bool {
 // connected again with the length of the outage. The retries of the library and
 // Run between them log nothing.
 func (w *WhatsApp) handle(event any) bool {
+       w.mutex.Lock()
+
+       ctx := w.ctx
+       w.mutex.Unlock()
+
        switch event := event.(type) {
        case *events.Message:
        switch event := event.(type) {
        case *events.Message:
-               return w.inbox.receive(w.link(), event)
+               return w.inbox.receive(ctx, w.link(), event)
        case *events.GroupInfo:
                if event.Name != nil {
                        w.groups.set(event.JID.String(), event.Name.Name)
        case *events.GroupInfo:
                if event.Name != nil {
                        w.groups.set(event.JID.String(), event.Name.Name)
@@ -986,7 +998,7 @@ func (w *WhatsApp) handle(event any) bool {
        w.mutex.Unlock()
 
        if line != "" {
        w.mutex.Unlock()
 
        if line != "" {
-               w.logger.Log(context.Background(), level, line, attrs...)
+               w.logger.Log(ctx, level, line, attrs...)
        }
 
        if notice != "" {
        }
 
        if notice != "" {