A lot more to go, but this is the core. Need to think about how to test the queue handlers.
184 lines
4.5 KiB
Go
184 lines
4.5 KiB
Go
package domain64
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
_ "embed"
|
|
"fmt"
|
|
"log"
|
|
"slices"
|
|
"sync"
|
|
|
|
sqlc "git.jadud.com/jadudm/grosbeak/internal/domain64/sqlc"
|
|
"github.com/jpillora/go-tld"
|
|
)
|
|
|
|
//go:embed sqlc/schema.sql
|
|
var ddl string
|
|
|
|
type Domain64Map struct {
|
|
mu sync.Mutex
|
|
m map[string]int
|
|
DB *sql.DB
|
|
Queries *sqlc.Queries
|
|
}
|
|
|
|
func NewDomain64Map() (*Domain64Map, error) {
|
|
d64m := &Domain64Map{}
|
|
d64m.DB = nil
|
|
d64m.Queries = nil
|
|
return d64m, nil
|
|
}
|
|
|
|
func (d64m *Domain64Map) Setup(db *sql.DB) {
|
|
log.Printf("creating domain64 tables\n")
|
|
if _, err := db.ExecContext(context.Background(), ddl); err != nil {
|
|
log.Printf("setup err: %s", err.Error())
|
|
panic(err)
|
|
}
|
|
d64m.DB = db
|
|
d64m.Queries = sqlc.New(db)
|
|
}
|
|
|
|
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{}
|
|
|
|
// These manipulate both the DB and the Domain64 struct
|
|
err := _get_or_insert_tld(d64m.Queries, d64, url)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
err = _get_or_insert_domain(d64m.Queries, d64, url)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
err = _get_or_insert_subdomain(d64m.Queries, d64, url)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
err = _get_or_insert_path(d64m.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}
|
|
}
|