Initial restructure of server
This commit is contained in:
47
cache/cache.go
vendored
Normal file
47
cache/cache.go
vendored
Normal file
@ -0,0 +1,47 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
type KeyNotFound struct {
|
||||
key string
|
||||
}
|
||||
|
||||
func (e KeyNotFound) Error() string {
|
||||
return e.key + " " + "not found"
|
||||
}
|
||||
|
||||
type KeyExpired struct {
|
||||
Key string
|
||||
}
|
||||
|
||||
func (e KeyExpired) Error() string {
|
||||
return e.Key + " " + "expired"
|
||||
}
|
||||
|
||||
type CacheIsFull struct {
|
||||
}
|
||||
|
||||
func (e CacheIsFull) Error() string {
|
||||
return "Cache is Full"
|
||||
}
|
||||
|
||||
type SerializerError struct {
|
||||
err error
|
||||
}
|
||||
|
||||
func (e SerializerError) Error() string {
|
||||
return fmt.Sprintf("Serializer error: got %v", e.err)
|
||||
}
|
||||
|
||||
type Cache interface {
|
||||
Get(key string) (Msg *dns.Msg, err error)
|
||||
Set(key string, Msg *dns.Msg) error
|
||||
Exists(key string) bool
|
||||
Remove(key string) error
|
||||
Full() bool
|
||||
Purge() error
|
||||
}
|
70
cache/cache_memcached.go
vendored
Normal file
70
cache/cache_memcached.go
vendored
Normal file
@ -0,0 +1,70 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"github.com/bradfitz/gomemcache/memcache"
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
func NewMemcachedCache(servers []string, expire int32) *MemcachedCache {
|
||||
c := memcache.New(servers...)
|
||||
return &MemcachedCache{
|
||||
backend: c,
|
||||
expire: expire,
|
||||
}
|
||||
}
|
||||
|
||||
type MemcachedCache struct {
|
||||
backend *memcache.Client
|
||||
expire int32
|
||||
}
|
||||
|
||||
func (m *MemcachedCache) Set(key string, msg *dns.Msg) error {
|
||||
var val []byte
|
||||
var err error
|
||||
|
||||
// handle cases for negacache where it sets nil values
|
||||
if msg == nil {
|
||||
val = []byte("nil")
|
||||
} else {
|
||||
val, err = msg.Pack()
|
||||
}
|
||||
if err != nil {
|
||||
err = SerializerError{err}
|
||||
}
|
||||
return m.backend.Set(&memcache.Item{Key: key, Value: val, Expiration: m.expire})
|
||||
}
|
||||
|
||||
func (m *MemcachedCache) Get(key string) (*dns.Msg, error) {
|
||||
var msg dns.Msg
|
||||
item, err := m.backend.Get(key)
|
||||
if err != nil {
|
||||
err = KeyNotFound{key}
|
||||
return &msg, err
|
||||
}
|
||||
err = msg.Unpack(item.Value)
|
||||
if err != nil {
|
||||
err = SerializerError{err}
|
||||
}
|
||||
return &msg, err
|
||||
}
|
||||
|
||||
func (m *MemcachedCache) Exists(key string) bool {
|
||||
_, err := m.backend.Get(key)
|
||||
if err != nil {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (m *MemcachedCache) Remove(key string) error {
|
||||
return m.backend.Delete(key)
|
||||
}
|
||||
|
||||
func (m *MemcachedCache) Full() bool {
|
||||
// memcache is never full (LRU)
|
||||
return false
|
||||
}
|
||||
|
||||
func (m *MemcachedCache) Purge() error {
|
||||
return m.backend.DeleteAll()
|
||||
}
|
100
cache/cache_memory.go
vendored
Normal file
100
cache/cache_memory.go
vendored
Normal file
@ -0,0 +1,100 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"github.com/miekg/dns"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
func NewMemoryCache(expire time.Duration, maxCount int) *MemoryCache {
|
||||
return &MemoryCache{
|
||||
backend: make(map[string]Mesg),
|
||||
Expire: expire,
|
||||
Maxcount: maxCount,
|
||||
}
|
||||
}
|
||||
|
||||
type Mesg struct {
|
||||
Msg *dns.Msg
|
||||
Expire time.Time
|
||||
}
|
||||
|
||||
type MemoryCache struct {
|
||||
Cache
|
||||
|
||||
backend map[string]Mesg
|
||||
Expire time.Duration
|
||||
Maxcount int
|
||||
mu sync.RWMutex
|
||||
}
|
||||
|
||||
func (c *MemoryCache) initialize() {
|
||||
c.backend = make(map[string]Mesg)
|
||||
}
|
||||
|
||||
func (c *MemoryCache) Get(key string) (*dns.Msg, error) {
|
||||
c.mu.RLock()
|
||||
mesg, ok := c.backend[key]
|
||||
c.mu.RUnlock()
|
||||
if !ok {
|
||||
return nil, KeyNotFound{key}
|
||||
}
|
||||
|
||||
if mesg.Expire.Before(time.Now()) {
|
||||
c.Remove(key)
|
||||
return nil, KeyExpired{key}
|
||||
}
|
||||
|
||||
return mesg.Msg, nil
|
||||
|
||||
}
|
||||
|
||||
func (c *MemoryCache) Set(key string, msg *dns.Msg) error {
|
||||
if c.Full() && !c.Exists(key) {
|
||||
return CacheIsFull{}
|
||||
}
|
||||
|
||||
expire := time.Now().Add(c.Expire)
|
||||
mesg := Mesg{msg, expire}
|
||||
c.mu.Lock()
|
||||
c.backend[key] = mesg
|
||||
c.mu.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *MemoryCache) Remove(key string) error {
|
||||
c.mu.Lock()
|
||||
delete(c.backend, key)
|
||||
c.mu.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *MemoryCache) Exists(key string) bool {
|
||||
c.mu.RLock()
|
||||
_, ok := c.backend[key]
|
||||
c.mu.RUnlock()
|
||||
return ok
|
||||
}
|
||||
|
||||
func (c *MemoryCache) Length() int {
|
||||
c.mu.RLock()
|
||||
defer c.mu.RUnlock()
|
||||
return len(c.backend)
|
||||
}
|
||||
|
||||
func (c *MemoryCache) Full() bool {
|
||||
// if Maxcount is zero. the cache will never be full.
|
||||
if c.Maxcount == 0 {
|
||||
return false
|
||||
}
|
||||
return c.Length() >= c.Maxcount
|
||||
}
|
||||
|
||||
func (c *MemoryCache) Purge() error {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
|
||||
c.initialize()
|
||||
|
||||
return nil
|
||||
}
|
100
cache/cache_redis.go
vendored
Normal file
100
cache/cache_redis.go
vendored
Normal file
@ -0,0 +1,100 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"github.com/go-redis/redis/v7"
|
||||
"github.com/miekg/dns"
|
||||
"meow.tf/joker/godns/settings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func NewRedisCache(c settings.RedisSettings, expire int32) *RedisCache {
|
||||
rc := redis.NewClient(&redis.Options{Addr: c.Addr(), DB: c.DB, Password: c.Password})
|
||||
|
||||
return &RedisCache{
|
||||
backend: rc,
|
||||
expire: expire,
|
||||
}
|
||||
}
|
||||
|
||||
type RedisCache struct {
|
||||
Cache
|
||||
|
||||
backend *redis.Client
|
||||
expire int32
|
||||
}
|
||||
|
||||
func (m *RedisCache) Set(key string, msg *dns.Msg) error {
|
||||
var val []byte
|
||||
var err error
|
||||
|
||||
key = "cache:" + key
|
||||
|
||||
// handle cases for negacache where it sets nil values
|
||||
if msg == nil {
|
||||
val = []byte("nil")
|
||||
} else {
|
||||
val, err = msg.Pack()
|
||||
}
|
||||
if err != nil {
|
||||
err = SerializerError{err}
|
||||
}
|
||||
return m.backend.Set(key, val, time.Duration(m.expire) * time.Second).Err()
|
||||
}
|
||||
|
||||
func (m *RedisCache) Get(key string) (*dns.Msg, error) {
|
||||
var msg dns.Msg
|
||||
var err error
|
||||
key = "cache:" + key
|
||||
|
||||
item, err := m.backend.Get(key).Bytes()
|
||||
|
||||
if err != nil {
|
||||
err = KeyNotFound{key}
|
||||
return &msg, err
|
||||
}
|
||||
|
||||
err = msg.Unpack(item)
|
||||
if err != nil {
|
||||
err = SerializerError{err}
|
||||
}
|
||||
return &msg, err
|
||||
}
|
||||
|
||||
func (m *RedisCache) Exists(key string) bool {
|
||||
res, err := m.backend.Exists(key).Result()
|
||||
|
||||
if err != nil {
|
||||
return true
|
||||
}
|
||||
|
||||
return res == 1
|
||||
}
|
||||
|
||||
func (m *RedisCache) Remove(key string) error {
|
||||
return m.backend.Del(key).Err()
|
||||
}
|
||||
|
||||
func (m *RedisCache) Full() bool {
|
||||
// redis is never full (LRU)
|
||||
return false
|
||||
}
|
||||
|
||||
func (m *RedisCache) Purge() error {
|
||||
iter := m.backend.Scan(0, "cache:*", 0).Iterator()
|
||||
|
||||
if iter.Err() != nil {
|
||||
return iter.Err()
|
||||
}
|
||||
|
||||
var err error
|
||||
|
||||
for iter.Next() {
|
||||
err = m.backend.Del(iter.Val()).Err()
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
Reference in New Issue
Block a user