Repository navigation
Expand file tree
/
Copy pathcontrol_handler.go
More file actions
126 lines (111 loc) · 4.27 KB
/
Copy pathcontrol_handler.go
File metadata and controls
126 lines (111 loc) · 4.27 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
package main
import (
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"strings"
)
const maxControlBodyBytes = 1024 * 1024
type gatewayRegistration struct {
PhoneNumber string `json:"phone_number"`
PhoneAPIKey string `json:"phone_api_key"`
PhoneID string `json:"phone_id"`
}
type incomingMessageRequest struct {
Contact string `json:"contact"`
Content string `json:"content"`
Encrypted bool `json:"encrypted"`
}
func (instance *emulator) controlHandler() http.Handler {
mux := http.NewServeMux()
mux.HandleFunc("PUT /test/gateways/{gatewayID}", instance.handleGatewayRegistration)
mux.HandleFunc("POST /test/gateways/{gatewayID}/incoming", instance.handleIncomingMessage)
mux.HandleFunc("GET /test/gateways/{gatewayID}/notifications", instance.handleNotificationRecords)
mux.HandleFunc("GET /health", instance.handleHealth)
return mux
}
func (instance *emulator) handleGatewayRegistration(writer http.ResponseWriter, request *http.Request) {
var registration gatewayRegistration
if err := decodeControlJSON(writer, request, ®istration); err != nil {
writeControlError(writer, http.StatusBadRequest, err)
return
}
registration.PhoneNumber = strings.TrimSpace(registration.PhoneNumber)
registration.PhoneAPIKey = strings.TrimSpace(registration.PhoneAPIKey)
registration.PhoneID = strings.TrimSpace(registration.PhoneID)
if registration.PhoneNumber == "" || registration.PhoneAPIKey == "" || registration.PhoneID == "" {
writeControlError(writer, http.StatusBadRequest, errors.New("phone_number, phone_api_key and phone_id are required"))
return
}
instance.registerGateway(request.PathValue("gatewayID"), registration)
writer.WriteHeader(http.StatusNoContent)
}
func (instance *emulator) handleIncomingMessage(writer http.ResponseWriter, request *http.Request) {
registeredGateway, ok := instance.loadGateway(request.PathValue("gatewayID"))
if !ok {
writeControlError(writer, http.StatusNotFound, errors.New("unknown gateway"))
return
}
var incoming incomingMessageRequest
if err := decodeControlJSON(writer, request, &incoming); err != nil {
writeControlError(writer, http.StatusBadRequest, err)
return
}
incoming.Contact = strings.TrimSpace(incoming.Contact)
if incoming.Contact == "" {
writeControlError(writer, http.StatusBadRequest, errors.New("contact is required"))
return
}
message, err := instance.receiveMessage(request.Context(), registeredGateway, incoming)
if err != nil {
writeControlError(writer, http.StatusBadGateway, err)
return
}
writeControlJSON(writer, http.StatusOK, map[string]any{"data": message})
}
func (instance *emulator) handleNotificationRecords(writer http.ResponseWriter, request *http.Request) {
gatewayID := request.PathValue("gatewayID")
if _, ok := instance.loadGateway(gatewayID); !ok {
writeControlError(writer, http.StatusNotFound, errors.New("unknown gateway"))
return
}
records := instance.listGatewayRecords(gatewayID)
if messageID := strings.TrimSpace(request.URL.Query().Get("message_id")); messageID != "" {
filtered := make([]notificationRecord, 0, len(records))
for _, record := range records {
if record.MessageID == messageID {
filtered = append(filtered, record)
}
}
records = filtered
}
writeControlJSON(writer, http.StatusOK, map[string]any{
"data": records,
})
}
func (*emulator) handleHealth(writer http.ResponseWriter, _ *http.Request) {
writer.Header().Set("Content-Type", "text/plain; charset=utf-8")
writer.WriteHeader(http.StatusOK)
_, _ = writer.Write([]byte("ok\n"))
}
func decodeControlJSON(writer http.ResponseWriter, request *http.Request, result any) error {
request.Body = http.MaxBytesReader(writer, request.Body, maxControlBodyBytes)
decoder := json.NewDecoder(request.Body)
if err := decoder.Decode(result); err != nil {
return fmt.Errorf("decode request body: %w", err)
}
if err := decoder.Decode(&struct{}{}); !errors.Is(err, io.EOF) {
return errors.New("request body must contain one JSON value")
}
return nil
}
func writeControlError(writer http.ResponseWriter, status int, err error) {
writeControlJSON(writer, status, map[string]any{"error": err.Error()})
}
func writeControlJSON(writer http.ResponseWriter, status int, payload any) {
writer.Header().Set("Content-Type", "application/json")
writer.WriteHeader(status)
_ = json.NewEncoder(writer).Encode(payload)
}