Skip to content

Commit

Permalink
Added static file monitoring and auto-reload.
Browse files Browse the repository at this point in the history
Any request that comes in, reload!

Signed-off-by: Dave Shanley <[email protected]>
  • Loading branch information
daveshanley committed Jul 8, 2023
1 parent 7cd43cf commit a223746
Show file tree
Hide file tree
Showing 9 changed files with 212 additions and 73 deletions.
5 changes: 5 additions & 0 deletions cmd/run_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,11 @@ func runWiretapService(wiretapConfig *shared.WiretapConfiguration) (server.Platf
// boot the monitor
serveMonitor(wiretapConfig)

// if static dir is configured, monitor static content
if wiretapConfig.StaticDir != "" {
daemon.MonitorStatic(wiretapConfig)
}

// boot wiretap
platformServer.StartServer(sysChan)
return platformServer, nil
Expand Down
37 changes: 37 additions & 0 deletions daemon/handle_request.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
package daemon

import (
_ "embed"
"fmt"
"github.com/pb33f/libopenapi-validator/parameters"
"github.com/pb33f/libopenapi-validator/requests"
Expand All @@ -15,31 +16,67 @@ import (
"net/http"
"os"
"path/filepath"
"text/template"
"time"
)

//go:embed templates/socket-include.html
var staticTemplate string

type staticTemplateModel struct {
OriginalContent string
WebSocketPort string
}

func (ws *WiretapService) handleHttpRequest(request *model.Request) {

// determine if this is a request for a file or not.
if ws.config.StaticDir != "" {
fp := filepath.Join(ws.config.StaticDir, request.HttpRequest.URL.Path)

isRoot := false
// check if this is a static path catch-all
if len(ws.config.StaticPathsCompiled) > 0 {
for key := range ws.config.StaticPathsCompiled {
if ws.config.StaticPathsCompiled[key].Match(request.HttpRequest.URL.Path) {
fp = filepath.Join(ws.config.StaticDir, ws.config.StaticIndex)
isRoot = true
break
}
}
}

// check if this is a root request
if fp == ws.config.StaticDir {
isRoot = true
fp = filepath.Join(ws.config.StaticDir, "index.html")
}
localStat, _ := os.Stat(fp)
if localStat != nil {

if isRoot {

// if this root, we need to modify the index to inject some JS.
tmpFile, _ := os.CreateTemp("", "index.html")
defer os.Remove(tmpFile.Name())

tmpl, _ := template.New("index").Parse(staticTemplate)
indexBytes, _ := os.ReadFile(fp)

// prep a model
m := staticTemplateModel{
OriginalContent: string(indexBytes),
WebSocketPort: ws.config.WebSocketPort,
}

// execute the new template
tmpl.Execute(tmpFile, m)

// serve it.
http.ServeFile(request.HttpResponseWriter, request.HttpRequest, tmpFile.Name())
return
}

if !localStat.IsDir() {
http.ServeFile(request.HttpResponseWriter, request.HttpRequest, fp)
return
Expand Down
67 changes: 67 additions & 0 deletions daemon/monitor_static.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// Copyright 2023 Princess B33f Heavy Industries / Dave Shanley
// SPDX-License-Identifier: MIT

package daemon

import (
"fmt"
"github.com/fsnotify/fsnotify"
"github.com/google/uuid"
"github.com/pb33f/ranch/bus"
"github.com/pb33f/ranch/model"
"github.com/pb33f/wiretap/shared"
"github.com/pterm/pterm"
"os"
"path/filepath"
)

func MonitorStatic(wiretapConfig *shared.WiretapConfiguration) {

b := bus.GetBus()
staticChan, _ := b.GetChannelManager().GetChannel(WiretapStaticChangeChan)

go func() {
var err error

watcher, _ := fsnotify.NewWatcher()
defer watcher.Close()

watchDir := func(path string, fi os.FileInfo, err error) error {
if fi.Mode().IsDir() {
return watcher.Add(path)
}
return nil
}

if wErr := filepath.Walk(wiretapConfig.StaticDir, watchDir); err != nil {
pterm.Fatal.Println(fmt.Sprintf("Error trying to monitor static directory: %s", wErr))
}

for {
select {
case event := <-watcher.Events:
if event.Has(fsnotify.Write) {
pterm.Info.Println(pterm.LightMagenta(fmt.Sprintf("[wiretap] static file changed: %s", event.Name)))

// broadcast the change to all connected clients
ch := make(map[string]string)
ch["file"] = event.Name

id, _ := uuid.NewUUID()
staticChan.Send(&model.Message{
Id: &id,
DestinationId: &id,
Error: err,
Channel: WiretapStaticChangeChan,
Destination: WiretapStaticChangeChan,
Payload: ch,
Direction: model.ResponseDir,
})

}
case wErr := <-watcher.Errors:
pterm.Error.Println(fmt.Sprintf("[wiretap] static error: %s", wErr.Error()))
}
}
}()
}
21 changes: 21 additions & 0 deletions daemon/templates/socket-include.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{{ .OriginalContent }}
<!-- auto-injected into the page by wiretap -->
<script type="importmap">
{
"imports": {
"@stomp/stompjs": "https://ga.jspm.io/npm:@stomp/[email protected]/esm6/index.js"
}
}
</script>
<script type="module">
import { Client } from '@stomp/stompjs';
const client = new Client({
brokerURL: 'ws://localhost:{{ .WebSocketPort }}/ranch',
onConnect: () => {
client.subscribe("/topic/wiretap-static-change", message => {
window.location.reload();
});
},
});
client.activate();
</script>
22 changes: 13 additions & 9 deletions daemon/wiretap_init.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,19 @@ package daemon
import "github.com/pb33f/ranch/service"

func (ws *WiretapService) Init(core service.FabricServiceCore) error {
ws.serviceCore = core
eventBus := core.Bus()
ws.serviceCore = core
eventBus := core.Bus()

// create broadcast channel and set it to galactic
channel := eventBus.GetChannelManager().CreateChannel(WiretapBroadcastChan)
channel.SetGalactic(WiretapBroadcastChan)
// create broadcast channel and set it to galactic
channel := eventBus.GetChannelManager().CreateChannel(WiretapBroadcastChan)
channel.SetGalactic(WiretapBroadcastChan)

ws.broadcastChan = channel
ws.bus = eventBus
core.SetDefaultJSONHeaders()
return nil
// create static change channel and set it to galactic
staticChan := eventBus.GetChannelManager().CreateChannel(WiretapStaticChangeChan)
staticChan.SetGalactic(WiretapStaticChangeChan)

ws.broadcastChan = channel
ws.bus = eventBus
core.SetDefaultJSONHeaders()
return nil
}
101 changes: 51 additions & 50 deletions daemon/wiretap_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,75 +4,76 @@
package daemon

import (
"github.com/pb33f/libopenapi"
"github.com/pb33f/libopenapi/datamodel/high/v3"
"github.com/pb33f/ranch/bus"
"github.com/pb33f/ranch/model"
"github.com/pb33f/ranch/service"
"github.com/pb33f/wiretap/controls"
"github.com/pb33f/wiretap/shared"
"net/http"
"time"
"github.com/pb33f/libopenapi"
"github.com/pb33f/libopenapi/datamodel/high/v3"
"github.com/pb33f/ranch/bus"
"github.com/pb33f/ranch/model"
"github.com/pb33f/ranch/service"
"github.com/pb33f/wiretap/controls"
"github.com/pb33f/wiretap/shared"
"net/http"
"time"
)

const (
WiretapServiceChan = "wiretap"
WiretapBroadcastChan = "wiretap-broadcast"
IncomingHttpRequest = "incoming-http-request"
WiretapServiceChan = "wiretap"
WiretapBroadcastChan = "wiretap-broadcast"
WiretapStaticChangeChan = "wiretap-static-change"
IncomingHttpRequest = "incoming-http-request"
)

type WiretapService struct {
transport *http.Transport
document libopenapi.Document
docModel *v3.Document
serviceCore service.FabricServiceCore
broadcastChan *bus.Channel
bus bus.EventBus
controlsStore bus.BusStore
transactionStore bus.BusStore
config *shared.WiretapConfiguration
fs http.Handler
transport *http.Transport
document libopenapi.Document
docModel *v3.Document
serviceCore service.FabricServiceCore
broadcastChan *bus.Channel
bus bus.EventBus
controlsStore bus.BusStore
transactionStore bus.BusStore
config *shared.WiretapConfiguration
fs http.Handler
}

func NewWiretapService(document libopenapi.Document, config *shared.WiretapConfiguration) *WiretapService {
storeManager := bus.GetBus().GetStoreManager()
controlsStore := storeManager.CreateStore(controls.ControlServiceChan)
transactionStore := storeManager.CreateStore(WiretapServiceChan)
storeManager := bus.GetBus().GetStoreManager()
controlsStore := storeManager.CreateStore(controls.ControlServiceChan)
transactionStore := storeManager.CreateStore(WiretapServiceChan)

tr := &http.Transport{
MaxIdleConns: 20,
IdleConnTimeout: 30 * time.Second,
}
tr := &http.Transport{
MaxIdleConns: 20,
IdleConnTimeout: 30 * time.Second,
}

wts := &WiretapService{
wts := &WiretapService{

transport: tr,
controlsStore: controlsStore,
transactionStore: transactionStore,
}
if document != nil {
m, _ := document.BuildV3Model()
wts.document = document
wts.docModel = &m.Model
}
transport: tr,
controlsStore: controlsStore,
transactionStore: transactionStore,
}
if document != nil {
m, _ := document.BuildV3Model()
wts.document = document
wts.docModel = &m.Model
}

// hard-wire the config, change this later if needed.
wts.config = config
return wts
// hard-wire the config, change this later if needed.
wts.config = config

return wts

}

func (ws *WiretapService) HandleServiceRequest(request *model.Request, core service.FabricServiceCore) {
switch request.RequestCommand {
case IncomingHttpRequest:
ws.handleHttpRequest(request)
default:
core.HandleUnknownRequest(request)
}
switch request.RequestCommand {
case IncomingHttpRequest:
ws.handleHttpRequest(request)
default:
core.HandleUnknownRequest(request)
}
}

func (ws *WiretapService) HandleHttpRequest(request *model.Request) {

ws.handleHttpRequest(request)
ws.handleHttpRequest(request)
}
4 changes: 2 additions & 2 deletions daemon/wiretap_utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
"github.com/stretchr/testify/assert"
)

func TestReconstructURL(t *testing.T){
func TestReconstructURL(t *testing.T) {
protocol := "http"
host := "localhost"
port := "8000"
Expand All @@ -34,4 +34,4 @@ func TestReconstructURL(t *testing.T){
assert.Equal(t, "http://localhost:8000?doctor=who", reconstructURL(r, protocol, host, port))
r, _ = http.NewRequest("GET", "http://localhost:1337?doctor=who", nil)
assert.Equal(t, "http://localhost?doctor=who", reconstructURL(r, protocol, host, ""))
}
}
1 change: 1 addition & 0 deletions ui/src/model/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export const WiretapControlsChannel = "controls";
export const WiretapReportChannel = "report";

export const WiretapConfigurationChannel = "configuration";
export const WiretapStaticChannel = "wiretap-static-change";

export const WiretapHttpTransactionStore = "http-transaction-store";
export const WiretapSelectedTransactionStore = "selected-transaction-store";
Expand Down
Loading

0 comments on commit a223746

Please sign in to comment.