Skip to content

Commit 198a734

Browse files
committed
Add 3cx integration
1 parent 171da3e commit 198a734

5 files changed

Lines changed: 390 additions & 0 deletions

File tree

api/pkg/di/container.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,9 @@ func NewContainer(projectID string, version string) (container *Container) {
129129
container.RegisterWebhookListeners()
130130

131131
container.RegisterLemonsqueezyRoutes()
132+
132133
container.RegisterIntegration3CXRoutes()
134+
container.RegisterIntegration3CXListeners()
133135

134136
container.RegisterDiscordRoutes()
135137
container.RegisterDiscordListeners()
@@ -709,6 +711,17 @@ func (container *Container) WebhookService() (service *services.WebhookService)
709711
)
710712
}
711713

714+
// Integration3CXService creates a new instance of services.Integration3CXService
715+
func (container *Container) Integration3CXService() (service *services.Integration3CXService) {
716+
container.logger.Debug(fmt.Sprintf("creating %T", service))
717+
return services.NewIntegration3CXService(
718+
container.Logger(),
719+
container.Tracer(),
720+
container.HTTPClient("integration_3cx"),
721+
container.Integration3CXRepository(),
722+
)
723+
}
724+
712725
// HTTPClient creates a new http.Client
713726
func (container *Container) HTTPClient(name string) *http.Client {
714727
container.logger.Debug(fmt.Sprintf("creating %s %T", name, http.DefaultClient))
@@ -1063,6 +1076,20 @@ func (container *Container) RegisterDiscordListeners() {
10631076
}
10641077
}
10651078

1079+
// RegisterIntegration3CXListeners registers event listeners for listeners.Integration3CXListener
1080+
func (container *Container) RegisterIntegration3CXListeners() {
1081+
container.logger.Debug(fmt.Sprintf("registering listeners for %T", listeners.Integration3CXListener{}))
1082+
_, routes := listeners.NewIntegration3CXListener(
1083+
container.Logger(),
1084+
container.Tracer(),
1085+
container.Integration3CXService(),
1086+
)
1087+
1088+
for event, handler := range routes {
1089+
container.EventDispatcher().Subscribe(event, handler)
1090+
}
1091+
}
1092+
10661093
// RegisterWebhookListeners registers event listeners for listeners.WebhookListener
10671094
func (container *Container) RegisterWebhookListeners() {
10681095
container.logger.Debug(fmt.Sprintf("registering listeners for %T", listeners.WebhookListener{}))
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
package listeners
2+
3+
import (
4+
"context"
5+
"fmt"
6+
7+
"github.com/NdoleStudio/httpsms/pkg/events"
8+
"github.com/NdoleStudio/httpsms/pkg/services"
9+
"github.com/NdoleStudio/httpsms/pkg/telemetry"
10+
cloudevents "github.com/cloudevents/sdk-go/v2"
11+
"github.com/palantir/stacktrace"
12+
)
13+
14+
// Integration3CXListener sends 3CX events to users
15+
type Integration3CXListener struct {
16+
logger telemetry.Logger
17+
tracer telemetry.Tracer
18+
service *services.Integration3CXService
19+
}
20+
21+
// NewIntegration3CXListener creates a new instance of Integration3CXListener
22+
func NewIntegration3CXListener(
23+
logger telemetry.Logger,
24+
tracer telemetry.Tracer,
25+
service *services.Integration3CXService,
26+
) (l *Integration3CXListener, routes map[string]events.EventListener) {
27+
l = &Integration3CXListener{
28+
logger: logger.WithService(fmt.Sprintf("%T", l)),
29+
tracer: tracer,
30+
service: service,
31+
}
32+
33+
return l, map[string]events.EventListener{
34+
events.EventTypeMessagePhoneReceived: l.OnMessagePhoneReceived,
35+
events.EventTypeMessagePhoneDelivered: l.OnMessagePhoneDelivered,
36+
events.EventTypeMessageSendFailed: l.OnMessageSendFailed,
37+
events.EventTypeMessagePhoneSent: l.OnMessagePhoneSent,
38+
}
39+
}
40+
41+
// OnMessagePhoneReceived handles the events.EventTypeMessagePhoneReceived event
42+
func (listener *Integration3CXListener) OnMessagePhoneReceived(ctx context.Context, event cloudevents.Event) error {
43+
ctx, span := listener.tracer.Start(ctx)
44+
defer span.End()
45+
46+
var payload events.MessagePhoneReceivedPayload
47+
if err := event.DataAs(&payload); err != nil {
48+
msg := fmt.Sprintf("cannot decode [%s] into [%T]", event.Data(), payload)
49+
return listener.tracer.WrapErrorSpan(span, stacktrace.Propagate(err, msg))
50+
}
51+
52+
if err := listener.service.Send(ctx, payload.UserID, event); err != nil {
53+
msg := fmt.Sprintf("cannot process [%s] event with ID [%s]", event.Type(), event.ID())
54+
return listener.tracer.WrapErrorSpan(span, stacktrace.Propagate(err, msg))
55+
}
56+
57+
return nil
58+
}
59+
60+
// OnMessageSendFailed handles the events.EventTypeMessageSendFailed event
61+
func (listener *Integration3CXListener) OnMessageSendFailed(ctx context.Context, event cloudevents.Event) error {
62+
ctx, span := listener.tracer.Start(ctx)
63+
defer span.End()
64+
65+
var payload events.MessageSendFailedPayload
66+
if err := event.DataAs(&payload); err != nil {
67+
msg := fmt.Sprintf("cannot decode [%s] into [%T]", event.Data(), payload)
68+
return listener.tracer.WrapErrorSpan(span, stacktrace.Propagate(err, msg))
69+
}
70+
71+
if err := listener.service.Send(ctx, payload.UserID, event); err != nil {
72+
msg := fmt.Sprintf("cannot process [%s] event with ID [%s]", event.Type(), event.ID())
73+
return listener.tracer.WrapErrorSpan(span, stacktrace.Propagate(err, msg))
74+
}
75+
76+
return nil
77+
}
78+
79+
// OnMessagePhoneSent handles the events.EventTypeMessagePhoneSent event
80+
func (listener *Integration3CXListener) OnMessagePhoneSent(ctx context.Context, event cloudevents.Event) error {
81+
ctx, span := listener.tracer.Start(ctx)
82+
defer span.End()
83+
84+
var payload events.MessagePhoneSentPayload
85+
if err := event.DataAs(&payload); err != nil {
86+
msg := fmt.Sprintf("cannot decode [%s] into [%T]", event.Data(), payload)
87+
return listener.tracer.WrapErrorSpan(span, stacktrace.Propagate(err, msg))
88+
}
89+
90+
if err := listener.service.Send(ctx, payload.UserID, event); err != nil {
91+
msg := fmt.Sprintf("cannot process [%s] event with ID [%s]", event.Type(), event.ID())
92+
return listener.tracer.WrapErrorSpan(span, stacktrace.Propagate(err, msg))
93+
}
94+
95+
return nil
96+
}
97+
98+
// OnMessagePhoneDelivered handles the events.EventTypeMessagePhoneDelivered event
99+
func (listener *Integration3CXListener) OnMessagePhoneDelivered(ctx context.Context, event cloudevents.Event) error {
100+
ctx, span := listener.tracer.Start(ctx)
101+
defer span.End()
102+
103+
var payload events.MessagePhoneDeliveredPayload
104+
if err := event.DataAs(&payload); err != nil {
105+
msg := fmt.Sprintf("cannot decode [%s] into [%T]", event.Data(), payload)
106+
return listener.tracer.WrapErrorSpan(span, stacktrace.Propagate(err, msg))
107+
}
108+
109+
if err := listener.service.Send(ctx, payload.UserID, event); err != nil {
110+
msg := fmt.Sprintf("cannot process [%s] event with ID [%s]", event.Type(), event.ID())
111+
return listener.tracer.WrapErrorSpan(span, stacktrace.Propagate(err, msg))
112+
}
113+
114+
return nil
115+
}

api/pkg/repositories/gorm_integration_3cx_repository.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package repositories
22

33
import (
44
"context"
5+
"errors"
56
"fmt"
67

78
"github.com/NdoleStudio/httpsms/pkg/entities"
@@ -30,6 +31,26 @@ func NewGormIntegration3CXRepository(
3031
}
3132
}
3233

34+
// Load an entities.Integration3CX based on the entities.UserID
35+
func (repository *gormIntegration3CxRepository) Load(ctx context.Context, userID entities.UserID) (*entities.Integration3CX, error) {
36+
ctx, span := repository.tracer.Start(ctx)
37+
defer span.End()
38+
39+
integration := new(entities.Integration3CX)
40+
err := repository.db.WithContext(ctx).Where("user_id = ?", userID).First(&integration).Error
41+
if errors.Is(err, gorm.ErrRecordNotFound) {
42+
msg := fmt.Sprintf("[3cx] integration for user [%s] does not exist", userID)
43+
return nil, repository.tracer.WrapErrorSpan(span, stacktrace.PropagateWithCode(err, ErrCodeNotFound, msg))
44+
}
45+
46+
if err != nil {
47+
msg := fmt.Sprintf("cannot load [3cx] integration for user [%s]", userID)
48+
return nil, repository.tracer.WrapErrorSpan(span, stacktrace.Propagate(err, msg))
49+
}
50+
51+
return integration, nil
52+
}
53+
3354
// Save an entities.Integration3CX
3455
func (repository *gormIntegration3CxRepository) Save(ctx context.Context, integration *entities.Integration3CX) error {
3556
ctx, span := repository.tracer.Start(ctx)

api/pkg/repositories/integration_3cx_repository.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,7 @@ import (
1010
type Integration3CxRepository interface {
1111
// Save an entities.Integration3CX
1212
Save(ctx context.Context, heartbeat *entities.Integration3CX) error
13+
14+
// Load an entities.Integration3CX based on the entities.UserID
15+
Load(ctx context.Context, userID entities.UserID) (*entities.Integration3CX, error)
1316
}

0 commit comments

Comments
 (0)