Skip to content

Commit

Permalink
Merge pull request #146 from launchdarkly/eb/ch83491/core-packages-1
Browse files Browse the repository at this point in the history
(v6 - #14) move some things into core subpackages, expose fewer impl details
  • Loading branch information
eli-darkly authored Aug 4, 2020
2 parents b2ae3b3 + ef462d5 commit e92ea8d
Show file tree
Hide file tree
Showing 25 changed files with 137 additions and 93 deletions.
5 changes: 2 additions & 3 deletions cmd/ld-relay/ld-relay.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,8 @@ import (
relay "github.com/launchdarkly/ld-relay/v6"
"github.com/launchdarkly/ld-relay/v6/application"
"github.com/launchdarkly/ld-relay/v6/config"
"github.com/launchdarkly/ld-relay/v6/internal/logging"
"github.com/launchdarkly/ld-relay/v6/core/logging"
"github.com/launchdarkly/ld-relay/v6/internal/version"
"github.com/launchdarkly/ld-relay/v6/sdkconfig"
)

func main() {
Expand Down Expand Up @@ -42,7 +41,7 @@ func main() {
}
}

r, err := relay.NewRelay(c, loggers, sdkconfig.DefaultClientFactory)
r, err := relay.NewRelay(c, loggers, nil)
if err != nil {
loggers.Errorf("Unable to create relay: %s", err)
os.Exit(1)
Expand Down
2 changes: 1 addition & 1 deletion config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import (
"time"

ct "github.com/launchdarkly/go-configtypes"
"github.com/launchdarkly/ld-relay/v6/internal/logging"
"github.com/launchdarkly/ld-relay/v6/core/logging"
)

const (
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package sdkconfig
package sdks

import (
"time"
Expand Down
2 changes: 1 addition & 1 deletion sdkconfig/data_stores.go → core/sdks/data_stores.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package sdkconfig
package sdks

import (
"errors"
Expand Down
3 changes: 3 additions & 0 deletions core/sdks/package_info.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// Package sdks contains types and helpers for describing the behavior of different kinds of
// SDKs that can connect to Relay, and also for Relay's own use of the Go SDK.
package sdks
32 changes: 22 additions & 10 deletions sdk_kinds.go → core/sdks/sdk_kinds.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package relay
package sdks

import (
"errors"
Expand All @@ -10,12 +10,21 @@ import (
"github.com/launchdarkly/ld-relay/v6/config"
)

type sdkKind string
// Kind represents any of the supported SDK categories that has distinct behavior from the others.
type Kind string

const (
serverSdk sdkKind = "server"
jsClientSdk sdkKind = "js"
mobileSdk sdkKind = "mobile"
// Server represents server-side SDKs, which use server-side endpoints and authenticate their requests
// with an SDK key.
Server Kind = "server"

// Mobile represents mobile SDKs, which use mobile endpoints and authenticate their requests with a
// mobile key.
Mobile Kind = "mobile"

// JSClient represents client-side JavaScript-based SDKs, which use client-side endpoints and
// authenticate their requests insecurely with an environment ID.
JSClient Kind = "js"
)

var (
Expand All @@ -24,21 +33,24 @@ var (
errUnknownSDKKind = errors.New("unknown SDK kind")
)

func (s sdkKind) getSDKCredential(req *http.Request) (config.SDKCredential, error) {
switch s {
case serverSdk:
// GetCredential attempts to get the appropriate kind of authentication credential for this SDK kind
// from an HTTP request. For Server and Mobile, this uses the Authorization header; for JSClient, it
// is in a path parameter.
func (k Kind) GetCredential(req *http.Request) (config.SDKCredential, error) {
switch k {
case Server:
value, err := fetchAuthToken(req)
if err == nil {
return config.SDKKey(value), nil
}
return nil, err
case mobileSdk:
case Mobile:
value, err := fetchAuthToken(req)
if err == nil {
return config.MobileKey(value), nil
}
return nil, err
case jsClientSdk:
case JSClient:
value := mux.Vars(req)["envId"]
if value == "" {
return nil, errNoEnvID
Expand Down
3 changes: 1 addition & 2 deletions docs/in-app.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ Here is an example of how you might run the Relay Proxy endpoints inside your we
import (
relay "github.com/launchdarkly/ld-relay/v6"
"github.com/launchdarkly/ld-relay/v6/config"
"github.com/launchdarkly/ld-relay/v6/sdkconfig"
)

func createRelayConfig() config.Config {
Expand All @@ -21,7 +20,7 @@ func createRelayConfig() config.Config {
return cfg
}

r, err := relay.NewRelay(createRelayConfig, sdkconfig.DefaultClientFactory)
r, err := relay.NewRelay(createRelayConfig, nil)
if err != nil {
log.Fatalf("Error creating relay: %s", err)
}
Expand Down
2 changes: 1 addition & 1 deletion internal/metrics/measures.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
"go.opencensus.io/tag"
"go.opencensus.io/trace"

"github.com/launchdarkly/ld-relay/v6/internal/logging"
"github.com/launchdarkly/ld-relay/v6/core/logging"
)

var (
Expand Down
2 changes: 1 addition & 1 deletion internal/metrics/prometheus.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
"gopkg.in/launchdarkly/go-sdk-common.v2/ldlog"

"github.com/launchdarkly/ld-relay/v6/config"
"github.com/launchdarkly/ld-relay/v6/internal/logging"
"github.com/launchdarkly/ld-relay/v6/core/logging"
)

var prometheusExporterType exporterType = prometheusExporterTypeImpl{}
Expand Down
8 changes: 4 additions & 4 deletions internal/relayenv/env_context.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ import (
"time"

"github.com/launchdarkly/ld-relay/v6/config"
"github.com/launchdarkly/ld-relay/v6/core/sdks"
"github.com/launchdarkly/ld-relay/v6/internal/events"
"github.com/launchdarkly/ld-relay/v6/internal/streams"
"github.com/launchdarkly/ld-relay/v6/sdkconfig"
"gopkg.in/launchdarkly/go-sdk-common.v2/ldlog"
"gopkg.in/launchdarkly/go-server-sdk.v5/interfaces"
)
Expand All @@ -30,9 +30,9 @@ type EnvContext interface {
GetCredentials() Credentials

// GetClient returns the SDK client instance for this environment. This is nil if initialization is not yet
// complete. Rather than providing the full client object, we use the simpler sdkconfig.LDClientContext
// which includes only the operations Relay needs to do.
GetClient() sdkconfig.LDClientContext
// complete. Rather than providing the full client object, we use the simpler sdks.LDClientContext which
// includes only the operations Relay needs to do.
GetClient() sdks.LDClientContext

// GetStore returns the SDK data store instance for this environment. This is nil if initialization is not
// yet complete.
Expand Down
10 changes: 5 additions & 5 deletions internal/relayenv/env_context_impl.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ import (
"gopkg.in/launchdarkly/go-server-sdk.v5/interfaces/ldstoretypes"

"github.com/launchdarkly/ld-relay/v6/config"
"github.com/launchdarkly/ld-relay/v6/core/sdks"
"github.com/launchdarkly/ld-relay/v6/internal/events"
"github.com/launchdarkly/ld-relay/v6/internal/httpconfig"
"github.com/launchdarkly/ld-relay/v6/internal/metrics"
"github.com/launchdarkly/ld-relay/v6/internal/store"
"github.com/launchdarkly/ld-relay/v6/internal/streams"
"github.com/launchdarkly/ld-relay/v6/internal/util"
"github.com/launchdarkly/ld-relay/v6/sdkconfig"
"gopkg.in/launchdarkly/go-sdk-common.v2/ldlog"
ld "gopkg.in/launchdarkly/go-server-sdk.v5"
"gopkg.in/launchdarkly/go-server-sdk.v5/interfaces"
Expand All @@ -26,7 +26,7 @@ import (

type envContextImpl struct {
mu sync.RWMutex
client sdkconfig.LDClientContext
client sdks.LDClientContext
storeAdapter *store.SSERelayDataStoreAdapter
loggers ldlog.Loggers
credentials Credentials
Expand Down Expand Up @@ -62,7 +62,7 @@ func NewEnvContext(
envName string,
envConfig config.EnvConfig,
allConfig config.Config,
clientFactory sdkconfig.ClientFactoryFunc,
clientFactory sdks.ClientFactoryFunc,
dataStoreFactory interfaces.DataStoreFactory,
streamProviders []streams.StreamProvider,
jsClientContext JSClientContext,
Expand Down Expand Up @@ -217,13 +217,13 @@ func (c *envContextImpl) GetCredentials() Credentials {
return c.credentials
}

func (c *envContextImpl) GetClient() sdkconfig.LDClientContext {
func (c *envContextImpl) GetClient() sdks.LDClientContext {
c.mu.RLock()
defer c.mu.RUnlock()
return c.client
}

func (c *envContextImpl) SetClient(client sdkconfig.LDClientContext) {
func (c *envContextImpl) SetClient(client sdks.LDClientContext) {
c.mu.Lock()
defer c.mu.Unlock()
c.client = client
Expand Down
7 changes: 4 additions & 3 deletions middleware.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (

"github.com/gorilla/mux"

"github.com/launchdarkly/ld-relay/v6/core/sdks"
"github.com/launchdarkly/ld-relay/v6/internal/cors"
"github.com/launchdarkly/ld-relay/v6/internal/metrics"
"gopkg.in/launchdarkly/go-sdk-common.v2/lduser"
Expand All @@ -25,10 +26,10 @@ func chainMiddleware(middlewares ...mux.MiddlewareFunc) mux.MiddlewareFunc {
}
}

func selectEnvironmentByAuthorizationKey(sdkKind sdkKind, envs RelayEnvironments) mux.MiddlewareFunc {
func selectEnvironmentByAuthorizationKey(sdkKind sdks.Kind, envs RelayEnvironments) mux.MiddlewareFunc {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
credential, err := sdkKind.getSDKCredential(req)
credential, err := sdkKind.GetCredential(req)
if err != nil {
w.WriteHeader(http.StatusUnauthorized)
return
Expand Down Expand Up @@ -61,7 +62,7 @@ func selectEnvironmentByAuthorizationKey(sdkKind sdkKind, envs RelayEnvironments
func selectEnvironmentByEnvIDUrlParam(envs RelayEnvironments) mux.MiddlewareFunc {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
envId, err := jsClientSdk.getSDKCredential(req)
envId, err := sdks.JSClient.GetCredential(req)
if err != nil {
w.WriteHeader(http.StatusNotFound)
w.Write([]byte("URL did not contain an environment ID"))
Expand Down
15 changes: 8 additions & 7 deletions middleware_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/stretchr/testify/assert"

"github.com/launchdarkly/ld-relay/v6/config"
"github.com/launchdarkly/ld-relay/v6/core/sdks"
"github.com/launchdarkly/ld-relay/v6/internal/events"
"github.com/launchdarkly/ld-relay/v6/internal/relayenv"
)
Expand All @@ -34,7 +35,7 @@ func TestSelectEnvironmentByAuthorizationKey(t *testing.T) {
testEnvMain.config.SDKKey: env1,
testEnvMobile.config.SDKKey: env2,
}
selector := selectEnvironmentByAuthorizationKey(serverSdk, envs)
selector := selectEnvironmentByAuthorizationKey(sdks.Server, envs)
envCh := make(chan relayenv.EnvContext, 1)

req := buildPreRoutedRequestWithAuth(testEnvMain.config.SDKKey)
Expand All @@ -50,7 +51,7 @@ func TestSelectEnvironmentByAuthorizationKey(t *testing.T) {
testEnvMobile.config.SDKKey: env2,
testEnvMobile.config.MobileKey: env2,
}
selector := selectEnvironmentByAuthorizationKey(mobileSdk, envs)
selector := selectEnvironmentByAuthorizationKey(sdks.Mobile, envs)
envCh := make(chan relayenv.EnvContext, 1)

req := buildPreRoutedRequestWithAuth(testEnvMobile.config.MobileKey)
Expand All @@ -62,7 +63,7 @@ func TestSelectEnvironmentByAuthorizationKey(t *testing.T) {

t.Run("rejects unknown SDK key", func(t *testing.T) {
envs := testEnvironments{testEnvMain.config.SDKKey: env1}
selector := selectEnvironmentByAuthorizationKey(serverSdk, envs)
selector := selectEnvironmentByAuthorizationKey(sdks.Server, envs)

req1 := buildPreRoutedRequestWithAuth(undefinedSDKKey)
resp1, _ := doRequest(req1, selector(nullHandler()))
Expand All @@ -72,7 +73,7 @@ func TestSelectEnvironmentByAuthorizationKey(t *testing.T) {

t.Run("rejects unknown mobile key", func(t *testing.T) {
envs := testEnvironments{testEnvMain.config.MobileKey: env1}
selector := selectEnvironmentByAuthorizationKey(mobileSdk, envs)
selector := selectEnvironmentByAuthorizationKey(sdks.Mobile, envs)

req1 := buildPreRoutedRequestWithAuth(undefinedMobileKey)
resp1, _ := doRequest(req1, selector(nullHandler()))
Expand All @@ -82,7 +83,7 @@ func TestSelectEnvironmentByAuthorizationKey(t *testing.T) {

t.Run("rejects malformed SDK key", func(t *testing.T) {
envs := testEnvironments{malformedSDKKey: newTestEnvContext("server", false, nil)}
selector := selectEnvironmentByAuthorizationKey(serverSdk, envs)
selector := selectEnvironmentByAuthorizationKey(sdks.Server, envs)

req1 := buildPreRoutedRequestWithAuth(malformedSDKKey)
resp1, _ := doRequest(req1, selector(nullHandler()))
Expand All @@ -95,7 +96,7 @@ func TestSelectEnvironmentByAuthorizationKey(t *testing.T) {
malformedSDKKey: newTestEnvContext("server", false, nil),
malformedMobileKey: newTestEnvContext("server", false, nil),
}
selector := selectEnvironmentByAuthorizationKey(mobileSdk, envs)
selector := selectEnvironmentByAuthorizationKey(sdks.Mobile, envs)

req1 := buildPreRoutedRequestWithAuth(malformedMobileKey)
resp1, _ := doRequest(req1, selector(nullHandler()))
Expand All @@ -106,7 +107,7 @@ func TestSelectEnvironmentByAuthorizationKey(t *testing.T) {
t.Run("returns 503 if client has not been created", func(t *testing.T) {
notReadyEnv := newTestEnvContextWithClientFactory("env", clientFactoryThatFails(errors.New("sorry")), nil)
envs := testEnvironments{testEnvMain.config.SDKKey: notReadyEnv}
selector := selectEnvironmentByAuthorizationKey(serverSdk, envs)
selector := selectEnvironmentByAuthorizationKey(sdks.Server, envs)

req := buildPreRoutedRequestWithAuth(testEnvMain.config.SDKKey)
resp, _ := doRequest(req, selector(nullHandler()))
Expand Down
24 changes: 18 additions & 6 deletions relay.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@ package relay
import (
"net/http"

"gopkg.in/launchdarkly/go-sdk-common.v2/ldtime"
"gopkg.in/launchdarkly/go-sdk-common.v2/ldvalue"

"gopkg.in/launchdarkly/go-sdk-common.v2/ldlog"
"gopkg.in/launchdarkly/go-sdk-common.v2/ldreason"
"gopkg.in/launchdarkly/go-sdk-common.v2/ldtime"
"gopkg.in/launchdarkly/go-sdk-common.v2/ldvalue"

"github.com/launchdarkly/ld-relay/v6/config"
"github.com/launchdarkly/ld-relay/v6/sdkconfig"
"github.com/launchdarkly/ld-relay/v6/core/sdks"

ld "gopkg.in/launchdarkly/go-server-sdk.v5"
)

const (
Expand All @@ -36,10 +37,21 @@ type evalXResult struct {
Reason *ldreason.EvaluationReason `json:"reason,omitempty"`
}

// NewRelay creates a new relay given a configuration and a method to create a client.
// ClientFactoryFunc is a function that can be used with NewRelay to specify custom behavior when
// Relay needs to create a Go SDK client instance.
type ClientFactoryFunc func(sdkKey config.SDKKey, config ld.Config) (*ld.LDClient, error)

// NewRelay creates a new Relay given a configuration and a method to create a client.
//
// If any metrics exporters are enabled in c.MetricsConfig, it also registers those in OpenCensus.
func NewRelay(c config.Config, loggers ldlog.Loggers, clientFactory sdkconfig.ClientFactoryFunc) (*Relay, error) {
//
// The clientFactory parameter can be nil and is only needed if you want to customize how Relay
// creates the Go SDK client instance.
func NewRelay(c config.Config, loggers ldlog.Loggers, clientFactory ClientFactoryFunc) (*Relay, error) {
return newRelayInternal(c, loggers, ClientFactoryFromLDClientFactory(clientFactory))
}

func newRelayInternal(c config.Config, loggers ldlog.Loggers, clientFactory sdks.ClientFactoryFunc) (*Relay, error) {
core, err := NewRelayCore(c, loggers, clientFactory)
if err != nil {
return nil, err
Expand Down
Loading

0 comments on commit e92ea8d

Please sign in to comment.