Skip to content

Commit

Permalink
feat: add event emit and listen arch, user end is still left
Browse files Browse the repository at this point in the history
Signed-off-by: sarthakjdev <[email protected]>
  • Loading branch information
sarthakjdev committed May 28, 2024
1 parent 570a1ab commit b34d46e
Show file tree
Hide file tree
Showing 14 changed files with 325 additions and 110 deletions.
86 changes: 46 additions & 40 deletions example-chat-bot/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (

"github.com/sarthakjdev/wapi.go/internal/manager"
wapi "github.com/sarthakjdev/wapi.go/pkg/client"
wapiComponents "github.com/sarthakjdev/wapi.go/pkg/components"
"github.com/sarthakjdev/wapi.go/pkg/events"
)

func main() {
Expand All @@ -28,9 +28,9 @@ func main() {
}

// create a message
textMessage, err := wapiComponents.NewTextMessage(wapiComponents.TextMessageConfigs{
Text: "Hello, from wapi.go",
})
// textMessage, err := wapiComponents.NewTextMessage(wapiComponents.TextMessageConfigs{
// Text: "Hello, from wapi.go",
// })

// if err != nil {
// fmt.Println("error creating text message", err)
Expand Down Expand Up @@ -66,58 +66,64 @@ func main() {
// }

// send the message
whatsappClient.Message.Send(manager.SendMessageParams{Message: textMessage, PhoneNumber: "919643500545"})
// whatsappClient.Message.Send(manager.SendMessageParams{Message: textMessage, PhoneNumber: "919643500545"})
// whatsappClient.Message.Send(manager.SendMessageParams{Message: contactMessage, PhoneNumber: "919643500545"})
// whatsappClient.Message.Send(manager.SendMessageParams{Message: locationMessage, PhoneNumber: "919643500545"})
// whatsappClient.Message.Send(manager.SendMessageParams{Message: reactionMessage, PhoneNumber: "919643500545"})

listMessage, err := wapiComponents.NewListMessage(wapiComponents.ListMessageParams{
ButtonText: "Button 1",
BodyText: "Body 1",
})
// listMessage, err := wapiComponents.NewListMessage(wapiComponents.ListMessageParams{
// ButtonText: "Button 1",
// BodyText: "Body 1",
// })

if err != nil {
fmt.Println("error creating list message", err)
return
}
// if err != nil {
// fmt.Println("error creating list message", err)
// return
// }

listSectionRow, err := wapiComponents.NewListSectionRow("1", "Title 1", "Description 1")
// listSectionRow, err := wapiComponents.NewListSectionRow("1", "Title 1", "Description 1")

if err != nil {
fmt.Println("error creating list section row", err)
return
}
// if err != nil {
// fmt.Println("error creating list section row", err)
// return
// }

listSection, err := wapiComponents.NewListSection("Section1")
// listSection, err := wapiComponents.NewListSection("Section1")

if err != nil {
fmt.Println("error creating list section row", err)
return
}
// if err != nil {
// fmt.Println("error creating list section row", err)
// return
// }

listSection.AddRow(listSectionRow)
listMessage.AddSection(listSection)
jsonData, err := listMessage.ToJson(wapiComponents.ApiCompatibleJsonConverterConfigs{SendToPhoneNumber: "919643500545"})
// listSection.AddRow(listSectionRow)
// listMessage.AddSection(listSection)
// jsonData, err := listMessage.ToJson(wapiComponents.ApiCompatibleJsonConverterConfigs{SendToPhoneNumber: "919643500545"})

if err != nil {
fmt.Println("error converting message to json", err)
return
}
// if err != nil {
// fmt.Println("error converting message to json", err)
// return
// }

fmt.Println(string(jsonData))
// fmt.Println(string(jsonData))

whatsappClient.Message.Send(manager.SendMessageParams{Message: listMessage, PhoneNumber: "919643500545"})
// whatsappClient.Message.Send(manager.SendMessageParams{Message: listMessage, PhoneNumber: "919643500545"})

buttonMessage, err := wapiComponents.NewQuickReplyButtonMessage("Body 1")
// buttonMessage, err := wapiComponents.NewQuickReplyButtonMessage("Body 1")

if err != nil {
fmt.Println("error creating button message", err)
return
}
// if err != nil {
// fmt.Println("error creating button message", err)
// return
// }

// buttonMessage.AddButton("1", "Button 1")
// buttonMessage.AddButton("2", "Button 2")

buttonMessage.AddButton("1", "Button 1")
buttonMessage.AddButton("2", "Button 2")
// whatsappClient.Message.Send(manager.SendMessageParams{Message: buttonMessage, PhoneNumber: "919643500545"})

whatsappClient.On(manager.ReadyEvent, func(event events.BaseEvent) {
fmt.Println("client is ready")
})

whatsappClient.Message.Send(manager.SendMessageParams{Message: buttonMessage, PhoneNumber: "919643500545"})
whatsappClient.InitiateClient()

}
107 changes: 107 additions & 0 deletions internal/manager/event_manager.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package manager

import (
"fmt"
"sync"

"github.com/sarthakjdev/wapi.go/pkg/events"
)

type EventType string

const (
TextMessageEvent EventType = "text_message"
AudioMessageEvent EventType = "audio_message"
VideoMessageEvent EventType = "video_message"
ImageMessageEvent EventType = "image_message"
ContactMessageEvent EventType = "contact_message"
DocumentMessageEvent EventType = "document_message"
LocationMessageEvent EventType = "location_message"
ReactionMessageEvent EventType = "reaction_message"
ListInteractionMessageEvent EventType = "list_interaction_message"
TemplateMessageEvent EventType = "template_message"
QuickReplyMessageEvent EventType = "quick_reply_message"
ReplyButtonInteractionEvent EventType = "reply_button_interaction"
StickerMessageEvent EventType = "sticker_message"
AdInteractionEvent EventType = "ad_interaction_message"
CustomerIdentityChangedEvent EventType = "customer_identity_changed"
CustomerNumberChangedEvent EventType = "customer_number_changed"
MessageDeliveredEvent EventType = "message_delivered"
MessageFailedEvent EventType = "message_failed"
MessageReadEvent EventType = "message_read"
MessageSentEvent EventType = "message_sent"
MessageUndeliveredEvent EventType = "message_undelivered"
OrderReceivedEvent EventType = "order_received"
ProductInquiryEvent EventType = "product_inquiry"
UnknownEvent EventType = "unknown"
ErrorEvent EventType = "error"
WarnEvent EventType = "warn"
ReadyEvent EventType = "ready"
)

type ChannelEvent struct {
Type EventType
Data events.BaseEvent
}

type EventManger struct {
subscribers map[string]chan ChannelEvent
sync.RWMutex
}

func NewEventManager() *EventManger {
return &EventManger{
subscribers: make(map[string]chan ChannelEvent),
}
}

// subscriber to this event listener will be notified when the event is published
func (em *EventManger) Subscribe(eventName string) (chan ChannelEvent, error) {
em.Lock()
defer em.Unlock()
if ch, ok := em.subscribers[eventName]; ok {
return ch, nil
}
em.subscribers[eventName] = make(chan ChannelEvent, 100)
return em.subscribers[eventName], nil

}

// subscriber to this event listener will be notified when the event is published
func (em *EventManger) Unsubscribe(id string) {
em.Lock()
defer em.Unlock()
delete(em.subscribers, id)
}

// publish event to this events system and let all the subscriber consume them
func (em *EventManger) Publish(eventType EventType, data events.BaseEvent) error {
fmt.Println("Publishing event: ", eventType)
em.Lock()
defer em.Unlock()

for _, ch := range em.subscribers {
select {
case ch <- ChannelEvent{
Type: eventType,
Data: data,
}:
default:
return fmt.Errorf("event queue full for type: %s", eventType)
}
}
return nil
}

func (em *EventManger) On(name EventType, handler func(events.BaseEvent)) string {
ch, _ := em.Subscribe(string(name))
go func() {
for {
select {
case event := <-ch:
handler(event.Data)
}
}
}()
return string(name)
}
4 changes: 2 additions & 2 deletions internal/manager/media_manager.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package manager

type MediaManager struct {
requester requestClient
requester RequestClient
}

func NewMediaManager(requester requestClient) *MediaManager {
func NewMediaManager(requester RequestClient) *MediaManager {
return &MediaManager{
requester: requester,
}
Expand Down
4 changes: 2 additions & 2 deletions internal/manager/message_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ import (
)

type MessageManager struct {
requester requestClient
requester RequestClient
}

func NewMessageManager(requester requestClient) *MessageManager {
func NewMessageManager(requester RequestClient) *MessageManager {
return &MessageManager{
requester: requester,
}
Expand Down
4 changes: 2 additions & 2 deletions internal/manager/phone_manager.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package manager

type PhoneNumbersManager struct {
requester requestClient
requester RequestClient
}

func NewPhoneNumbersManager(requester requestClient) *PhoneNumbersManager {
func NewPhoneNumbersManager(requester RequestClient) *PhoneNumbersManager {
return &PhoneNumbersManager{
requester: requester,
}
Expand Down
8 changes: 4 additions & 4 deletions internal/manager/request_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,15 @@ const (
REQUEST_PROTOCOL = "https"
)

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

func NewRequestClient(phoneNumberId string, apiAccessToken string) *requestClient {
return &requestClient{
func NewRequestClient(phoneNumberId string, apiAccessToken string) *RequestClient {
return &RequestClient{
apiVersion: API_VERSION,
baseUrl: BASE_URL,
phoneNumberId: phoneNumberId,
Expand All @@ -34,7 +34,7 @@ type requestCloudApiParams struct {
path string
}

func (requestClientInstance *requestClient) requestCloudApi(params requestCloudApiParams) {
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
Expand Down
90 changes: 90 additions & 0 deletions internal/manager/webhook_manager.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package manager

import (
"context"
"fmt"
"log"
"net/http"
"os"
"os/signal"
"time"

"github.com/labstack/echo/v4"
"github.com/sarthakjdev/wapi.go/pkg/events"
)

// references for event driven architecture in golang: https://medium.com/@souravchoudhary0306/implementation-of-event-driven-architecture-in-go-golang-28d9a1c01f91
type WebhookManager struct {
secret string
path string
port int
EventManager EventManger
Requester RequestClient
}

type WebhookManagerConfig struct {
Secret string
Path string
Port int
EventManager EventManger
Requester RequestClient
}

func NewWebhook(options *WebhookManagerConfig) *WebhookManager {
return &WebhookManager{
secret: options.Secret,
path: options.Path,
port: options.Port,
EventManager: options.EventManager,
Requester: options.Requester,
}
}

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

}

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

func (wh *WebhookManager) postRequestHandler(req *http.Request) {
// emits events based on the payload of the request

wh.EventManager.Publish(TextMessageEvent, events.NewTextMessageEvent(
"wiuhbiueqwdqwd",
"2134141414",
"hello",
))

}

func (wh *WebhookManager) ListenToEvents() {

fmt.Println("Listening to events")
server := wh.createEchoHttpServer()

// Start server in a goroutine
go func() {
if err := server.Start(":8080"); err != nil {
return
}
}()

wh.EventManager.Publish(ReadyEvent, events.NewReadyEvent())

// Wait for an interrupt signal (e.g., Ctrl+C)
quit := make(chan os.Signal, 1)
signal.Notify(quit, os.Interrupt) // Capture SIGINT (Ctrl+C)
<-quit // Wait for the signal

// Gracefully shut down the server (optional)
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
if err := server.Shutdown(ctx); err != nil {
log.Fatal(err) // Handle shutdown errors gracefully
}

}
10 changes: 0 additions & 10 deletions internal/webhook/handler.go

This file was deleted.

Loading

0 comments on commit b34d46e

Please sign in to comment.