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
|
package dns
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"grow.rievo.dev/discordBots/cmd/domaincheckbot/repository"
|
|
||||||
"net"
|
"net"
|
||||||
"sort"
|
"sort"
|
||||||
)
|
)
|
||||||
|
|
||||||
func CheckDomain(domain string) repository.Domain {
|
type Domain struct {
|
||||||
|
Name string
|
||||||
|
NS []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func CheckDomain(domain string) Domain {
|
||||||
nameservers, err := net.LookupNS(domain)
|
nameservers, err := net.LookupNS(domain)
|
||||||
|
|
||||||
if len(nameservers) > 0 && err == nil {
|
if len(nameservers) > 0 && err == nil {
|
||||||
return repository.Domain{
|
return Domain{
|
||||||
Name: domain,
|
Name: domain,
|
||||||
NS: nsToArray(nameservers),
|
NS: nsToArray(nameservers),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return repository.Domain{
|
return Domain{
|
||||||
Name: domain,
|
Name: domain,
|
||||||
NS: []string{},
|
NS: []string{},
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,23 +2,27 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"database/sql"
|
||||||
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/dgraph-io/badger/v4"
|
|
||||||
"github.com/disgoorg/disgo"
|
"github.com/disgoorg/disgo"
|
||||||
"github.com/disgoorg/disgo/discord"
|
"github.com/disgoorg/disgo/discord"
|
||||||
"github.com/disgoorg/disgo/rest"
|
"github.com/disgoorg/disgo/rest"
|
||||||
"github.com/disgoorg/disgo/webhook"
|
"github.com/disgoorg/disgo/webhook"
|
||||||
"github.com/disgoorg/snowflake/v2"
|
"github.com/disgoorg/snowflake/v2"
|
||||||
|
"grow.rievo.dev/discordBots"
|
||||||
"grow.rievo.dev/discordBots/cmd/domaincheckbot/config"
|
"grow.rievo.dev/discordBots/cmd/domaincheckbot/config"
|
||||||
"grow.rievo.dev/discordBots/cmd/domaincheckbot/dns"
|
"grow.rievo.dev/discordBots/cmd/domaincheckbot/dns"
|
||||||
"grow.rievo.dev/discordBots/cmd/domaincheckbot/repository"
|
"grow.rievo.dev/discordBots/pkg/db"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"reflect"
|
"reflect"
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
_ "modernc.org/sqlite"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -39,11 +43,22 @@ func main() {
|
||||||
client := webhook.New(webhookID, webhookToken)
|
client := webhook.New(webhookID, webhookToken)
|
||||||
defer client.Close(context.TODO())
|
defer client.Close(context.TODO())
|
||||||
|
|
||||||
repo := repository.InitDb()
|
ctx := context.Background()
|
||||||
defer repo.Close()
|
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)
|
// create tables
|
||||||
tickerGC := time.NewTicker(15 * time.Minute)
|
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{})
|
quit := make(chan struct{})
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
|
@ -51,20 +66,11 @@ func main() {
|
||||||
select {
|
select {
|
||||||
case <-ticker.C:
|
case <-ticker.C:
|
||||||
for _, d := range config.Domains {
|
for _, d := range config.Domains {
|
||||||
go checkDomain(0, d, repo, client)
|
go checkDomain(0, d, query, 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")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case <-quit:
|
case <-quit:
|
||||||
ticker.Stop()
|
ticker.Stop()
|
||||||
tickerGC.Stop()
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -77,9 +83,13 @@ func main() {
|
||||||
<-s
|
<-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)
|
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) {
|
if reflect.DeepEqual(domain, retrievedDomain) {
|
||||||
logger.Debug("domain did not change", slog.String("domain", d))
|
logger.Debug("domain did not change", slog.String("domain", d))
|
||||||
return
|
return
|
||||||
|
@ -88,14 +98,23 @@ func checkDomain(counter int, d string, repo *repository.DomainRepository, clien
|
||||||
counter += 1
|
counter += 1
|
||||||
if counter >= 2 {
|
if counter >= 2 {
|
||||||
go sendWebhook(client, domain, retrievedDomain)
|
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
|
return
|
||||||
}
|
}
|
||||||
time.Sleep(1 * time.Minute)
|
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
|
var status string
|
||||||
|
|
||||||
status = fmt.Sprintf("```md\n# %v", domain.Name)
|
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