feat: Go SearXNG client; throttled is not absence (#16)
This commit is contained in:
@@ -0,0 +1,97 @@
|
||||
package websearch
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
_ "modernc.org/sqlite"
|
||||
)
|
||||
|
||||
const cacheSchema = `
|
||||
CREATE TABLE IF NOT EXISTS responses (
|
||||
key TEXT PRIMARY KEY,
|
||||
fetched REAL NOT NULL,
|
||||
payload TEXT NOT NULL
|
||||
);
|
||||
CREATE TABLE IF NOT EXISTS meta (
|
||||
key TEXT PRIMARY KEY,
|
||||
value REAL NOT NULL
|
||||
);
|
||||
`
|
||||
|
||||
type Cache struct {
|
||||
db *sql.DB
|
||||
}
|
||||
|
||||
func OpenCache(path string) (*Cache, error) {
|
||||
if err := os.MkdirAll(filepath.Dir(path), 0o700); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
db, err := sql.Open("sqlite", path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if _, err := db.Exec(cacheSchema); err != nil {
|
||||
db.Close()
|
||||
return nil, err
|
||||
}
|
||||
return &Cache{db: db}, nil
|
||||
}
|
||||
|
||||
func (c *Cache) Close() error {
|
||||
if c == nil || c.db == nil {
|
||||
return nil
|
||||
}
|
||||
return c.db.Close()
|
||||
}
|
||||
|
||||
func (c *Cache) Get(key string, ttl, now float64) (*Payload, error) {
|
||||
var fetched float64
|
||||
var raw string
|
||||
err := c.db.QueryRow("SELECT fetched, payload FROM responses WHERE key = ?", key).Scan(&fetched, &raw)
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, nil
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if now-fetched > ttl {
|
||||
return nil, nil
|
||||
}
|
||||
var p Payload
|
||||
if err := json.Unmarshal([]byte(raw), &p); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &p, nil
|
||||
}
|
||||
|
||||
func (c *Cache) Put(key string, p Payload, now float64) error {
|
||||
raw, err := json.Marshal(p)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = c.db.Exec(
|
||||
"INSERT OR REPLACE INTO responses (key, fetched, payload) VALUES (?, ?, ?)",
|
||||
key, now, string(raw),
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *Cache) LastCall() (*float64, error) {
|
||||
var v float64
|
||||
err := c.db.QueryRow("SELECT value FROM meta WHERE key = 'last_call'").Scan(&v)
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, nil
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &v, nil
|
||||
}
|
||||
|
||||
func (c *Cache) MarkCall(now float64) error {
|
||||
_, err := c.db.Exec("INSERT OR REPLACE INTO meta (key, value) VALUES ('last_call', ?)", now)
|
||||
return err
|
||||
}
|
||||
Reference in New Issue
Block a user