]> git.giacomolli.uk - onechat/blobdiff - whatsapp.go
Order model and chat declarations
[onechat] / whatsapp.go
index 57bfab078301a01907a3c6d898421f24c37df814..ee785a36c19501197ebac0accf76100998ee3353 100644 (file)
@@ -2,6 +2,7 @@ package main
 
 import (
        "context"
 
 import (
        "context"
+       "crypto/sha256"
        "database/sql"
        "errors"
        "fmt"
        "database/sql"
        "errors"
        "fmt"
@@ -97,60 +98,6 @@ type WhatsAppClient interface {
        SendMessage(ctx context.Context, to types.JID, message *waE2E.Message, extra ...whatsmeow.SendRequestExtra) (whatsmeow.SendResponse, error)
 }
 
        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
 // 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
@@ -211,6 +158,78 @@ type WhatsApp struct {
        closed         bool
 }
 
        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
 // 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
@@ -466,7 +485,7 @@ func (w *WhatsApp) Find(ctx context.Context, name string) (string, error) {
 // Send returns the answer of whatsapp_send for text and an optional stored
 // image to chat, with the durable send id that whatsappSend describes.
 func (w *WhatsApp) Send(ctx context.Context, id, chat, text, image string) (string, error) {
 // Send returns the answer of whatsapp_send for text and an optional stored
 // image to chat, with the durable send id that whatsappSend describes.
 func (w *WhatsApp) Send(ctx context.Context, id, chat, text, image string) (string, error) {
-       return whatsappSend(ctx, w.link(), w.groups, w.state, w.inbox.images, w.clock, id, chat, text, image)
+       return whatsappSend(ctx, w.link(), w.groups, w.state, w.inbox.images, w.logger, w.clock, id, chat, text, image)
 }
 
 func (w *WhatsApp) sessionPath() string {
 }
 
 func (w *WhatsApp) sessionPath() string {
@@ -1046,24 +1065,6 @@ func (w *WhatsApp) redact(text string) string {
        return whatsappRedact(w.own, text)
 }
 
        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
 // 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
@@ -1144,6 +1145,14 @@ func whatsappOwnIDs(ids ...string) []string {
        return own
 }
 
        return own
 }
 
+// whatsappChatHash returns a short hash of chat for the daemon log, so that a
+// log line can tell chats apart without a phone number.
+func whatsappChatHash(chat types.JID) string {
+       digest := sha256.Sum256([]byte(chat.ToNonAD().String()))
+
+       return fmt.Sprintf("%x", digest[:6])
+}
+
 // whatsappRedact replaces each of the own IDs own in text with OWN.
 func whatsappRedact(own []string, text string) string {
        for _, id := range own {
 // whatsappRedact replaces each of the own IDs own in text with OWN.
 func whatsappRedact(own []string, text string) string {
        for _, id := range own {