Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add a v1 and v2 handler to the proxy for different config cdn urls #21

Merged
merged 6 commits into from
Aug 23, 2024
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
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.17.0
github.com/devcyclehq/go-server-sdk/v2 v2.18.1
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 @@ -27,7 +28,6 @@ require (
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
github.com/launchdarkly/eventsource v1.7.1 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
github.com/matryer/try v0.0.0-20161228173917-9ac251b645a2 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
Expand Down
12 changes: 8 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,14 @@ 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.16.1 h1:NZ0vHZhhrPOb2hbU/r5sIIDSG4tPc+TiO/ovJaP0Gk8=
github.com/devcyclehq/go-server-sdk/v2 v2.16.1/go.mod h1:DzKrJ4s2apfphFwB/Aq8YDf7brB+NDr6IxX0TNi2c24=
github.com/devcyclehq/go-server-sdk/v2 v2.17.0 h1:eBvoJesVPYvy7htJBjhIWRGbQq5fsmlcv4nvsrHqPDU=
github.com/devcyclehq/go-server-sdk/v2 v2.17.0/go.mod h1:DzKrJ4s2apfphFwB/Aq8YDf7brB+NDr6IxX0TNi2c24=
github.com/devcyclehq/go-server-sdk/v2 v2.18.0 h1:9STdu/bTnrjM1cFh3OJddO4nxAaAUqlOAO180x6SWpk=
github.com/devcyclehq/go-server-sdk/v2 v2.18.0/go.mod h1:DzKrJ4s2apfphFwB/Aq8YDf7brB+NDr6IxX0TNi2c24=
github.com/devcyclehq/go-server-sdk/v2 v2.18.1-0.20240822213335-a3201264237c h1:HABqfIWonwH731k8kd+yYLExjsuVH5S+xL9Ed3Kywhw=
github.com/devcyclehq/go-server-sdk/v2 v2.18.1-0.20240822213335-a3201264237c/go.mod h1:DzKrJ4s2apfphFwB/Aq8YDf7brB+NDr6IxX0TNi2c24=
github.com/devcyclehq/go-server-sdk/v2 v2.18.1-0.20240823134625-106c09774905 h1:tOTq2TbgeYtdFuaOl71Sups5p8setOA5VHan6DRGOnU=
github.com/devcyclehq/go-server-sdk/v2 v2.18.1-0.20240823134625-106c09774905/go.mod h1:DzKrJ4s2apfphFwB/Aq8YDf7brB+NDr6IxX0TNi2c24=
github.com/devcyclehq/go-server-sdk/v2 v2.18.1 h1:4Rwxr0Sx4S56zGgSqm0C06Xj88038iYVbWZinpPx8C4=
github.com/devcyclehq/go-server-sdk/v2 v2.18.1/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 Down
69 changes: 37 additions & 32 deletions http_endpoints.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,53 +111,58 @@ func BatchEvents() gin.HandlerFunc {
}
}

func GetConfig() gin.HandlerFunc {
func GetConfig(client *devcycle.Client, version ...string) 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)
var ret, rawConfig []byte
var etag, lm string
var err error
if client != nil {
rawConfig, etag, lm, err = client.GetRawConfig()
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,
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
ret, err = json.Marshal(config)
} else {
ret = rawConfig
}
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{})
return
}
} else if client == nil && len(version) > 0 {
ret, etag, lm = instance.BypassSDKConfig(version[0])
}
c.Header("ETag", etag)
c.Header("Last-Modified", lm)
c.Data(http.StatusOK, "application/json", ret)
}
}
Expand Down
35 changes: 35 additions & 0 deletions options.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ import (
"fmt"
"github.com/devcyclehq/go-server-sdk/v2/api"
"github.com/launchdarkly/eventsource"
"io"
"log"
"net/http"
"os"
"runtime"
"time"
Expand Down Expand Up @@ -38,6 +40,7 @@ type ProxyInstance struct {
dvcClient *devcycle.Client
sseServer *eventsource.Server
sseEvents chan api.ClientEvent
bypassConfig []byte
}

type SDKConfig struct {
Expand Down Expand Up @@ -73,13 +76,45 @@ func (i *ProxyInstance) BuildDevCycleOptions() *devcycle.Options {
EnableBetaRealtimeUpdates: i.SSEEnabled,
AdvancedOptions: devcycle.AdvancedOptions{
OverridePlatformData: &i.PlatformData,
OverrideConfigWithV1: false,
},
ClientEventHandler: i.sseEvents,
}
options.CheckDefaults()
return &options
}

func (i *ProxyInstance) BypassSDKConfig(version string) (config []byte, etag, lastModified string) {

request, err := http.NewRequest("GET", fmt.Sprintf("https://config-cdn.devcycle.com/config/%s/server/%s.json", version, i.SDKKey), nil)
if err != nil {
return i.bypassConfig, "", ""
}

resp, err := http.DefaultClient.Do(request)

if err != nil {
return i.bypassConfig, "", ""
}

if resp.StatusCode == http.StatusNotModified {
return i.bypassConfig, resp.Header.Get("ETag"), resp.Header.Get("Last-Modified")
}

if resp.StatusCode != http.StatusOK {
return i.bypassConfig, "", ""
}

body, err := io.ReadAll(resp.Body)
defer resp.Body.Close()
if err != nil {
return i.bypassConfig, "", ""
}

i.bypassConfig = body
return i.bypassConfig, resp.Header.Get("ETag"), resp.Header.Get("Last-Modified")
}

func (i *ProxyInstance) EventRebroadcaster() {
for event := range i.sseEvents {
if event.EventType == api.ClientEventType_RealtimeUpdates {
Expand Down
10 changes: 8 additions & 2 deletions proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ func NewBucketingProxyInstance(instance *ProxyInstance) (*ProxyInstance, error)

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)
Expand Down Expand Up @@ -116,9 +119,12 @@ func newRouter(client *devcycle.Client, instance *ProxyInstance) *gin.Engine {
}
configCDNv1 := r.Group("/config/v1")
{
configCDNv1.GET("/server/:sdkKey", GetConfig())
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
Expand Down
Loading