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} }