From d403bfe4605a5c0eb3e93fc71408f5b42700843c Mon Sep 17 00:00:00 2001 From: Gabriel Augusto Date: Sun, 5 Nov 2023 16:17:32 -0300 Subject: [PATCH] fix: database locked error --- configs/app.go | 20 +++++++++++-- controllers/get_qrcode_controller.go | 6 ++++ controllers/get_status_controller.go | 6 ++++ main.go | 4 +-- routes/routes.go | 2 ++ services/wpp_service.go | 43 +++++++++++++++------------- workers/history_sync_worker.go | 2 +- 7 files changed, 58 insertions(+), 25 deletions(-) diff --git a/configs/app.go b/configs/app.go index a027323..9138e95 100644 --- a/configs/app.go +++ b/configs/app.go @@ -18,7 +18,7 @@ type ZapMeow struct { WhatsmeowContainer *sqlstore.Container DatabaseClient *gorm.DB RedisClient *redis.Client - Instances map[string]*Instance + Instances *sync.Map Config ZapMeowConfig Wg *sync.WaitGroup Mutex *sync.Mutex @@ -29,7 +29,7 @@ func NewZapMeow( whatsmeowContainer *sqlstore.Container, databaseClient *gorm.DB, redisClient *redis.Client, - instances map[string]*Instance, + instances *sync.Map, config ZapMeowConfig, wg *sync.WaitGroup, mutex *sync.Mutex, @@ -46,3 +46,19 @@ func NewZapMeow( StopCh: stopCh, } } + +func (a *ZapMeow) LoadInstance(instanceID string) *Instance { + value, _ := a.Instances.Load(instanceID) + if value != nil { + return value.(*Instance) + } + return nil +} + +func (a *ZapMeow) StoreInstance(instanceID string, instance *Instance) { + a.Instances.Store(instanceID, instance) +} + +func (a *ZapMeow) DeleteInstance(instanceID string) { + a.Instances.Delete(instanceID) +} diff --git a/controllers/get_qrcode_controller.go b/controllers/get_qrcode_controller.go index 11eb509..0af281a 100644 --- a/controllers/get_qrcode_controller.go +++ b/controllers/get_qrcode_controller.go @@ -1,6 +1,7 @@ package controllers import ( + "zapmeow/configs" "zapmeow/services" "zapmeow/utils" @@ -8,6 +9,7 @@ import ( ) type getQrCodeController struct { + app *configs.ZapMeow wppService services.WppService messageService services.MessageService accountService services.AccountService @@ -18,11 +20,13 @@ type getQrCodeResponse struct { } func NewGetQrCodeController( + app *configs.ZapMeow, wppService services.WppService, messageService services.MessageService, accountService services.AccountService, ) *getQrCodeController { return &getQrCodeController{ + app: app, wppService: wppService, messageService: messageService, accountService: accountService, @@ -46,6 +50,8 @@ func (q *getQrCodeController) Handler(c *gin.Context) { return } + q.app.Mutex.Lock() + defer q.app.Mutex.Unlock() account, err := q.accountService.GetAccountByInstanceID(instanceID) if err != nil { utils.RespondInternalServerError(c, err.Error()) diff --git a/controllers/get_status_controller.go b/controllers/get_status_controller.go index 5046bac..a259e89 100644 --- a/controllers/get_status_controller.go +++ b/controllers/get_status_controller.go @@ -1,6 +1,7 @@ package controllers import ( + "zapmeow/configs" "zapmeow/services" "zapmeow/utils" @@ -8,6 +9,7 @@ import ( ) type getStatusController struct { + app *configs.ZapMeow wppService services.WppService accountService services.AccountService } @@ -17,10 +19,12 @@ type getStatusResponse struct { } func NewGetStatusController( + app *configs.ZapMeow, wppService services.WppService, accountService services.AccountService, ) *getStatusController { return &getStatusController{ + app: app, wppService: wppService, accountService: accountService, } @@ -44,6 +48,8 @@ func (s *getStatusController) Handler(c *gin.Context) { return } + s.app.Mutex.Lock() + defer s.app.Mutex.Unlock() account, err := s.accountService.GetAccountByInstanceID(instanceID) if err != nil { utils.RespondInternalServerError(c, err.Error()) diff --git a/main.go b/main.go index 5b7cffb..20bbac3 100644 --- a/main.go +++ b/main.go @@ -37,7 +37,7 @@ func main() { } // whatsmeow instances - instances := make(map[string]*configs.Instance) + var instances sync.Map // whatsmeow configs dbLog := waLog.Stdout("Database", "DEBUG", true) @@ -88,7 +88,7 @@ func main() { whatsmeowContainer, databaseClient, redisClient, - instances, + &instances, config, &wg, &mutex, diff --git a/routes/routes.go b/routes/routes.go index f61c994..57afa17 100644 --- a/routes/routes.go +++ b/routes/routes.go @@ -28,6 +28,7 @@ func SetupRouter( } getQrCodeController := controllers.NewGetQrCodeController( + app, wppService, messageService, accountService, @@ -38,6 +39,7 @@ func SetupRouter( accountService, ) getStatusController := controllers.NewGetStatusController( + app, wppService, accountService, ) diff --git a/services/wpp_service.go b/services/wpp_service.go index 911d6ef..317d39c 100644 --- a/services/wpp_service.go +++ b/services/wpp_service.go @@ -114,9 +114,9 @@ func NewWppService( } func (w *wppService) GetInstance(instanceID string) (*configs.Instance, error) { - instance, ok := w.app.Instances[instanceID] + instance := w.app.LoadInstance(instanceID) - if ok && instance != nil { + if instance != nil { return instance, nil } @@ -125,28 +125,31 @@ func (w *wppService) GetInstance(instanceID string) (*configs.Instance, error) { return nil, err } - w.app.Instances[instanceID] = &configs.Instance{ + w.app.StoreInstance(instanceID, &configs.Instance{ ID: instanceID, Client: client, - } - w.app.Instances[instanceID].Client.AddEventHandler(func(evt interface{}) { + }) + + instance = w.app.LoadInstance(instanceID) + + instance.Client.AddEventHandler(func(evt interface{}) { w.eventHandler(instanceID, evt) }) - if w.app.Instances[instanceID].Client.Store.ID == nil { + if instance.Client.Store.ID == nil { go w.qrcode(instanceID) } else { - err := w.app.Instances[instanceID].Client.Connect() + err := instance.Client.Connect() if err != nil { return nil, err } - if !w.app.Instances[instanceID].Client.WaitForConnection(5 * time.Second) { + if !instance.Client.WaitForConnection(5 * time.Second) { return nil, errors.New("websocket didn't reconnect within 5 seconds of failed") } } - return w.app.Instances[instanceID], nil + return instance, nil } func (w *wppService) GetAuthenticatedInstance(instanceID string) (*configs.Instance, error) { @@ -392,7 +395,7 @@ func (w *wppService) destroyInstance(instanceID string) error { } instance.Client.Disconnect() - delete(w.app.Instances, instanceID) + w.app.DeleteInstance(instanceID) return nil } @@ -503,7 +506,7 @@ func (w *wppService) getClient(instanceID string) (*whatsmeow.Client, error) { } func (w *wppService) qrcode(instanceID string) { - instance := w.app.Instances[instanceID] + instance := w.app.LoadInstance(instanceID) if instance.Client.Store.ID == nil { qrChan, err := instance.Client.GetQRChannel(context.Background()) if err != nil { @@ -521,28 +524,28 @@ func (w *wppService) qrcode(instanceID string) { case "success": return case "timeout": - for { - w.app.Mutex.Lock() + { + // w.app.Mutex.Lock() + // defer w.app.Mutex.Unlock() err := w.accountService.UpdateAccount(instanceID, map[string]interface{}{ "QrCode": "", "Status": "TIMEOUT", }) - w.app.Mutex.Unlock() if err != nil { fmt.Println("[qrcode]: ", err) } - delete(w.app.Instances, instanceID) + w.app.DeleteInstance(instanceID) } case "code": - for { - w.app.Mutex.Lock() + { + // w.app.Mutex.Lock() + // defer w.app.Mutex.Unlock() w.accountService.UpdateAccount(instanceID, map[string]interface{}{ "QrCode": evt.Code, "Status": "UNPAIRED", "WasSynced": false, }) - w.app.Mutex.Unlock() if err != nil { fmt.Println("[qrcode]: ", err) } @@ -581,7 +584,7 @@ func (w *wppService) handleHistorySync(instanceID string, evt *events.HistorySyn } func (w *wppService) handleConnected(instanceID string) { - var instance = w.app.Instances[instanceID] + var instance = w.app.LoadInstance(instanceID) err := w.accountService.UpdateAccount(instanceID, map[string]interface{}{ "User": instance.Client.Store.ID.User, "Agent": instance.Client.Store.ID.Agent, @@ -615,7 +618,7 @@ func (w *wppService) handleLoggedOut(instanceID string) { } func (w *wppService) handleMessage(instanceId string, evt *events.Message) { - instance := w.app.Instances[instanceId] + instance := w.app.LoadInstance(instanceId) parsedEventMessage, err := w.ParseEventMessage(instance, evt) if err != nil { diff --git a/workers/history_sync_worker.go b/workers/history_sync_worker.go index 911b078..d4bd7a3 100644 --- a/workers/history_sync_worker.go +++ b/workers/history_sync_worker.go @@ -67,7 +67,7 @@ func (q *historySyncWorker) ProcessQueue() { continue } - instance := q.app.Instances[data.InstanceID] + instance := q.app.LoadInstance(data.InstanceID) account, err := q.accountService.GetAccountByInstanceID(data.InstanceID) if err != nil { fmt.Println(err)