-
Notifications
You must be signed in to change notification settings - Fork 0
/
proxy.go
135 lines (124 loc) · 3.65 KB
/
proxy.go
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
127
128
129
130
131
132
133
134
135
package local_bucketing_proxy
import (
"fmt"
"github.com/devcyclehq/go-server-sdk/v2/api"
"github.com/launchdarkly/eventsource"
"log"
"os"
"strconv"
"time"
devcycle "github.com/devcyclehq/go-server-sdk/v2"
"github.com/gin-gonic/gin"
)
func NewBucketingProxyInstance(instance *ProxyInstance) (*ProxyInstance, error) {
gin.DisableConsoleColor()
if instance.LogFile != "" {
logFile, err := os.OpenFile(instance.LogFile, os.O_CREATE|os.O_APPEND|os.O_RDWR, 0666)
if err != nil {
_ = fmt.Errorf("error opening log file: %s", err)
return nil, err
}
gin.DefaultWriter = logFile
log.SetOutput(logFile)
} else {
log.SetOutput(os.Stdout)
}
if instance.SSEEnabled {
instance.sseEvents = make(chan api.ClientEvent, 100)
instance.sseServer = eventsource.NewServer()
instance.sseServer.ReplayAll = false
eventsource.NewSliceRepository()
go instance.EventRebroadcaster()
log.Printf("Initialized SSE server at %s", instance.SSEHostname)
}
options := instance.BuildDevCycleOptions()
client, err := devcycle.NewClient(instance.SDKKey, options)
if err != nil {
return nil, fmt.Errorf("error creating DevCycle client: %v", err)
}
instance.dvcClient = client
r := newRouter(client, instance)
if instance.HTTPEnabled {
if instance.HTTPPort == 0 {
return nil, fmt.Errorf("HTTP port must be set")
}
go func() {
err = r.Run(":" + strconv.Itoa(instance.HTTPPort))
if err != nil {
log.Printf("Error running HTTP server: %s", err)
}
}()
log.Printf("HTTP server started on port %d", instance.HTTPPort)
}
if instance.UnixSocketEnabled {
if _, err = os.Stat(instance.UnixSocketPath); err == nil {
return nil, fmt.Errorf("unix socket path %s already exists. Skipping instance creation", instance.UnixSocketPath)
}
err = nil
go func() {
err = r.RunUnix(instance.UnixSocketPath)
if err != nil {
log.Printf("Error running Unix socket server: %s", err)
}
}()
_, err = os.Stat(instance.UnixSocketPath)
for ; err != nil; _, err = os.Stat(instance.UnixSocketPath) {
time.Sleep(1 * time.Second)
}
fileModeOctal, err := strconv.ParseUint(instance.UnixSocketPermissions, 8, 32)
if err != nil {
log.Printf("error parsing Unix socket permissions: %s", err)
return nil, err
}
if err = os.Chmod(instance.UnixSocketPath, os.FileMode(fileModeOctal)); err != nil {
log.Printf("Error setting Unix socket permissions: %s", err)
}
log.Printf("Running on unix socket: %s with file permissions %s", instance.UnixSocketPath, instance.UnixSocketPermissions)
}
return instance, err
}
// Add the DevCycle client to the request context
func devCycleMiddleware(client *devcycle.Client) gin.HandlerFunc {
return func(c *gin.Context) {
c.Set("devcycle", client)
c.Next()
}
}
func sdkProxyMiddleware(instance *ProxyInstance) gin.HandlerFunc {
return func(c *gin.Context) {
c.Set("instance", instance)
c.Next()
}
}
func newRouter(client *devcycle.Client, instance *ProxyInstance) *gin.Engine {
r := gin.New()
if instance.LogFile != "" {
r.Use(gin.Logger())
}
r.Use(gin.Recovery())
r.Use(devCycleMiddleware(client))
r.Use(sdkProxyMiddleware(instance))
r.GET("/healthz", Health)
v1 := r.Group("/v1")
v1.Use(DevCycleAuthRequired())
{
// Bucketing API
v1.POST("/variables/:key", Variable())
v1.POST("/variables", Variable())
v1.POST("/features", Feature())
v1.POST("/track", Track())
// Events API
v1.POST("/events", Track())
v1.POST("/events/batch", BatchEvents())
}
configCDNv1 := r.Group("/config/v1")
{
configCDNv1.GET("/server/:sdkKey", GetConfig(nil, "v1"))
}
configCDNv2 := r.Group("/config/v2")
{
configCDNv2.GET("/server/:sdkKey", GetConfig(client))
}
r.GET("/event-stream", SSE())
return r
}