diff --git a/cmd/run_service.go b/cmd/run_service.go index 2a31da8..bb5cde3 100644 --- a/cmd/run_service.go +++ b/cmd/run_service.go @@ -78,6 +78,8 @@ func runWiretapService(wiretapConfig *shared.WiretapConfiguration, doc libopenap staticMockService, staticMock.StaticMockServiceChan); err != nil { panic(err) } + // Start watcher to look for changes to static mock definitions + staticMockService.StartWatcher() // register spec service if err = platformServer.RegisterService( diff --git a/go.mod b/go.mod index e0f6c8a..526bc80 100644 --- a/go.mod +++ b/go.mod @@ -23,7 +23,6 @@ require ( github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/dprotaso/go-yit v0.0.0-20240618133044-5a0af90af097 // indirect github.com/fatih/color v1.17.0 // indirect - github.com/fsnotify/fsnotify v1.7.0 github.com/go-stomp/stomp/v3 v3.1.2 // indirect github.com/gobwas/glob v0.2.3 github.com/gookit/color v1.5.4 // indirect @@ -63,7 +62,11 @@ require ( gopkg.in/yaml.v3 v3.0.1 ) -require github.com/json-iterator/go v1.1.12 +require ( + github.com/fsnotify/fsevents v0.2.0 + github.com/fsnotify/fsnotify v1.7.0 + github.com/json-iterator/go v1.1.12 +) require ( github.com/pelletier/go-toml/v2 v2.2.3 // indirect diff --git a/go.sum b/go.sum index cf39065..92c9bd5 100644 --- a/go.sum +++ b/go.sum @@ -40,6 +40,8 @@ github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4= github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= +github.com/fsnotify/fsevents v0.2.0 h1:BRlvlqjvNTfogHfeBOFvSC9N0Ddy+wzQCQukyoD7o/c= +github.com/fsnotify/fsevents v0.2.0/go.mod h1:B3eEk39i4hz8y1zaWS/wPrAP4O6wkIl7HQwKBr1qH/w= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= diff --git a/static-mock/static_mock_service.go b/static-mock/static_mock_service.go index c6ea383..3094a03 100644 --- a/static-mock/static_mock_service.go +++ b/static-mock/static_mock_service.go @@ -9,7 +9,9 @@ import ( "encoding/json" "log/slog" "os" + "time" + "github.com/fsnotify/fsevents" "github.com/pb33f/ranch/model" "github.com/pb33f/ranch/service" "github.com/pb33f/wiretap/daemon" @@ -137,6 +139,48 @@ func loadStaticMockRequestsAndResponses(wiretapService *daemon.WiretapService, l return staticMockDefinitions } +// StartWatcher Function to start a watcher on mock-definitions folder +func (sms *StaticMockService) StartWatcher() { + pathToWatch := sms.wiretapService.StaticMockDir + MockDefinitionsPath + + dev, err := fsevents.DeviceForPath(pathToWatch) + if err != nil { + sms.logger.Error("Error when starting fsevents for path => '%s'...\n\n", pathToWatch, err) + } + + // Create an event stream + es := &fsevents.EventStream{ + Paths: []string{pathToWatch}, + Latency: 100 * time.Millisecond, // Debounce time + Device: dev, + Flags: fsevents.FileEvents | fsevents.WatchRoot, // FileEvents enables detailed file monitoring + } + + // Start the event stream + es.Start() + + go func(sms *StaticMockService) { + for msg := range es.Events { + for _, event := range msg { + // If files are created, deleted or modified, call the handler + mockDefinitionsModified := event.Flags&fsevents.ItemCreated != 0 || event.Flags&fsevents.ItemModified != 0 || event.Flags&fsevents.ItemRemoved != 0 || event.Flags&fsevents.ItemRenamed != 0 + if mockDefinitionsModified { + sms.handleStaticMockChange() + } + } + } + }(sms) + +} + +// handleStaticMockChange Function to handle changes to mock definitions. It loads the mock definitions in realtime +// so that the entire wiretap service doesn't need a restart +func (sms *StaticMockService) handleStaticMockChange() { + sms.logger.Info("Mock definitions modified. Rebuilding mocks...") + sms.mockDefinitions = loadStaticMockRequestsAndResponses(sms.wiretapService, sms.logger) + sms.logger.Info("New mock definitions loaded") +} + func (sms *StaticMockService) HandleServiceRequest(request *model.Request, core service.FabricServiceCore) { switch request.RequestCommand { case IncomingHttpRequest: