Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package doggo for openSUSE:Factory checked 
in at 2024-10-01 17:16:50
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/doggo (Old)
 and      /work/SRC/openSUSE:Factory/.doggo.new.29891 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "doggo"

Tue Oct  1 17:16:50 2024 rev:3 rq:1204816 version:1.0.5

Changes:
--------
--- /work/SRC/openSUSE:Factory/doggo/doggo.changes      2024-07-04 
16:23:36.352237062 +0200
+++ /work/SRC/openSUSE:Factory/.doggo.new.29891/doggo.changes   2024-10-01 
17:16:56.046525245 +0200
@@ -1,0 +2,16 @@
+Mon Sep 30 16:56:31 UTC 2024 - opensuse_buildserv...@ojkastl.de
+
+- Update to version 1.0.5:
+  * chore: upgrade deps
+  * fix fishCompletion
+  * update globalping client
+  * update args
+  * add support for --json, --short && update docs
+  * feat: integrate Globalping API for global network diagnostics
+  * chore: document completions subcommand in --help output
+  * Update README.md
+  * fix: change DefaultResolvConfPath to var instead of const
+  * fix(logger): Change log destination to stderr
+  * Update README.md
+
+-------------------------------------------------------------------

Old:
----
  doggo-1.0.4.obscpio

New:
----
  doggo-1.0.5.obscpio

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ doggo.spec ++++++
--- /var/tmp/diff_new_pack.wPZWZB/_old  2024-10-01 17:16:57.670592958 +0200
+++ /var/tmp/diff_new_pack.wPZWZB/_new  2024-10-01 17:16:57.670592958 +0200
@@ -17,7 +17,7 @@
 
 
 Name:           doggo
-Version:        1.0.4
+Version:        1.0.5
 Release:        0
 Summary:        CLI tool and API server DNS client implemented in Go
 License:        GPL-3.0-only

++++++ _service ++++++
--- /var/tmp/diff_new_pack.wPZWZB/_old  2024-10-01 17:16:57.698594126 +0200
+++ /var/tmp/diff_new_pack.wPZWZB/_new  2024-10-01 17:16:57.702594292 +0200
@@ -2,7 +2,7 @@
   <service name="obs_scm" mode="manual">
     <param name="scm">git</param>
     <param name="url">https://github.com/mr-karan/doggo.git</param>
-    <param name="revision">v1.0.4</param>
+    <param name="revision">v1.0.5</param>
     <param name="match-tag">*</param>
     <param name="versionrewrite-pattern">v(\d+\.\d+\.\d+)</param>
     <param name="versionformat">@PARENT_TAG@</param>

++++++ _servicedata ++++++
--- /var/tmp/diff_new_pack.wPZWZB/_old  2024-10-01 17:16:57.726595293 +0200
+++ /var/tmp/diff_new_pack.wPZWZB/_new  2024-10-01 17:16:57.730595460 +0200
@@ -1,6 +1,6 @@
 <servicedata>
 <service name="tar_scm">
                 <param name="url">https://github.com/mr-karan/doggo.git</param>
-              <param 
name="changesrevision">bac855567c203714c35586f026b91e4caf687636</param></service></servicedata>
+              <param 
name="changesrevision">16ba284a136354fb4f11fd4d566db9b4364e9a32</param></service></servicedata>
 (No newline at EOF)
 

++++++ doggo-1.0.4.obscpio -> doggo-1.0.5.obscpio ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/doggo-1.0.4/README.md new/doggo-1.0.5/README.md
--- old/doggo-1.0.4/README.md   2024-07-03 18:37:16.000000000 +0200
+++ new/doggo-1.0.5/README.md   2024-09-30 11:30:03.000000000 +0200
@@ -14,7 +14,6 @@
   <img src="www/static/doggo.png" alt="doggo CLI usage">
 </p>
 
-
 ---
 
 **doggo** is a modern command-line DNS client (like _dig_) written in Golang. 
It outputs information in a neat concise manner and supports protocols like 
DoH, DoT, DoQ, and DNSCrypt as well.
@@ -32,8 +31,10 @@
 ### Package Managers
 
 - Homebrew: `brew install doggo`
+- MacPorts (macOS): `port install doggo`
 - Arch Linux: `yay -S doggo-bin`
 - Scoop (Windows): `scoop install doggo`
+- Eget: `eget mr-karan/doggo`
 
 ### Binary Install
 
@@ -77,6 +78,9 @@
 
 # Reverse DNS lookup
 doggo --reverse 8.8.8.8 --short
+
+# Using Globalping
+doggo example.com --gp-from Germany,Japan --gp-limit 2
 ```
 
 ## Features
@@ -109,4 +113,4 @@
 
 ## License
 
-This project is licensed under the [MIT License](./LICENSE).
\ No newline at end of file
+This project is licensed under the [MIT License](./LICENSE).
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/doggo-1.0.4/cmd/doggo/cli.go 
new/doggo-1.0.5/cmd/doggo/cli.go
--- old/doggo-1.0.4/cmd/doggo/cli.go    2024-07-03 18:37:16.000000000 +0200
+++ new/doggo-1.0.5/cmd/doggo/cli.go    2024-09-30 11:30:03.000000000 +0200
@@ -5,10 +5,12 @@
        "encoding/json"
        "fmt"
        "log/slog"
+       "math"
        "os"
        "sync"
        "time"
 
+       "github.com/jsdelivr/globalping-cli/globalping"
        "github.com/knadh/koanf/providers/posflag"
        "github.com/knadh/koanf/v2"
        "github.com/mr-karan/doggo/internal/app"
@@ -43,6 +45,26 @@
        logger := utils.InitLogger(cfg.debug)
        app := initializeApp(logger, cfg)
 
+       if app.QueryFlags.GPFrom != "" {
+               res, err := app.GlobalpingMeasurement()
+               if err != nil {
+                       logger.Error("Error fetching globalping measurement", 
"error", err)
+                       os.Exit(2)
+               }
+               if app.QueryFlags.ShowJSON {
+                       err = app.OutputGlobalpingJSON(res)
+               } else if app.QueryFlags.ShortOutput {
+                       err = app.OutputGlobalpingShort(res)
+               } else {
+                       err = app.OutputGlobalping(res)
+               }
+               if err != nil {
+                       logger.Error("Error outputting globalping measurement", 
"error", err)
+                       os.Exit(2)
+               }
+               return
+       }
+
        if cfg.reverseLookup {
                app.ReverseLookup()
        }
@@ -121,6 +143,9 @@
        f.StringSliceP("nameserver", "n", []string{}, "Address of the 
nameserver to send packets to")
        f.BoolP("reverse", "x", false, "Performs a DNS Lookup for an IPv4 or 
IPv6 address")
 
+       f.String("gp-from", "", "Probe locations as a comma-separated list")
+       f.Int("gp-limit", 1, "Limit the number of probes to use")
+
        f.DurationP("timeout", "T", 5*time.Second, "Sets the timeout for a 
query")
        f.Bool("search", true, "Use the search list provided in resolv.conf")
        f.Int("ndots", -1, "Specify the ndots parameter")
@@ -162,7 +187,21 @@
 }
 
 func initializeApp(logger *slog.Logger, cfg *config) *app.App {
-       app := app.New(logger, buildVersion)
+       gpConfig := globalping.Config{
+               APIURL:    "https://api.globalping.io/v1";,
+               AuthURL:   "https://auth.globalping.io";,
+               UserAgent: fmt.Sprintf("doggo/%s 
(https://github.com/mr-karan/doggo)", buildVersion),
+       }
+       gpToken := os.Getenv("GLOBALPING_TOKEN")
+       if gpToken != "" {
+               gpConfig.AuthToken = &globalping.Token{
+                       AccessToken: gpToken,
+                       Expiry:      time.Now().Add(math.MaxInt64),
+               }
+       }
+       globlpingClient := globalping.NewClient(gpConfig)
+
+       app := app.New(logger, globlpingClient, buildVersion)
 
        if err := k.Unmarshal("", &app.QueryFlags); err != nil {
                logger.Error("Error loading args", "error", err)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/doggo-1.0.4/cmd/doggo/completions.go 
new/doggo-1.0.5/cmd/doggo/completions.go
--- old/doggo-1.0.4/cmd/doggo/completions.go    2024-07-03 18:37:16.000000000 
+0200
+++ new/doggo-1.0.5/cmd/doggo/completions.go    2024-09-30 11:30:03.000000000 
+0200
@@ -13,7 +13,7 @@
     cur="${COMP_WORDS[COMP_CWORD]}"
     prev="${COMP_WORDS[COMP_CWORD-1]}"
 
-    opts="-v --version -h --help -q --query -t --type -n --nameserver -c 
--class -r --reverse --strategy --ndots --search --timeout -4 --ipv4 -6 --ipv6 
--tls-hostname --skip-hostname-verification -J --json --short --color --debug 
--time"
+    opts="-v --version -h --help -q --query -t --type -n --nameserver -c 
--class -r --reverse --strategy --ndots --search --timeout -4 --ipv4 -6 --ipv6 
--tls-hostname --skip-hostname-verification -J --json --short --color --debug 
--time --gp-from --gp-limit"
 
     case "${prev}" in
         -t|--type)
@@ -77,6 +77,8 @@
     '--color[Colored output]:setting:(true false)' \
     '--debug[Enable debug logging]' \
     '--time[Shows how long the response took from the server]' \
+    '--gp-from[Query using Globalping API from a specific location]' \
+    '--gp-limit[Limit the number of probes to use from Globalping]' \
     '*:hostname:_hosts' \
     && ret=0
 
@@ -131,6 +133,10 @@
 complete -c doggo -n '__fish_doggo_no_subcommand' -l 'tls-hostname'            
   -d "Hostname for certificate verification" -x -a "(__fish_print_hostnames)"
 complete -c doggo -n '__fish_doggo_no_subcommand' -l 
'skip-hostname-verification' -d "Skip TLS hostname verification in case of DoT 
lookups"
 
+# Globalping options
+complete -c doggo -n '__fish_doggo_no_subcommand' -l 'gp-from'  -d "Query 
using Globalping API from a specific location"
+complete -c doggo -n '__fish_doggo_no_subcommand' -l 'gp-limit' -d "Limit the 
number of probes to use from Globalping"
+
 # Completions command
 complete -c doggo -n '__fish_doggo_no_subcommand' -a completions -d "Generate 
shell completion scripts"
 complete -c doggo -n '__fish_seen_subcommand_from completions' -a "bash zsh 
fish" -d "Shell type"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/doggo-1.0.4/cmd/doggo/help.go 
new/doggo-1.0.5/cmd/doggo/help.go
--- old/doggo-1.0.4/cmd/doggo/help.go   2024-07-03 18:37:16.000000000 +0200
+++ new/doggo-1.0.5/cmd/doggo/help.go   2024-09-30 11:30:03.000000000 +0200
@@ -34,6 +34,11 @@
   {{ printf "%-12s" $opt.Scheme | color "yellow" "" }}{{ printf "%-68s" 
$opt.Example }}{{ $opt.Description | color "cyan" "" }}
   {{- end }}
 
+{{ "SUBCOMMANDS" | color "" "heading" }}:
+  {{- range $opt := .Subcommands }}
+  {{ printf "%-30s" $opt.Flag | color "yellow" "" }}{{ $opt.Description }}
+  {{- end }}
+
 {{ "QUERY OPTIONS" | color "" "heading" }}:
   {{- range $opt := .QueryOptions }}
   {{ printf "%-30s" $opt.Flag | color "yellow" "" }}{{ $opt.Description }}
@@ -53,6 +58,11 @@
   {{- range $opt := .OutputOptions }}
   {{ printf "%-30s" $opt.Flag | color "yellow" "" }}{{ $opt.Description }}
   {{- end }}
+
+{{ "GLOBALPING OPTIONS" | color "" "heading" }}:
+  {{- range $opt := .GlobalPingOptions }}
+  {{ printf "%-30s" $opt.Flag | color "yellow" "" }}{{ $opt.Description }}
+  {{- end }}
 `
 
 func renderCustomHelp() {
@@ -84,6 +94,7 @@
                        {"-q mrkaran.dev -t MX -n 1.1.1.1", "Using named 
arguments."},
                        {"mrkaran.dev --aa --ad", "Query with Authoritative 
Answer and Authenticated Data flags set."},
                        {"mrkaran.dev --cd --do", "Query with Checking Disabled 
and DNSSEC OK flags set."},
+                       {"mrkaran.dev --gp-from Germany", "Query using 
Globalping API from a specific location."},
                },
                "TransportOptions": []TransportOption{
                        {"@udp://", "eg: @1.1.1.1", "initiates a UDP query to 
1.1.1.1:53."},
@@ -93,6 +104,9 @@
                        {"@sdns://", "initiates a DNSCrypt or DoH query using a 
DNS stamp.", ""},
                        {"@quic://", "initiates a DOQ query.", ""},
                },
+               "Subcommands": []Option{
+                       {"completions [bash|zsh|fish]", "Generate the shell 
completion script for the specified shell."},
+               },
                "QueryOptions": []Option{
                        {"-q, --query=HOSTNAME", "Hostname to query the DNS 
records for (eg mrkaran.dev)."},
                        {"-t, --type=TYPE", "Type of the DNS Record (A, MX, NS 
etc)."},
@@ -126,6 +140,10 @@
                        {"--debug", "Enable debug logging."},
                        {"--time", "Shows how long the response took from the 
server."},
                },
+               "GlobalPingOptions": []Option{
+                       {"--gp-from=Germany", "Query using Globalping API from 
a specific location."},
+                       {"--gp-limit=INT", "Limit the number of probes to use 
from Globalping."},
+               },
        }
 
        tmpl, err := template.New("help").Funcs(template.FuncMap{
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/doggo-1.0.4/docs/src/content/docs/features/output.md 
new/doggo-1.0.5/docs/src/content/docs/features/output.md
--- old/doggo-1.0.4/docs/src/content/docs/features/output.md    2024-07-03 
18:37:16.000000000 +0200
+++ new/doggo-1.0.5/docs/src/content/docs/features/output.md    2024-09-30 
11:30:03.000000000 +0200
@@ -16,6 +16,20 @@
 mrkaran.dev.    A       IN      300s    172.67.187.239  127.0.0.53:53
 ```
 
+```bash
+doggo mrkaran.dev --gp-from Europe,Asia --gp-limit 2
+LOCATION                       NAME            TYPE    CLASS   TTL     ADDRESS 
        NAMESERVER
+Vienna, AT, EU, EDIS GmbH
+(AS57169)
+                               mrkaran.dev.    A       IN      300s    
104.21.7.168    private
+                               mrkaran.dev.    A       IN      300s    
172.67.187.239  private
+Tokyo, JP, AS, Tencent
+Building, Kejizhongyi Avenue
+(AS132203)
+                               mrkaran.dev.    A       IN      300s    
104.21.7.168    private
+                               mrkaran.dev.    A       IN      300s    
172.67.187.239  private
+```
+
 To disable colored output, use the `--color=false` flag:
 
 ```bash
@@ -42,7 +56,7 @@
         "address": "104.27.158.96",
         "rtt": "37ms",
         "nameserver": "127.0.0.1:53"
-      },
+      }
       // ... more entries ...
     ],
     "queries": [
@@ -56,6 +70,49 @@
 }
 ```
 
+```bash
+doggo mrkaran.dev --gp-from Europe,Asia --gp-limit 2 --json | jq
+```
+
+```json
+{
+  "responses": [
+    {
+      "location": "Groningen, NL, EU, Google LLC (AS396982)",
+      "answers": [
+        {
+          "name": "mrkaran.dev.",
+          "type": "A",
+          "class": "IN",
+          "ttl": "300s",
+          "address": "172.67.187.239",
+          "status": "",
+          "rtt": "",
+          "nameserver": "private"
+        }
+        // ... more entries ...
+      ]
+    },
+    {
+      "location": "Jakarta, ID, AS, Zenlayer Inc (AS21859)",
+      "answers": [
+        {
+          "name": "mrkaran.dev.",
+          "type": "A",
+          "class": "IN",
+          "ttl": "300s",
+          "address": "172.67.187.239",
+          "status": "",
+          "rtt": "",
+          "nameserver": "private"
+        }
+        // ... more entries ...
+      ]
+    }
+  ]
+}
+```
+
 ### Short Output
 
 For a more concise view, use the `--short` flag to show only the response 
section:
@@ -65,3 +122,13 @@
 104.21.7.168
 172.67.187.239
 ```
+
+```bash
+doggo mrkaran.dev --gp-from Europe,Asia --gp-limit 2 --short
+Frankfurt, DE, EU, WIBO Baltic UAB (AS59939)
+104.21.7.168
+172.67.187.239
+Saratov, RU, AS, LLC "SMART CENTER" (AS48763)
+172.67.187.239
+104.21.7.168
+```
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/doggo-1.0.4/docs/src/content/docs/guide/examples.md 
new/doggo-1.0.5/docs/src/content/docs/guide/examples.md
--- old/doggo-1.0.4/docs/src/content/docs/guide/examples.md     2024-07-03 
18:37:16.000000000 +0200
+++ new/doggo-1.0.5/docs/src/content/docs/guide/examples.md     2024-09-30 
11:30:03.000000000 +0200
@@ -8,55 +8,75 @@
 ## Basic Queries
 
 1. Simple A record lookup:
+
    ```bash
    doggo example.com
    ```
 
 2. Query for a specific record type:
+
    ```bash
    doggo AAAA example.com
    ```
 
 3. Query multiple record types simultaneously:
+
    ```bash
    doggo A AAAA MX example.com
    ```
 
+4. Query using Globalping API from a specific location:
+   ```bash
+   doggo example.com --gp-from Germany
+   ```
+
 ### Using Different Resolvers
 
 4. Query using a specific DNS resolver:
+
    ```bash
    doggo example.com @1.1.1.1
    ```
 
 5. Use DNS-over-HTTPS (DoH):
+
    ```bash
    doggo example.com @https://cloudflare-dns.com/dns-query
    ```
 
 6. Use DNS-over-TLS (DoT):
+
    ```bash
    doggo example.com @tls://1.1.1.1
    ```
 
 7. Query multiple resolvers and compare results:
+
    ```bash
    doggo example.com @1.1.1.1 @8.8.8.8 @9.9.9.9
    ```
 
+8. Using Globalping API
+   ```bash
+   doggo example.com @1.1.1.1  --gp-from Germany
+   ```
+
 ### Advanced Queries
 
 8. Perform a reverse DNS lookup:
+
    ```bash
    doggo --reverse 8.8.8.8
    ```
 
 9. Set query flags for DNSSEC validation:
+
    ```bash
    doggo example.com --do --cd
    ```
 
 10. Use the short output format for concise results:
+
     ```bash
     doggo example.com --short
     ```
@@ -69,11 +89,13 @@
 ### Combining Flags
 
 12. Perform a reverse lookup with short output and custom resolver:
+
     ```bash
     doggo --reverse 8.8.8.8 --short @1.1.1.1
     ```
 
 13. Query for MX records using DoH with JSON output:
+
     ```bash
     doggo MX example.com @https://dns.google/dns-query --json
     ```
@@ -83,7 +105,6 @@
     doggo AAAA example.com -6 --timeout 3s --do
     ```
 
-
 ## Scripting and Automation
 
 16. Use JSON output for easy parsing in scripts:
@@ -93,16 +114,19 @@
     ```
 
 17. Batch query multiple domains from a file:
+
     ```bash
     cat domains.txt | xargs -I {} doggo {} --short
     ```
 
 18. Find all nameservers for a domain and its parent domains:
+
     ```bash
     doggo NS example.com example.com. com. . --short
     ```
 
 19. Extract all MX records and their priorities:
+
     ```bash
     doggo MX gmail.com --json | jq -r '.responses[0].answers[] | "\(.address) 
\(.preference)"'
     ```
@@ -115,23 +139,28 @@
 ## Troubleshooting and Debugging
 
 21. Enable debug logging for verbose output:
+
     ```bash
     doggo example.com --debug
     ```
 
 22. Compare responses with and without EDNS Client Subnet:
+
     ```bash
     doggo example.com @8.8.8.8
     doggo example.com @8.8.8.8 --z
     ```
 
 23. Test DNSSEC validation:
+
     ```bash
     doggo rsasecured.net --do @8.8.8.8
     ```
+
     This example uses a domain known to be DNSSEC-signed. The `--do` flag sets 
the DNSSEC OK bit.
 
     Note: DNSSEC validation can be complex and depends on various factors:
+
     - The domain must be properly DNSSEC-signed
     - The resolver must support DNSSEC
     - The resolver must be configured to perform DNSSEC validation
@@ -139,12 +168,14 @@
     If you don't see DNSSEC-related information in the output, try using a 
resolver known to support DNSSEC, like 8.8.8.8 (Google) or 9.9.9.9 (Quad9).
 
 24. Compare responses with and without EDNS Client Subnet:
+
     ```bash
     doggo example.com @8.8.8.8
     doggo example.com @8.8.8.8 --z
     ```
 
 25. Check for DNSSEC records (DNSKEY, DS, RRSIG):
+
     ```bash
     doggo DNSKEY example.com @8.8.8.8
     doggo DS example.com @8.8.8.8
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/doggo-1.0.4/docs/src/content/docs/guide/reference.md 
new/doggo-1.0.5/docs/src/content/docs/guide/reference.md
--- old/doggo-1.0.4/docs/src/content/docs/guide/reference.md    2024-07-03 
18:37:16.000000000 +0200
+++ new/doggo-1.0.5/docs/src/content/docs/guide/reference.md    2024-09-30 
11:30:03.000000000 +0200
@@ -68,31 +68,48 @@
 | `@sdns://`  | DNSCrypt or DoH using DNS stamp | `@sdns://...`                
           |
 | `@quic://`  | DNS over QUIC                   | `@quic://dns.adguard.com`    
           |
 
+## Globalping API Options
+
+| Option       | Description                        | Example                 |
+| ------------ | ---------------------------------- | ----------------------- |
+| `--gp-from`  | Specify the location to query from | `--gp-from Europe,Asia` |
+| `--gp-limit` | Limit the number of probes to use  | `--gp-limit 5`          |
+
 ## Examples
 
 1. Query a domain using defaults:
+
    ```
    doggo example.com
    ```
 
 2. Query for a CNAME record:
+
    ```
    doggo example.com CNAME
    ```
 
 3. Use a custom DNS resolver:
+
    ```
    doggo example.com MX @9.9.9.9
    ```
 
 4. Using named arguments:
+
    ```
    doggo -q example.com -t MX -n 1.1.1.1
    ```
 
 5. Query with specific flags:
+
    ```
    doggo example.com --aa --ad
    ```
 
+6. Query using Globalping API from a specific location:
+   ```
+   doggo example.com --gp-from Europe,Asia --gp-limit 5
+   ```
+
 For more detailed usage examples, refer to the [Examples](/guide/examples) 
section.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/doggo-1.0.4/go.mod new/doggo-1.0.5/go.mod
--- old/doggo-1.0.4/go.mod      2024-07-03 18:37:16.000000000 +0200
+++ new/doggo-1.0.5/go.mod      2024-09-30 11:30:03.000000000 +0200
@@ -1,46 +1,50 @@
 module github.com/mr-karan/doggo
 
-go 1.22.4
+go 1.22.6
+
+toolchain go1.23.1
 
 require (
        github.com/ameshkov/dnscrypt/v2 v2.3.0
        github.com/ameshkov/dnsstamps v1.0.3
        github.com/fatih/color v1.17.0
        github.com/go-chi/chi/v5 v5.1.0
+       github.com/jsdelivr/globalping-cli v1.3.1-0.20240925142143-6b5f0951f8e1
        github.com/knadh/koanf/parsers/toml v0.1.0
-       github.com/knadh/koanf/providers/env v0.1.0
-       github.com/knadh/koanf/providers/file v1.0.0
+       github.com/knadh/koanf/providers/env v1.0.0
+       github.com/knadh/koanf/providers/file v1.1.0
        github.com/knadh/koanf/providers/posflag v0.1.0
        github.com/knadh/koanf/v2 v2.1.1
-       github.com/miekg/dns v1.1.61
+       github.com/miekg/dns v1.1.62
        github.com/olekukonko/tablewriter v0.0.5
-       github.com/quic-go/quic-go v0.45.1
+       github.com/quic-go/quic-go v0.47.0
        github.com/spf13/pflag v1.0.5
-       golang.org/x/sys v0.21.0
+       golang.org/x/sys v0.25.0
 )
 
 require (
-       github.com/AdguardTeam/golibs v0.24.1 // indirect
+       github.com/AdguardTeam/golibs v0.27.0 // indirect
        github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da // indirect
        github.com/aead/poly1305 v0.0.0-20180717145839-3fee0db0b635 // indirect
+       github.com/andybalholm/brotli v1.1.0 // indirect
        github.com/fsnotify/fsnotify v1.7.0 // indirect
        github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
-       github.com/go-viper/mapstructure/v2 v2.0.0 // indirect
-       github.com/google/pprof v0.0.0-20240625030939-27f56978b8b0 // indirect
+       github.com/go-viper/mapstructure/v2 v2.2.1 // indirect
+       github.com/google/pprof v0.0.0-20240929191954-255acd752d31 // indirect
        github.com/knadh/koanf/maps v0.1.1 // indirect
        github.com/mattn/go-colorable v0.1.13 // indirect
        github.com/mattn/go-isatty v0.0.20 // indirect
-       github.com/mattn/go-runewidth v0.0.15 // indirect
+       github.com/mattn/go-runewidth v0.0.16 // indirect
        github.com/mitchellh/copystructure v1.2.0 // indirect
        github.com/mitchellh/reflectwalk v1.0.2 // indirect
-       github.com/onsi/ginkgo/v2 v2.19.0 // indirect
+       github.com/onsi/ginkgo/v2 v2.20.2 // indirect
        github.com/pelletier/go-toml v1.9.5 // indirect
        github.com/rivo/uniseg v0.4.7 // indirect
        go.uber.org/mock v0.4.0 // indirect
-       golang.org/x/crypto v0.24.0 // indirect
-       golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 // indirect
-       golang.org/x/mod v0.18.0 // indirect
-       golang.org/x/net v0.26.0 // indirect
-       golang.org/x/sync v0.7.0 // indirect
-       golang.org/x/tools v0.22.0 // indirect
+       golang.org/x/crypto v0.27.0 // indirect
+       golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 // indirect
+       golang.org/x/mod v0.21.0 // indirect
+       golang.org/x/net v0.29.0 // indirect
+       golang.org/x/sync v0.8.0 // indirect
+       golang.org/x/tools v0.25.0 // indirect
 )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/doggo-1.0.4/go.sum new/doggo-1.0.5/go.sum
--- old/doggo-1.0.4/go.sum      2024-07-03 18:37:16.000000000 +0200
+++ new/doggo-1.0.5/go.sum      2024-09-30 11:30:03.000000000 +0200
@@ -1,5 +1,5 @@
-github.com/AdguardTeam/golibs v0.24.1 
h1:/ulkfm65wi33p72ybxiOt3lSdP0nr1GggSoaT4sHbns=
-github.com/AdguardTeam/golibs v0.24.1/go.mod 
h1:9/vJcYznW7RlmCT/Qzi8XNZGj+ZbWfHZJmEXKnRpCAU=
+github.com/AdguardTeam/golibs v0.27.0 
h1:YxCFK6HBGp/ZXp3bv5uei+oLH12UfIYB8u2rh1B6nnU=
+github.com/AdguardTeam/golibs v0.27.0/go.mod 
h1:iWdjXPCwmK2g2FKIb/OwEPnovSXeMqRhI8FWLxF5oxE=
 github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da 
h1:KjTM2ks9d14ZYCvmHS9iAKVt9AyzRSqNU1qabPih5BY=
 github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da/go.mod 
h1:eHEWzANqSiWQsof+nXEI9bUVUyV6F53Fp89EuCh2EAA=
 github.com/aead/poly1305 v0.0.0-20180717145839-3fee0db0b635 
h1:52m0LGchQBBVqJRyYYufQuIbVqRawmubW3OFGqK1ekw=
@@ -8,6 +8,8 @@
 github.com/ameshkov/dnscrypt/v2 v2.3.0/go.mod 
h1:N5hDwgx2cNb4Ay7AhvOSKst+eUiOZ/vbKRO9qMpQttE=
 github.com/ameshkov/dnsstamps v1.0.3 
h1:Srzik+J9mivH1alRACTbys2xOxs0lRH9qnTA7Y1OYVo=
 github.com/ameshkov/dnsstamps v1.0.3/go.mod 
h1:Ii3eUu73dx4Vw5O4wjzmT5+lkCwovjzaEZZ4gKyIH5A=
+github.com/andybalholm/brotli v1.1.0 
h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M=
+github.com/andybalholm/brotli v1.1.0/go.mod 
h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
 github.com/davecgh/go-spew v1.1.1 
h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/davecgh/go-spew v1.1.1/go.mod 
h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4=
@@ -16,24 +18,26 @@
 github.com/fsnotify/fsnotify v1.7.0/go.mod 
h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
 github.com/go-chi/chi/v5 v5.1.0 h1:acVI1TYaD+hhedDJ3r54HyA6sExp3HfXq7QWEEY/xMw=
 github.com/go-chi/chi/v5 v5.1.0/go.mod 
h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
-github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
-github.com/go-logr/logr v1.4.1/go.mod 
h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
+github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
+github.com/go-logr/logr v1.4.2/go.mod 
h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
 github.com/go-task/slim-sprig/v3 v3.0.0 
h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
 github.com/go-task/slim-sprig/v3 v3.0.0/go.mod 
h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
-github.com/go-viper/mapstructure/v2 v2.0.0 
h1:dhn8MZ1gZ0mzeodTG3jt5Vj/o87xZKuNAprG2mQfMfc=
-github.com/go-viper/mapstructure/v2 v2.0.0/go.mod 
h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
+github.com/go-viper/mapstructure/v2 v2.2.1 
h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss=
+github.com/go-viper/mapstructure/v2 v2.2.1/go.mod 
h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
 github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
 github.com/google/go-cmp v0.6.0/go.mod 
h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
-github.com/google/pprof v0.0.0-20240625030939-27f56978b8b0 
h1:e+8XbKB6IMn8A4OAyZccO4pYfB3s7bt6azNIPE7AnPg=
-github.com/google/pprof v0.0.0-20240625030939-27f56978b8b0/go.mod 
h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo=
+github.com/google/pprof v0.0.0-20240929191954-255acd752d31 
h1:LcRdQWywSgfi5jPsYZ1r2avbbs5IQ5wtyhMBCcokyo4=
+github.com/google/pprof v0.0.0-20240929191954-255acd752d31/go.mod 
h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
+github.com/jsdelivr/globalping-cli v1.3.1-0.20240925142143-6b5f0951f8e1 
h1:UrEC+iF/FHS/5UTJZJXOkm8y7wct2sqhNftJ2WQN7WI=
+github.com/jsdelivr/globalping-cli v1.3.1-0.20240925142143-6b5f0951f8e1/go.mod 
h1:2+lO4/xYSauKsf+pZ62bro1c4StxDO3cYcrLx4jsYmI=
 github.com/knadh/koanf/maps v0.1.1 
h1:G5TjmUh2D7G2YWf5SQQqSiHRJEjaicvU0KpypqB3NIs=
 github.com/knadh/koanf/maps v0.1.1/go.mod 
h1:npD/QZY3V6ghQDdcQzl1W4ICNVTkohC8E73eI2xW4yI=
 github.com/knadh/koanf/parsers/toml v0.1.0 
h1:S2hLqS4TgWZYj4/7mI5m1CQQcWurxUz6ODgOub/6LCI=
 github.com/knadh/koanf/parsers/toml v0.1.0/go.mod 
h1:yUprhq6eo3GbyVXFFMdbfZSo928ksS+uo0FFqNMnO18=
-github.com/knadh/koanf/providers/env v0.1.0 
h1:LqKteXqfOWyx5Ab9VfGHmjY9BvRXi+clwyZozgVRiKg=
-github.com/knadh/koanf/providers/env v0.1.0/go.mod 
h1:RE8K9GbACJkeEnkl8L/Qcj8p4ZyPXZIQ191HJi44ZaQ=
-github.com/knadh/koanf/providers/file v1.0.0 
h1:DtPvSQBeF+N0QLPMz0yf2bx0nFSxUcncpqQvzCxfCyk=
-github.com/knadh/koanf/providers/file v1.0.0/go.mod 
h1:/faSBcv2mxPVjFrXck95qeoyoZ5myJ6uxN8OOVNJJCI=
+github.com/knadh/koanf/providers/env v1.0.0 
h1:ufePaI9BnWH+ajuxGGiJ8pdTG0uLEUWC7/HDDPGLah0=
+github.com/knadh/koanf/providers/env v1.0.0/go.mod 
h1:mzFyRZueYhb37oPmC1HAv/oGEEuyvJDA98r3XAa8Gak=
+github.com/knadh/koanf/providers/file v1.1.0 
h1:MTjA+gRrVl1zqgetEAIaXHqYje0XSosxSiMD4/7kz0o=
+github.com/knadh/koanf/providers/file v1.1.0/go.mod 
h1:/faSBcv2mxPVjFrXck95qeoyoZ5myJ6uxN8OOVNJJCI=
 github.com/knadh/koanf/providers/posflag v0.1.0 
h1:mKJlLrKPcAP7Ootf4pBZWJ6J+4wHYujwipe7Ie3qW6U=
 github.com/knadh/koanf/providers/posflag v0.1.0/go.mod 
h1:SYg03v/t8ISBNrMBRMlojH8OsKowbkXV7giIbBVgbz0=
 github.com/knadh/koanf/v2 v2.1.1 
h1:/R8eXqasSTsmDCsAyYj+81Wteg8AqrV9CP6gvsTsOmM=
@@ -44,26 +48,26 @@
 github.com/mattn/go-isatty v0.0.20 
h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
 github.com/mattn/go-isatty v0.0.20/go.mod 
h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
 github.com/mattn/go-runewidth v0.0.9/go.mod 
h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
-github.com/mattn/go-runewidth v0.0.15 
h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
-github.com/mattn/go-runewidth v0.0.15/go.mod 
h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
-github.com/miekg/dns v1.1.61 h1:nLxbwF3XxhwVSm8g9Dghm9MHPaUZuqhPiGL+675ZmEs=
-github.com/miekg/dns v1.1.61/go.mod 
h1:mnAarhS3nWaW+NVP2wTkYVIZyHNJ098SJZUki3eykwQ=
+github.com/mattn/go-runewidth v0.0.16 
h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
+github.com/mattn/go-runewidth v0.0.16/go.mod 
h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
+github.com/miekg/dns v1.1.62 h1:cN8OuEF1/x5Rq6Np+h1epln8OiyPWV+lROx9LxcGgIQ=
+github.com/miekg/dns v1.1.62/go.mod 
h1:mvDlcItzm+br7MToIKqkglaGhlFMHJ9DTNNWONWXbNQ=
 github.com/mitchellh/copystructure v1.2.0 
h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
 github.com/mitchellh/copystructure v1.2.0/go.mod 
h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
 github.com/mitchellh/reflectwalk v1.0.2 
h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
 github.com/mitchellh/reflectwalk v1.0.2/go.mod 
h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
 github.com/olekukonko/tablewriter v0.0.5 
h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
 github.com/olekukonko/tablewriter v0.0.5/go.mod 
h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
-github.com/onsi/ginkgo/v2 v2.19.0 
h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA=
-github.com/onsi/ginkgo/v2 v2.19.0/go.mod 
h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To=
-github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk=
-github.com/onsi/gomega v1.33.1/go.mod 
h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0=
+github.com/onsi/ginkgo/v2 v2.20.2 
h1:7NVCeyIWROIAheY21RLS+3j2bb52W0W82tkberYytp4=
+github.com/onsi/ginkgo/v2 v2.20.2/go.mod 
h1:K9gyxPIlb+aIvnZ8bd9Ak+YP18w3APlR+5coaZoE2ag=
+github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k=
+github.com/onsi/gomega v1.34.1/go.mod 
h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY=
 github.com/pelletier/go-toml v1.9.5 
h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8=
 github.com/pelletier/go-toml v1.9.5/go.mod 
h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
 github.com/pmezard/go-difflib v1.0.0 
h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod 
h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/quic-go/quic-go v0.45.1 
h1:tPfeYCk+uZHjmDRwHHQmvHRYL2t44ROTujLeFVBmjCA=
-github.com/quic-go/quic-go v0.45.1/go.mod 
h1:1dLehS7TIR64+vxGR70GDcatWTOtMX2PUtnKsjbTurI=
+github.com/quic-go/quic-go v0.47.0 
h1:yXs3v7r2bm1wmPTYNLKAAJTHMYkPEsfYJmTazXrCZ7Y=
+github.com/quic-go/quic-go v0.47.0/go.mod 
h1:3bCapYsJvXGZcipOHuu7plYtaV6tnF+z7wIFsU0WK9E=
 github.com/rivo/uniseg v0.2.0/go.mod 
h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
 github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
 github.com/rivo/uniseg v0.4.7/go.mod 
h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
@@ -73,27 +77,27 @@
 github.com/stretchr/testify v1.9.0/go.mod 
h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
 go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU=
 go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
-golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI=
-golang.org/x/crypto v0.24.0/go.mod 
h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
-golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 
h1:yixxcjnhBmY0nkL253HFVIm0JsFHwrHdT3Yh6szTnfY=
-golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8/go.mod 
h1:jj3sYF3dwk5D+ghuXyeI3r5MFf+NT2An6/9dOA95KSI=
-golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0=
-golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
-golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ=
-golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
-golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
-golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A=
+golang.org/x/crypto v0.27.0/go.mod 
h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70=
+golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 
h1:e66Fs6Z+fZTbFBAxKfP3PALWBtpfqks2bwGcexMxgtk=
+golang.org/x/exp v0.0.0-20240909161429-701f63a606c0/go.mod 
h1:2TbTHSBQa924w8M6Xs1QcRcFwyucIwBGpK1p2f1YFFY=
+golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0=
+golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
+golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo=
+golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0=
+golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
+golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
 golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod 
h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
-golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
-golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
-golang.org/x/text v0.16.0/go.mod 
h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
+golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
+golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
+golang.org/x/text v0.18.0/go.mod 
h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
 golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
 golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
-golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA=
-golang.org/x/tools v0.22.0/go.mod 
h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c=
-google.golang.org/protobuf v1.33.0 
h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
-google.golang.org/protobuf v1.33.0/go.mod 
h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
+golang.org/x/tools v0.25.0 h1:oFU9pkj/iJgs+0DT+VMHrx+oBKs/LJMV+Uvg78sl+fE=
+golang.org/x/tools v0.25.0/go.mod 
h1:/vtpO8WL1N9cQC3FN5zPqb//fRXskFHbLKk4OW1Q7rg=
+google.golang.org/protobuf v1.34.1 
h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
+google.golang.org/protobuf v1.34.1/go.mod 
h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
 gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
 gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/doggo-1.0.4/internal/app/app.go 
new/doggo-1.0.5/internal/app/app.go
--- old/doggo-1.0.4/internal/app/app.go 2024-07-03 18:37:16.000000000 +0200
+++ new/doggo-1.0.5/internal/app/app.go 2024-09-30 11:30:03.000000000 +0200
@@ -3,6 +3,7 @@
 import (
        "log/slog"
 
+       "github.com/jsdelivr/globalping-cli/globalping"
        "github.com/miekg/dns"
        "github.com/mr-karan/doggo/pkg/models"
        "github.com/mr-karan/doggo/pkg/resolvers"
@@ -17,10 +18,16 @@
        Resolvers    []resolvers.Resolver
        ResolverOpts resolvers.Options
        Nameservers  []models.Nameserver
+
+       globalping globalping.Client
 }
 
 // NewApp initializes an instance of App which holds app wide configuration.
-func New(logger *slog.Logger, buildVersion string) App {
+func New(
+       logger *slog.Logger,
+       globalping globalping.Client,
+       buildVersion string,
+) App {
        app := App{
                Logger:  logger,
                Version: buildVersion,
@@ -31,6 +38,7 @@
                        Nameservers: []string{},
                },
                Nameservers: []models.Nameserver{},
+               globalping:  globalping,
        }
        return app
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/doggo-1.0.4/internal/app/globalping.go 
new/doggo-1.0.5/internal/app/globalping.go
--- old/doggo-1.0.4/internal/app/globalping.go  1970-01-01 01:00:00.000000000 
+0100
+++ new/doggo-1.0.5/internal/app/globalping.go  2024-09-30 11:30:03.000000000 
+0200
@@ -0,0 +1,246 @@
+package app
+
+import (
+       "encoding/json"
+       "errors"
+       "fmt"
+       "net"
+       "net/url"
+       "strconv"
+       "strings"
+       "time"
+
+       "github.com/fatih/color"
+       "github.com/jsdelivr/globalping-cli/globalping"
+       "github.com/mr-karan/doggo/pkg/resolvers"
+       "github.com/olekukonko/tablewriter"
+)
+
+var (
+       ErrTargetIPVersionNotAllowed   = errors.New("ipVersion is not allowed 
when target is not a domain")
+       ErrResolverIPVersionNotAllowed = errors.New("ipVersion is not allowed 
when resolver is not a domain")
+)
+
+func (app *App) GlobalpingMeasurement() (*globalping.Measurement, error) {
+       if len(app.QueryFlags.QNames) > 1 {
+               return nil, errors.New("only one target is allowed for 
globalping")
+       }
+       if len(app.QueryFlags.QTypes) > 1 {
+               return nil, errors.New("only one query type is allowed for 
globalping")
+       }
+
+       target := app.QueryFlags.QNames[0]
+       resolver, port, protocol, err := 
parseGlobalpingResolver(app.QueryFlags.Nameservers)
+       if err != nil {
+               return nil, err
+       }
+
+       if app.QueryFlags.UseIPv4 || app.QueryFlags.UseIPv6 {
+               if net.ParseIP(target) != nil {
+                       return nil, ErrTargetIPVersionNotAllowed
+               }
+               if resolver != "" && net.ParseIP(resolver) != nil {
+                       return nil, ErrResolverIPVersionNotAllowed
+               }
+       }
+
+       o := &globalping.MeasurementCreate{
+               Type:      "dns",
+               Target:    target,
+               Limit:     app.QueryFlags.GPLimit,
+               Locations: parseGlobalpingLocations(app.QueryFlags.GPFrom),
+               Options: &globalping.MeasurementOptions{
+                       Protocol: protocol,
+                       Port:     port,
+               },
+       }
+       if app.QueryFlags.UseIPv4 {
+               o.Options.IPVersion = globalping.IPVersion4
+       } else if app.QueryFlags.UseIPv6 {
+               o.Options.IPVersion = globalping.IPVersion6
+       }
+       if resolver != "" {
+               o.Options.Resolver = resolver
+       }
+       if len(app.QueryFlags.QTypes) > 0 {
+               o.Options.Query = &globalping.QueryOptions{
+                       Type: app.QueryFlags.QTypes[0],
+               }
+       }
+       res, err := app.globalping.CreateMeasurement(o)
+       if err != nil {
+               return nil, err
+       }
+       measurement, err := app.globalping.GetMeasurement(res.ID)
+       if err != nil {
+               return nil, err
+       }
+       for measurement.Status == globalping.StatusInProgress {
+               time.Sleep(500 * time.Millisecond)
+               measurement, err = app.globalping.GetMeasurement(res.ID)
+               if err != nil {
+                       return nil, err
+               }
+       }
+
+       if measurement.Status != globalping.StatusFinished {
+               return nil, &globalping.MeasurementError{
+                       Message: "measurement did not complete successfully",
+               }
+       }
+       return measurement, nil
+}
+
+func (app *App) OutputGlobalping(m *globalping.Measurement) error {
+       // Disables colorized output if user specified.
+       if !app.QueryFlags.Color {
+               color.NoColor = true
+       }
+
+       table := tablewriter.NewWriter(color.Output)
+       header := []string{"Location", "Name", "Type", "Class", "TTL", 
"Address", "Nameserver"}
+
+       // Formatting options for the table.
+       table.SetHeader(header)
+       table.SetAutoWrapText(true)
+       table.SetAutoFormatHeaders(true)
+       table.SetHeaderAlignment(tablewriter.ALIGN_LEFT)
+       table.SetAlignment(tablewriter.ALIGN_LEFT)
+       table.SetCenterSeparator("")
+       table.SetColumnSeparator("")
+       table.SetRowSeparator("")
+       table.SetHeaderLine(false)
+       table.SetBorder(false)
+       table.SetTablePadding("\t") // pad with tabs
+       table.SetNoWhiteSpace(true)
+
+       for i := range m.Results {
+               table.Append([]string{getGlobalPingLocationText(&m.Results[i]), 
"", "", "", "", "", ""})
+               answers, err := 
globalping.DecodeDNSAnswers(m.Results[i].Result.AnswersRaw)
+               if err != nil {
+                       return err
+               }
+               resolver := m.Results[i].Result.Resolver
+               for _, ans := range answers {
+                       typOut := getColoredType(ans.Type)
+                       output := []string{"", TerminalColorGreen(ans.Name), 
typOut, ans.Class, fmt.Sprintf("%ds", ans.TTL), ans.Value, resolver}
+                       table.Append(output)
+               }
+       }
+       table.Render()
+       return nil
+}
+
+func (app *App) OutputGlobalpingShort(m *globalping.Measurement) error {
+       for i := range m.Results {
+               fmt.Printf("%s\n", getGlobalPingLocationText(&m.Results[i]))
+               answers, err := 
globalping.DecodeDNSAnswers(m.Results[i].Result.AnswersRaw)
+               if err != nil {
+                       return err
+               }
+               for _, ans := range answers {
+                       fmt.Printf("%s\n", ans.Value)
+               }
+       }
+       return nil
+}
+
+type GlobalpingOutputResponse struct {
+       Location string             `json:"location"`
+       Answers  []resolvers.Answer `json:"answers"`
+}
+
+func (app *App) OutputGlobalpingJSON(m *globalping.Measurement) error {
+       jsonOutput := struct {
+               Responses []GlobalpingOutputResponse `json:"responses"`
+       }{
+               Responses: make([]GlobalpingOutputResponse, 0, len(m.Results)),
+       }
+       for i := range m.Results {
+               jsonOutput.Responses = append(jsonOutput.Responses, 
GlobalpingOutputResponse{})
+               jsonOutput.Responses[i].Location = 
getGlobalPingLocationText(&m.Results[i])
+               answers, err := 
globalping.DecodeDNSAnswers(m.Results[i].Result.AnswersRaw)
+               if err != nil {
+                       return err
+               }
+               resolver := m.Results[i].Result.Resolver
+               for _, ans := range answers {
+                       jsonOutput.Responses[i].Answers = 
append(jsonOutput.Responses[i].Answers, resolvers.Answer{
+                               Name:       ans.Name,
+                               Type:       ans.Type,
+                               Class:      ans.Class,
+                               TTL:        fmt.Sprintf("%ds", ans.TTL),
+                               Address:    ans.Value,
+                               Nameserver: resolver,
+                       })
+               }
+       }
+
+       // Pretty print with 4 spaces.
+       res, err := json.MarshalIndent(jsonOutput, "", "    ")
+       if err != nil {
+               return err
+       }
+       fmt.Printf("%s\n", res)
+       return nil
+}
+
+func parseGlobalpingLocations(from string) []globalping.Locations {
+       if from == "" {
+               return []globalping.Locations{
+                       {
+                               Magic: "world",
+                       },
+               }
+       }
+       fromArr := strings.Split(from, ",")
+       locations := make([]globalping.Locations, len(fromArr))
+       for i, v := range fromArr {
+               locations[i] = globalping.Locations{
+                       Magic: strings.TrimSpace(v),
+               }
+       }
+       return locations
+}
+
+func getGlobalPingLocationText(m *globalping.ProbeMeasurement) string {
+       state := ""
+       if m.Probe.State != "" {
+               state = " (" + m.Probe.State + ")"
+       }
+       return m.Probe.City + state + ", " +
+               m.Probe.Country + ", " +
+               m.Probe.Continent + ", " +
+               m.Probe.Network + " " +
+               "(AS" + fmt.Sprint(m.Probe.ASN) + ")"
+}
+
+// parses the resolver string and returns the hostname, port, and protocol.
+func parseGlobalpingResolver(nameservers []string) (string, int, string, 
error) {
+       port := 53
+       protocol := "udp"
+       if len(nameservers) == 0 {
+               return "", port, protocol, nil
+       }
+
+       if len(nameservers) > 1 {
+               return "", 0, "", errors.New("only one resolver is allowed for 
globalping")
+       }
+
+       u, err := url.Parse(nameservers[0])
+       if err != nil {
+               return "", 0, "", err
+       }
+       if u.Port() != "" {
+               port, err = strconv.Atoi(u.Port())
+               if err != nil {
+                       return "", 0, "", err
+               }
+       }
+       switch u.Scheme {
+       case "tcp":
+               protocol = "tcp"
+       }
+
+       return u.Hostname(), port, protocol, nil
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/doggo-1.0.4/internal/app/output.go 
new/doggo-1.0.5/internal/app/output.go
--- old/doggo-1.0.4/internal/app/output.go      2024-07-03 18:37:16.000000000 
+0200
+++ new/doggo-1.0.5/internal/app/output.go      2024-09-30 11:30:03.000000000 
+0200
@@ -11,6 +11,15 @@
        "github.com/olekukonko/tablewriter"
 )
 
+var (
+       TerminalColorGreen   = color.New(color.FgGreen, color.Bold).SprintFunc()
+       TerminalColorBlue    = color.New(color.FgBlue, color.Bold).SprintFunc()
+       TerminalColorYellow  = color.New(color.FgYellow, 
color.Bold).SprintFunc()
+       TerminalColorCyan    = color.New(color.FgCyan, color.Bold).SprintFunc()
+       TerminalColorRed     = color.New(color.FgRed, color.Bold).SprintFunc()
+       TerminalColorMagenta = color.New(color.FgMagenta, 
color.Bold).SprintFunc()
+)
+
 func (app *App) outputJSON(rsp []resolvers.Response) {
        jsonOutput := struct {
                Responses []resolvers.Response `json:"responses"`
@@ -36,15 +45,6 @@
 }
 
 func (app *App) outputTerminal(rsp []resolvers.Response) {
-       var (
-               green   = color.New(color.FgGreen, color.Bold).SprintFunc()
-               blue    = color.New(color.FgBlue, color.Bold).SprintFunc()
-               yellow  = color.New(color.FgYellow, color.Bold).SprintFunc()
-               cyan    = color.New(color.FgCyan, color.Bold).SprintFunc()
-               red     = color.New(color.FgRed, color.Bold).SprintFunc()
-               magenta = color.New(color.FgMagenta, color.Bold).SprintFunc()
-       )
-
        // Disables colorized output if user specified.
        if !app.QueryFlags.Color {
                color.NoColor = true
@@ -92,32 +92,14 @@
 
        for _, r := range rsp {
                for _, ans := range r.Answers {
-                       var typOut string
-                       switch typ := ans.Type; typ {
-                       case "A":
-                               typOut = blue(ans.Type)
-                       case "AAAA":
-                               typOut = blue(ans.Type)
-                       case "MX":
-                               typOut = magenta(ans.Type)
-                       case "NS":
-                               typOut = cyan(ans.Type)
-                       case "CNAME":
-                               typOut = yellow(ans.Type)
-                       case "TXT":
-                               typOut = yellow(ans.Type)
-                       case "SOA":
-                               typOut = red(ans.Type)
-                       default:
-                               typOut = blue(ans.Type)
-                       }
-                       output := []string{green(ans.Name), typOut, ans.Class, 
ans.TTL, ans.Address, ans.Nameserver}
+                       typOut := getColoredType(ans.Type)
+                       output := []string{TerminalColorGreen(ans.Name), 
typOut, ans.Class, ans.TTL, ans.Address, ans.Nameserver}
                        // Print how long it took
                        if app.QueryFlags.DisplayTimeTaken {
                                output = append(output, ans.RTT)
                        }
                        if outputStatus {
-                               output = append(output, red(ans.Status))
+                               output = append(output, 
TerminalColorRed(ans.Status))
                        }
                        table.Append(output)
                }
@@ -125,17 +107,17 @@
                        var typOut string
                        switch typ := auth.Type; typ {
                        case "SOA":
-                               typOut = red(auth.Type)
+                               typOut = TerminalColorRed(auth.Type)
                        default:
-                               typOut = blue(auth.Type)
+                               typOut = TerminalColorBlue(auth.Type)
                        }
-                       output := []string{green(auth.Name), typOut, 
auth.Class, auth.TTL, auth.MName, auth.Nameserver}
+                       output := []string{TerminalColorGreen(auth.Name), 
typOut, auth.Class, auth.TTL, auth.MName, auth.Nameserver}
                        // Print how long it took
                        if app.QueryFlags.DisplayTimeTaken {
                                output = append(output, auth.RTT)
                        }
                        if outputStatus {
-                               output = append(output, red(auth.Status))
+                               output = append(output, 
TerminalColorRed(auth.Status))
                        }
                        table.Append(output)
                }
@@ -143,6 +125,27 @@
        table.Render()
 }
 
+func getColoredType(t string) string {
+       switch t {
+       case "A":
+               return TerminalColorBlue(t)
+       case "AAAA":
+               return TerminalColorBlue(t)
+       case "MX":
+               return TerminalColorMagenta(t)
+       case "NS":
+               return TerminalColorCyan(t)
+       case "CNAME":
+               return TerminalColorYellow(t)
+       case "TXT":
+               return TerminalColorYellow(t)
+       case "SOA":
+               return TerminalColorRed(t)
+       default:
+               return TerminalColorBlue(t)
+       }
+}
+
 // Output takes a list of `dns.Answers` and based
 // on the output format specified displays the information.
 func (app *App) Output(responses []resolvers.Response) {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/doggo-1.0.4/pkg/config/config_unix.go 
new/doggo-1.0.5/pkg/config/config_unix.go
--- old/doggo-1.0.4/pkg/config/config_unix.go   2024-07-03 18:37:16.000000000 
+0200
+++ new/doggo-1.0.5/pkg/config/config_unix.go   2024-09-30 11:30:03.000000000 
+0200
@@ -9,7 +9,7 @@
 )
 
 // DefaultResolvConfPath specifies path to default resolv config file on UNIX.
-const DefaultResolvConfPath = "/etc/resolv.conf"
+var DefaultResolvConfPath = "/etc/resolv.conf"
 
 // GetDefaultServers get system default nameserver
 func GetDefaultServers() ([]string, int, []string, error) {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/doggo-1.0.4/pkg/models/models.go 
new/doggo-1.0.5/pkg/models/models.go
--- old/doggo-1.0.4/pkg/models/models.go        2024-07-03 18:37:16.000000000 
+0200
+++ new/doggo-1.0.5/pkg/models/models.go        2024-09-30 11:30:03.000000000 
+0200
@@ -45,6 +45,10 @@
        InsecureSkipVerify bool          `koanf:"skip-hostname-verification" 
skip-hostname-verification:"-"`
        TLSHostname        string        `koanf:"tls-hostname" tls-hostname:"-"`
        QueryAny           bool          `koanf:"any" json:"any"`
+
+       // Globalping flags
+       GPFrom  string `koanf:"gp-from" json:"gp-from"`
+       GPLimit int    `koanf:"gp-limit" json:"gp-limit"`
 }
 
 // Nameserver represents the type of Nameserver
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/doggo-1.0.4/pkg/utils/logger.go 
new/doggo-1.0.5/pkg/utils/logger.go
--- old/doggo-1.0.4/pkg/utils/logger.go 2024-07-03 18:37:16.000000000 +0200
+++ new/doggo-1.0.5/pkg/utils/logger.go 2024-09-30 11:30:03.000000000 +0200
@@ -16,6 +16,6 @@
                Level: lvl,
        }
 
-       logger := slog.New(slog.NewTextHandler(os.Stdout, lgrOpts))
+       logger := slog.New(slog.NewTextHandler(os.Stderr, lgrOpts))
        return logger
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/doggo-1.0.4/web/api.go new/doggo-1.0.5/web/api.go
--- old/doggo-1.0.4/web/api.go  2024-07-03 18:37:16.000000000 +0200
+++ new/doggo-1.0.5/web/api.go  2024-09-30 11:30:03.000000000 +0200
@@ -32,7 +32,7 @@
        logger := utils.InitLogger(ko.Bool("app.debug"))
 
        // Initialize app.
-       app := app.New(logger, buildVersion)
+       app := app.New(logger, nil, buildVersion)
 
        // Register router instance.
        r := chi.NewRouter()

++++++ doggo.obsinfo ++++++
--- /var/tmp/diff_new_pack.wPZWZB/_old  2024-10-01 17:16:57.934603966 +0200
+++ /var/tmp/diff_new_pack.wPZWZB/_new  2024-10-01 17:16:57.938604132 +0200
@@ -1,5 +1,5 @@
 name: doggo
-version: 1.0.4
-mtime: 1720024636
-commit: bac855567c203714c35586f026b91e4caf687636
+version: 1.0.5
+mtime: 1727688603
+commit: 16ba284a136354fb4f11fd4d566db9b4364e9a32
 

++++++ vendor.tar.xz ++++++
++++ 292795 lines of diff (skipped)

Reply via email to