feature: switch domaincheckbot to sqlite kv

This commit is contained in:
Seraphim Strub 2024-07-12 13:51:36 +00:00
parent 50cd000ee5
commit 773318a079
3 changed files with 48 additions and 133 deletions

View file

@ -1,21 +1,25 @@
package dns
import (
"grow.rievo.dev/discordBots/cmd/domaincheckbot/repository"
"net"
"sort"
)
func CheckDomain(domain string) repository.Domain {
type Domain struct {
Name string
NS []string
}
func CheckDomain(domain string) Domain {
nameservers, err := net.LookupNS(domain)
if len(nameservers) > 0 && err == nil {
return repository.Domain{
return Domain{
Name: domain,
NS: nsToArray(nameservers),
}
}
return repository.Domain{
return Domain{
Name: domain,
NS: []string{},
}

View file

@ -2,23 +2,27 @@ package main
import (
"context"
"database/sql"
"encoding/json"
"errors"
"fmt"
"github.com/dgraph-io/badger/v4"
"github.com/disgoorg/disgo"
"github.com/disgoorg/disgo/discord"
"github.com/disgoorg/disgo/rest"
"github.com/disgoorg/disgo/webhook"
"github.com/disgoorg/snowflake/v2"
"grow.rievo.dev/discordBots"
"grow.rievo.dev/discordBots/cmd/domaincheckbot/config"
"grow.rievo.dev/discordBots/cmd/domaincheckbot/dns"
"grow.rievo.dev/discordBots/cmd/domaincheckbot/repository"
"grow.rievo.dev/discordBots/pkg/db"
"log/slog"
"os"
"os/signal"
"reflect"
"syscall"
"time"
_ "modernc.org/sqlite"
)
var (
@ -39,11 +43,22 @@ func main() {
client := webhook.New(webhookID, webhookToken)
defer client.Close(context.TODO())
repo := repository.InitDb()
defer repo.Close()
ctx := context.Background()
con, err := sql.Open("sqlite", "file:db/domain.db?cache=shared")
if err != nil {
logger.Error("error opening db", slog.Any("error", err))
panic(err)
}
defer con.Close()
ticker := time.NewTicker(10 * time.Minute)
tickerGC := time.NewTicker(15 * time.Minute)
// create tables
if _, err := con.ExecContext(ctx, discordBots.Schema); err != nil {
logger.Error("error creating db schema", slog.Any("error", err))
panic(err)
}
query := db.New(con)
ticker := time.NewTicker(1 * time.Minute)
quit := make(chan struct{})
go func() {
@ -51,20 +66,11 @@ func main() {
select {
case <-ticker.C:
for _, d := range config.Domains {
go checkDomain(0, d, repo, client)
}
case <-tickerGC.C:
err := repo.RunGC()
if err != nil && !errors.Is(err, badger.ErrNoRewrite) {
logger.Error("GC failed", slog.Any("error", err))
} else {
logger.Debug("GC successful")
go checkDomain(0, d, query, client)
}
case <-quit:
ticker.Stop()
tickerGC.Stop()
return
}
}
@ -77,9 +83,13 @@ func main() {
<-s
}
func checkDomain(counter int, d string, repo *repository.DomainRepository, client webhook.Client) {
func checkDomain(counter int, d string, query *db.Queries, client webhook.Client) {
domain := dns.CheckDomain(d)
retrievedDomain, _ := repo.GetValue(d)
retrievedDomainJson, dbErr := query.GetItem(context.TODO(), d)
retrievedDomain := dns.Domain{}
if err := json.Unmarshal(retrievedDomainJson.Data, &retrievedDomain); !errors.Is(dbErr, sql.ErrNoRows) && err != nil {
logger.Error("failed unmarshalling deal", slog.Any("error", err))
}
if reflect.DeepEqual(domain, retrievedDomain) {
logger.Debug("domain did not change", slog.String("domain", d))
return
@ -88,14 +98,23 @@ func checkDomain(counter int, d string, repo *repository.DomainRepository, clien
counter += 1
if counter >= 2 {
go sendWebhook(client, domain, retrievedDomain)
repo.SetValue(domain)
domainJson, _ := json.Marshal(domain)
err := query.CreateItem(context.TODO(), db.CreateItemParams{
ID: domain.Name,
Data: domainJson,
})
if err != nil {
logger.Error("failed saving domain", slog.Any("error", err))
}
return
}
time.Sleep(1 * time.Minute)
checkDomain(counter, d, repo, client)
checkDomain(counter, d, query, client)
}
func sendWebhook(client webhook.Client, domain repository.Domain, oldDomain repository.Domain) {
func sendWebhook(client webhook.Client, domain dns.Domain, oldDomain dns.Domain) {
var status string
status = fmt.Sprintf("```md\n# %v", domain.Name)

View file

@ -1,108 +0,0 @@
package repository
import (
"encoding/json"
"github.com/dgraph-io/badger/v4"
"log"
)
type Domain struct {
Name string
NS []string
}
type Repository interface {
GetAll() ([]Domain, error)
GetValue(domainName string) Domain
SetValue(domain Domain) error
DeleteValue(domainName string) error
Close() error
}
type DomainRepository struct {
db *badger.DB
}
func InitDb() *DomainRepository {
opts := badger.DefaultOptions("./badger")
opts.Logger = nil
db, err := badger.Open(opts)
if err != nil {
log.Fatal(err)
}
return &DomainRepository{db}
}
func (d *DomainRepository) Close() error {
return d.db.Close()
}
func (d *DomainRepository) RunGC() error {
return d.db.RunValueLogGC(0.7)
}
func (d *DomainRepository) GetAll() ([]Domain, error) {
var domains []Domain
err := d.db.View(func(txn *badger.Txn) error {
opts := badger.DefaultIteratorOptions
opts.PrefetchSize = 10
it := txn.NewIterator(opts)
defer it.Close()
for it.Rewind(); it.Valid(); it.Next() {
item := it.Item()
err := item.Value(func(val []byte) error {
retrievedDomain := Domain{}
err := json.Unmarshal(val, &retrievedDomain)
domains = append(domains, retrievedDomain)
return err
})
if err != nil {
return err
}
}
return nil
})
return domains, err
}
func (d *DomainRepository) GetValue(domainName string) (Domain, error) {
retrievedDomain := Domain{}
err := d.db.View(func(txn *badger.Txn) error {
item, err := txn.Get([]byte(domainName))
if err != nil {
return err
}
err = item.Value(func(val []byte) error {
err = json.Unmarshal(val, &retrievedDomain)
return err
})
return err
})
if err != nil {
return Domain{}, err
}
return retrievedDomain, nil
}
func (d *DomainRepository) SetValue(domain Domain) error {
jsonBytes, err := json.Marshal(domain)
if err != nil {
return err
}
err = d.db.Update(func(txn *badger.Txn) error {
err := txn.Set([]byte(domain.Name), jsonBytes)
return err
})
if err != nil {
return err
}
return nil
}
func (d *DomainRepository) DeleteValue(domainName string) error {
err := d.db.Update(func(txn *badger.Txn) error {
err := txn.Delete([]byte(domainName))
return err
})
return err
}