diff --git a/docs/configuration.md b/docs/configuration.md index b14c568..8289822 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -1311,7 +1311,7 @@ headers: When set to `true`, removes the border and padding around the widget. ##### `template` -The template that will be used to display the data. It relies on Go's `html/template` package so it's recommended to go through [its documentation](https://pkg.go.dev/text/template) to understand how to do basic things such as conditionals, loops, etc. In addition, it also uses [tidwall's gjson](https://pkg.go.dev/github.com/tidwall/gjson) package to parse the JSON data so it's worth going through its documentation if you want to use more advanced JSON selectors. You can view additional examples with explanations and function definitions [here](custom-api.md). +The template that will be used to display the data. It relies on Go's `html/template` package so it's recommended to go through [its documentation](https://pkg.go.dev/text/template) to understand how to do basic things such as conditionals, loops, etc. In addition, it also uses [tidwall's gjson](https://github.com/tidwall/gjson) package to parse the JSON data so it's worth going through its documentation if you want to use more advanced JSON selectors. You can view additional examples with explanations and function definitions [here](custom-api.md). ### Extension Display a widget provided by an external source (3rd party). If you want to learn more about developing extensions, checkout the [extensions documentation](extensions.md) (WIP). @@ -1619,7 +1619,7 @@ services: glance: image: glanceapp/glance environment: - - GITHUB_TOKEN: + - GITHUB_TOKEN= ``` and then use it in your `glance.yml` like this: diff --git a/internal/glance/config.go b/internal/glance/config.go index 7b3377b..0d424a2 100644 --- a/internal/glance/config.go +++ b/internal/glance/config.go @@ -242,7 +242,7 @@ func configFilesWatcher( // needed for lastContents and lastIncludes because they get updated in multiple goroutines mu := sync.Mutex{} - checkForContentChangesBeforeCallback := func() { + parseAndCompareBeforeCallback := func() { currentContents, currentIncludes, err := parseYAMLIncludes(mainFilePath) if err != nil { onErr(fmt.Errorf("parsing main file contents for comparison: %w", err)) @@ -268,15 +268,22 @@ func configFilesWatcher( const debounceDuration = 500 * time.Millisecond var debounceTimer *time.Timer - debouncedCallback := func() { + debouncedParseAndCompareBeforeCallback := func() { if debounceTimer != nil { debounceTimer.Stop() debounceTimer.Reset(debounceDuration) } else { - debounceTimer = time.AfterFunc(debounceDuration, checkForContentChangesBeforeCallback) + debounceTimer = time.AfterFunc(debounceDuration, parseAndCompareBeforeCallback) } } + deleteLastInclude := func(filePath string) { + mu.Lock() + defer mu.Unlock() + fileAbsPath, _ := filepath.Abs(filePath) + delete(lastIncludes, fileAbsPath) + } + go func() { for { select { @@ -285,16 +292,33 @@ func configFilesWatcher( return } if event.Has(fsnotify.Write) { - debouncedCallback() - } else if event.Has(fsnotify.Remove) { - func() { - mu.Lock() - defer mu.Unlock() - fileAbsPath, _ := filepath.Abs(event.Name) - delete(lastIncludes, fileAbsPath) - }() + debouncedParseAndCompareBeforeCallback() + } else if event.Has(fsnotify.Rename) { + // on linux the file will no longer be watched after a rename, on windows + // it will continue to be watched with the new name but we have no access to + // the new name in this event in order to stop watching it manually and match the + // behavior in linux, may lead to weird unintended behaviors on windows as we're + // only handling renames from linux's perspective + // see https://github.com/fsnotify/fsnotify/issues/255 - debouncedCallback() + // remove the old file from our manually tracked includes, calling + // debouncedParseAndCompareBeforeCallback will re-add it if it's still + // required after it triggers + deleteLastInclude(event.Name) + + // wait for file to maybe get created again + // see https://github.com/glanceapp/glance/pull/358 + for i := 0; i < 10; i++ { + if _, err := os.Stat(event.Name); err == nil { + break + } + time.Sleep(200 * time.Millisecond) + } + + debouncedParseAndCompareBeforeCallback() + } else if event.Has(fsnotify.Remove) { + deleteLastInclude(event.Name) + debouncedParseAndCompareBeforeCallback() } case err, isOpen := <-watcher.Errors: if !isOpen { diff --git a/internal/glance/widget-docker-containers.go b/internal/glance/widget-docker-containers.go index 8bd83b1..f38cdeb 100644 --- a/internal/glance/widget-docker-containers.go +++ b/internal/glance/widget-docker-containers.go @@ -241,7 +241,7 @@ func isDockerContainerHidden(container *dockerContainerJsonResponse, hideByDefau func fetchAllDockerContainersFromSock(socketPath string) ([]dockerContainerJsonResponse, error) { client := &http.Client{ - Timeout: 3 * time.Second, + Timeout: 5 * time.Second, Transport: &http.Transport{ DialContext: func(_ context.Context, _, _ string) (net.Conn, error) { return net.Dial("unix", socketPath) diff --git a/internal/glance/widget-markets.go b/internal/glance/widget-markets.go index 63eda1a..93dd9c6 100644 --- a/internal/glance/widget-markets.go +++ b/internal/glance/widget-markets.go @@ -124,6 +124,7 @@ func fetchMarketsDataFromYahoo(marketRequests []marketRequest) (marketList, erro for i := range marketRequests { request, _ := http.NewRequest("GET", fmt.Sprintf("https://query1.finance.yahoo.com/v8/finance/chart/%s?range=1mo&interval=1d", marketRequests[i].Symbol), nil) + setBrowserUserAgentHeader(request) requests = append(requests, request) } diff --git a/internal/glance/widget-utils.go b/internal/glance/widget-utils.go index 77a9d5c..8fb76dd 100644 --- a/internal/glance/widget-utils.go +++ b/internal/glance/widget-utils.go @@ -8,8 +8,11 @@ import ( "errors" "fmt" "io" + "math/rand/v2" "net/http" + "strconv" "sync" + "sync/atomic" "time" ) @@ -35,8 +38,15 @@ type requestDoer interface { Do(*http.Request) (*http.Response, error) } +var userAgentPersistentVersion atomic.Int32 + func setBrowserUserAgentHeader(request *http.Request) { - request.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:123.0) Gecko/20100101 Firefox/123.0") + if rand.IntN(2000) == 0 { + userAgentPersistentVersion.Store(rand.Int32N(5)) + } + + version := strconv.Itoa(130 + int(userAgentPersistentVersion.Load())) + request.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:"+version+".0) Gecko/20100101 Firefox/"+version+".0") } func decodeJsonFromRequest[T any](client requestDoer, request *http.Request) (T, error) { diff --git a/pkg/sysinfo/sysinfo.go b/pkg/sysinfo/sysinfo.go index 09df02f..673b9d2 100644 --- a/pkg/sysinfo/sysinfo.go +++ b/pkg/sysinfo/sysinfo.go @@ -202,7 +202,8 @@ func Collect(req *SystemInfoRequest) (*SystemInfo, []error) { // keeps returning a single sensor with key "ACPI\\ThermalZone\\TZ00_0" which // doesn't seem to be the CPU sensor or correspond to anything useful when // compared against the temperatures Libre Hardware Monitor reports - if runtime.GOOS != "windows" { + // also disabled on openbsd because it's not implemented by go-psutil + if runtime.GOOS != "windows" && runtime.GOOS != "openbsd" { sensorReadings, err := sensors.SensorsTemperatures() if err == nil { if req.CPUTempSensor != "" {