Skip to content

Commit 76f8ab8

Browse files
committed
Handle dis
1 parent 91eff9b commit 76f8ab8

File tree

1 file changed

+76
-7
lines changed

1 file changed

+76
-7
lines changed

pkg/channels/whatsapp_native.go

Lines changed: 76 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"path/filepath"
1414
"strings"
1515
"sync"
16+
"time"
1617

1718
"github.com/mdp/qrterminal/v3"
1819
_ "modernc.org/sqlite"
@@ -35,16 +36,24 @@ import (
3536
const (
3637
sqliteDriver = "sqlite"
3738
whatsappDBName = "store.db"
39+
40+
reconnectInitial = 5 * time.Second
41+
reconnectMax = 5 * time.Minute
42+
reconnectMultiplier = 2.0
3843
)
3944

4045
// WhatsAppNativeChannel implements the WhatsApp channel using whatsmeow (in-process, no external bridge).
4146
type WhatsAppNativeChannel struct {
4247
*BaseChannel
43-
config config.WhatsAppConfig
44-
storePath string
45-
client *whatsmeow.Client
46-
container *sqlstore.Container
47-
mu sync.Mutex
48+
config config.WhatsAppConfig
49+
storePath string
50+
client *whatsmeow.Client
51+
container *sqlstore.Container
52+
mu sync.Mutex
53+
runCtx context.Context
54+
runCancel context.CancelFunc
55+
reconnectMu sync.Mutex
56+
reconnecting bool
4857
}
4958

5059
// NewWhatsAppNativeChannel creates a WhatsApp channel that uses whatsmeow for connection.
@@ -133,13 +142,17 @@ func (c *WhatsAppNativeChannel) Start(ctx context.Context) error {
133142
}
134143
}
135144

145+
c.runCtx, c.runCancel = context.WithCancel(ctx)
136146
c.setRunning(true)
137147
logger.InfoCF("channels", "WhatsApp native channel connected", nil)
138148
return nil
139149
}
140150

141151
func (c *WhatsAppNativeChannel) Stop(ctx context.Context) error {
142152
logger.InfoCF("channels", "Stopping WhatsApp native channel", nil)
153+
if c.runCancel != nil {
154+
c.runCancel()
155+
}
143156
c.mu.Lock()
144157
client := c.client
145158
container := c.container
@@ -158,9 +171,65 @@ func (c *WhatsAppNativeChannel) Stop(ctx context.Context) error {
158171
}
159172

160173
func (c *WhatsAppNativeChannel) eventHandler(evt interface{}) {
161-
switch v := evt.(type) {
174+
switch evt.(type) {
162175
case *events.Message:
163-
c.handleIncoming(v)
176+
c.handleIncoming(evt.(*events.Message))
177+
case *events.Disconnected:
178+
logger.InfoCF("channels", "WhatsApp disconnected, will attempt reconnection", nil)
179+
c.reconnectMu.Lock()
180+
if c.reconnecting {
181+
c.reconnectMu.Unlock()
182+
return
183+
}
184+
c.reconnecting = true
185+
c.reconnectMu.Unlock()
186+
go c.reconnectWithBackoff()
187+
}
188+
}
189+
190+
func (c *WhatsAppNativeChannel) reconnectWithBackoff() {
191+
defer func() {
192+
c.reconnectMu.Lock()
193+
c.reconnecting = false
194+
c.reconnectMu.Unlock()
195+
}()
196+
197+
backoff := reconnectInitial
198+
for {
199+
select {
200+
case <-c.runCtx.Done():
201+
return
202+
default:
203+
}
204+
205+
c.mu.Lock()
206+
client := c.client
207+
c.mu.Unlock()
208+
if client == nil {
209+
return
210+
}
211+
212+
logger.InfoCF("channels", "WhatsApp reconnecting", map[string]any{"backoff": backoff.String()})
213+
err := client.Connect()
214+
if err == nil {
215+
logger.InfoCF("channels", "WhatsApp reconnected", nil)
216+
return
217+
}
218+
219+
logger.WarnCF("channels", "WhatsApp reconnect failed", map[string]any{"error": err.Error()})
220+
221+
select {
222+
case <-c.runCtx.Done():
223+
return
224+
case <-time.After(backoff):
225+
if backoff < reconnectMax {
226+
next := time.Duration(float64(backoff) * reconnectMultiplier)
227+
if next > reconnectMax {
228+
next = reconnectMax
229+
}
230+
backoff = next
231+
}
232+
}
164233
}
165234
}
166235

0 commit comments

Comments
 (0)