2025-09-09 09:07:48 +02:00
|
|
|
|
package pmocover
|
|
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
|
"database/sql"
|
|
|
|
|
|
"path/filepath"
|
|
|
|
|
|
"time"
|
|
|
|
|
|
|
|
|
|
|
|
_ "modernc.org/sqlite"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
// DB représente la base SQLite du cache
|
|
|
|
|
|
type DB struct {
|
|
|
|
|
|
conn *sql.DB
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// InitDB ouvre ou crée la base SQLite dans le répertoire dir
|
|
|
|
|
|
func InitDB(dir string) (*DB, error) {
|
|
|
|
|
|
path := filepath.Join(dir, "cache.db")
|
|
|
|
|
|
conn, err := sql.Open("sqlite", path)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return nil, err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
db := &DB{conn: conn}
|
|
|
|
|
|
if err := db.initTables(); err != nil {
|
|
|
|
|
|
conn.Close()
|
|
|
|
|
|
return nil, err
|
|
|
|
|
|
}
|
|
|
|
|
|
return db, nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// initTables crée la table covers si elle n’existe pas
|
|
|
|
|
|
func (db *DB) initTables() error {
|
|
|
|
|
|
_, err := db.conn.Exec(`
|
|
|
|
|
|
CREATE TABLE IF NOT EXISTS covers (
|
|
|
|
|
|
pk TEXT PRIMARY KEY,
|
|
|
|
|
|
source_url TEXT,
|
|
|
|
|
|
hits INTEGER DEFAULT 0,
|
|
|
|
|
|
last_used TEXT
|
|
|
|
|
|
);
|
|
|
|
|
|
`)
|
|
|
|
|
|
return err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Add ajoute ou met à jour une entrée cover
|
|
|
|
|
|
func (db *DB) Add(pk, url string) error {
|
|
|
|
|
|
_, err := db.conn.Exec(`
|
|
|
|
|
|
INSERT INTO covers(pk, source_url, hits, last_used)
|
|
|
|
|
|
VALUES(?, ?, 0, ?)
|
|
|
|
|
|
ON CONFLICT(pk) DO UPDATE SET
|
|
|
|
|
|
source_url=excluded.source_url,
|
|
|
|
|
|
last_used=excluded.last_used;
|
|
|
|
|
|
`, pk, url, time.Now().UTC().Format(time.RFC3339))
|
|
|
|
|
|
return err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Get récupère une entrée
|
|
|
|
|
|
func (db *DB) Get(pk string) (*CacheEntry, error) {
|
|
|
|
|
|
row := db.conn.QueryRow(`
|
|
|
|
|
|
SELECT pk, source_url, hits, last_used
|
|
|
|
|
|
FROM covers
|
|
|
|
|
|
WHERE pk = ?
|
|
|
|
|
|
`, pk)
|
|
|
|
|
|
entry := &CacheEntry{}
|
|
|
|
|
|
var lastUsed sql.NullString
|
|
|
|
|
|
err := row.Scan(&entry.PK, &entry.SourceURL, &entry.Hits, &lastUsed)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return nil, err
|
|
|
|
|
|
}
|
|
|
|
|
|
if lastUsed.Valid {
|
|
|
|
|
|
entry.LastUsed = lastUsed.String
|
|
|
|
|
|
}
|
|
|
|
|
|
return entry, nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// UpdateHit incrémente hits et met à jour last_used
|
|
|
|
|
|
func (db *DB) UpdateHit(pk string) error {
|
|
|
|
|
|
_, err := db.conn.Exec(`
|
|
|
|
|
|
UPDATE covers
|
|
|
|
|
|
SET hits = hits + 1,
|
|
|
|
|
|
last_used = ?
|
|
|
|
|
|
WHERE pk = ?
|
|
|
|
|
|
`, time.Now().UTC().Format(time.RFC3339), pk)
|
|
|
|
|
|
return err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Purge supprime toutes les entrées de la base
|
|
|
|
|
|
func (db *DB) Purge() error {
|
|
|
|
|
|
_, err := db.conn.Exec(`DELETE FROM covers`)
|
|
|
|
|
|
return err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// GetAll récupère toutes les entrées triées par hits décroissant
|
|
|
|
|
|
func (db *DB) GetAll() ([]*CacheEntry, error) {
|
|
|
|
|
|
rows, err := db.conn.Query(`
|
|
|
|
|
|
SELECT pk, source_url, hits, last_used
|
|
|
|
|
|
FROM covers
|
|
|
|
|
|
ORDER BY hits DESC
|
|
|
|
|
|
`)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return nil, err
|
|
|
|
|
|
}
|
|
|
|
|
|
defer rows.Close()
|
|
|
|
|
|
|
|
|
|
|
|
var entries []*CacheEntry
|
|
|
|
|
|
for rows.Next() {
|
|
|
|
|
|
entry := &CacheEntry{}
|
|
|
|
|
|
var lastUsed sql.NullString
|
|
|
|
|
|
if err := rows.Scan(&entry.PK, &entry.SourceURL, &entry.Hits, &lastUsed); err != nil {
|
|
|
|
|
|
continue
|
|
|
|
|
|
}
|
|
|
|
|
|
if lastUsed.Valid {
|
|
|
|
|
|
entry.LastUsed = lastUsed.String
|
|
|
|
|
|
}
|
|
|
|
|
|
entries = append(entries, entry)
|
|
|
|
|
|
}
|
|
|
|
|
|
return entries, nil
|
|
|
|
|
|
}
|
2025-09-09 19:49:49 +02:00
|
|
|
|
|
|
|
|
|
|
// Delete supprime une entrée spécifique
|
|
|
|
|
|
func (db *DB) Delete(pk string) error {
|
|
|
|
|
|
_, err := db.conn.Exec(`DELETE FROM covers WHERE pk = ?`, pk)
|
|
|
|
|
|
return err
|
|
|
|
|
|
}
|