Skip to content
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 66 additions & 9 deletions wmiau.go
Original file line number Diff line number Diff line change
Expand Up @@ -400,7 +400,8 @@ func (s *server) startClient(userID string, textjid string, token string, subscr
jid, _ := parseJID(textjid)
deviceStore, err = container.GetDevice(context.Background(), jid)
if err != nil {
panic(err)
log.Error().Err(err).Msg("Failed to get device")
deviceStore = container.NewDevice()
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This block of code (lines 399-409) appears to be a duplicate of an earlier block (lines 370-380). The deviceStore is re-initialized here, but this new value is not used, as the whatsmeow.Client was already created on lines 392/394 with the deviceStore from the first block. This redundant code can be confusing and should be removed to improve maintainability.

} else {
log.Warn().Msg("No jid found. Creating new device")
Expand Down Expand Up @@ -437,28 +438,28 @@ func (s *server) startClient(userID string, textjid string, token string, subscr
var proxyURL string
err = s.db.Get(&proxyURL, "SELECT proxy_url FROM users WHERE id=$1", userID)
if err == nil && proxyURL != "" {

parsed, perr := url.Parse(proxyURL)
if perr != nil {
log.Warn().Err(perr).Str("proxy", proxyURL).Msg("Invalid proxy URL, skipping proxy setup")
} else {

log.Info().Str("proxy", proxyURL).Msg("Configuring proxy")

if parsed.Scheme == "socks5" || parsed.Scheme == "socks5h" {
// Build SOCKS dialer from URL (supports user:pass in URL)
dialer, derr := proxy.FromURL(parsed, nil)
if derr != nil {
log.Warn().Err(derr).Str("proxy", proxyURL).Msg("Failed to build SOCKS proxy dialer, skipping proxy setup")
} else {
// Apply proxy to both clients now that we know it's valid.
httpClient.SetProxy(proxyURL)
client.SetSOCKSProxy(dialer, whatsmeow.SetProxyOptions{})
log.Info().Msg("SOCKS proxy configured successfully")
}
} else {
// For http/https, apply to both clients.
httpClient.SetProxy(proxyURL)
client.SetProxyAddress(parsed.String(), whatsmeow.SetProxyOptions{})
log.Info().Msg("HTTP/HTTPS proxy configured successfully")
}
}

}
clientManager.SetHTTPClient(userID, httpClient)

Expand Down Expand Up @@ -555,9 +556,65 @@ func (s *server) startClient(userID string, textjid string, token string, subscr
} else {
// Already logged in, just connect
log.Info().Msg("Already logged in, just connect")
err = client.Connect()
if err != nil {
panic(err)

// Retry logic com backoff exponencial
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This comment is not in English and incorrectly describes the backoff strategy as exponential. The implementation time.Duration(attempt) * 5 * time.Second results in a linear backoff (5s, 10s, ...). Please update the comment to be in English and accurately reflect the linear backoff.

Suggested change
// Retry logic com backoff exponencial
// Retry logic with linear backoff

maxRetries := 3
var lastErr error

for attempt := 0; attempt < maxRetries; attempt++ {
if attempt > 0 {
waitTime := time.Duration(attempt) * 5 * time.Second
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The values 3 for max retries and 5 * time.Second for the backoff interval are hardcoded. It's a good practice to define these 'magic numbers' as named constants (e.g., maxConnectionRetries and connectionRetryBaseWait) at the top of the function or file. This improves readability and makes the code easier to maintain and configure.

log.Warn().
Int("attempt", attempt+1).
Int("max_retries", maxRetries).
Dur("wait_time", waitTime).
Msg("Retrying connection after delay")
time.Sleep(waitTime)
}

err = client.Connect()
if err == nil {
log.Info().
Int("attempt", attempt+1).
Msg("Successfully connected to WhatsApp")
break
}

lastErr = err
log.Warn().
Err(err).
Int("attempt", attempt+1).
Int("max_retries", maxRetries).
Msg("Failed to connect to WhatsApp")
}

if lastErr != nil {
log.Error().
Err(lastErr).
Str("userid", userID).
Int("attempts", maxRetries).
Msg("Failed to connect to WhatsApp after all retry attempts")

clientManager.DeleteWhatsmeowClient(userID)
clientManager.DeleteMyClient(userID)
clientManager.DeleteHTTPClient(userID)

sqlStmt := `UPDATE users SET qrcode='', connected=0 WHERE id=$1`
_, dbErr := s.db.Exec(sqlStmt, userID)
if dbErr != nil {
log.Error().Err(dbErr).Msg("Failed to update user status after connection error")
}

mycli := MyClient{client, 1, userID, token, subscriptions, s.db, s}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The mycli variable is already defined in the outer scope of this function (on line 415). Re-creating an identical instance here is redundant. You can remove this line, and the sendEventWithWebHook call on line 615 will use the existing mycli instance from the outer scope.

postmap := make(map[string]interface{})
postmap["event"] = "ConnectFailure"
postmap["error"] = lastErr.Error()
postmap["type"] = "ConnectFailure"
postmap["attempts"] = maxRetries
postmap["reason"] = "Failed to connect after retry attempts"
sendEventWithWebHook(&mycli, postmap, "")

return
}
}

Expand Down