Browse Source

feat: standardize error

pull/48/head
Aldino Kemal 3 years ago
parent
commit
df980a091b
  1. 1
      src/go.mod
  2. 3
      src/go.sum
  3. 6
      src/internal/rest/app.go
  4. 3
      src/internal/rest/middleware/recovery.go
  5. 9
      src/internal/rest/send.go
  6. 6
      src/internal/rest/user.go
  7. 108
      src/pkg/error/app_error.go
  8. 19
      src/pkg/error/auth_error.go
  9. 18
      src/pkg/error/whatsapp_error.go
  10. 4
      src/pkg/utils/response.go
  11. 23
      src/services/app.go

1
src/go.mod

@ -35,6 +35,7 @@ require (
github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/rivo/uniseg v0.4.3 // indirect github.com/rivo/uniseg v0.4.3 // indirect
github.com/savsgio/gotils v0.0.0-20220530130905-52f3993e8d6d // indirect github.com/savsgio/gotils v0.0.0-20220530130905-52f3993e8d6d // indirect
github.com/sirupsen/logrus v1.9.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect github.com/spf13/pflag v1.0.5 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/tcplisten v1.0.0 // indirect github.com/valyala/tcplisten v1.0.0 // indirect

3
src/go.sum

@ -365,6 +365,8 @@ github.com/savsgio/gotils v0.0.0-20220530130905-52f3993e8d6d/go.mod h1:Gy+0tqhJv
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0= github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0=
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M= github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
@ -617,6 +619,7 @@ golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220111092808-5a964db01320/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220111092808-5a964db01320/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ= golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ=

6
src/internal/rest/app.go

@ -27,7 +27,8 @@ func (handler *App) Login(c *fiber.Ctx) error {
return c.JSON(utils.ResponseData{ return c.JSON(utils.ResponseData{
Status: 200, Status: 200,
Message: "Success",
Code: "SUCCESS",
Message: "Login success",
Results: map[string]any{ Results: map[string]any{
"qr_link": fmt.Sprintf("%s://%s/%s", c.Protocol(), c.Hostname(), response.ImagePath), "qr_link": fmt.Sprintf("%s://%s/%s", c.Protocol(), c.Hostname(), response.ImagePath),
"qr_duration": response.Duration, "qr_duration": response.Duration,
@ -41,6 +42,7 @@ func (handler *App) Logout(c *fiber.Ctx) error {
return c.JSON(utils.ResponseData{ return c.JSON(utils.ResponseData{
Status: 200, Status: 200,
Code: "SUCCESS",
Message: "Success logout", Message: "Success logout",
Results: nil, Results: nil,
}) })
@ -52,6 +54,7 @@ func (handler *App) Reconnect(c *fiber.Ctx) error {
return c.JSON(utils.ResponseData{ return c.JSON(utils.ResponseData{
Status: 200, Status: 200,
Code: "SUCCESS",
Message: "Reconnect success", Message: "Reconnect success",
Results: nil, Results: nil,
}) })
@ -63,6 +66,7 @@ func (handler *App) Devices(c *fiber.Ctx) error {
return c.JSON(utils.ResponseData{ return c.JSON(utils.ResponseData{
Status: 200, Status: 200,
Code: "SUCCESS",
Message: "Fetch device success", Message: "Fetch device success",
Results: devices, Results: devices,
}) })

3
src/internal/rest/middleware/recovery.go

@ -14,7 +14,8 @@ func Recovery() fiber.Handler {
if err != nil { if err != nil {
var res utils.ResponseData var res utils.ResponseData
res.Status = 500 res.Status = 500
res.Message = fmt.Sprintf("%s", err)
res.Code = "INTERNAL_SERVER_ERROR"
res.Message = fmt.Sprintf("%v", err)
errValidation, isValidationError := err.(pkgError.GenericError) errValidation, isValidationError := err.(pkgError.GenericError)
if isValidationError { if isValidationError {

9
src/internal/rest/send.go

@ -37,6 +37,7 @@ func (controller *Send) SendText(c *fiber.Ctx) error {
return c.JSON(utils.ResponseData{ return c.JSON(utils.ResponseData{
Status: 200, Status: 200,
Code: "SUCCESS",
Message: response.Status, Message: response.Status,
Results: response, Results: response,
}) })
@ -60,6 +61,7 @@ func (controller *Send) SendImage(c *fiber.Ctx) error {
return c.JSON(utils.ResponseData{ return c.JSON(utils.ResponseData{
Status: 200, Status: 200,
Code: "SUCCESS",
Message: response.Status, Message: response.Status,
Results: response, Results: response,
}) })
@ -81,6 +83,7 @@ func (controller *Send) SendFile(c *fiber.Ctx) error {
return c.JSON(utils.ResponseData{ return c.JSON(utils.ResponseData{
Status: 200, Status: 200,
Code: "SUCCESS",
Message: response.Status, Message: response.Status,
Results: response, Results: response,
}) })
@ -102,6 +105,7 @@ func (controller *Send) SendVideo(c *fiber.Ctx) error {
return c.JSON(utils.ResponseData{ return c.JSON(utils.ResponseData{
Status: 200, Status: 200,
Code: "SUCCESS",
Message: response.Status, Message: response.Status,
Results: response, Results: response,
}) })
@ -119,6 +123,7 @@ func (controller *Send) SendContact(c *fiber.Ctx) error {
return c.JSON(utils.ResponseData{ return c.JSON(utils.ResponseData{
Status: 200, Status: 200,
Code: "SUCCESS",
Message: response.Status, Message: response.Status,
Results: response, Results: response,
}) })
@ -136,6 +141,7 @@ func (controller *Send) SendLink(c *fiber.Ctx) error {
return c.JSON(utils.ResponseData{ return c.JSON(utils.ResponseData{
Status: 200, Status: 200,
Code: "SUCCESS",
Message: response.Status, Message: response.Status,
Results: response, Results: response,
}) })
@ -153,6 +159,7 @@ func (controller *Send) SendLocation(c *fiber.Ctx) error {
return c.JSON(utils.ResponseData{ return c.JSON(utils.ResponseData{
Status: 200, Status: 200,
Code: "SUCCESS",
Message: response.Status, Message: response.Status,
Results: response, Results: response,
}) })
@ -171,6 +178,7 @@ func (controller *Send) RevokeMessage(c *fiber.Ctx) error {
return c.JSON(utils.ResponseData{ return c.JSON(utils.ResponseData{
Status: 200, Status: 200,
Code: "SUCCESS",
Message: response.Status, Message: response.Status,
Results: response, Results: response,
}) })
@ -189,6 +197,7 @@ func (controller *Send) UpdateMessage(c *fiber.Ctx) error {
return c.JSON(utils.ResponseData{ return c.JSON(utils.ResponseData{
Status: 200, Status: 200,
Code: "SUCCESS",
Message: response.Status, Message: response.Status,
Results: response, Results: response,
}) })

6
src/internal/rest/user.go

@ -33,7 +33,8 @@ func (controller *User) UserInfo(c *fiber.Ctx) error {
return c.JSON(utils.ResponseData{ return c.JSON(utils.ResponseData{
Status: 200, Status: 200,
Message: "Success",
Code: "SUCCESS",
Message: "Success get user info",
Results: response.Data[0], Results: response.Data[0],
}) })
} }
@ -50,6 +51,7 @@ func (controller *User) UserAvatar(c *fiber.Ctx) error {
return c.JSON(utils.ResponseData{ return c.JSON(utils.ResponseData{
Status: 200, Status: 200,
Code: "SUCCESS",
Message: "Success get avatar", Message: "Success get avatar",
Results: response, Results: response,
}) })
@ -61,6 +63,7 @@ func (controller *User) UserMyPrivacySetting(c *fiber.Ctx) error {
return c.JSON(utils.ResponseData{ return c.JSON(utils.ResponseData{
Status: 200, Status: 200,
Code: "SUCCESS",
Message: "Success get privacy", Message: "Success get privacy",
Results: response, Results: response,
}) })
@ -72,6 +75,7 @@ func (controller *User) UserMyListGroups(c *fiber.Ctx) error {
return c.JSON(utils.ResponseData{ return c.JSON(utils.ResponseData{
Status: 200, Status: 200,
Code: "SUCCESS",
Message: "Success get list groups", Message: "Success get list groups",
Results: response, Results: response,
}) })

108
src/pkg/error/app_error.go

@ -0,0 +1,108 @@
package error
import "net/http"
type LoginError string
// Error for complying the error interface
func (e LoginError) Error() string {
return string(e)
}
// ErrCode will return the error code based on the error data type
func (e LoginError) ErrCode() string {
return "ALREADY_LOGGED_IN"
}
// StatusCode will return the HTTP status code based on the error data type
func (e LoginError) StatusCode() int {
return http.StatusBadRequest
}
type ReconnectError string
func throwReconnectError(text string) GenericError {
return AuthError(text)
}
// Error for complying the error interface
func (e ReconnectError) Error() string {
return string(e)
}
// ErrCode will return the error code based on the error data type
func (e ReconnectError) ErrCode() string {
return "RECONNECT_ERROR"
}
// StatusCode will return the HTTP status code based on the error data type
func (e ReconnectError) StatusCode() int {
return http.StatusBadRequest
}
type AuthError string
func throwAuthError(text string) GenericError {
return AuthError(text)
}
func (err AuthError) Error() string {
return string(err)
}
// ErrCode will return the error code based on the error data type
func (err AuthError) ErrCode() string {
return "AUTHENTICATION_ERROR"
}
// StatusCode will return the HTTP status code based on the error data type
func (err AuthError) StatusCode() int {
return http.StatusUnauthorized
}
type qrChannelError string
func throwQrChannelError(text string) GenericError {
return qrChannelError(text)
}
func (err qrChannelError) Error() string {
return string(err)
}
// ErrCode will return the error code based on the error data type
func (err qrChannelError) ErrCode() string {
return "QR_CHANNEL_ERROR"
}
// StatusCode will return the HTTP status code based on the error data type
func (err qrChannelError) StatusCode() int {
return http.StatusInternalServerError
}
type sessionSavedError string
func throwSessionSavedError(text string) GenericError {
return sessionSavedError(text)
}
func (err sessionSavedError) Error() string {
return string(err)
}
// ErrCode will return the error code based on the error data type
func (err sessionSavedError) ErrCode() string {
return "SESSION_SAVED_ERROR"
}
// StatusCode will return the HTTP status code based on the error data type
func (err sessionSavedError) StatusCode() int {
return http.StatusInternalServerError
}
var (
ErrAlreadyLoggedIn = LoginError("You already logged in :)")
ErrReconnect = throwReconnectError("Reconnect error")
ErrQrChannel = throwQrChannelError("QR channel error")
ErrorSessionSaved = throwSessionSavedError("Your session have been saved, please wait to connect 2 second and refresh again")
)

19
src/pkg/error/auth_error.go

@ -1,19 +0,0 @@
package error
import "net/http"
type AuthError string
func (err AuthError) Error() string {
return string(err)
}
// ErrCode will return the error code based on the error data type
func (err AuthError) ErrCode() string {
return "AUTHENTICATION_ERROR"
}
// StatusCode will return the HTTP status code based on the error data type
func (err AuthError) StatusCode() int {
return http.StatusUnauthorized
}

18
src/pkg/error/whatsapp_error.go

@ -36,6 +36,24 @@ func (e WebhookError) StatusCode() int {
return http.StatusInternalServerError return http.StatusInternalServerError
} }
type WaCliError string
// Error for complying the error interface
func (e WaCliError) Error() string {
return string(e)
}
// ErrCode will return the error code based on the error data type
func (e WaCliError) ErrCode() string {
return "INVALID_WA_CLI"
}
// StatusCode will return the HTTP status code based on the error data type
func (e WaCliError) StatusCode() int {
return http.StatusInternalServerError
}
const ( const (
ErrInvalidJID = InvalidJID("your JID is invalid") ErrInvalidJID = InvalidJID("your JID is invalid")
ErrWaCLI = WaCliError("your WhatsApp CLI is invalid or empty")
) )

4
src/pkg/utils/response.go

@ -2,7 +2,7 @@ package utils
type ResponseData struct { type ResponseData struct {
Status int `json:"-"` Status int `json:"-"`
Code string `json:"code,omitempty"`
Code string `json:"code"`
Message string `json:"message"` Message string `json:"message"`
Results any `json:"results"`
Results any `json:"results,omitempty"`
} }

23
src/services/app.go

@ -6,8 +6,11 @@ import (
"fmt" "fmt"
"github.com/aldinokemal/go-whatsapp-web-multidevice/config" "github.com/aldinokemal/go-whatsapp-web-multidevice/config"
domainApp "github.com/aldinokemal/go-whatsapp-web-multidevice/domains/app" domainApp "github.com/aldinokemal/go-whatsapp-web-multidevice/domains/app"
pkgError "github.com/aldinokemal/go-whatsapp-web-multidevice/pkg/error"
fiberUtils "github.com/gofiber/fiber/v2/utils" fiberUtils "github.com/gofiber/fiber/v2/utils"
"github.com/sirupsen/logrus"
"github.com/skip2/go-qrcode" "github.com/skip2/go-qrcode"
"go.mau.fi/libsignal/logger"
"go.mau.fi/whatsmeow" "go.mau.fi/whatsmeow"
"go.mau.fi/whatsmeow/store/sqlstore" "go.mau.fi/whatsmeow/store/sqlstore"
"os" "os"
@ -30,7 +33,7 @@ func NewAppService(waCli *whatsmeow.Client, db *sqlstore.Container) domainApp.IA
func (service serviceApp) Login(_ context.Context) (response domainApp.LoginResponse, err error) { func (service serviceApp) Login(_ context.Context) (response domainApp.LoginResponse, err error) {
if service.WaCli == nil { if service.WaCli == nil {
return response, errors.New("wa cli nil cok")
return response, pkgError.ErrWaCLI
} }
// Disconnect for reconnecting // Disconnect for reconnecting
@ -40,15 +43,16 @@ func (service serviceApp) Login(_ context.Context) (response domainApp.LoginResp
ch, err := service.WaCli.GetQRChannel(context.Background()) ch, err := service.WaCli.GetQRChannel(context.Background())
if err != nil { if err != nil {
logrus.Error(err.Error())
// This error means that we're already logged in, so ignore it. // This error means that we're already logged in, so ignore it.
if errors.Is(err, whatsmeow.ErrQRStoreContainsID) { if errors.Is(err, whatsmeow.ErrQRStoreContainsID) {
_ = service.WaCli.Connect() // just connect to websocket _ = service.WaCli.Connect() // just connect to websocket
if service.WaCli.IsLoggedIn() { if service.WaCli.IsLoggedIn() {
return response, errors.New("you already logged in :)")
return response, pkgError.ErrAlreadyLoggedIn
} }
return response, errors.New("your session have been saved, please wait to connect 2 second and refresh again")
return response, pkgError.ErrorSessionSaved
} else { } else {
return response, errors.New("Error when GetQRChannel:" + err.Error())
return response, pkgError.ErrQrChannel
} }
} else { } else {
go func() { go func() {
@ -59,18 +63,18 @@ func (service serviceApp) Login(_ context.Context) (response domainApp.LoginResp
qrPath := fmt.Sprintf("%s/scan-qr-%s.png", config.PathQrCode, fiberUtils.UUIDv4()) qrPath := fmt.Sprintf("%s/scan-qr-%s.png", config.PathQrCode, fiberUtils.UUIDv4())
err = qrcode.WriteFile(evt.Code, qrcode.Medium, 512, qrPath) err = qrcode.WriteFile(evt.Code, qrcode.Medium, 512, qrPath)
if err != nil { if err != nil {
fmt.Println("error when write qrImage file", err.Error())
logrus.Error("Error when write qr code to file: ", err)
} }
go func() { go func() {
time.Sleep(response.Duration * time.Second) time.Sleep(response.Duration * time.Second)
err := os.Remove(qrPath) err := os.Remove(qrPath)
if err != nil { if err != nil {
fmt.Println("Failed to remove qrPath " + qrPath)
logrus.Error("error when remove qrImage file", err.Error())
} }
}() }()
chImage <- qrPath chImage <- qrPath
} else { } else {
fmt.Printf("QR channel result: %s", evt.Event)
logrus.Error("error when get qrCode", evt.Event)
} }
} }
}() }()
@ -78,7 +82,8 @@ func (service serviceApp) Login(_ context.Context) (response domainApp.LoginResp
err = service.WaCli.Connect() err = service.WaCli.Connect()
if err != nil { if err != nil {
return response, errors.New("Failed to connect bro " + err.Error())
logger.Error("Error when connect to whatsapp", err)
return response, pkgError.ErrReconnect
} }
response.ImagePath = <-chImage response.ImagePath = <-chImage
@ -137,7 +142,7 @@ func (service serviceApp) Reconnect(_ context.Context) (err error) {
func (service serviceApp) FetchDevices(_ context.Context) (response []domainApp.FetchDevicesResponse, err error) { func (service serviceApp) FetchDevices(_ context.Context) (response []domainApp.FetchDevicesResponse, err error) {
if service.WaCli == nil { if service.WaCli == nil {
return response, errors.New("wa cli nil cok")
return response, pkgError.ErrWaCLI
} }
devices, err := service.db.GetAllDevices() devices, err := service.db.GetAllDevices()

Loading…
Cancel
Save