@@ -106,7 +106,7 @@ func NewServeCommand(parent argparser.Registerer, g *global.Data, build *BuildCo
106106 c .CmdClause .Flag ("metadata-filter-envvars" , "Redact specified environment variables from [scripts.env_vars] using comma-separated list" ).Action (c .metadataFilterEnvVars .Set ).StringVar (& c .metadataFilterEnvVars .Value )
107107 c .CmdClause .Flag ("metadata-show" , "Inspect the Wasm binary metadata" ).Action (c .metadataShow .Set ).BoolVar (& c .metadataShow .Value )
108108 c .CmdClause .Flag ("package-name" , "Package name" ).Action (c .packageName .Set ).StringVar (& c .packageName .Value )
109- c .CmdClause .Flag ("experimental-enable-pushpin" , "Enable experimental Pushpin support for local testing of Fanout and WebSockets " ).BoolVar (& c .enablePushpin )
109+ c .CmdClause .Flag ("experimental-enable-pushpin" , "Enable experimental Pushpin support for local testing of Fanout" ).BoolVar (& c .enablePushpin )
110110 c .CmdClause .Flag ("pushpin-path" , "The path to a user installed version of the Pushpin runner binary" ).StringVar (& c .pushpinRunnerBinPath )
111111 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 )
112112 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 )
@@ -600,22 +600,22 @@ func (c *ServeCommand) GetPushpinProxyPort(out io.Writer) (uint16, error) {
600600 }
601601 pushpinProxyPort = uint16 (pushpinProxyPortInt )
602602 if c .Globals .Verbose () {
603- text .Info (out , "Using Pushpin proxy port from --pushpin-proxy-port flag: %d\n \n " , pushpinProxyPort )
603+ text .Info (out , "Using Pushpin proxy port from --pushpin-proxy-port flag: %d" , pushpinProxyPort )
604604 }
605605 return pushpinProxyPort , nil
606606 }
607607
608608 pushpinProxyPort = c .Globals .Manifest .File .LocalServer .Pushpin .PushpinProxyPort
609609 if pushpinProxyPort != 0 {
610610 if c .Globals .Verbose () {
611- text .Info (out , "Using Pushpin proxy port via `local_server.pushpin.proxy_port` setting: %d\n \n " , pushpinProxyPort )
611+ text .Info (out , "Using Pushpin proxy port via `local_server.pushpin.proxy_port` setting: %d" , pushpinProxyPort )
612612 }
613613 return pushpinProxyPort , nil
614614 }
615615
616616 pushpinProxyPort = 7677
617617 if c .Globals .Verbose () {
618- text .Info (out , "Using default Pushpin proxy port %d\n \n " , pushpinProxyPort )
618+ text .Info (out , "Using default Pushpin proxy port %d" , pushpinProxyPort )
619619 }
620620 return pushpinProxyPort , nil
621621}
@@ -640,22 +640,22 @@ func (c *ServeCommand) GetPushpinPublishPort(out io.Writer) (uint16, error) {
640640 }
641641 pushpinPublishPort = uint16 (pushpinPublishPortInt )
642642 if c .Globals .Verbose () {
643- text .Info (out , "Using Pushpin publish handler port from --pushpin-publish-port flag: %d\n \n " , pushpinPublishPort )
643+ text .Info (out , "Using Pushpin publish handler port from --pushpin-publish-port flag: %d" , pushpinPublishPort )
644644 }
645645 return pushpinPublishPort , nil
646646 }
647647
648648 pushpinPublishPort = c .Globals .Manifest .File .LocalServer .Pushpin .PushpinPublishPort
649649 if pushpinPublishPort != 0 {
650650 if c .Globals .Verbose () {
651- text .Info (out , "Using Pushpin publish handler port via `local_server.pushpin.publish_port` setting: %d\n \n " , pushpinPublishPort )
651+ text .Info (out , "Using Pushpin publish handler port via `local_server.pushpin.publish_port` setting: %d" , pushpinPublishPort )
652652 }
653653 return pushpinPublishPort , nil
654654 }
655655
656656 pushpinPublishPort = 5561
657657 if c .Globals .Verbose () {
658- text .Info (out , "Using default Pushpin publish handler port %d\n \n " , pushpinPublishPort )
658+ text .Info (out , "Using default Pushpin publish handler port %d" , pushpinPublishPort )
659659 }
660660 return pushpinPublishPort , nil
661661}
@@ -669,15 +669,15 @@ func (c *ServeCommand) GetPushpinRunner(out io.Writer) (bin string, err error) {
669669 pushpinRunnerBinPath := c .pushpinRunnerBinPath
670670 if pushpinRunnerBinPath != "" {
671671 if c .Globals .Verbose () {
672- text .Info (out , "Using user provided install of Pushpin runner via --pushpin-path flag: %s\n \n " , pushpinRunnerBinPath )
672+ text .Info (out , "Using user provided install of Pushpin runner via --pushpin-path flag: %s" , pushpinRunnerBinPath )
673673 }
674674 return filepath .Abs (pushpinRunnerBinPath )
675675 }
676676
677677 pushpinRunnerBinPath = c .Globals .Manifest .File .LocalServer .Pushpin .PushpinPath
678678 if pushpinRunnerBinPath != "" {
679679 if c .Globals .Verbose () {
680- text .Info (out , "Using user provided install of Pushpin runner via `local_server.pushpin.pushpin_path` setting: %s\n \n " , pushpinRunnerBinPath )
680+ text .Info (out , "Using user provided install of Pushpin runner via `local_server.pushpin.pushpin_path` setting: %s" , pushpinRunnerBinPath )
681681 }
682682 return filepath .Abs (pushpinRunnerBinPath )
683683 }
@@ -694,7 +694,7 @@ func (c *ServeCommand) GetPushpinRunner(out io.Writer) (bin string, err error) {
694694 }
695695
696696 if c .Globals .Verbose () {
697- text .Info (out , "Found Pushpin runner via $PATH lookup: %s\n \n " , pushpinRunnerBinPath )
697+ text .Info (out , "Found Pushpin runner via $PATH lookup: %s" , pushpinRunnerBinPath )
698698 }
699699 return filepath .Abs (pushpinRunnerBinPath )
700700}
@@ -767,6 +767,8 @@ func formatPushpinLog(line string) (string, string) {
767767// pushpinContext contains information about the instance of Pushpin that is
768768// executed when enabled.
769769type pushpinContext struct {
770+ instanceID uint32
771+ confFilePath string
770772 pushpinRunnerBin string
771773 pushpinRunDir string
772774 pushpinLogDir string
@@ -810,43 +812,76 @@ func (c *pushpinContext) buildPushpinConf() string {
810812// command line and/or fastly.toml. The cleanup function on the returned pushpinContext
811813// needs to eventually be called by the caller to shut down Pushpin.
812814func (c * ServeCommand ) startPushpin (spinner text.Spinner , out io.Writer ) (pushpinContext , error ) {
815+ text .Info (out , "Enabling experimental Pushpin support for local testing of Fanout." )
816+
813817 pushpinCtx := pushpinContext {}
814818
815- var cleanup func ()
819+ // Generate a non-zero instance ID to represent this Pushpin instance and build temporary
820+ // files
821+ for {
822+ p := make ([]byte , 4 )
823+ _ , _ = rand .Read (p )
824+ pushpinCtx .instanceID = binary .BigEndian .Uint32 (p )
825+ if pushpinCtx .instanceID != 0 {
826+ break
827+ }
828+ }
816829
817- err := spinner .Start ()
830+ var err error
831+ pushpinCtx .proxyPort , err = c .GetPushpinProxyPort (out )
818832 if err != nil {
819833 return pushpinCtx , err
820834 }
821- msg := "Running local Pushpin"
822- spinner . Message ( msg + "..." )
823-
824- spinner . StopMessage ( msg )
825- err = spinner . Stop ( )
835+ pushpinCtx . publishPort , err = c . GetPushpinPublishPort ( out )
836+ if err != nil {
837+ return pushpinCtx , err
838+ }
839+ pushpinCtx . pushpinRunnerBin , err = c . GetPushpinRunner ( out )
826840 if err != nil {
827841 return pushpinCtx , err
828842 }
829843
830844 pwd , _ := os .Getwd ()
831845 pushpinCtx .pushpinLogDir = filepath .Join (pwd , "pushpin-logs" )
832846
833- pushpinCtx .proxyPort , err = c .GetPushpinProxyPort (out )
847+ pushpinCtx .pushpinRunDir = filepath .Join (
848+ os .TempDir (),
849+ fmt .Sprintf ("pushpin-%08x" , pushpinCtx .instanceID ),
850+ )
851+ pushpinCtx .confFilePath = filepath .Join (
852+ os .TempDir (),
853+ fmt .Sprintf ("pushpin-%08x.conf" , pushpinCtx .instanceID ),
854+ )
855+ pushpinCtx .routesFilePath = filepath .Join (
856+ os .TempDir (),
857+ fmt .Sprintf ("pushpin-routes-%08x" , pushpinCtx .instanceID ),
858+ )
859+
860+ text .Break (out )
861+
862+ err = spinner .Start ()
834863 if err != nil {
835864 return pushpinCtx , err
836865 }
837- pushpinCtx .publishPort , err = c .GetPushpinPublishPort (out )
866+ msg := "Starting Pushpin"
867+ spinner .Message (msg + "..." )
868+
869+ spinner .StopMessage (msg )
870+ err = spinner .Stop ()
838871 if err != nil {
839872 return pushpinCtx , err
840873 }
841- pushpinCtx .pushpinRunnerBin , err = c .GetPushpinRunner (out )
874+
875+ pushpinConfContents := pushpinCtx .buildPushpinConf ()
876+ err = os .WriteFile (pushpinCtx .confFilePath , []byte (pushpinConfContents ), 0o600 )
842877 if err != nil {
843- return pushpinCtx , err
878+ return pushpinCtx , fmt . Errorf ( "error writing config file %s: %w" , pushpinCtx . confFilePath , err )
844879 }
845- if c . Globals . Verbose () {
846- text . Info ( out , "Local pushpin proxy port: %d" , pushpinCtx . proxyPort )
847- text . Info ( out , "Local pushpin publisher port: %d" , pushpinCtx . publishPort )
848- text . Info ( out , "Local pushpin other reserved ports: %d - %d" , pushpinCtx . publishPort + 1 , pushpinCtx . publishPort + 3 )
849- text . Info ( out , "Local pushpin runner: %s " , pushpinCtx .pushpinRunnerBin )
880+
881+ pushpinRoutesContents := strings . Join ( c . BuildPushpinRoutes () , "\n " ) + " \n "
882+ err = os . WriteFile ( pushpinCtx . routesFilePath , [] byte ( pushpinRoutesContents ), 0o600 )
883+ if err != nil {
884+ return pushpinCtx , fmt . Errorf ( "error writing routes file %s: %w " , pushpinCtx .routesFilePath , err )
850885 }
851886
852887 // Pushpin is configured with the following.
@@ -863,72 +898,20 @@ func (c *ServeCommand) startPushpin(spinner text.Spinner, out io.Writer) (pushpi
863898 // - if the backend enables HTTPS, then we enable that
864899 // - if the backend has a path prefix, then we set that up
865900 // - enables WebSocket-over-HTTP
866-
867901 // The runtime temporary directory, as well as the conf file and routes file
868902 // are set up and torn down along with fastly compute serve.
869- var pushpinInstanceID uint32
870- for {
871- p := make ([]byte , 4 )
872- _ , _ = rand .Read (p )
873- pushpinInstanceID = binary .BigEndian .Uint32 (p )
874- if pushpinInstanceID != 0 {
875- break
876- }
877- }
878-
879- pushpinRunDir := filepath .Join (
880- os .TempDir (),
881- fmt .Sprintf ("pushpin-%08x" , pushpinInstanceID ),
882- )
883- if c .Globals .Verbose () {
884- text .Break (out )
885- text .Info (out , "Pushpin temporary runtime directory is %s" , pushpinRunDir )
886- }
887-
888- pushpinConfFilePath := filepath .Join (
889- os .TempDir (),
890- fmt .Sprintf ("pushpin-%08x.conf" , pushpinInstanceID ),
891- )
892- pushpinRoutesFilePath := filepath .Join (
893- os .TempDir (),
894- fmt .Sprintf ("pushpin-routes-%08x" , pushpinInstanceID ),
895- )
896-
897- if c .Globals .Verbose () {
898- text .Info (out , "Writing config file to %s..." , pushpinConfFilePath )
899- }
900-
901- pushpinConfContents := pushpinCtx .buildPushpinConf ()
902- err = os .WriteFile (pushpinConfFilePath , []byte (pushpinConfContents ), 0o600 )
903- if err != nil {
904- return pushpinCtx , fmt .Errorf ("error writing config file %s: %w" , pushpinConfFilePath , err )
905- }
906-
907- if c .Globals .Verbose () {
908- text .Info (out , "Writing routes file to %s..." , pushpinRoutesFilePath )
909- }
910- pushpinRoutesContents := strings .Join (c .BuildPushpinRoutes (), "\n " ) + "\n "
911- err = os .WriteFile (pushpinRoutesFilePath , []byte (pushpinRoutesContents ), 0o600 )
912- if err != nil {
913- return pushpinCtx , fmt .Errorf ("error writing routes file %s: %w" , pushpinRoutesFilePath , err )
914- }
915-
916- if c .Globals .Verbose () {
917- text .Info (out , "Starting local Pushpin..." )
918- text .Break (out )
919- }
920903
921904 args := []string {
922- fmt .Sprintf ("--config=%s" , pushpinConfFilePath ),
905+ fmt .Sprintf ("--config=%s" , pushpinCtx . confFilePath ),
923906 "--verbose" ,
924907 }
925908
926- // Set up a context that can be canceled (prevent rogue Pushpin process)
909+ // Set up a context that can be canceled (prevent zombie Pushpin process)
927910 var pushpinCmd * exec.Cmd
928911 ctx , cancel := context .WithCancel (context .Background ())
929912
930913 var once sync.Once
931- cleanup = func () {
914+ pushpinCtx . cleanup = func () {
932915 once .Do (func () {
933916 if pushpinCmd != nil && pushpinCmd .Process != nil {
934917 if c .Globals .Verbose () {
@@ -937,17 +920,17 @@ func (c *ServeCommand) startPushpin(spinner text.Spinner, out io.Writer) (pushpi
937920 killProcessTree (pushpinCmd .Process .Pid )
938921 }
939922 if c .Globals .Verbose () {
940- text .Output (out , "removing %s" , pushpinRunDir )
923+ text .Output (out , "removing %s" , pushpinCtx . pushpinRunDir )
941924 }
942- _ = os .RemoveAll (pushpinRunDir )
925+ _ = os .RemoveAll (pushpinCtx . pushpinRunDir )
943926 if c .Globals .Verbose () {
944- text .Output (out , "deleting %s" , pushpinConfFilePath )
927+ text .Output (out , "deleting %s" , pushpinCtx . confFilePath )
945928 }
946- _ = os .Remove (pushpinConfFilePath )
929+ _ = os .Remove (pushpinCtx . confFilePath )
947930 if c .Globals .Verbose () {
948- text .Output (out , "deleting %s" , pushpinRoutesFilePath )
931+ text .Output (out , "deleting %s" , pushpinCtx . routesFilePath )
949932 }
950- _ = os .Remove (pushpinRoutesFilePath )
933+ _ = os .Remove (pushpinCtx . routesFilePath )
951934 cancel ()
952935 })
953936 }
@@ -957,7 +940,7 @@ func (c *ServeCommand) startPushpin(spinner text.Spinner, out io.Writer) (pushpi
957940 signal .Notify (sigCh , os .Interrupt , syscall .SIGTERM , syscall .SIGHUP , syscall .SIGQUIT )
958941 go func () {
959942 <- sigCh
960- cleanup ()
943+ pushpinCtx . Close ()
961944 }()
962945
963946 // gosec flagged this:
@@ -974,8 +957,13 @@ func (c *ServeCommand) startPushpin(spinner text.Spinner, out io.Writer) (pushpi
974957
975958 // Start Pushpin
976959 if c .Globals .Verbose () {
977- text .Info (out , "Starting Pushpin runner in the background..." )
978960 text .Output (out , "%s: %s" , text .BoldYellow ("Pushpin command" ), strings .Join (pushpinCmd .Args , " " ))
961+ text .Output (out , "%s: %d" , text .BoldYellow ("Pushpin proxy port" ), pushpinCtx .proxyPort )
962+ text .Output (out , "%s: %d" , text .BoldYellow ("Pushpin publisher port" ), pushpinCtx .publishPort )
963+ text .Output (out , "%s: %d - %d" , text .BoldYellow ("Pushpin other reserved ports" ), pushpinCtx .publishPort + 1 , pushpinCtx .publishPort + 3 )
964+ text .Output (out , "%s: %s" , text .BoldYellow ("Pushpin temporary runtime directory" ), pushpinCtx .pushpinRunDir )
965+ text .Output (out , "%s: %s" , text .BoldYellow ("Pushpin conf file" ), pushpinCtx .confFilePath )
966+ text .Output (out , "%s: %s" , text .BoldYellow ("Pushpin routes file" ), pushpinCtx .routesFilePath )
979967 }
980968 if err := pushpinCmd .Start (); err != nil {
981969 return pushpinCtx , fmt .Errorf ("failed to start Pushpin runner: %w" , err )
@@ -1015,14 +1003,12 @@ func (c *ServeCommand) startPushpin(spinner text.Spinner, out io.Writer) (pushpi
10151003 if err != nil {
10161004 return pushpinCtx , fsterr.RemediationError {
10171005 Inner : err ,
1018- Remediation : fmt .Sprintf ("A process may already be running on port %d." , pushpinCtx .proxyPort ),
1006+ Remediation : fmt .Sprintf ("Check that your disk isn't full and that a process isn't already running on ports %d or %d - %d ." , pushpinCtx .proxyPort , pushpinCtx . publishPort , pushpinCtx . publishPort + 3 ),
10191007 }
10201008 }
10211009
1022- if c .Globals .Verbose () {
1023- text .Info (out , "Local Pushpin started on port %d." , pushpinCtx .proxyPort )
1024- text .Break (out )
1025- }
1010+ text .Success (out , "Pushpin started." )
1011+ text .Break (out )
10261012
10271013 return pushpinCtx , nil
10281014}
0 commit comments