mirror of
https://github.com/qdm12/ddns-updater.git
synced 2026-04-05 00:43:53 -04:00
chore(lint): add ireturn linter
- Return concrete structs - Accept interfaces - Define narrow interfaces locally where needed
This commit is contained in:
@@ -41,6 +41,7 @@ linters:
|
||||
- gosec
|
||||
# - goerr113 # TODO
|
||||
- importas
|
||||
- ireturn
|
||||
- lll
|
||||
- misspell
|
||||
- nakedret
|
||||
|
||||
@@ -23,7 +23,7 @@ import (
|
||||
"github.com/qdm12/ddns-updater/internal/health"
|
||||
"github.com/qdm12/ddns-updater/internal/models"
|
||||
jsonparams "github.com/qdm12/ddns-updater/internal/params"
|
||||
"github.com/qdm12/ddns-updater/internal/persistence"
|
||||
persistence "github.com/qdm12/ddns-updater/internal/persistence/json"
|
||||
recordslib "github.com/qdm12/ddns-updater/internal/records"
|
||||
"github.com/qdm12/ddns-updater/internal/server"
|
||||
"github.com/qdm12/ddns-updater/internal/update"
|
||||
@@ -164,7 +164,7 @@ func _main(ctx context.Context, env params.Interface, args []string, logger logg
|
||||
}
|
||||
}
|
||||
|
||||
persistentDB, err := persistence.NewJSON(config.Paths.DataDir)
|
||||
persistentDB, err := persistence.NewDatabase(config.Paths.DataDir)
|
||||
if err != nil {
|
||||
notify(err.Error())
|
||||
return err
|
||||
|
||||
@@ -3,25 +3,17 @@ package data
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/qdm12/ddns-updater/internal/persistence"
|
||||
"github.com/qdm12/ddns-updater/internal/records"
|
||||
)
|
||||
|
||||
var _ Database = (*database)(nil)
|
||||
|
||||
type Database interface {
|
||||
EphemeralDatabase
|
||||
PersistentDatabase
|
||||
}
|
||||
|
||||
type database struct {
|
||||
data []records.Record
|
||||
sync.RWMutex
|
||||
persistentDB persistence.Database
|
||||
persistentDB PersistentDatabase
|
||||
}
|
||||
|
||||
// NewDatabase creates a new in memory database.
|
||||
func NewDatabase(data []records.Record, persistentDB persistence.Database) Database {
|
||||
func NewDatabase(data []records.Record, persistentDB PersistentDatabase) *database {
|
||||
return &database{
|
||||
data: data,
|
||||
persistentDB: persistentDB,
|
||||
|
||||
@@ -1,20 +1,15 @@
|
||||
package persistence
|
||||
package data
|
||||
|
||||
import (
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/qdm12/ddns-updater/internal/models"
|
||||
"github.com/qdm12/ddns-updater/internal/persistence/json"
|
||||
)
|
||||
|
||||
type Database interface {
|
||||
type PersistentDatabase interface {
|
||||
Close() error
|
||||
StoreNewIP(domain, host string, ip net.IP, t time.Time) (err error)
|
||||
GetEvents(domain, host string) (events []models.HistoryEvent, err error)
|
||||
Check() error
|
||||
}
|
||||
|
||||
func NewJSON(dataDir string) (Database, error) {
|
||||
return json.NewDatabase(dataDir)
|
||||
}
|
||||
@@ -6,11 +6,6 @@ import (
|
||||
"github.com/qdm12/ddns-updater/internal/records"
|
||||
)
|
||||
|
||||
type EphemeralDatabase interface {
|
||||
Select(id int) (record records.Record, err error)
|
||||
SelectAll() (records []records.Record)
|
||||
}
|
||||
|
||||
func (db *database) Select(id int) (record records.Record, err error) {
|
||||
db.RLock()
|
||||
defer db.RUnlock()
|
||||
|
||||
@@ -7,14 +7,6 @@ import (
|
||||
"github.com/qdm12/ddns-updater/internal/records"
|
||||
)
|
||||
|
||||
var _ PersistentDatabase = (*database)(nil)
|
||||
|
||||
type PersistentDatabase interface {
|
||||
GetEvents(domain, host string) (events []models.HistoryEvent, err error)
|
||||
Update(id int, record records.Record) (err error)
|
||||
Close() (err error)
|
||||
}
|
||||
|
||||
func (db *database) GetEvents(domain, host string) (events []models.HistoryEvent, err error) {
|
||||
return db.persistentDB.GetEvents(domain, host)
|
||||
}
|
||||
|
||||
@@ -6,20 +6,19 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/qdm12/ddns-updater/internal/constants"
|
||||
"github.com/qdm12/ddns-updater/internal/data"
|
||||
"github.com/qdm12/golibs/logging"
|
||||
)
|
||||
|
||||
type lookupIPFunc func(host string) ([]net.IP, error)
|
||||
|
||||
func MakeIsHealthy(db data.Database, lookupIP lookupIPFunc, logger logging.Logger) func() error {
|
||||
func MakeIsHealthy(db AllSelecter, lookupIP lookupIPFunc, logger logging.Logger) func() error {
|
||||
return func() (err error) {
|
||||
return isHealthy(db, lookupIP)
|
||||
}
|
||||
}
|
||||
|
||||
// isHealthy checks all the records were updated successfully and returns an error if not.
|
||||
func isHealthy(db data.Database, lookupIP lookupIPFunc) (err error) {
|
||||
func isHealthy(db AllSelecter, lookupIP lookupIPFunc) (err error) {
|
||||
records := db.SelectAll()
|
||||
for _, record := range records {
|
||||
if record.Status == constants.FAIL {
|
||||
|
||||
@@ -14,15 +14,11 @@ func IsClientMode(args []string) bool {
|
||||
return len(args) > 1 && args[1] == "healthcheck"
|
||||
}
|
||||
|
||||
type Client interface {
|
||||
Query(ctx context.Context, port uint16) error
|
||||
}
|
||||
|
||||
type client struct {
|
||||
*http.Client
|
||||
}
|
||||
|
||||
func NewClient() Client {
|
||||
func NewClient() *client {
|
||||
const timeout = 5 * time.Second
|
||||
return &client{
|
||||
Client: &http.Client{Timeout: timeout},
|
||||
|
||||
7
internal/health/interfaces.go
Normal file
7
internal/health/interfaces.go
Normal file
@@ -0,0 +1,7 @@
|
||||
package health
|
||||
|
||||
import "github.com/qdm12/ddns-updater/internal/records"
|
||||
|
||||
type AllSelecter interface {
|
||||
SelectAll() (records []records.Record)
|
||||
}
|
||||
@@ -8,17 +8,13 @@ import (
|
||||
"github.com/qdm12/golibs/logging"
|
||||
)
|
||||
|
||||
type Server interface {
|
||||
Run(ctx context.Context, done chan<- struct{})
|
||||
}
|
||||
|
||||
type server struct {
|
||||
address string
|
||||
logger logging.Logger
|
||||
handler http.Handler
|
||||
}
|
||||
|
||||
func NewServer(address string, logger logging.Logger, healthcheck func() error) Server {
|
||||
func NewServer(address string, logger logging.Logger, healthcheck func() error) *server {
|
||||
handler := newHandler(logger, healthcheck)
|
||||
return &server{
|
||||
address: address,
|
||||
|
||||
@@ -4,15 +4,10 @@ import (
|
||||
"io/fs"
|
||||
"os"
|
||||
|
||||
"github.com/qdm12/ddns-updater/internal/settings"
|
||||
"github.com/qdm12/golibs/logging"
|
||||
"github.com/qdm12/golibs/params"
|
||||
)
|
||||
|
||||
type Reader interface {
|
||||
JSONSettings(filePath string) (allSettings []settings.Settings, warnings []string, err error)
|
||||
}
|
||||
|
||||
type reader struct {
|
||||
logger logging.Logger
|
||||
env envInterface
|
||||
@@ -20,7 +15,7 @@ type reader struct {
|
||||
writeFile func(filename string, data []byte, perm fs.FileMode) (err error)
|
||||
}
|
||||
|
||||
func NewReader(logger logging.Logger) Reader {
|
||||
func NewReader(logger logging.Logger) *reader {
|
||||
return &reader{
|
||||
logger: logger,
|
||||
env: params.New(),
|
||||
|
||||
@@ -31,7 +31,7 @@ var (
|
||||
dnsOMaticPassword = regexp.MustCompile(`^[a-zA-Z0-9][a-zA-Z0-9._-]{5,19}$`)
|
||||
)
|
||||
|
||||
func NewMatcher() Matcher {
|
||||
func NewMatcher() *matcher {
|
||||
return &matcher{
|
||||
gandiKey: gandiKey,
|
||||
goDaddyKey: goDaddyKey,
|
||||
|
||||
@@ -9,15 +9,13 @@ import (
|
||||
|
||||
"github.com/go-chi/chi"
|
||||
"github.com/go-chi/chi/middleware"
|
||||
"github.com/qdm12/ddns-updater/internal/data"
|
||||
"github.com/qdm12/ddns-updater/internal/update"
|
||||
)
|
||||
|
||||
type handlers struct {
|
||||
ctx context.Context
|
||||
// Objects
|
||||
db data.Database
|
||||
runner update.Runner
|
||||
db Database
|
||||
runner UpdateForcer
|
||||
indexTemplate *template.Template
|
||||
// Mockable functions
|
||||
timeNow func() time.Time
|
||||
@@ -27,7 +25,7 @@ type handlers struct {
|
||||
var uiFS embed.FS
|
||||
|
||||
func newHandler(ctx context.Context, rootURL string,
|
||||
db data.Database, runner update.Runner) http.Handler {
|
||||
db Database, runner UpdateForcer) http.Handler {
|
||||
indexTemplate := template.Must(template.ParseFS(uiFS, "ui/index.html"))
|
||||
|
||||
handlers := &handlers{
|
||||
|
||||
15
internal/server/interfaces.go
Normal file
15
internal/server/interfaces.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/qdm12/ddns-updater/internal/records"
|
||||
)
|
||||
|
||||
type Database interface {
|
||||
SelectAll() (records []records.Record)
|
||||
}
|
||||
|
||||
type UpdateForcer interface {
|
||||
ForceUpdate(ctx context.Context) (errors []error)
|
||||
}
|
||||
@@ -5,23 +5,17 @@ import (
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/qdm12/ddns-updater/internal/data"
|
||||
"github.com/qdm12/ddns-updater/internal/update"
|
||||
"github.com/qdm12/golibs/logging"
|
||||
)
|
||||
|
||||
type Server interface {
|
||||
Run(ctx context.Context, done chan<- struct{})
|
||||
}
|
||||
|
||||
type server struct {
|
||||
address string
|
||||
logger logging.Logger
|
||||
handler http.Handler
|
||||
}
|
||||
|
||||
func New(ctx context.Context, address, rootURL string, db data.Database, logger logging.Logger,
|
||||
runner update.Runner) Server {
|
||||
func New(ctx context.Context, address, rootURL string, db Database,
|
||||
logger logging.Logger, runner UpdateForcer) *server {
|
||||
handler := newHandler(ctx, rootURL, db, runner)
|
||||
return &server{
|
||||
address: address,
|
||||
|
||||
@@ -61,7 +61,7 @@ type Settings interface {
|
||||
var ErrProviderUnknown = errors.New("unknown provider")
|
||||
|
||||
//nolint:gocyclo
|
||||
func New(provider models.Provider, data json.RawMessage, domain, host string,
|
||||
func New(provider models.Provider, data json.RawMessage, domain, host string, //nolint:ireturn
|
||||
ipVersion ipversion.IPVersion, matcher regex.Matcher) (
|
||||
settings Settings, err error) {
|
||||
switch provider {
|
||||
|
||||
25
internal/update/interfaces.go
Normal file
25
internal/update/interfaces.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package update
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/qdm12/ddns-updater/internal/records"
|
||||
)
|
||||
|
||||
type PublicIPFetcher interface {
|
||||
IP(ctx context.Context) (net.IP, error)
|
||||
IP4(ctx context.Context) (net.IP, error)
|
||||
IP6(ctx context.Context) (net.IP, error)
|
||||
}
|
||||
|
||||
type Updater interface {
|
||||
Update(ctx context.Context, recordID int, ip net.IP, now time.Time) (err error)
|
||||
}
|
||||
|
||||
type Database interface {
|
||||
Select(recordID int) (record records.Record, err error)
|
||||
SelectAll() (records []records.Record)
|
||||
Update(recordID int, record records.Record) (err error)
|
||||
}
|
||||
@@ -7,36 +7,29 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/qdm12/ddns-updater/internal/constants"
|
||||
"github.com/qdm12/ddns-updater/internal/data"
|
||||
"github.com/qdm12/ddns-updater/internal/models"
|
||||
librecords "github.com/qdm12/ddns-updater/internal/records"
|
||||
"github.com/qdm12/ddns-updater/pkg/publicip"
|
||||
"github.com/qdm12/ddns-updater/pkg/publicip/ipversion"
|
||||
"github.com/qdm12/golibs/logging"
|
||||
)
|
||||
|
||||
type Runner interface {
|
||||
Run(ctx context.Context, done chan<- struct{})
|
||||
ForceUpdate(ctx context.Context) []error
|
||||
}
|
||||
|
||||
type runner struct {
|
||||
period time.Duration
|
||||
db data.Database
|
||||
db Database
|
||||
updater Updater
|
||||
force chan struct{}
|
||||
forceResult chan []error
|
||||
ipv6Mask net.IPMask
|
||||
cooldown time.Duration
|
||||
resolver *net.Resolver
|
||||
ipGetter publicip.Fetcher
|
||||
ipGetter PublicIPFetcher
|
||||
logger logging.Logger
|
||||
timeNow func() time.Time
|
||||
}
|
||||
|
||||
func NewRunner(db data.Database, updater Updater, ipGetter publicip.Fetcher,
|
||||
func NewRunner(db Database, updater Updater, ipGetter PublicIPFetcher,
|
||||
period time.Duration, ipv6Mask net.IPMask, cooldown time.Duration,
|
||||
logger logging.Logger, timeNow func() time.Time) Runner {
|
||||
logger logging.Logger, timeNow func() time.Time) *runner {
|
||||
return &runner{
|
||||
period: period,
|
||||
db: db,
|
||||
@@ -246,7 +239,7 @@ func getIPMatchingVersion(ip, ipv4, ipv6 net.IP, ipVersion ipversion.IPVersion)
|
||||
return nil
|
||||
}
|
||||
|
||||
func setInitialUpToDateStatus(db data.Database, id int, updateIP net.IP, now time.Time) error {
|
||||
func setInitialUpToDateStatus(db Database, id int, updateIP net.IP, now time.Time) error {
|
||||
record, err := db.Select(id)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -9,18 +9,13 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/qdm12/ddns-updater/internal/constants"
|
||||
"github.com/qdm12/ddns-updater/internal/data"
|
||||
"github.com/qdm12/ddns-updater/internal/models"
|
||||
settingserrors "github.com/qdm12/ddns-updater/internal/settings/errors"
|
||||
"github.com/qdm12/golibs/logging"
|
||||
)
|
||||
|
||||
type Updater interface {
|
||||
Update(ctx context.Context, id int, ip net.IP, now time.Time) (err error)
|
||||
}
|
||||
|
||||
type updater struct {
|
||||
db data.Database
|
||||
db Database
|
||||
client *http.Client
|
||||
notify notifyFunc
|
||||
logger logging.Logger
|
||||
@@ -28,7 +23,7 @@ type updater struct {
|
||||
|
||||
type notifyFunc func(message string)
|
||||
|
||||
func NewUpdater(db data.Database, client *http.Client, notify notifyFunc, logger logging.Logger) Updater {
|
||||
func NewUpdater(db Database, client *http.Client, notify notifyFunc, logger logging.Logger) *updater {
|
||||
client = makeLogClient(client, logger)
|
||||
return &updater{
|
||||
db: db,
|
||||
|
||||
@@ -1,18 +1,11 @@
|
||||
package dns
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
type Fetcher interface {
|
||||
IP(ctx context.Context) (publicIP net.IP, err error)
|
||||
IP4(ctx context.Context) (publicIP net.IP, err error)
|
||||
IP6(ctx context.Context) (publicIP net.IP, err error)
|
||||
}
|
||||
|
||||
type fetcher struct {
|
||||
ring ring
|
||||
client Client
|
||||
@@ -26,7 +19,7 @@ type ring struct {
|
||||
providers []Provider
|
||||
}
|
||||
|
||||
func New(options ...Option) (f Fetcher, err error) {
|
||||
func New(options ...Option) (f *fetcher, err error) {
|
||||
settings := newDefaultSettings()
|
||||
for _, option := range options {
|
||||
if err := option(&settings); err != nil {
|
||||
|
||||
@@ -11,12 +11,9 @@ import (
|
||||
func Test_New(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
intf, err := New(SetTimeout(time.Hour))
|
||||
impl, err := New(SetTimeout(time.Hour))
|
||||
require.NoError(t, err)
|
||||
|
||||
impl, ok := intf.(*fetcher)
|
||||
require.True(t, ok)
|
||||
|
||||
assert.NotNil(t, impl.ring.counter)
|
||||
assert.NotEmpty(t, impl.ring.providers)
|
||||
assert.NotNil(t, impl.client)
|
||||
|
||||
@@ -1,20 +1,12 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/qdm12/ddns-updater/pkg/publicip/ipversion"
|
||||
)
|
||||
|
||||
type Fetcher interface {
|
||||
IP(ctx context.Context) (publicIP net.IP, err error)
|
||||
IP4(ctx context.Context) (publicIP net.IP, err error)
|
||||
IP6(ctx context.Context) (publicIP net.IP, err error)
|
||||
}
|
||||
|
||||
type fetcher struct {
|
||||
client *http.Client
|
||||
timeout time.Duration
|
||||
@@ -28,7 +20,7 @@ type urlsRing struct {
|
||||
urls []string
|
||||
}
|
||||
|
||||
func New(client *http.Client, options ...Option) (f Fetcher, err error) {
|
||||
func New(client *http.Client, options ...Option) (f *fetcher, err error) {
|
||||
settings := newDefaultSettings()
|
||||
for _, option := range options {
|
||||
if err := option(&settings); err != nil {
|
||||
|
||||
@@ -75,18 +75,16 @@ func Test_New(t *testing.T) {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
f, err := New(client, testCase.options...)
|
||||
fetcher, err := New(client, testCase.options...)
|
||||
|
||||
if testCase.err != nil {
|
||||
require.Error(t, err)
|
||||
assert.Equal(t, testCase.err.Error(), err.Error())
|
||||
assert.Nil(t, f)
|
||||
assert.Nil(t, fetcher)
|
||||
return
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
implementation, ok := f.(*fetcher)
|
||||
require.True(t, ok)
|
||||
assert.Equal(t, testCase.fetcher, implementation)
|
||||
assert.Equal(t, testCase.fetcher, fetcher)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
"github.com/qdm12/ddns-updater/pkg/publicip/http"
|
||||
)
|
||||
|
||||
type Fetcher interface {
|
||||
type ipFetcher interface {
|
||||
IP(ctx context.Context) (ip net.IP, err error)
|
||||
IP4(ctx context.Context) (ipv4 net.IP, err error)
|
||||
IP6(ctx context.Context) (ipv6 net.IP, err error)
|
||||
@@ -17,14 +17,14 @@ type Fetcher interface {
|
||||
|
||||
type fetcher struct {
|
||||
settings settings
|
||||
fetchers []Fetcher
|
||||
fetchers []ipFetcher
|
||||
// Cycling effect if both are enabled
|
||||
counter *uint32 // 32 bit for 32 bit systems
|
||||
}
|
||||
|
||||
var ErrNoFetchTypeSpecified = errors.New("at least one fetcher type must be specified")
|
||||
|
||||
func NewFetcher(dnsSettings DNSSettings, httpSettings HTTPSettings) (f Fetcher, err error) {
|
||||
func NewFetcher(dnsSettings DNSSettings, httpSettings HTTPSettings) (f *fetcher, err error) {
|
||||
settings := settings{
|
||||
dns: dnsSettings,
|
||||
http: httpSettings,
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
func (f *fetcher) getSubFetcher() Fetcher {
|
||||
func (f *fetcher) getSubFetcher() ipFetcher { //nolint:ireturn
|
||||
fetcher := f.fetchers[0]
|
||||
if len(f.fetchers) > 1 { // cycling effect
|
||||
index := int(atomic.AddUint32(f.counter, 1)) % len(f.fetchers)
|
||||
|
||||
Reference in New Issue
Block a user