Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 0 additions & 13 deletions .github/dependabot.yml

This file was deleted.

10 changes: 9 additions & 1 deletion .idea/local-bucketing-proxy.iml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

50 changes: 25 additions & 25 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ A simple healthcheck for each proxy instance can be performed by sending a GET r

We recommend setting the file permissions for the unix socket to be as restrictive as possible. However, as a workaround
for deployment issues, you can set the permissions to your own custom mask via the
`DVC_LB_PROXY_UNIX_SOCKET_PERMISSIONS` environment variable, or the unixSocketPermissions option in the config file. The
`DEVCYCLE_PROXY_UNIX_SOCKET_PERMISSIONS` environment variable, or the unixSocketPermissions option in the config file. The
default is 0755

### Command Line Arguments
Expand All @@ -48,27 +48,27 @@ default is 0755

### Environment Variables

| KEY | TYPE | DEFAULT | REQUIRED | DESCRIPTION |
|--------------------------------------------------------|---------------|---------|----------|---------------------------------------------------------------------------------|
| DVC_LB_PROXY_CONFIG | String | | | The path to a JSON configuration file. |
| DVC_LB_PROXY_UNIX_SOCKET_PATH | String | | | The path to the Unix socket. |
| DVC_LB_PROXY_HTTP_PORT | Integer | 8080 | | The port to listen on for HTTP requests. Defaults to 8080. |
| DVC_LB_PROXY_UNIX_SOCKET_ENABLED | True or False | false | | Whether to enable the Unix socket. Defaults to false. |
| DVC_LB_PROXY_UNIX_SOCKET_PERMISSIONS | String | 0755 | | The permissions to set on the Unix socket. Defaults to 0755 |
| DVC_LB_PROXY_HTTP_ENABLED | True or False | true | | Whether to enable the HTTP server. Defaults to true. |
| DVC_LB_PROXY_SDK_KEY | String | | true | The Server SDK key to use for this instance. |
| DVC_LB_PROXY_PLATFORMDATA_SDKTYPE | String | | | |
| DVC_LB_PROXY_PLATFORMDATA_SDKVERSION | String | | | |
| DVC_LB_PROXY_PLATFORMDATA_PLATFORMVERSION | String | | | |
| DVC_LB_PROXY_PLATFORMDATA_DEVICEMODEL | String | | | |
| DVC_LB_PROXY_PLATFORMDATA_PLATFORM | String | | | |
| DVC_LB_PROXY_PLATFORMDATA_HOSTNAME | String | | | |
| DVC_LB_PROXY_SDKCONFIG_EVENT_FLUSH_INTERVAL_MS | Duration | | | The interval at which events are flushed to the events api in milliseconds. |
| DVC_LB_PROXY_SDKCONFIG_CONFIG_POLLING_INTERVAL_MS | Duration | | | The interval at which the SDK polls the config CDN for updates in milliseconds. |
| DVC_LB_PROXY_SDKCONFIG_REQUEST_TIMEOUT | Duration | | | The timeout for requests to the config CDN and events API in milliseconds. |
| DVC_LB_PROXY_SDKCONFIG_DISABLE_AUTOMATIC_EVENT_LOGGING | True or False | false | | Whether to disable automatic event logging. Defaults to false. |
| DVC_LB_PROXY_SDKCONFIG_DISABLE_CUSTOM_EVENT_LOGGING | True or False | false | | Whether to disable custom event logging. Defaults to false. |
| DVC_LB_PROXY_SDKCONFIG_MAX_EVENT_QUEUE_SIZE | Integer | | | The maximum number of events to be in the queue before dropping events. |
| DVC_LB_PROXY_SDKCONFIG_FLUSH_EVENT_QUEUE_SIZE | Integer | | | The minimum number of events to be in the queue before flushing events. |
| DVC_LB_PROXY_SDKCONFIG_CONFIG_CDN_URI | String | | | The URI of the Config CDN - leave unspecified if not needing an outbound proxy. |
| DVC_LB_PROXY_SDKCONFIG_EVENTSAPIURI | String | | | The URI of the Events API - leave unspecified if not needing an outbound proxy. |
| KEY | TYPE | DEFAULT | REQUIRED | DESCRIPTION |
|----------------------------------------------------------|---------------|---------|----------|---------------------------------------------------------------------------------|
| DEVCYCLE_PROXY_CONFIG | String | | | The path to a JSON configuration file. |
Copy link
Member

@jonathannorris jonathannorris Jun 12, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will we need to do a major version increase for these name changes?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep

| DEVCYCLE_PROXY_UNIX_SOCKET_PATH | String | | | The path to the Unix socket. |
| DEVCYCLE_PROXY_HTTP_PORT | Integer | 8080 | | The port to listen on for HTTP requests. Defaults to 8080. |
| DEVCYCLE_PROXY_UNIX_SOCKET_ENABLED | True or False | false | | Whether to enable the Unix socket. Defaults to false. |
| DEVCYCLE_PROXY_UNIX_SOCKET_PERMISSIONS | String | 0755 | | The permissions to set on the Unix socket. Defaults to 0755 |
| DEVCYCLE_PROXY_HTTP_ENABLED | True or False | true | | Whether to enable the HTTP server. Defaults to true. |
| DEVCYCLE_PROXY_SDK_KEY | String | | true | The Server SDK key to use for this instance. |
| DEVCYCLE_PROXY_PLATFORMDATA_SDKTYPE | String | | | |
| DEVCYCLE_PROXY_PLATFORMDATA_SDKVERSION | String | | | |
| DEVCYCLE_PROXY_PLATFORMDATA_PLATFORMVERSION | String | | | |
| DEVCYCLE_PROXY_PLATFORMDATA_DEVICEMODEL | String | | | |
| DEVCYCLE_PROXY_PLATFORMDATA_PLATFORM | String | | | |
| DEVCYCLE_PROXY_PLATFORMDATA_HOSTNAME | String | | | |
| DEVCYCLE_PROXY_SDKCONFIG_EVENT_FLUSH_INTERVAL_MS | Duration | | | The interval at which events are flushed to the events api in milliseconds. |
| DEVCYCLE_PROXY_SDKCONFIG_CONFIG_POLLING_INTERVAL_MS | Duration | | | The interval at which the SDK polls the config CDN for updates in milliseconds. |
| DEVCYCLE_PROXY_SDKCONFIG_REQUEST_TIMEOUT | Duration | | | The timeout for requests to the config CDN and events API in milliseconds. |
| DEVCYCLE_PROXY_SDKCONFIG_DISABLE_AUTOMATIC_EVENT_LOGGING | True or False | false | | Whether to disable automatic event logging. Defaults to false. |
| DEVCYCLE_PROXY_SDKCONFIG_DISABLE_CUSTOM_EVENT_LOGGING | True or False | false | | Whether to disable custom event logging. Defaults to false. |
| DEVCYCLE_PROXY_SDKCONFIG_MAX_EVENT_QUEUE_SIZE | Integer | | | The maximum number of events to be in the queue before dropping events. |
| DEVCYCLE_PROXY_SDKCONFIG_FLUSH_EVENT_QUEUE_SIZE | Integer | | | The minimum number of events to be in the queue before flushing events. |
| DEVCYCLE_PROXY_SDKCONFIG_CONFIG_CDN_URI | String | | | The URI of the Config CDN - leave unspecified if not needing an outbound proxy. |
| DEVCYCLE_PROXY_SDKCONFIG_EVENTSAPIURI | String | | | The URI of the Events API - leave unspecified if not needing an outbound proxy. |
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ module github.com/devcyclehq/sdk-proxy
go 1.20

require (
github.com/devcyclehq/go-server-sdk/v2 v2.15.0
github.com/devcyclehq/go-server-sdk/v2 v2.16.0
github.com/gin-gonic/gin v1.10.0
github.com/kelseyhightower/envconfig v1.4.0
github.com/kr/pretty v0.3.1
github.com/launchdarkly/eventsource v1.7.1
github.com/stretchr/testify v1.9.0
)

Expand All @@ -24,7 +25,6 @@ require (
github.com/go-playground/validator/v10 v10.20.0 // indirect
github.com/goccy/go-json v0.10.2 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/jarcoal/httpmock v1.2.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
github.com/kr/text v0.2.0 // indirect
Expand Down
14 changes: 10 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
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/devcyclehq/go-server-sdk/v2 v2.15.0 h1:bK2Z9OTooACeETPvSq0h3JOoOwYUekcbxKb9gqgzfig=
github.com/devcyclehq/go-server-sdk/v2 v2.15.0/go.mod h1:/F805DZbz6ghCPCUf+au7UycoIEYlW62Kh8JN1da0+k=
github.com/devcyclehq/go-server-sdk/v2 v2.16.0 h1:8yefgJISXZgSIlXcCNMK+RGM6X9kuuB1nZAs3kzSExQ=
github.com/devcyclehq/go-server-sdk/v2 v2.16.0/go.mod h1:DzKrJ4s2apfphFwB/Aq8YDf7brB+NDr6IxX0TNi2c24=
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/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
Expand All @@ -36,7 +36,6 @@ github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/jarcoal/httpmock v1.2.0 h1:gSvTxxFR/MEMfsGrvRbdfpRUMBStovlSRLw0Ep1bwwc=
github.com/jarcoal/httpmock v1.2.0/go.mod h1:oCoTsnAz4+UoOUIf5lJOWV2QQIW5UoeUI6aM2YnWAZk=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8=
Expand All @@ -49,13 +48,16 @@ github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/launchdarkly/eventsource v1.7.1 h1:StoRQeiPyrcQIXjlQ7b5jWMzHW4p+GGczN2r2oBhujg=
github.com/launchdarkly/eventsource v1.7.1/go.mod h1:LHxSeb4OnqznNZxCSXbFghxS/CjIQfzHovNoAqbO/Wk=
github.com/launchdarkly/go-test-helpers/v2 v2.2.0 h1:L3kGILP/6ewikhzhdNkHy1b5y4zs50LueWenVF0sBbs=
github.com/launchdarkly/go-test-helpers/v2 v2.2.0/go.mod h1:L7+th5govYp5oKU9iN7To5PgznBuIjBPn+ejqKR0avw=
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/matryer/try v0.0.0-20161228173917-9ac251b645a2 h1:JAEbJn3j/FrhdWA9jW8B5ajsLIjeuEHLi8xE4fk997o=
github.com/matryer/try v0.0.0-20161228173917-9ac251b645a2/go.mod h1:0KeJpeMD6o+O4hW7qJOT7vyQPKrWmj26uf5wMc/IiIs=
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/maxatome/go-testdeep v1.11.0 h1:Tgh5efyCYyJFGUYiT0qxBSIDeXw0F5zSoatlou685kk=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
Expand All @@ -75,6 +77,8 @@ github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSS
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
Expand Down Expand Up @@ -107,6 +111,8 @@ google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFW
google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
Expand Down
63 changes: 56 additions & 7 deletions http_endpoints.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,17 @@ import (
"strings"

devcycle "github.com/devcyclehq/go-server-sdk/v2"
devcycle_api "github.com/devcyclehq/go-server-sdk/v2/api"
"github.com/gin-gonic/gin"
)

func Health(c *gin.Context) {
c.Status(200)
}

func Variable(client *devcycle.Client) gin.HandlerFunc {
func Variable() gin.HandlerFunc {
return func(c *gin.Context) {
client := c.Value("devcycle").(*devcycle.Client)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ohh, interesting so the devcycle client is now attached to the request context?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah - I wanted to make it more context friendly and properly scoped to each request since it's handled by a different gin instance

user := getUserFromBody(c)
if user == nil {
return
Expand Down Expand Up @@ -50,8 +52,10 @@ func Variable(client *devcycle.Client) gin.HandlerFunc {
}
}

func Feature(client *devcycle.Client) gin.HandlerFunc {
func Feature() gin.HandlerFunc {
return func(c *gin.Context) {
client := c.Value("devcycle").(*devcycle.Client)

user := getUserFromBody(c)
if user == nil {
return
Expand All @@ -65,8 +69,10 @@ func Feature(client *devcycle.Client) gin.HandlerFunc {
}
}

func Track(client *devcycle.Client) gin.HandlerFunc {
func Track() gin.HandlerFunc {
return func(c *gin.Context) {
client := c.Value("devcycle").(*devcycle.Client)

event := getEventFromBody(c)
for _, e := range event.Events {
_, err := client.Track(event.User.User, e)
Expand All @@ -77,8 +83,10 @@ func Track(client *devcycle.Client) gin.HandlerFunc {
}
}

func BatchEvents(client *devcycle.Client) gin.HandlerFunc {
func BatchEvents() gin.HandlerFunc {
return func(c *gin.Context) {
client := c.Value("devcycle").(*devcycle.Client)

// Passthrough proxy to the configured events api endpoint.
httpC := http.DefaultClient
req, err := http.NewRequest("POST", client.DevCycleOptions.EventsAPIURI+"/v1/events/batch", c.Request.Body)
Expand All @@ -103,20 +111,61 @@ func BatchEvents(client *devcycle.Client) gin.HandlerFunc {
}
}

func GetConfig(client *devcycle.Client) gin.HandlerFunc {
func GetConfig() gin.HandlerFunc {
return func(c *gin.Context) {
instance := c.Value("instance").(*ProxyInstance)
client := c.Value("devcycle").(*devcycle.Client)

if c.Param("sdkKey") == "" || !strings.HasSuffix(c.Param("sdkKey"), ".json") {
c.AbortWithStatus(http.StatusForbidden)
return
}

var ret []byte
rawConfig, etag, err := client.GetRawConfig()
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{})
return
}
if instance.SSEEnabled {
config := map[string]interface{}{}
err = json.Unmarshal(rawConfig, &config)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{})
return
}
hostname := fmt.Sprintf("http://%s:%d", instance.SSEHostname, instance.HTTPPort)
// This is the only indicator that a unix socket request was made
if c.Request.RemoteAddr == "" {
hostname = fmt.Sprintf("unix:%s", instance.UnixSocketPath)
}
fmt.Println(c.Request)
if val, ok := config["sse"]; ok {
path := val.(map[string]interface{})["path"].(string)

config["sse"] = devcycle_api.SSEHost{
Hostname: hostname,
Path: path,
}
}

ret, err = json.Marshal(config)
} else {
ret = rawConfig
}

if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{})
return
}
c.Header("ETag", etag)
c.Data(http.StatusOK, "application/json", rawConfig)
c.Data(http.StatusOK, "application/json", ret)
}
}

func SSE() gin.HandlerFunc {
return func(c *gin.Context) {
instance := c.Value("instance").(*ProxyInstance)
instance.sseServer.Handler(instance.SDKKey).ServeHTTP(c.Writer, c.Request)
}
}

Expand Down
Loading