Skip to content
Open
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
### Enhancements:

- feat(audit-log): add event-mapping command group ([#1875](https://github.com/fastly/cli/pull/1875))
- feat(compute/serve): add `--experimental-websockets-passthrough` flag and `[local_server.websockets_passthrough]` section in `fastly.toml`, allowing local WebSocket passthrough to be disabled (it remains enabled by default)

### Dependencies:

Expand Down
1 change: 1 addition & 0 deletions pkg/commands/compute/compute_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ func TestFlagDivergenceServe(t *testing.T) {
"addr",
"debug",
"experimental-enable-pushpin",
"experimental-websockets-passthrough",
"file",
"profile-guest",
"pushpin-path",
Expand Down
111 changes: 67 additions & 44 deletions pkg/commands/compute/serve.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,20 +63,21 @@ type ServeCommand struct {
ViceroyVersioner github.AssetVersioner

// Serve private fields
addr string
debug bool
enablePushpin bool
pushpinRunnerBinPath string
pushpinProxyPort string
pushpinPublishPort string
env argparser.OptionalString
file argparser.OptionalString
profileGuest bool
profileGuestDir argparser.OptionalString
projectDir string
skipBuild bool
watch bool
watchDir argparser.OptionalString
addr string
debug bool
enablePushpin bool
enableWebsocketsPassthrough argparser.OptionalBool
pushpinRunnerBinPath string
pushpinProxyPort string
pushpinPublishPort string
env argparser.OptionalString
file argparser.OptionalString
profileGuest bool
profileGuestDir argparser.OptionalString
projectDir string
skipBuild bool
watch bool
watchDir argparser.OptionalString
}

// NewServeCommand returns a usable command registered under the parent.
Expand All @@ -102,6 +103,7 @@ func NewServeCommand(parent argparser.Registerer, g *global.Data, build *BuildCo
c.CmdClause.Flag("pushpin-path", "The path to a user installed version of the Pushpin runner binary").StringVar(&c.pushpinRunnerBinPath)
c.CmdClause.Flag("pushpin-proxy-port", "The port to run the Pushpin runner on. Overrides 'local_server.pushpin.proxy_port' from 'fastly.toml', and if not specified there, defaults to 7677.").StringVar(&c.pushpinProxyPort)
c.CmdClause.Flag("pushpin-publish-port", "The port to run the Pushpin publish handler on. Overrides 'local_server.pushpin.publish_port' from 'fastly.toml', and if not specified there, defaults to 5561.").StringVar(&c.pushpinPublishPort)
c.CmdClause.Flag("experimental-websockets-passthrough", "Enable WebSocket passthrough support for local testing of WebSockets. Overrides 'local_server.websockets_passthrough.enable' from 'fastly.toml', and if not specified there, defaults to true.").Action(c.enableWebsocketsPassthrough.Set).BoolVar(&c.enableWebsocketsPassthrough.Value)
c.CmdClause.Flag("profile-guest", "Profile the Wasm guest under Viceroy (requires Viceroy 0.9.1 or higher). View profiles at https://profiler.firefox.com/.").BoolVar(&c.profileGuest)
c.CmdClause.Flag("profile-guest-dir", "The directory where the per-request profiles are saved to. Defaults to guest-profiles.").Action(c.profileGuestDir.Set).StringVar(&c.profileGuestDir.Value)
c.CmdClause.Flag("skip-build", "Skip the build step").BoolVar(&c.skipBuild)
Expand Down Expand Up @@ -223,6 +225,19 @@ func (c *ServeCommand) Exec(in io.Reader, out io.Writer) (err error) {
defer pushpinCtx.Close()
}

// WebSocket passthrough is enabled unless it's explicitly disabled via the
// --experimental-websockets-passthrough flag, or via
// `local_server.websockets_passthrough.enable` in fastly.toml. The flag
// takes precedence over the manifest.
enableWebsocketsPassthrough := true
switch {
case c.enableWebsocketsPassthrough.WasSet:
enableWebsocketsPassthrough = c.enableWebsocketsPassthrough.Value
case c.Globals.Manifest.File.LocalServer.WebsocketsPassthrough != nil &&
c.Globals.Manifest.File.LocalServer.WebsocketsPassthrough.EnableWebsocketsPassthrough != nil:
enableWebsocketsPassthrough = *c.Globals.Manifest.File.LocalServer.WebsocketsPassthrough.EnableWebsocketsPassthrough
}

err = spinner.Start()
if err != nil {
return err
Expand All @@ -243,21 +258,22 @@ func (c *ServeCommand) Exec(in io.Reader, out io.Writer) (err error) {
var restart bool
for {
err = local(localOpts{
addr: c.addr,
bin: bin,
debug: c.debug,
errLog: c.Globals.ErrLog,
extraArgs: c.ViceroyBinExtraArgs,
manifestPath: manifestPath,
out: out,
profileGuest: c.profileGuest,
profileGuestDir: c.profileGuestDir,
pushpinProxyPort: pushpinCtx.proxyPort,
restarted: restart,
verbose: c.Globals.Verbose(),
wasmBinPath: wasmBinaryToRun,
watch: c.watch,
watchDir: c.watchDir,
addr: c.addr,
bin: bin,
debug: c.debug,
enableWebsocketsPassthrough: enableWebsocketsPassthrough,
errLog: c.Globals.ErrLog,
extraArgs: c.ViceroyBinExtraArgs,
manifestPath: manifestPath,
out: out,
profileGuest: c.profileGuest,
profileGuestDir: c.profileGuestDir,
pushpinProxyPort: pushpinCtx.proxyPort,
restarted: restart,
verbose: c.Globals.Verbose(),
wasmBinPath: wasmBinaryToRun,
watch: c.watch,
watchDir: c.watchDir,
})
if err != nil {
if err != fsterr.ErrViceroyRestart {
Expand Down Expand Up @@ -820,21 +836,22 @@ func (c *ServeCommand) startPushpin(spinner text.Spinner, out io.Writer) (pushpi

// localOpts represents the inputs for `local()`.
type localOpts struct {
addr string
bin string
debug bool
errLog fsterr.LogInterface
extraArgs string
manifestPath string
out io.Writer
profileGuest bool
profileGuestDir argparser.OptionalString
pushpinProxyPort uint16
restarted bool
verbose bool
wasmBinPath string
watch bool
watchDir argparser.OptionalString
addr string
bin string
debug bool
enableWebsocketsPassthrough bool
errLog fsterr.LogInterface
extraArgs string
manifestPath string
out io.Writer
profileGuest bool
profileGuestDir argparser.OptionalString
pushpinProxyPort uint16
restarted bool
verbose bool
wasmBinPath string
watch bool
watchDir argparser.OptionalString
}

// local spawns a subprocess that runs the compiled binary.
Expand Down Expand Up @@ -863,6 +880,12 @@ func local(opts localOpts) error {
args = append(args, fmt.Sprintf("--local-pushpin-proxy-port=%d", opts.pushpinProxyPort))
}

// Viceroy enables WebSocket passthrough by default, so we only need to pass
// the flag when it has been explicitly disabled in the manifest.
if !opts.enableWebsocketsPassthrough {
args = append(args, "--enable-local-websocket-passthrough=false")
}

if opts.extraArgs != "" {
extraArgs := strings.Split(opts.extraArgs, " ")
args = append(args, extraArgs...)
Expand Down
8 changes: 8 additions & 0 deletions pkg/manifest/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,14 @@ func (f *File) MarshalTOML() ([]byte, error) {
localServer["pushpin"] = pushpin
}

if f.LocalServer.WebsocketsPassthrough != nil {
websocketsPassthrough := make(map[string]any)
if f.LocalServer.WebsocketsPassthrough.EnableWebsocketsPassthrough != nil {
websocketsPassthrough["enable"] = *f.LocalServer.WebsocketsPassthrough.EnableWebsocketsPassthrough
}
localServer["websockets_passthrough"] = websocketsPassthrough
}

if f.LocalServer.SecretStores != nil {
secretStores := make(map[string]any)
for key, entry := range f.LocalServer.SecretStores {
Expand Down
19 changes: 13 additions & 6 deletions pkg/manifest/local_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,13 @@ import (

// LocalServer represents a list of mocked Viceroy resources.
type LocalServer struct {
Backends map[string]LocalBackend `toml:"backends"`
ConfigStores map[string]LocalConfigStore `toml:"config_stores,omitempty"`
KVStores LocalKVStoreMap `toml:"kv_stores,omitempty"`
SecretStores LocalSecretStoreMap `toml:"secret_stores,omitempty"`
Pushpin *LocalPushpinMap `toml:"pushpin,omitempty"`
ViceroyVersion string `toml:"viceroy_version,omitempty"`
Backends map[string]LocalBackend `toml:"backends"`
ConfigStores map[string]LocalConfigStore `toml:"config_stores,omitempty"`
KVStores LocalKVStoreMap `toml:"kv_stores,omitempty"`
SecretStores LocalSecretStoreMap `toml:"secret_stores,omitempty"`
Pushpin *LocalPushpinMap `toml:"pushpin,omitempty"`
WebsocketsPassthrough *LocalWebsocketsPassthroughMap `toml:"websockets_passthrough,omitempty"`
ViceroyVersion string `toml:"viceroy_version,omitempty"`
}

// LocalBackend represents a backend to be mocked by the local testing server.
Expand Down Expand Up @@ -203,6 +204,12 @@ type LocalPushpinMap struct {
PushpinPublishPort *uint16 `toml:"publish_port,omitempty"`
}

// LocalWebsocketsPassthroughMap represents configuration of local WebSocket
// passthrough support, used for local testing of handoff_websocket.
type LocalWebsocketsPassthroughMap struct {
EnableWebsocketsPassthrough *bool `toml:"enable,omitempty"`
}

func decodeTOMLMap(m map[string]any, out any) error {
buf := new(bytes.Buffer)
enc := toml.NewEncoder(buf)
Expand Down
3 changes: 3 additions & 0 deletions pkg/manifest/testdata/fastly-viceroy-update.toml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ pushpin_path = "path/to/pushpin"
proxy_port = 7777
publish_port = 6666

[local_server.websockets_passthrough]
enable = false

[local_server.secret_stores]
store_one = [
{ key = "first", data = "This is some secret data" },
Expand Down
Loading