Browse Source

update with some improvement

pull/4/head
Dimas Restu H 4 years ago
parent
commit
9856a242b9
  1. 10
      .env.default
  2. 23
      .env.development
  3. 23
      .env.production
  4. 1
      Dockerfile
  5. 1
      README.md
  6. 36
      cmd/main/main.go
  7. 2
      go.mod
  8. 12
      internal/route.go
  9. 5
      internal/startup.go
  10. 4
      internal/whatsapp/types/request.go
  11. 2
      internal/whatsapp/types/response.go
  12. 19
      internal/whatsapp/whatsapp.go
  13. 62
      pkg/whatsapp/whatsapp.go

10
.env.example → .env.default

@ -1,7 +1,13 @@
# -----------------------------------
# HTTP Server Configuration
# Server Configuration
# -----------------------------------
# HTTP_BASE_URL=/
# SERVER_ADDRESS=127.0.0.1
# SERVER_PORT=3000
# -----------------------------------
# HTTP Configuration
# -----------------------------------
# HTTP_BASE_URL=/api/v1/whatsapp
# HTTP_CORS_ORIGIN=*
# HTTP_BODY_LIMIT_SIZE=8m

23
.env.development

@ -0,0 +1,23 @@
# -----------------------------------
# Server Configuration
# -----------------------------------
SERVER_ADDRESS=127.0.0.1
SERVER_PORT=3000
# -----------------------------------
# HTTP Configuration
# -----------------------------------
HTTP_BASE_URL=/api/v1/whatsapp
# HTTP_CORS_ORIGIN=*
# HTTP_BODY_LIMIT_SIZE=8m
# HTTP_GZIP_LEVEL=1
# -----------------------------------
# Authentication Configuration
# -----------------------------------
AUTH_BASIC_USERNAME=admin
AUTH_BASIC_PASSWORD=83e4060e-78e1-4fe5-9977-aeeccd46a2b8
AUTH_JWT_SECRET=9e4eb4cf-be25-4a29-bba3-fefb5a30f6ab
AUTH_JWT_EXPIRED_HOUR=24

23
.env.production

@ -0,0 +1,23 @@
# -----------------------------------
# Server Configuration
# -----------------------------------
SERVER_ADDRESS=0.0.0.0
SERVER_PORT=3000
# -----------------------------------
# HTTP Configuration
# -----------------------------------
HTTP_BASE_URL=/api/v1/whatsapp
# HTTP_CORS_ORIGIN=*
# HTTP_BODY_LIMIT_SIZE=8m
# HTTP_GZIP_LEVEL=1
# -----------------------------------
# Authentication Configuration
# -----------------------------------
AUTH_BASIC_USERNAME=admin
AUTH_BASIC_PASSWORD=83e4060e-78e1-4fe5-9977-aeeccd46a2b8
AUTH_JWT_SECRET=9e4eb4cf-be25-4a29-bba3-fefb5a30f6ab
AUTH_JWT_EXPIRED_HOUR=24

1
Dockerfile

@ -21,6 +21,7 @@ ENV PATH $PATH:/usr/app/${SERVICE_NAME}
WORKDIR /usr/app/${SERVICE_NAME}
COPY --from=go-builder /usr/src/app/.env.production ./.env
COPY --from=go-builder /usr/src/app/main ./main
EXPOSE 3000

1
README.md

@ -40,6 +40,7 @@ make vendor
```
* Until this step you already can run this code by using this command
```
ln -sf .env.development .env
make run
```

36
cmd/main/main.go

@ -13,12 +13,18 @@ import (
"github.com/go-playground/validator/v10"
"github.com/dimaskiddo/go-whatsapp-multidevice-rest/pkg/env"
"github.com/dimaskiddo/go-whatsapp-multidevice-rest/pkg/log"
"github.com/dimaskiddo/go-whatsapp-multidevice-rest/pkg/router"
"github.com/dimaskiddo/go-whatsapp-multidevice-rest/internal"
)
type Server struct {
Address string
Port string
}
type EchoValidator struct {
Validator *validator.Validate
}
@ -28,6 +34,8 @@ func (ev *EchoValidator) Validate(i interface{}) error {
}
func main() {
var err error
// Initialize Echo
e := echo.New()
@ -70,12 +78,28 @@ func main() {
e.HTTPErrorHandler = router.HttpErrorHandler
e.GET("/favicon.ico", router.ResponseNoContent)
// Router Load Routes
// Load Internal Routes
internal.Routes(e)
// Running Startup Tasks
internal.Startup()
// Get Server Configuration
var serverConfig Server
serverConfig.Address, err = env.GetEnvString("SERVER_ADDRESS")
if err != nil {
serverConfig.Address = "127.0.0.1"
}
serverConfig.Port, err = env.GetEnvString("SERVER_PORT")
if err != nil {
serverConfig.Port = "3000"
}
// Start Server
go func() {
err := e.Start(":3000")
err := e.Start(serverConfig.Address + ":" + serverConfig.Port)
if err != nil && err != http.ErrServerClosed {
log.Print(nil).Fatal(err.Error())
}
@ -87,12 +111,12 @@ func main() {
signal.Notify(sigShutdown, syscall.SIGTERM)
<-sigShutdown
// Wait 5 Seconds for Graceful Shutdown
ctx, cancelShutdown := context.WithTimeout(context.Background(), 5*time.Second)
defer cancelShutdown()
// Wait 5 Seconds Before Graceful Shutdown
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
// Try To Shutdown Server
err := e.Shutdown(ctx)
err = e.Shutdown(ctx)
if err != nil {
log.Print(nil).Fatal(err.Error())
}

2
go.mod

@ -11,6 +11,7 @@ require (
github.com/sirupsen/logrus v1.8.1
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
go.mau.fi/whatsmeow v0.0.0-20220416192948-8b34d886d543
google.golang.org/protobuf v1.27.1
)
require (
@ -30,5 +31,4 @@ require (
golang.org/x/sys v0.0.0-20211103235746-7861aae1554b // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/time v0.0.0-20201208040808-7e3f01d25324 // indirect
google.golang.org/protobuf v1.27.1 // indirect
)

12
internal/route.go

@ -32,12 +32,10 @@ func Routes(e *echo.Echo) {
e.POST(router.BaseURL+"/login", ctlWhatsApp.Login, middleware.JWTWithConfig(authJWTConfig))
e.POST(router.BaseURL+"/send/text", ctlWhatsApp.SendText, middleware.JWTWithConfig(authJWTConfig))
/*
e.POST(router.BaseURL+"/send/location", ctlWhatsApp.SendLocation, middleware.JWTWithConfig(authJWTConfig))
e.POST(router.BaseURL+"/send/document", ctlWhatsApp.SendDocument, middleware.JWTWithConfig(authJWTConfig))
e.POST(router.BaseURL+"/send/audio", ctlWhatsApp.SendAudio, middleware.JWTWithConfig(authJWTConfig))
e.POST(router.BaseURL+"/send/image", ctlWhatsApp.SendImage, middleware.JWTWithConfig(authJWTConfig))
e.POST(router.BaseURL+"/send/video", ctlWhatsApp.SendVideo, middleware.JWTWithConfig(authJWTConfig))
*/
// e.POST(router.BaseURL+"/send/location", ctlWhatsApp.SendLocation, middleware.JWTWithConfig(authJWTConfig))
// e.POST(router.BaseURL+"/send/document", ctlWhatsApp.SendDocument, middleware.JWTWithConfig(authJWTConfig))
// e.POST(router.BaseURL+"/send/audio", ctlWhatsApp.SendAudio, middleware.JWTWithConfig(authJWTConfig))
// e.POST(router.BaseURL+"/send/image", ctlWhatsApp.SendImage, middleware.JWTWithConfig(authJWTConfig))
// e.POST(router.BaseURL+"/send/video", ctlWhatsApp.SendVideo, middleware.JWTWithConfig(authJWTConfig))
e.POST(router.BaseURL+"/logout", ctlWhatsApp.Logout, middleware.JWTWithConfig(authJWTConfig))
}

5
internal/startup.go

@ -0,0 +1,5 @@
package internal
func Startup() {
}

4
internal/whatsapp/types/request.go

@ -7,14 +7,10 @@ type RequestLogin struct {
type RequestSendMessage struct {
RJID string
Message string
// QuotedID string
// QuotedMessage string
}
type RequestSendLocation struct {
RJID string
Latitude float64
Longitude float64
// QuotedID string
// QuotedMessage string
}

2
internal/whatsapp/types/response.go

@ -1,6 +1,6 @@
package types
type ResponseLogin struct {
Timeout string `json:"timeout"`
QRCode string `json:"qrcode"`
Timeout int `json:"timeout"`
}

19
internal/whatsapp/whatsapp.go

@ -1,6 +1,9 @@
package whatsapp
import (
"strconv"
"strings"
"github.com/golang-jwt/jwt"
"github.com/labstack/echo/v4"
@ -22,9 +25,9 @@ func Login(c echo.Context) error {
jid := jwtPayload(c).JID
var reqLogin typWhatsApp.RequestLogin
reqLogin.Output = c.FormValue("output")
reqLogin.Output = strings.TrimSpace(c.FormValue("output"))
if reqLogin.Output == "" {
if len(reqLogin.Output) == 0 {
reqLogin.Output = "html"
}
@ -46,14 +49,14 @@ func Login(c echo.Context) error {
htmlContent := `
<html>
<head>
<title>WhatsApp MultiDevice Login</title>
<title>WhatsApp Multi-Device Login</title>
</head>
<body>
<img src="` + resLogin.QRCode + `" />
<p>
<b>QR Code Scan</b>
<br/>
Timeout in ` + resLogin.Timeout + `
Timeout in ` + strconv.Itoa(resLogin.Timeout) + ` Second(s)
</p>
</body>
</html>`
@ -79,8 +82,12 @@ func SendText(c echo.Context) error {
jid := jwtPayload(c).JID
var reqSendMessage typWhatsApp.RequestSendMessage
reqSendMessage.RJID = c.FormValue("msisdn")
reqSendMessage.Message = c.FormValue("message")
reqSendMessage.RJID = strings.TrimSpace(c.FormValue("msisdn"))
reqSendMessage.Message = strings.TrimSpace(c.FormValue("message"))
if len(reqSendMessage.RJID) == 0 {
return router.ResponseBadRequest(c, "Missing Form Value MSISDN")
}
err := pkgWhatsApp.WhatsAppSendText(jid, reqSendMessage.RJID, reqSendMessage.Message)
if err != nil {

62
pkg/whatsapp/whatsapp.go

@ -6,6 +6,7 @@ import (
"errors"
"fmt"
"os"
"strings"
_ "github.com/mattn/go-sqlite3"
qrCode "github.com/skip2/go-qrcode"
@ -38,7 +39,7 @@ func WhatsAppInit(jid string) (*whatsmeow.Client, error) {
}
// Set Client Properties
store.CompanionProps.Os = proto.String("Go WhatsApp MultiDevice REST")
store.CompanionProps.Os = proto.String("Go WhatsApp Multi-Device REST")
store.CompanionProps.PlatformType = waproto.CompanionProps_DESKTOP.Enum()
// Create New Client Connection
@ -63,9 +64,9 @@ func WhatAppConnect(jid string) error {
return nil
}
func WhatsAppGenerateQR(qrChan <-chan whatsmeow.QRChannelItem) (string, string) {
func WhatsAppGenerateQR(qrChan <-chan whatsmeow.QRChannelItem) (string, int) {
qrChanCode := make(chan string)
qrChanTimeout := make(chan string)
qrChanTimeout := make(chan int)
qrChanBase64 := make(chan string)
// Get QR Code Data and Timeout
@ -73,7 +74,7 @@ func WhatsAppGenerateQR(qrChan <-chan whatsmeow.QRChannelItem) (string, string)
for evt := range qrChan {
if evt.Event == "code" {
qrChanCode <- evt.Code
qrChanTimeout <- evt.Timeout.String()
qrChanTimeout <- int(evt.Timeout.Seconds())
}
}
}()
@ -91,7 +92,7 @@ func WhatsAppGenerateQR(qrChan <-chan whatsmeow.QRChannelItem) (string, string)
return <-qrChanBase64, <-qrChanTimeout
}
func WhatsAppLogin(jid string) (string, string, error) {
func WhatsAppLogin(jid string) (string, int, error) {
if WhatsAppClient[jid] != nil {
// Make Sure WebSocket Connection is Disconnected
WhatsAppClient[jid].Disconnect()
@ -104,7 +105,7 @@ func WhatsAppLogin(jid string) (string, string, error) {
// Connect WebSocket while Initialize QR Code Data to be Sent
err := WhatsAppClient[jid].Connect()
if err != nil {
return "", "", err
return "", 0, err
}
// Get Generated QR Code and Timeout Information
@ -117,13 +118,13 @@ func WhatsAppLogin(jid string) (string, string, error) {
// Reconnect WebSocket
err := WhatsAppClient[jid].Connect()
if err != nil {
return "", "", err
return "", 0, err
}
}
}
// Return Error WhatsApp Client is Not Valid
return "", "", errors.New("WhatsApp Client is not Valid")
// Return Error WhatsApp Client is not Valid
return "", 0, errors.New("WhatsApp Client is not Valid")
}
func WhatsAppLogout(jid string) error {
@ -144,33 +145,60 @@ func WhatsAppLogout(jid string) error {
return nil
}
// Return Error WhatsApp Client is Not Valid
// Return Error WhatsApp Client is not Valid
return errors.New("WhatsApp Client is not Valid")
}
func WhatsAppCreateUserJID(jid string) types.JID {
return types.NewJID(jid, types.DefaultUserServer)
func WhatsAppComposeJID(jid string) types.JID {
// Check if JID Contains '@' Symbol
if strings.ContainsRune(jid, '@') {
// Split JID Based on '@' Symbol
// and Get Only The First Section Before The Symbol
buffers := strings.Split(jid, "@")
jid = buffers[0]
}
func WhatsAppCreateGroupJID(gjid string) types.JID {
return types.NewJID(gjid, types.GroupServer)
// Check if JID First Chracter is '+' Symbol
if jid[0] == '+' {
// Remove '+' Symbol from JID
jid = jid[1:]
}
// Check if JID Contains '-' Symbol
if strings.ContainsRune(jid, '-') {
// Check if the JID is a Group ID
if len(strings.SplitN(jid, "-", 2)) == 2 {
// Return JID as Group Server (@g.us)
return types.NewJID(jid, types.GroupServer)
}
}
// Return JID as Default User Server (@s.whatsapp.net)
return types.NewJID(jid, types.DefaultUserServer)
}
func WhatsAppSendText(jid string, rjid string, message string) error {
if WhatsAppClient[jid] != nil {
// Make Sure WhatsApp Client WebSocket is Connected and Logged In
if WhatsAppClient[jid].IsConnected() && WhatsAppClient[jid].IsLoggedIn() {
_, err := WhatsAppClient[jid].SendMessage(WhatsAppCreateUserJID(rjid), "", &waproto.Message{
// Compose WhatsApp Proto
content := &waproto.Message{
Conversation: proto.String(message),
})
}
// Send WhatsApp Message Proto
_, err := WhatsAppClient[jid].SendMessage(WhatsAppComposeJID(rjid), "", content)
if err != nil {
return err
}
return nil
}
// Return Error WhatsApp Client is not Connected or Logged In
return errors.New("WhatsApp Client is not Connected or Logged In")
}
// Return Error WhatsApp Client is Not Valid
// Return Error WhatsApp Client is not Valid
return errors.New("WhatsApp Client is not Valid")
}
Loading…
Cancel
Save