diff --git a/middleware/monitor/README.md b/middleware/monitor/README.md index 8ac23e4211..5987aec00b 100644 --- a/middleware/monitor/README.md +++ b/middleware/monitor/README.md @@ -53,7 +53,7 @@ type Config struct { // Optional. Default: 3 seconds Refresh time.Duration - // To disable serving HTML, you can make true this option. + // Whether the service should expose only the monitoring API. // // Optional. Default: false APIOnly bool @@ -62,6 +62,23 @@ type Config struct { // // Optional. Default: nil Next func(c *fiber.Ctx) bool + + // Custom HTML Code to Head Section(Before End) + // + // Optional. Default: empty + CustomHead string + + // FontURL for specify font resource path or URL . also you can use relative path + // + // Optional. Default: https://fonts.googleapis.com/css2?family=Roboto:wght@400;900&display=swap + + FontURL string + // ChartJsURL for specify ChartJS library path or URL . also you can use relative path + // + // Optional. Default: https://cdn.jsdelivr.net/npm/chart.js@2.9/dist/Chart.bundle.min.js + + ChartJsURL string + } ``` @@ -73,5 +90,9 @@ var ConfigDefault = Config{ Refresh: 3 * time.Second, APIOnly: false, Next: nil, + CustomHead:"", + FontURL:"https://fonts.googleapis.com/css2?family=Roboto:wght@400;900&display=swap", + ChartJsURL:"https://cdn.jsdelivr.net/npm/chart.js@2.9/dist/Chart.bundle.min.js" + } ``` diff --git a/middleware/monitor/config.go b/middleware/monitor/config.go index dbd3186835..a5d08b65ca 100644 --- a/middleware/monitor/config.go +++ b/middleware/monitor/config.go @@ -28,28 +28,49 @@ type Config struct { // Optional. Default: nil Next func(c *fiber.Ctx) bool - // customized indexHtml + // Custom HTML Code to Head Section(Before End) + // + // Optional. Default: empty + CustomHead string + + // FontURL for specify font resource path or URL . also you can use relative path + // + // Optional. Default: https://fonts.googleapis.com/css2?family=Roboto:wght@400;900&display=swap + FontURL string + + // ChartJsURL for specify ChartJS library path or URL . also you can use relative path + // + // Optional. Default: https://cdn.jsdelivr.net/npm/chart.js@2.9/dist/Chart.bundle.min.js + ChartJsURL string + index string } var ConfigDefault = Config{ - Title: defaultTitle, - Refresh: defaultRefresh, - APIOnly: false, - Next: nil, - index: newIndex(defaultTitle, defaultRefresh), + Title: defaultTitle, + Refresh: defaultRefresh, + FontURL: defaultFontURL, + ChartJsURL: defaultChartJsURL, + CustomHead: defaultCustomHead, + APIOnly: false, + Next: nil, + index: newIndex(viewBag{defaultTitle, defaultRefresh, defaultFontURL, defaultChartJsURL, + defaultCustomHead}), } func configDefault(config ...Config) Config { // Users can change ConfigDefault.Title/Refresh which then // become incompatible with ConfigDefault.index - if ConfigDefault.Title != defaultTitle || ConfigDefault.Refresh != defaultRefresh { + if ConfigDefault.Title != defaultTitle || ConfigDefault.Refresh != defaultRefresh || + ConfigDefault.FontURL != defaultFontURL || ConfigDefault.ChartJsURL != defaultChartJsURL || + ConfigDefault.CustomHead != defaultCustomHead { if ConfigDefault.Refresh < minRefresh { ConfigDefault.Refresh = minRefresh } // update default index with new default title/refresh - ConfigDefault.index = newIndex(ConfigDefault.Title, ConfigDefault.Refresh) + ConfigDefault.index = newIndex(viewBag{ConfigDefault.Title, + ConfigDefault.Refresh, ConfigDefault.FontURL, ConfigDefault.ChartJsURL, ConfigDefault.CustomHead}) } // Return default config if nothing provided @@ -68,7 +89,13 @@ func configDefault(config ...Config) Config { if cfg.Refresh == 0 { cfg.Refresh = ConfigDefault.Refresh } + if cfg.FontURL == "" { + cfg.FontURL = defaultFontURL + } + if cfg.ChartJsURL == "" { + cfg.ChartJsURL = defaultChartJsURL + } if cfg.Title == ConfigDefault.Title && cfg.Refresh == ConfigDefault.Refresh { cfg.index = ConfigDefault.index } else { @@ -76,7 +103,8 @@ func configDefault(config ...Config) Config { cfg.Refresh = minRefresh } // update cfg.index with custom title/refresh - cfg.index = newIndex(cfg.Title, cfg.Refresh) + cfg.index = newIndex(viewBag{cfg.Title, + cfg.Refresh, cfg.FontURL, cfg.ChartJsURL, cfg.CustomHead}) } if cfg.Next == nil { diff --git a/middleware/monitor/index.go b/middleware/monitor/index.go index 4267b7c4e2..b17c95f9e4 100644 --- a/middleware/monitor/index.go +++ b/middleware/monitor/index.go @@ -6,25 +6,37 @@ import ( "time" ) +type viewBag struct { + title string + refresh time.Duration + fontUrl string + chartJsUrl string + customHead string +} + // returns index with new title/refresh -func newIndex(title string, refresh time.Duration) string { +func newIndex(dat viewBag) string { - timeout := refresh.Milliseconds() - timeoutDiff + timeout := dat.refresh.Milliseconds() - timeoutDiff if timeout < timeoutDiff { timeout = timeoutDiff } ts := strconv.FormatInt(timeout, 10) - - index := strings.ReplaceAll(indexHtml, "$TITLE", title) - return strings.ReplaceAll(index, "$TIMEOUT", ts) + replacer := strings.NewReplacer("$TITLE", dat.title, "$TIMEOUT", ts, + "$FONT_URL", dat.fontUrl, "$CHART_JS_URL", dat.chartJsUrl, "$CUSTOM_HEAD", dat.customHead, + ) + return replacer.Replace(indexHtml) } const ( defaultTitle = "Fiber Monitor" - defaultRefresh = 3 * time.Second - timeoutDiff = 200 // timeout will be Refresh (in millisconds) - timeoutDiff - minRefresh = timeoutDiff * time.Millisecond + defaultRefresh = 3 * time.Second + timeoutDiff = 200 // timeout will be Refresh (in milliseconds) - timeoutDiff + minRefresh = timeoutDiff * time.Millisecond + defaultFontURL = `https://fonts.googleapis.com/css2?family=Roboto:wght@400;900&display=swap` + defaultChartJsURL = `https://cdn.jsdelivr.net/npm/chart.js@2.9/dist/Chart.bundle.min.js` + defaultCustomHead = `` // parametrized by $TITLE and $TIMEOUT indexHtml = ` @@ -32,8 +44,9 @@ const ( - - + + + $TITLE @@ -253,5 +267,6 @@ const ( fetchJSON() -` + +` ) diff --git a/middleware/monitor/monitor_test.go b/middleware/monitor/monitor_test.go index 6fd4d654c6..7b73e295ed 100644 --- a/middleware/monitor/monitor_test.go +++ b/middleware/monitor/monitor_test.go @@ -61,6 +61,50 @@ func Test_Monitor_Html(t *testing.T) { conf.Refresh.Milliseconds()-timeoutDiff) utils.AssertEqual(t, true, bytes.Contains(buf, []byte(timeoutLine))) } +func Test_Monitor_Html_CustomCodes(t *testing.T) { + t.Parallel() + + app := fiber.New() + + // defaults + app.Get("/", New()) + resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil)) + + utils.AssertEqual(t, nil, err) + utils.AssertEqual(t, 200, resp.StatusCode) + utils.AssertEqual(t, fiber.MIMETextHTMLCharsetUTF8, + resp.Header.Get(fiber.HeaderContentType)) + buf, err := ioutil.ReadAll(resp.Body) + utils.AssertEqual(t, nil, err) + utils.AssertEqual(t, true, bytes.Contains(buf, []byte(""+defaultTitle+""))) + timeoutLine := fmt.Sprintf("setTimeout(fetchJSON, %d)", + defaultRefresh.Milliseconds()-timeoutDiff) + utils.AssertEqual(t, true, bytes.Contains(buf, []byte(timeoutLine))) + + // custom config + conf := Config{Title: "New " + defaultTitle, Refresh: defaultRefresh + time.Second, + ChartJsURL: "https://cdnjs.com/libraries/Chart.js", + FontURL: "/public/my-font.css", + CustomHead: ``, + } + app.Get("/custom", New(conf)) + resp, err = app.Test(httptest.NewRequest(fiber.MethodGet, "/custom", nil)) + + utils.AssertEqual(t, nil, err) + utils.AssertEqual(t, 200, resp.StatusCode) + utils.AssertEqual(t, fiber.MIMETextHTMLCharsetUTF8, + resp.Header.Get(fiber.HeaderContentType)) + buf, err = ioutil.ReadAll(resp.Body) + utils.AssertEqual(t, nil, err) + utils.AssertEqual(t, true, bytes.Contains(buf, []byte(""+conf.Title+""))) + utils.AssertEqual(t, true, bytes.Contains(buf, []byte("https://cdnjs.com/libraries/Chart.js"))) + utils.AssertEqual(t, true, bytes.Contains(buf, []byte("/public/my-font.css"))) + utils.AssertEqual(t, true, bytes.Contains(buf, []byte(conf.CustomHead))) + + timeoutLine = fmt.Sprintf("setTimeout(fetchJSON, %d)", + conf.Refresh.Milliseconds()-timeoutDiff) + utils.AssertEqual(t, true, bytes.Contains(buf, []byte(timeoutLine))) +} // go test -run Test_Monitor_JSON -race func Test_Monitor_JSON(t *testing.T) {