171 lines
4.2 KiB
Go
171 lines
4.2 KiB
Go
package domain64
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"fmt"
|
|
"log"
|
|
"slices"
|
|
"sync"
|
|
|
|
sqlc "git.jadud.com/grosbeak/internal/domain64/sqlc"
|
|
"github.com/jpillora/go-tld"
|
|
)
|
|
|
|
type Domain64Map struct {
|
|
mu sync.Mutex
|
|
m map[string]int
|
|
DB *sql.DB
|
|
Flushed bool
|
|
}
|
|
|
|
func NewDomain64Map(db *sql.DB) (*Domain64Map, error) {
|
|
d64m := &Domain64Map{}
|
|
d64m.DB = db
|
|
d64m.Flushed = true
|
|
// Init the tables if a DB pointer is passed in.
|
|
return d64m, nil
|
|
}
|
|
|
|
func (d64m *Domain64Map) URLToRFQDN(url *tld.URL) string {
|
|
s := ""
|
|
if url.TLD != "" {
|
|
s += url.TLD
|
|
}
|
|
if url.Domain != "" {
|
|
s += "." + url.Domain
|
|
}
|
|
if url.Subdomain != "" {
|
|
s += "." + url.Subdomain
|
|
}
|
|
s += url.Path
|
|
return s
|
|
}
|
|
|
|
func _get_or_insert_tld(queries *sqlc.Queries, d64 *Domain64, url *tld.URL) error {
|
|
ctx := context.Background()
|
|
tld_id, err := queries.GetTLDId(ctx, url.TLD)
|
|
if err != nil {
|
|
cnt, err := queries.CountTLDs(ctx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
d64.TLD = cnt + 1
|
|
err = queries.InsertTLD(ctx, sqlc.InsertTLDParams{TldID: d64.TLD, Tld: url.TLD})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
} else {
|
|
d64.TLD = tld_id
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func _get_or_insert_domain(queries *sqlc.Queries, d64 *Domain64, url *tld.URL) error {
|
|
ctx := context.Background()
|
|
domain_id, err := queries.GetDomainId(ctx, sqlc.GetDomainIdParams{TldID: d64.TLD, Domain: url.Domain})
|
|
if err != nil {
|
|
cnt, err := queries.CountDomains(ctx, d64.TLD)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
d64.Domain = cnt + 1
|
|
err = queries.InsertDomain(ctx, sqlc.InsertDomainParams{TldID: d64.TLD, DomainID: d64.Domain, Domain: url.Domain})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
} else {
|
|
d64.Domain = domain_id
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func _get_or_insert_subdomain(queries *sqlc.Queries, d64 *Domain64, url *tld.URL) error {
|
|
ctx := context.Background()
|
|
subdomain_id, err := queries.GetSubdomainId(ctx, sqlc.GetSubdomainIdParams{
|
|
TldID: int64(d64.TLD), DomainID: int64(d64.Domain), Subdomain: url.Subdomain,
|
|
})
|
|
if err != nil {
|
|
if url.Subdomain == "" {
|
|
d64.Subdomain = 0
|
|
} else {
|
|
cnt, err := queries.CountSubdomains(ctx, sqlc.CountSubdomainsParams{TldID: d64.TLD, DomainID: d64.Domain})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
d64.Subdomain = cnt + 1
|
|
err = queries.InsertSubdomain(ctx, sqlc.InsertSubdomainParams{TldID: d64.TLD, DomainID: d64.Domain, SubdomainID: d64.Subdomain, Subdomain: url.Subdomain})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
} else {
|
|
d64.Subdomain = subdomain_id
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func _get_or_insert_path(queries *sqlc.Queries, d64 *Domain64, url *tld.URL) error {
|
|
ctx := context.Background()
|
|
log.Println(url, url.Path)
|
|
path_id, err := queries.GetPathId(ctx, sqlc.GetPathIdParams{
|
|
TldID: d64.TLD, DomainID: d64.Domain, SubdomainID: d64.Subdomain, Path: url.Path,
|
|
})
|
|
if err != nil {
|
|
if url.Path == "/" {
|
|
d64.Path = 0
|
|
} else {
|
|
cnt, err := queries.CountPaths(ctx, sqlc.CountPathsParams{TldID: d64.TLD, DomainID: d64.Domain, SubdomainID: d64.Subdomain})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
d64.Path = cnt + 1
|
|
err = queries.InsertPath(ctx, sqlc.InsertPathParams{TldID: d64.TLD, DomainID: d64.Domain, SubdomainID: d64.Subdomain, PathID: d64.Path, Path: url.Path})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
} else {
|
|
d64.Path = path_id
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// FIXME: This feels like a very convoluted way to maintain the domain names.
|
|
// However, I also need to maintain uniqueness. Can I do this in one table?
|
|
func (d64m *Domain64Map) URLToDomain64(url *tld.URL) (*Domain64, error) {
|
|
allowed_schemes := []string{"https"}
|
|
if !slices.Contains(allowed_schemes, url.Scheme) {
|
|
return nil, fmt.Errorf("URL scheme must be in %q; given %s", allowed_schemes, url.Scheme)
|
|
}
|
|
|
|
d64 := &Domain64{}
|
|
queries := sqlc.New(d64m.DB)
|
|
// These manipulate both the DB and the Domain64 struct
|
|
err := _get_or_insert_tld(queries, d64, url)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
err = _get_or_insert_domain(queries, d64, url)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
err = _get_or_insert_subdomain(queries, d64, url)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
err = _get_or_insert_path(queries, d64, url)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return d64, nil
|
|
}
|
|
|
|
func NullInt64(i int64) sql.NullInt64 {
|
|
return sql.NullInt64{Int64: i, Valid: true}
|
|
}
|
|
|
|
func NullString(s string) sql.NullString {
|
|
return sql.NullString{String: s, Valid: true}
|
|
}
|