From 0b92dbb8463dee31c005c59f67c2bf754a9eae12 Mon Sep 17 00:00:00 2001 From: Shulhan Date: Sun, 22 May 2022 21:29:35 +0700 Subject: all: export and rename the hostsBlock type to Blockd In the Environment, we have a field HostsBlocks that reference an unexported type hostsFile. In order for any package to be able to use this field, we need to export this type. While at it, we rename the type from hostsBlock to Blockd to make it simple and consistent with name. --- blockd.go | 148 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 148 insertions(+) create mode 100644 blockd.go (limited to 'blockd.go') diff --git a/blockd.go b/blockd.go new file mode 100644 index 0000000..398bb96 --- /dev/null +++ b/blockd.go @@ -0,0 +1,148 @@ +// SPDX-FileCopyrightText: 2020 M. Shulhan +// SPDX-License-Identifier: GPL-3.0-or-later + +package rescached + +import ( + "bytes" + "fmt" + "io" + "log" + "net/http" + "os" + "path/filepath" + "time" +) + +const ( + lastUpdatedFormat = "2006-01-02 15:04:05 MST" +) + +type Blockd struct { + lastUpdated time.Time + + Name string `ini:"::name"` // Derived from hostname in URL. + URL string `ini:"::url"` + + file string + fileDisabled string + LastUpdated string + + IsEnabled bool // True if the hosts file un-hidden in block.d directory. + isFileExist bool // True if the file exist and enabled or disabled. +} + +// disable the hosts block by prefixing the file name with single dot. +func (hb *Blockd) disable() (err error) { + err = os.Rename(hb.file, hb.fileDisabled) + if err != nil { + return fmt.Errorf("disable: %w", err) + } + hb.IsEnabled = false + return nil +} + +// enable the hosts block file by removing the dot prefix from file name. +func (hb *Blockd) enable() (err error) { + if hb.isFileExist { + err = os.Rename(hb.fileDisabled, hb.file) + } else { + err = os.WriteFile(hb.file, []byte(""), 0600) + } + if err != nil { + return fmt.Errorf("enable: %w", err) + } + hb.IsEnabled = true + hb.isFileExist = true + return nil +} + +func (hb *Blockd) init(pathDirBlock string) { + var ( + fi os.FileInfo + err error + ) + + hb.file = filepath.Join(pathDirBlock, hb.Name) + hb.fileDisabled = filepath.Join(pathDirBlock, "."+hb.Name) + + fi, err = os.Stat(hb.file) + if err != nil { + hb.IsEnabled = false + + fi, err = os.Stat(hb.fileDisabled) + if err != nil { + return + } + + hb.isFileExist = true + } else { + hb.IsEnabled = true + hb.isFileExist = true + } + + hb.lastUpdated = fi.ModTime() + hb.LastUpdated = hb.lastUpdated.Format(lastUpdatedFormat) +} + +// isOld will return true if the host file has not been updated since seven +// days. +func (hb *Blockd) isOld() bool { + oneWeek := 7 * 24 * time.Hour + lastWeek := time.Now().Add(-1 * oneWeek) + + return hb.lastUpdated.Before(lastWeek) +} + +func (hb *Blockd) update() (err error) { + if !hb.isOld() { + return nil + } + + var ( + logp = "Blockd.update" + + res *http.Response + body []byte + errClose error + ) + + fmt.Printf("%s %s: updating ...\n", logp, hb.Name) + + err = os.MkdirAll(filepath.Dir(hb.file), 0700) + if err != nil { + return fmt.Errorf("%s %s: %w", logp, hb.Name, err) + } + + res, err = http.Get(hb.URL) + if err != nil { + return fmt.Errorf("%s %s: %w", logp, hb.Name, err) + } + defer func() { + errClose = res.Body.Close() + if errClose != nil { + log.Printf("%s %q: %s", logp, hb.Name, err) + } + }() + + body, err = io.ReadAll(res.Body) + if err != nil { + return fmt.Errorf("%s %q: %w", logp, hb.Name, err) + } + + body = bytes.ReplaceAll(body, []byte("\r\n"), []byte("\n")) + + if hb.IsEnabled { + err = os.WriteFile(hb.file, body, 0644) + } else { + err = os.WriteFile(hb.fileDisabled, body, 0644) + } + if err != nil { + return fmt.Errorf("%s %q: %w", logp, hb.Name, err) + } + + hb.lastUpdated = time.Now() + hb.LastUpdated = hb.lastUpdated.Format(lastUpdatedFormat) + + return nil +} -- cgit v1.3