Refactor monitor: allow insecure requests & use of simple icons

This commit is contained in:
Svilen Markov 2024-05-30 22:10:12 +01:00
parent b63b5eb262
commit 21fd842bde
4 changed files with 60 additions and 34 deletions

View File

@ -22,13 +22,13 @@
{{ define "site" }}
{{ if .IconUrl }}
<img class="monitor-site-icon" src="{{ .IconUrl }}" alt="" loading="lazy">
<img class="monitor-site-icon{{ if .IsSimpleIcon }} simple-icon{{ end }}" src="{{ .IconUrl }}" alt="" loading="lazy">
{{ end }}
<div>
<a class="size-h3 color-highlight" href="{{ .Url }}" {{ if not .SameTab }}target="_blank"{{ end }} rel="noreferrer">{{ .Title }}</a>
<a class="size-h3 color-highlight" href="{{ .URL }}" {{ if not .SameTab }}target="_blank"{{ end }} rel="noreferrer">{{ .Title }}</a>
<ul class="list-horizontal-text">
{{ if not .Status.Error }}
<li>{{ .StatusText }}</li>
<li title="{{ .Status.Code }}">{{ .StatusText }}</li>
<li>{{ .Status.ResponseTime.Milliseconds | formatNumber }}ms</li>
{{ else if .Status.TimedOut }}
<li class="color-negative">Timed Out</li>
@ -37,7 +37,7 @@
{{ end }}
</ul>
</div>
{{ if eq .StatusStyle "good" }}
{{ if eq .StatusStyle "ok" }}
<div class="monitor-site-status-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="var(--color-positive)">
<path fill-rule="evenodd" d="M2.25 12c0-5.385 4.365-9.75 9.75-9.75s9.75 4.365 9.75 9.75-4.365 9.75-9.75 9.75S2.25 17.385 2.25 12Zm13.36-1.814a.75.75 0 1 0-1.22-.872l-3.236 4.53L9.53 12.22a.75.75 0 0 0-1.06 1.06l2.25 2.25a.75.75 0 0 0 1.14-.094l3.75-5.25Z" clip-rule="evenodd" />

View File

@ -7,6 +7,11 @@ import (
"time"
)
type SiteStatusRequest struct {
URL string `yaml:"url"`
AllowInsecure bool `yaml:"allow-insecure"`
}
type SiteStatus struct {
Code int
TimedOut bool
@ -14,14 +19,28 @@ type SiteStatus struct {
Error error
}
func getSiteStatusTask(request *http.Request) (SiteStatus, error) {
func getSiteStatusTask(statusRequest *SiteStatusRequest) (SiteStatus, error) {
request, err := http.NewRequest(http.MethodGet, statusRequest.URL, nil)
if err != nil {
return SiteStatus{
Error: err,
}, nil
}
ctx, cancel := context.WithTimeout(context.Background(), time.Second*3)
defer cancel()
request = request.WithContext(ctx)
start := time.Now()
response, err := http.DefaultClient.Do(request)
took := time.Since(start)
status := SiteStatus{ResponseTime: took}
requestSentAt := time.Now()
var response *http.Response
if !statusRequest.AllowInsecure {
response, err = defaultClient.Do(request)
} else {
response, err = defaultInsecureClient.Do(request)
}
status := SiteStatus{ResponseTime: time.Since(requestSentAt)}
if err != nil {
if errors.Is(err, context.DeadlineExceeded) {
@ -29,7 +48,7 @@ func getSiteStatusTask(request *http.Request) (SiteStatus, error) {
}
status.Error = err
return status, err
return status, nil
}
defer response.Body.Close()
@ -39,7 +58,7 @@ func getSiteStatusTask(request *http.Request) (SiteStatus, error) {
return status, nil
}
func FetchStatusesForRequests(requests []*http.Request) ([]SiteStatus, error) {
func FetchStatusForSites(requests []*SiteStatusRequest) ([]SiteStatus, error) {
job := newJob(getSiteStatusTask, requests).withWorkers(20)
results, _, err := workerPoolDo(job)

View File

@ -2,6 +2,7 @@ package feed
import (
"context"
"crypto/tls"
"encoding/json"
"encoding/xml"
"fmt"
@ -11,8 +12,19 @@ import (
"time"
)
const defaultClientTimeout = 5 * time.Second
var defaultClient = &http.Client{
Timeout: 5 * time.Second,
Timeout: defaultClientTimeout,
}
var insecureClientTransport = &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
var defaultInsecureClient = &http.Client{
Timeout: defaultClientTimeout,
Transport: insecureClientTransport,
}
type RequestDoer interface {

View File

@ -2,9 +2,7 @@ package widget
import (
"context"
"fmt"
"html/template"
"net/http"
"strconv"
"time"
@ -37,20 +35,21 @@ func statusCodeToText(status int) string {
func statusCodeToStyle(status int) string {
if status == 200 {
return "good"
return "ok"
}
return "bad"
return "error"
}
type Monitor struct {
widgetBase `yaml:",inline"`
Sites []struct {
Title string `yaml:"title"`
Url OptionalEnvString `yaml:"url"`
IconUrl string `yaml:"icon"`
SameTab bool `yaml:"same-tab"`
*feed.SiteStatusRequest `yaml:",inline"`
Status *feed.SiteStatus `yaml:"-"`
Title string `yaml:"title"`
IconUrl string `yaml:"icon"`
IsSimpleIcon bool `yaml:"-"`
SameTab bool `yaml:"same-tab"`
StatusText string `yaml:"-"`
StatusStyle string `yaml:"-"`
} `yaml:"sites"`
@ -60,25 +59,21 @@ type Monitor struct {
func (widget *Monitor) Initialize() error {
widget.withTitle("Monitor").withCacheDuration(5 * time.Minute)
for i := range widget.Sites {
widget.Sites[i].IconUrl, widget.Sites[i].IsSimpleIcon = toSimpleIconIfPrefixed(widget.Sites[i].IconUrl)
}
return nil
}
func (widget *Monitor) Update(ctx context.Context) {
requests := make([]*http.Request, len(widget.Sites))
requests := make([]*feed.SiteStatusRequest, len(widget.Sites))
for i := range widget.Sites {
request, err := http.NewRequest("GET", string(widget.Sites[i].Url), nil)
if err != nil {
message := fmt.Errorf("failed to create http request for %s: %s", widget.Sites[i].Url, err)
widget.withNotice(message)
continue
requests[i] = widget.Sites[i].SiteStatusRequest
}
requests[i] = request
}
statuses, err := feed.FetchStatusesForRequests(requests)
statuses, err := feed.FetchStatusForSites(requests)
if !widget.canContinueUpdateAfterHandlingErr(err) {
return