summaryrefslogtreecommitdiff
path: root/blockd.go
diff options
context:
space:
mode:
Diffstat (limited to 'blockd.go')
-rw-r--r--blockd.go148
1 files changed, 148 insertions, 0 deletions
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 <ms@kilabit.info>
+// 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
+}