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(` +
+
%s
+
%s
+
+ `, + 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)