Skip to content

Commit

Permalink
feat: request client works fine and Message manager works fine too.
Browse files Browse the repository at this point in the history
Signed-off-by: sarthakjdev <[email protected]>
  • Loading branch information
sarthakjdev committed May 22, 2024
1 parent 8a91d40 commit c559e6b
Show file tree
Hide file tree
Showing 17 changed files with 297 additions and 47 deletions.
27 changes: 22 additions & 5 deletions example-chat-bot/main.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,30 @@
package main

import (
"fmt"

"github.com/sarthakjdev/wapi.go/internal/manager"
wapi "github.com/sarthakjdev/wapi.go/pkg/client"
wapiModels "github.com/sarthakjdev/wapi.go/pkg/models"
)

func main() {
fmt.Println("This is the main package entry point of my golang file")
whatsappClient := wapi.NewWapiClient(wapi.ClientConfig{})
fmt.Print(whatsappClient)
// creating a client
whatsappClient := wapi.New(wapi.ClientConfig{
PhoneNumberId: "113269274970227",
ApiAccessToken: "EABhCftGVaeIBOZCmTPNEWyAWSq1Bna8ZCs2Rl7YoXtHfjuXZCAZCMVkjUD8pauKlkGHO6NHP5dXLG9zG5wH7qZAm2GBu8ZChKo37TBa2LzFedZA5sAAZBfgKJ7k7sQZB8t5neJ46DiTH4ZAjxFGvBWRJbC2CP30WHZBhES64pcLCSrWAkoitZBCKAwt5NkOZCoYZCymbP1LnK7e7SZC72R60UJZB4h0xOUvZCF99ohbeO5qeSuxou3Y0ZD",
BusinessAccountId: "103043282674158",
WebhookPath: "/webhook",
WebhookSecret: "123456789",
WebhookServerPort: 8080,
})
// create a message
textMessage := wapiModels.NewTextMessage(wapiModels.TextMessageConfigs{
Text: "Hello",
AllowPreview: true,
})

contactMessage := wapiModels.NewContactMessage(wapiModels.ContactMessageConfigs{})

// send the message
whatsappClient.Message.Send(manager.SendMessageParams{Message: textMessage, PhoneNumber: "919643500545"})
whatsappClient.Message.Send(manager.SendMessageParams{Message: contactMessage, PhoneNumber: "919643500545"})
}
21 changes: 21 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,3 +1,24 @@
module github.com/sarthakjdev/wapi.go

go 1.21.3

require (
github.com/go-playground/validator/v10 v10.20.0
github.com/labstack/echo/v4 v4.12.0
)

require (
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/labstack/gommon v0.4.2 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasttemplate v1.2.2 // indirect
golang.org/x/crypto v0.22.0 // indirect
golang.org/x/net v0.24.0 // indirect
golang.org/x/sys v0.19.0 // indirect
golang.org/x/text v0.14.0 // indirect
)
43 changes: 43 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/go-playground/validator/v10 v10.20.0 h1:K9ISHbSaI0lyB2eWMPJo+kOS/FBExVwjEviJTixqxL8=
github.com/go-playground/validator/v10 v10.20.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
github.com/labstack/echo/v4 v4.12.0 h1:IKpw49IMryVB2p1a4dzwlhP1O2Tf2E0Ir/450lH+kI0=
github.com/labstack/echo/v4 v4.12.0/go.mod h1:UP9Cr2DJXbOK3Kr9ONYzNowSh7HP0aG0ShAyycHSJvM=
github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0=
github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU=
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=
github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30=
golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w=
golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
1 change: 0 additions & 1 deletion internal/manager/media_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ func NewMediaManager(requester requestClient) *MediaManager {

func (mm *MediaManager) UploadMedia() {
// upload media

}

func (mm *MediaManager) GetMediaUrlById() {
Expand Down
32 changes: 30 additions & 2 deletions internal/manager/message_manager.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
package manager

import (
"github.com/sarthakjdev/wapi.go/pkg/models"
)

type MessageManager struct {
requester requestClient
}
Expand All @@ -10,8 +14,32 @@ func NewMessageManager(requester requestClient) *MessageManager {
}
}

func (mm *MessageManager) Send() {
// Send message
type SendMessageParams struct {
Message models.BaseMessage
PhoneNumber string
}

// ! TODO: return the structured response from here
func (mm *MessageManager) Send(params SendMessageParams) {
// pass the phone number in this toJson method of every message
body, err := params.Message.ToJson()
if err != nil {
// emit a error event here
return
}

mm.requester.requestCloudApi(requestCloudApiParams{
body: string(body),
path: "/" + mm.requester.phoneNumberId + "/messages",
})

// if err != nil {
// // emit a error event here
// return
// }

// fmt.Println("Response from cloud api is", response)

}

func (mm *MessageManager) Reply() {
Expand Down
48 changes: 44 additions & 4 deletions internal/manager/request_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,55 @@ package manager

import (
"fmt"
"io"
"net/http"
"strings"
)

const (
API_VERSION = "v.19"
BASE_URL = "graph.facebook.com"
REQUEST_PROTOCOL = "https"
)

type requestClient struct {
apiVersion string
phoneNumberId string
baseUrl string
apiAccessToken string
}

func NewRequestClient(phoneNumberId string, apiAccessToken string) *requestClient {
return &requestClient{
apiVersion: API_VERSION,
baseUrl: BASE_URL,
phoneNumberId: phoneNumberId,
apiAccessToken: apiAccessToken,
}
}

func NewRequestClient() *requestClient {
return &requestClient{}
type requestCloudApiParams struct {
body string
path string
}

func (requestClientInstance *requestClient) requestCloudApi() {
fmt.Println("Requesting cloud api")
func (requestClientInstance *requestClient) requestCloudApi(params requestCloudApiParams) {
httpRequest, err := http.NewRequest("POST", fmt.Sprintf("%s://%s/%s", REQUEST_PROTOCOL, requestClientInstance.baseUrl, params.path), strings.NewReader(params.body))
if err != nil {
return
}
httpRequest.Header.Set("Content-Type", "application/json")
httpRequest.Header.Set("Authorization", fmt.Sprintf("Bearer %s", requestClientInstance.apiAccessToken))
client := &http.Client{}
response, err := client.Do(httpRequest)
if err != nil {
fmt.Println("Error while requesting cloud api", err)
return
}
defer response.Body.Close()
body, err := io.ReadAll(response.Body)
if err != nil {
return
}
fmt.Println("Response from cloud api is", string(body))
}
7 changes: 5 additions & 2 deletions internal/webhook/handler.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package webhook

func getRequestHandler() {
}
import "net/http"

func (wh *Webhook) getRequestHandler(req *http.Request) {
}

func (wh *Webhook) postRequestHandler(req *http.Request) {

}
11 changes: 11 additions & 0 deletions internal/webhook/webhook.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
package webhook

import (
"github.com/labstack/echo/v4"
)

// references for event driven architecture in golang: https://medium.com/@souravchoudhary0306/implementation-of-event-driven-architecture-in-go-golang-28d9a1c01f91
type Webhook struct {
secret string
Expand All @@ -21,6 +25,13 @@ func NewWebhook(options WebhookManagerConfig) *Webhook {
}
}

// this function is used in case if the client have not provided any custom http server
func (wh *Webhook) createEchoHttpServer() *echo.Echo {
e := echo.New()
return e

}

func (wh *Webhook) ListenToEvents() {

}
41 changes: 22 additions & 19 deletions pkg/client/client.go
Original file line number Diff line number Diff line change
@@ -1,47 +1,50 @@
package wapi

import (
"fmt"

manager "github.com/sarthakjdev/wapi.go/internal/manager"
"github.com/sarthakjdev/wapi.go/internal/webhook"
"github.com/sarthakjdev/wapi.go/utils"
)

// Client represents a WhatsApp client.
type Client struct {
Media manager.MediaManager
message manager.MessageManager
Message manager.MessageManager
Phone manager.PhoneNumbersManager
webhook webhook.Webhook
phoneNumberId string
apiAccessToken string
host string
businessAccountId string
apiVersion string
}

// ClientConfig represents the configuration options for the WhatsApp client.
type ClientConfig struct {
phoneNumberId string
apiAccessToken string
businessAccountId string
webhookPath string
webhookSecret string
webhookServerPort int
PhoneNumberId string `validate:"required"`
ApiAccessToken string `validate:"required"`
BusinessAccountId string `validate:"required"`
WebhookPath string `validate:"required"`
WebhookSecret string `validate:"required"`
WebhookServerPort int
}

// NewWapiClient creates a new instance of Client.
func NewWapiClient(options ClientConfig) *Client {
requester := *manager.NewRequestClient()

func New(configs ClientConfig) *Client {
err := utils.GetValidator().Struct(configs)
if err != nil {
fmt.Println("error validating client config", err)
return nil
}
requester := *manager.NewRequestClient(configs.PhoneNumberId, configs.ApiAccessToken)
return &Client{
Media: *manager.NewMediaManager(requester),
message: *manager.NewMessageManager(requester),
Message: *manager.NewMessageManager(requester),
Phone: *manager.NewPhoneNumbersManager(requester),
webhook: *webhook.NewWebhook(webhook.WebhookManagerConfig{Path: options.webhookPath, Secret: options.webhookSecret, Port: options.webhookServerPort}),
phoneNumberId: options.phoneNumberId,
apiAccessToken: options.apiAccessToken,
host: "graph.facebook.com",
businessAccountId: options.businessAccountId,
apiVersion: "v19.0",
webhook: *webhook.NewWebhook(webhook.WebhookManagerConfig{Path: configs.WebhookPath, Secret: configs.WebhookSecret, Port: configs.WebhookServerPort}),
phoneNumberId: configs.PhoneNumberId,
apiAccessToken: configs.ApiAccessToken,
businessAccountId: configs.BusinessAccountId,
}
}

Expand Down
17 changes: 16 additions & 1 deletion pkg/models/base_message.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,19 @@
package models

type BaseMessage struct {
type MessageType string

const (
MessageTypeText MessageType = "text"
MessageTypeAudio MessageType = "audio"
MessageTypeDocument MessageType = "document"
MessageTypeContact MessageType = "contact"
MessageTypeLocation MessageType = "location"
MessageTypeImage MessageType = "image"
MessageTypeVideo MessageType = "video"
MessageTypeInteractive MessageType = "interactive"
MessageTypeTemplate MessageType = "template"
)

type BaseMessage interface {
ToJson() ([]byte, error)
}
33 changes: 31 additions & 2 deletions pkg/models/contact_message.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,34 @@
package models

import (
"encoding/json"
"fmt"

"github.com/sarthakjdev/wapi.go/utils"
)

type ContactMessage struct {
BaseMessage
}
}

type ContactMessageConfigs struct {
}

func NewContactMessage(configs ContactMessageConfigs) *ContactMessage {
err := utils.GetValidator().Struct(configs)
fmt.Println("error validating text message config", err)
if err != nil {
return nil
}
return &ContactMessage{}
}

func (m *ContactMessage) ToJson() ([]byte, error) {
messageJson, err := json.Marshal(m)
if err != nil {
// emit a error event here
return nil, err
}
fmt.Println("text message json is", string(messageJson))

return messageJson, nil
}
4 changes: 0 additions & 4 deletions pkg/models/interactive_message.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
package models



type BaseInteractiveMessage struct {
BaseMessage
}

Loading

0 comments on commit c559e6b

Please sign in to comment.