diff --git a/dns.go b/dns.go
index a4dddb7..25da69f 100644
--- a/dns.go
+++ b/dns.go
@@ -3,6 +3,7 @@ package main
import (
// Standard
"fmt"
+ "maps"
"slices"
"strings"
)
@@ -17,6 +18,10 @@ type DNSRecord struct {
Type string
}
+type DomainPart struct {
+ Subparts map[string]*DomainPart `json:",omitempty"`
+}
+
type RecordsTree struct {
Record DNSRecord
Children []RecordsTree
@@ -74,36 +79,63 @@ func (r DNSRecord) NameReversed() string {
return strings.Join(parts, ".")
}
-func (rt *RecordsTree) BuildTree(records []DNSRecord, startAt, partsLevel int) (tree RecordsTree) {
- tree = RecordsTree{}
+func BuildRecordsTree(records []DNSRecord) *DomainPart {
+ topPart := new(DomainPart)
+ topPart.Subparts = make(map[string]*DomainPart)
- for i := startAt; i < len(records); i++ {
- // current: bar.foo.n44.se
- current := records[i]
- currentPart := current.Part(partsLevel)
+ for _, record := range records {
+ curPart := topPart
- for j := i; j < len(records); j++ {
- // next: baz.bar.foo.n44.se
- next := records[j]
- nextPart := next.Part(partsLevel)
- fmt.Printf("%04d %04d: %s ?= %s\n", i, j, currentPart, nextPart)
+ currentDomainNameSplit := strings.Split(record.Name, ".")
+ slices.Reverse(currentDomainNameSplit)
- if currentPart == nextPart {
- fmt.Printf("FOUND SOMETHING!\n")
- nextTree := RecordsTree{
- Record: next,
- }
-
- tree.Children = append(tree.Children, nextTree)
- }
-
- // Doesn't match anymore, return to other loop after all that are processed
- if currentPart != nextPart {
- i = j
- break
+ for _, part := range currentDomainNameSplit {
+ if nextDomainPart, found := curPart.Subparts[part]; !found {
+ newPart := new(DomainPart)
+ newPart.Subparts = make(map[string]*DomainPart)
+ curPart.Subparts[strings.ToLower(part)] = newPart
+ curPart = newPart
+ } else {
+ curPart = nextDomainPart
}
}
}
- return tree
+ return topPart
+}
+
+func (dp *DomainPart) ToHTML(parts []string) string {
+ html := ""
+
+ sortedParts := slices.Sorted(maps.Keys(dp.Subparts))
+
+ for _, part := range sortedParts {
+ subpart := dp.Subparts[part]
+ newParts := append(parts, part)
+
+ reversedParts := make([]string, len(newParts))
+ copy(reversedParts, newParts)
+ slices.Reverse(reversedParts)
+ fqdn := strings.Join(reversedParts, ".")
+
+ var subHTML string
+ if len(subpart.Subparts) == 0 {
+ html += fmt.Sprintf(`
%s
`, fqdn, fqdn)
+ } else {
+ subHTML = subpart.ToHTML(newParts)
+ html += fmt.Sprintf(`
+
+ `,
+ fqdn,
+ fqdn,
+ subHTML,
+ )
+ }
+
+ }
+
+ return html
}
diff --git a/go.sum b/go.sum
index 22df342..0422509 100644
--- a/go.sum
+++ b/go.sum
@@ -1,6 +1,6 @@
git.gibonuddevalla.se/go/html_template v1.0.0 h1:0YoqKiWMxYUsYZomqFlXLR/h0UNBicqw+VOsPyotcD4=
git.gibonuddevalla.se/go/html_template v1.0.0/go.mod h1:DGqGMulbZyGoRqWXInXISb6GQLswuUrTaX1WhH7jx/w=
-git.gibonuddevalla.se/go/vlog v1.0.0 h1:6iu7Wy3V3vTSg1usLSZWX9ipA+SY3FV4pi7HrHqagyc=
+git.gibonuddevalla.se/go/vlog v1.0.0 h1:AlArMDt1Aw6poI8yDtU22d4NyFl3iQocZSswvlzy48o=
git.gibonuddevalla.se/go/vlog v1.0.0/go.mod h1:rjS9ZINhZF+Bhrb+fdD4aEKOnLxFYU3PJFMx7nOi4c0=
git.gibonuddevalla.se/go/wrappederror v0.3.5 h1:/EzrdXETlZfNpS6TcK1Ix6BaV+Fl7qcGoxUM0GkrIN8=
git.gibonuddevalla.se/go/wrappederror v0.3.5/go.mod h1:j4w320Hk1wvhOPjUaK4GgLvmtnjUUM5yVu6JFO1OCSc=
diff --git a/static/css/index.css b/static/css/index.css
index b310509..8300fba 100644
--- a/static/css/index.css
+++ b/static/css/index.css
@@ -1,12 +1,34 @@
html {
- box-sizing: border-box;
+ box-sizing: border-box;
}
-*, *:before, *:after {
- box-sizing: inherit;
+*,
+*:before,
+*:after {
+ box-sizing: inherit;
}
[onClick] {
- cursor: pointer;
+ cursor: pointer;
}
+body {
+ font-family: sans-serif;
+}
+
+.records-tree {
+
+ .top {
+ font-weight: bold;
+ margin-left: 16px;
+ }
+
+ &>.top {
+ margin-left: 0px;
+ }
+
+ .record {
+ display: none;
+ color: #444;
+ }
+}
diff --git a/static/js/dns.mjs b/static/js/dns.mjs
new file mode 100644
index 0000000..3a237b9
--- /dev/null
+++ b/static/js/dns.mjs
@@ -0,0 +1,17 @@
+export class Application {
+ constructor() {
+ this.addTopHandlers()
+ }
+
+ addTopHandlers() {
+ for (const top of document.querySelectorAll('.top .fqdn'))
+ top.addEventListener('click', event=>this.handlerTop(event))
+ }
+
+ handlerTop(event) {
+ const fqdn = event.target
+ const top = fqdn.closest('.top')
+ const records = top.querySelector('.records')
+ console.log(fqdn, top, records)
+ }
+}
diff --git a/views/layouts/main.gotmpl b/views/layouts/main.gotmpl
index 92a8d15..012f9cf 100644
--- a/views/layouts/main.gotmpl
+++ b/views/layouts/main.gotmpl
@@ -4,7 +4,7 @@
-
+
diff --git a/views/pages/index.gotmpl b/views/pages/index.gotmpl
index 2b95ea6..3f05e0f 100644
--- a/views/pages/index.gotmpl
+++ b/views/pages/index.gotmpl
@@ -1,7 +1,13 @@
{{ define "page" }}
+
+
{{ .Data.Identity }}
-{{ range .Data.DNSRecords }}
-{{ .NameReversed }}
-{{ end }}
+
+{{ .Data.Tree }}
+
+
{{ end }}
diff --git a/webserver.go b/webserver.go
index 844caaa..0a59029 100644
--- a/webserver.go
+++ b/webserver.go
@@ -11,6 +11,7 @@ import (
"net/http"
"os"
"slices"
+ "html/template"
)
var (
@@ -65,12 +66,17 @@ func rootHandler(w http.ResponseWriter, r *http.Request) {
slices.SortFunc(entries, SortDNSRecord)
data["DNSRecords"] = entries
- tree := RecordsTree{}
- tree = tree.BuildTree(entries, 0, 1)
+ fmt.Printf("\n\x1b[32;1mSTART\x1b[0m\n")
+ tree := BuildRecordsTree(entries)
+ htmlTree := tree.ToHTML([]string{})
+ data["Tree"] = template.HTML(htmlTree)
+
+ fmt.Printf("\n\x1b[32;1mDONE\x1b[0m\n")
j, _ := json.Marshal(tree)
os.WriteFile("/tmp/tree.json", j, 0644)
+ data["VERSION"] = VERSION
page.Data = data
err = htmlEngine.Render(page, w, r)