feature: switch domaincheckbot to sqlite kv
This commit is contained in:
parent
50cd000ee5
commit
773318a079
3 changed files with 48 additions and 133 deletions
|
@ -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{},
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
}
|
Loading…
Reference in a new issue