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
24 changes: 18 additions & 6 deletions internal/dev_server/sdk/routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,31 @@ func BindRoutes(router *mux.Router) {
// events
router.HandleFunc("/bulk", DevNull)
router.HandleFunc("/diagnostic", DevNull)
// TODO need cors for events on client side
router.HandleFunc("/events/bulk/{envId}", DevNull)
router.HandleFunc("/events/diagnostic/{envId}", DevNull)
router.HandleFunc("/mobile", DevNull)
router.HandleFunc("/mobile/events", DevNull)
router.HandleFunc("/mobile/events/bulk", DevNull)
router.HandleFunc("/mobile/events/diagnostic", DevNull)

evalRouter := router.PathPrefix("/eval").Subrouter()
evalRouter.Use(CorsHeaders)
evalRouter.Methods("OPTIONS").HandlerFunc(ConstantResponseHandler(http.StatusOK, ""))
evalRouter.Use(GetProjectKeyFromEnvIdParameter("envId"))
evalRouter.HandleFunc("/{envId}", StreamClientFlags)
evalRouter.HandleFunc("/{envId}/{contextBase64}", StreamClientFlags)

clientsideSdkRouter := router.PathPrefix("/sdk").Subrouter()
clientsideSdkRouter.Use(CorsHeaders)
clientsideSdkRouter.Methods("OPTIONS").HandlerFunc(ConstantResponseHandler(http.StatusOK, ""))
clientsideSdkRouter.Use(GetProjectKeyFromEnvIdParameter("envId"))
clientsideSdkRouter.HandleFunc("/goals/{envId}", ConstantResponseHandler(http.StatusOK, "[]"))
clientsideSdkRouter.HandleFunc("/evalx/{envId}/contexts/{contextBase64}", GetClientFlags)
clientsideSdkRouter.HandleFunc("/evalx/{envId}/contexts", GetClientFlags)
clientsideSdkRouter.HandleFunc("/evalx/{envId}/users", GetClientFlags)
clientsideSdkRouter.HandleFunc("/evalx/{envId}/users/{userBase64}", GetClientFlags)

/*
/all GET stream. SSE stream for all data
✅ /bulk POST events. Receives analytics events from SDKs
Expand All @@ -45,15 +57,15 @@ func BindRoutes(router *mux.Router) {
/msdk/evalx/users/{contextBase64} GET clientsdk. Alternate name for /msdk/evalx/contexts/{contextBase64} used by older SDKs
/msdk/evalx/user REPORT clientsdk. Alternate name for /msdk/evalx/context used by older SDKs
/a/{envId}.gif?d=*events* GET events. Alternative analytics event mechanism used if browser does not allow CORS
/eval/{envId}/{contextBase64} GET clientstream. SSE stream of "ping" and other events for JS and other client-side SDK listeners
/eval/{envId} REPORT clientstream. Same as above but request body is the evaluation context JSON object (not in base64)
/eval/{envId}/{contextBase64} GET clientstream. SSE stream of "ping" and other events for JS and other client-side SDK listeners
/eval/{envId} REPORT clientstream. Same as above but request body is the evaluation context JSON object (not in base64)
✅ /events/bulk/{envId} POST events. Receives analytics events from SDKs
✅ /events/diagnostic/{envId} POST events. Receives diagnostic data from SDKs
/ping/{envId} GET clientstream. SSE stream for older SDKs that issues "ping" events when flags have changed
/sdk/evalx/{envId}/contexts/{contextBase64} GET clientsdk. Polling endpoint, returns flag evaluation results and additional metadata
/sdk/evalx/{envId}/contexts REPORT clientsdk. Same as above but request body is the evaluation context JSON object (not in base64)
/sdk/evalx/{envId}/users/{contextBase64} GET clientsdk. Alternate name for /sdk/evalx/{envId}/contexts/{contextBase64} used by older SDKs
/sdk/evalx/{envId}/users REPORT clientsdk. Alternate name for /sdk/evalx/{envId}/contexts used by older SDKs
/sdk/evalx/{envId}/contexts/{contextBase64} GET clientsdk. Polling endpoint, returns flag evaluation results and additional metadata
/sdk/evalx/{envId}/contexts REPORT clientsdk. Same as above but request body is the evaluation context JSON object (not in base64)
/sdk/evalx/{envId}/users/{contextBase64} GET clientsdk. Alternate name for /sdk/evalx/{envId}/contexts/{contextBase64} used by older SDKs
/sdk/evalx/{envId}/users REPORT clientsdk. Alternate name for /sdk/evalx/{envId}/contexts used by older SDKs
✅ /sdk/goals/{envId} GET clientsdk. Provides goals data used by JS SDK
*/
}
47 changes: 47 additions & 0 deletions internal/dev_server/sdk/stream_client_flags.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package sdk

import (
"encoding/json"
"net/http"
"time"

"github.com/launchdarkly/ldcli/internal/dev_server/model"
"github.com/pkg/errors"
)

func StreamClientFlags(w http.ResponseWriter, r *http.Request) {
flusher, ok := w.(http.Flusher)
if !ok {
panic("expected http.ResponseWriter to be an http.Flusher")
}
ctx := r.Context()
store := model.StoreFromContext(ctx)
projectKey := GetProjectKeyFromContext(ctx)
project, err := store.GetDevProject(ctx, projectKey)
if err != nil {
panic(errors.Wrap(err, "unable to get dev project"))
}
allFlags := project.GetFlagStateWithOverridesForProject(ctx, nil) // TODO fetch overrides
jsonBody, err := json.Marshal(allFlags)
if err != nil {
panic(errors.Wrap(err, "failed to marshal flag state"))
}
w.Header().Set("Content-Type", "text/event-stream")
_, err = w.Write([]byte("event: put\ndata: "))
if err != nil {
panic(errors.Wrap(err, "unable to write response"))
}
_, err = w.Write(jsonBody)
if err != nil {
panic(errors.Wrap(err, "unable to write response"))
}
flusher.Flush()
ticker := time.NewTicker(time.Minute)
for _ = range ticker.C {
_, err = w.Write([]byte(":\n"))
if err != nil {
panic(errors.Wrap(err, "unable to write response"))
}
flusher.Flush()
}
}