Start refactor
Cette révision appartient à :
Parent
006dc1c034
révision
496e1d4ba4
|
@ -1,33 +0,0 @@
|
|||
package cache
|
||||
|
||||
import (
|
||||
"github.com/NyaaPantsu/nyaa/cache/memcache"
|
||||
"github.com/NyaaPantsu/nyaa/cache/nop"
|
||||
"github.com/NyaaPantsu/nyaa/common"
|
||||
"github.com/NyaaPantsu/nyaa/config"
|
||||
"github.com/NyaaPantsu/nyaa/model"
|
||||
)
|
||||
|
||||
// Cache defines interface for caching search results
|
||||
type Cache interface {
|
||||
Get(key common.SearchParam, r func() ([]model.Torrent, int, error)) ([]model.Torrent, int, error)
|
||||
ClearAll()
|
||||
}
|
||||
|
||||
// Impl cache implementation instance
|
||||
var Impl Cache
|
||||
|
||||
func Configure(conf *config.CacheConfig) (err error) {
|
||||
switch conf.Dialect {
|
||||
/*case "native":
|
||||
Impl = native.New(conf.Size)
|
||||
return
|
||||
*/
|
||||
case "memcache":
|
||||
Impl = memcache.New()
|
||||
return
|
||||
default:
|
||||
Impl = nop.New()
|
||||
}
|
||||
return
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
package memcache
|
||||
|
||||
import (
|
||||
"github.com/NyaaPantsu/nyaa/common"
|
||||
"github.com/NyaaPantsu/nyaa/model"
|
||||
)
|
||||
|
||||
type Memcache struct {
|
||||
}
|
||||
|
||||
func (c *Memcache) Get(key common.SearchParam, r func() ([]model.Torrent, int, error)) (torrents []model.Torrent, num int, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (c *Memcache) ClearAll() {
|
||||
|
||||
}
|
||||
|
||||
func New() *Memcache {
|
||||
return &Memcache{}
|
||||
}
|
|
@ -1,145 +0,0 @@
|
|||
package native
|
||||
|
||||
/*
|
||||
import (
|
||||
"container/list"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/NyaaPantsu/nyaa/common"
|
||||
"github.com/NyaaPantsu/nyaa/model"
|
||||
)
|
||||
|
||||
const expiryTime = time.Minute
|
||||
|
||||
// NativeCache implements cache.Cache
|
||||
type NativeCache struct {
|
||||
cache map[common.SearchParam]*list.Element
|
||||
ll *list.List
|
||||
totalUsed int
|
||||
mu sync.Mutex
|
||||
|
||||
// Size sets the maximum size of the cache before evicting unread data in MB
|
||||
Size float64
|
||||
}
|
||||
|
||||
// New Creates New Native Cache instance
|
||||
func New(sz float64) *NativeCache {
|
||||
return &NativeCache{
|
||||
cache: make(map[common.SearchParam]*list.Element, 10),
|
||||
Size: sz,
|
||||
ll: list.New(),
|
||||
}
|
||||
}
|
||||
|
||||
// Key stores the ID of either a thread or board page
|
||||
type Key struct {
|
||||
LastN uint8
|
||||
Board string
|
||||
ID uint64
|
||||
}
|
||||
|
||||
// Single cache entry
|
||||
type store struct {
|
||||
sync.Mutex // Controls general access to the contents of the struct
|
||||
lastFetched time.Time
|
||||
key common.SearchParam
|
||||
data []model.Torrent
|
||||
count, size int
|
||||
n *NativeCache
|
||||
}
|
||||
|
||||
// Check the cache for and existing record. If miss, run fn to retrieve fresh
|
||||
// values.
|
||||
func (n *NativeCache) Get(key common.SearchParam, fn func() ([]model.Torrent, int, error)) (
|
||||
data []model.Torrent, count int, err error,
|
||||
) {
|
||||
s := n.getStore(key)
|
||||
|
||||
// Also keeps multiple requesters from simultaneously requesting the same
|
||||
// data
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
||||
if s.isFresh() {
|
||||
return s.data, s.count, nil
|
||||
}
|
||||
|
||||
data, count, err = fn()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
s.update(data, count)
|
||||
return
|
||||
}
|
||||
|
||||
// Retrieve a store from the cache or create a new one
|
||||
func (n *NativeCache) getStore(k common.SearchParam) (s *store) {
|
||||
n.mu.Lock()
|
||||
defer n.mu.Unlock()
|
||||
|
||||
el := n.cache[k]
|
||||
if el == nil {
|
||||
s = &store{key: k, n: n}
|
||||
n.cache[k] = n.ll.PushFront(s)
|
||||
} else {
|
||||
n.ll.MoveToFront(el)
|
||||
s = el.Value.(*store)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// Clear the cache. Only used for testing.
|
||||
func (n *NativeCache) ClearAll() {
|
||||
n.mu.Lock()
|
||||
defer n.mu.Unlock()
|
||||
|
||||
n.ll = list.New()
|
||||
n.cache = make(map[common.SearchParam]*list.Element, 10)
|
||||
}
|
||||
|
||||
// Update the total used memory counter and evict, if over limit
|
||||
func (n *NativeCache) updateUsedSize(delta int) {
|
||||
n.mu.Lock()
|
||||
defer n.mu.Unlock()
|
||||
|
||||
n.totalUsed += delta
|
||||
|
||||
for n.totalUsed > int(n.Size)<<20 {
|
||||
e := n.ll.Back()
|
||||
if e == nil {
|
||||
break
|
||||
}
|
||||
s := n.ll.Remove(e).(*store)
|
||||
delete(n.cache, s.key)
|
||||
s.Lock()
|
||||
n.totalUsed -= s.size
|
||||
s.Unlock()
|
||||
}
|
||||
}
|
||||
|
||||
// Return, if the data can still be considered fresh, without querying the DB
|
||||
func (s *store) isFresh() bool {
|
||||
if s.lastFetched.IsZero() { // New store
|
||||
return false
|
||||
}
|
||||
return s.lastFetched.Add(expiryTime).After(time.Now())
|
||||
}
|
||||
|
||||
// Stores the new values of s. Calculates and stores the new size. Passes the
|
||||
// delta to the central cache to fire eviction checks.
|
||||
func (s *store) update(data []model.Torrent, count int) {
|
||||
newSize := 0
|
||||
for _, d := range data {
|
||||
newSize += d.Size()
|
||||
}
|
||||
s.data = data
|
||||
s.count = count
|
||||
delta := newSize - s.size
|
||||
s.size = newSize
|
||||
s.lastFetched = time.Now()
|
||||
|
||||
// In a separate goroutine, to ensure there is never any lock intersection
|
||||
go s.n.updateUsedSize(delta)
|
||||
}
|
||||
*/
|
|
@ -1,49 +0,0 @@
|
|||
package native
|
||||
|
||||
/*
|
||||
import (
|
||||
"path"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/NyaaPantsu/nyaa/common"
|
||||
"github.com/NyaaPantsu/nyaa/config"
|
||||
"github.com/NyaaPantsu/nyaa/model"
|
||||
)
|
||||
|
||||
// run before config/parse.go:init()
|
||||
var _ = func() (_ struct{}) {
|
||||
config.ConfigPath = path.Join("..", "..", config.ConfigPath)
|
||||
config.DefaultConfigPath = path.Join("..", "..", config.DefaultConfigPath)
|
||||
config.Parse()
|
||||
return
|
||||
}()
|
||||
|
||||
// Basic test for deadlocks and race conditions
|
||||
func TestConcurrency(t *testing.T) {
|
||||
c := New(0.000001)
|
||||
|
||||
fn := func() ([]model.Torrent, int, error) {
|
||||
return []model.Torrent{{}, {}, {}}, 10, nil
|
||||
}
|
||||
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(300)
|
||||
for i := 0; i < 3; i++ {
|
||||
go func() {
|
||||
for j := 0; j < 100; j++ {
|
||||
go func(j int) {
|
||||
defer wg.Done()
|
||||
k := common.SearchParam{
|
||||
Page: j,
|
||||
}
|
||||
if _, _, err := c.Get(k, fn); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}(j)
|
||||
}
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
*/
|
|
@ -1,22 +0,0 @@
|
|||
package nop
|
||||
|
||||
import (
|
||||
"github.com/NyaaPantsu/nyaa/common"
|
||||
"github.com/NyaaPantsu/nyaa/model"
|
||||
)
|
||||
|
||||
type NopCache struct {
|
||||
}
|
||||
|
||||
func (c *NopCache) Get(key common.SearchParam, fn func() ([]model.Torrent, int, error)) ([]model.Torrent, int, error) {
|
||||
return fn()
|
||||
}
|
||||
|
||||
func (c *NopCache) ClearAll() {
|
||||
|
||||
}
|
||||
|
||||
// New creates a new Cache that does NOTHING :D
|
||||
func New() *NopCache {
|
||||
return &NopCache{}
|
||||
}
|
|
@ -1,110 +0,0 @@
|
|||
package database
|
||||
|
||||
import (
|
||||
"github.com/NyaaPantsu/nyaa/common"
|
||||
"github.com/NyaaPantsu/nyaa/config"
|
||||
"github.com/NyaaPantsu/nyaa/database/postgres"
|
||||
//"github.com/NyaaPantsu/nyaa/db/sqlite"
|
||||
"github.com/NyaaPantsu/nyaa/model"
|
||||
"github.com/NyaaPantsu/nyaa/util/log"
|
||||
|
||||
"errors"
|
||||
)
|
||||
|
||||
// Database obstraction layer
|
||||
type Database interface {
|
||||
|
||||
// Initialize internal state
|
||||
Init() error
|
||||
|
||||
// return true if we need to call MigrateNext again
|
||||
NeedsMigrate() (bool, error)
|
||||
// migrate to next database revision
|
||||
MigrateNext() error
|
||||
|
||||
// get torrents given parameters
|
||||
GetTorrentsWhere(param *common.TorrentParam) ([]model.Torrent, error)
|
||||
|
||||
// insert new comment
|
||||
InsertComment(comment *model.Comment) error
|
||||
// new torrent report
|
||||
InsertTorrentReport(report *model.TorrentReport) error
|
||||
|
||||
// check if user A follows B (by id)
|
||||
UserFollows(a, b uint32) (bool, error)
|
||||
|
||||
// delete reports given params
|
||||
DeleteTorrentReportsWhere(param *common.ReportParam) (uint32, error)
|
||||
|
||||
// get reports given params
|
||||
GetTorrentReportsWhere(param *common.ReportParam) ([]model.TorrentReport, error)
|
||||
|
||||
// bulk record scrape events in 1 transaction
|
||||
RecordScrapes(scrapes []common.ScrapeResult) error
|
||||
|
||||
// insert new user
|
||||
InsertUser(u *model.User) error
|
||||
|
||||
// update existing user info
|
||||
UpdateUser(u *model.User) error
|
||||
|
||||
// get users given paramteters
|
||||
GetUsersWhere(param *common.UserParam) ([]model.User, error)
|
||||
|
||||
// delete many users given parameters
|
||||
DeleteUsersWhere(param *common.UserParam) (uint32, error)
|
||||
|
||||
// get comments by given parameters
|
||||
GetCommentsWhere(param *common.CommentParam) ([]model.Comment, error)
|
||||
|
||||
// delete comment by given parameters
|
||||
DeleteCommentsWhere(param *common.CommentParam) (uint32, error)
|
||||
|
||||
// add user A following B
|
||||
AddUserFollowing(a, b uint32) error
|
||||
|
||||
// delete user A following B
|
||||
DeleteUserFollowing(a, b uint32) (bool, error)
|
||||
|
||||
// insert/update torrent
|
||||
UpsertTorrent(t *model.Torrent) error
|
||||
|
||||
// XXX: add more as needed
|
||||
}
|
||||
|
||||
var errInvalidDatabaseDialect = errors.New("invalid database dialect")
|
||||
var errSqliteSucksAss = errors.New("sqlite3 sucks ass so it's not supported yet")
|
||||
|
||||
// Impl : Database variable
|
||||
var Impl Database
|
||||
|
||||
// Configure : Configure Database
|
||||
func Configure(conf *config.Config) (err error) {
|
||||
switch conf.DBType {
|
||||
case "postgres":
|
||||
Impl, err = postgres.New(conf.DBParams)
|
||||
case "sqlite3":
|
||||
err = errSqliteSucksAss
|
||||
// Impl, err = sqlite.New(conf.DBParams)
|
||||
default:
|
||||
err = errInvalidDatabaseDialect
|
||||
}
|
||||
if err == nil {
|
||||
log.Infof("Init %s database", conf.DBType)
|
||||
err = Impl.Init()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Migrate migrates the database to latest revision, call after Configure
|
||||
func Migrate() (err error) {
|
||||
next := true
|
||||
for err == nil && next {
|
||||
next, err = Impl.NeedsMigrate()
|
||||
if next {
|
||||
err = Impl.MigrateNext()
|
||||
}
|
||||
|
||||
}
|
||||
return
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
package postgres
|
||||
|
||||
import (
|
||||
"github.com/NyaaPantsu/nyaa/common"
|
||||
"github.com/NyaaPantsu/nyaa/model"
|
||||
)
|
||||
|
||||
// InsertComment : Insert a comment
|
||||
func (db *Database) InsertComment(comment *model.Comment) (err error) {
|
||||
_, err = db.getPrepared(queryInsertComment).Exec(comment.ID, comment.TorrentID, comment.Content, comment.CreatedAt)
|
||||
return
|
||||
}
|
||||
|
||||
// GetCommentsWhere : Get comments on condition
|
||||
func (db *Database) GetCommentsWhere(param *common.CommentParam) (comments []model.Comment, err error) {
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// DeleteCommentsWhere : Delete comments on condition
|
||||
func (db *Database) DeleteCommentsWhere(param *common.CommentParam) (deleted uint32, err error) {
|
||||
|
||||
return
|
||||
}
|
|
@ -1,91 +0,0 @@
|
|||
package postgres
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// sql query
|
||||
type sqlQuery struct {
|
||||
query string
|
||||
params []interface{}
|
||||
}
|
||||
|
||||
func (q *sqlQuery) Exec(conn *sql.DB) (err error) {
|
||||
_, err = conn.Exec(q.query, q.params...)
|
||||
return
|
||||
}
|
||||
|
||||
func (q *sqlQuery) QueryRow(conn *sql.DB, visitor func(*sql.Row) error) (err error) {
|
||||
err = visitor(conn.QueryRow(q.query, q.params))
|
||||
return
|
||||
}
|
||||
|
||||
func (q *sqlQuery) Query(conn *sql.DB, visitor func(*sql.Rows) error) (err error) {
|
||||
var rows *sql.Rows
|
||||
rows, err = conn.Query(q.query, q.params...)
|
||||
if err == sql.ErrNoRows {
|
||||
err = nil
|
||||
} else if err == nil {
|
||||
err = visitor(rows)
|
||||
rows.Close()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// make a createQuery that creates an index for column on table
|
||||
func createIndex(table, column string) sqlQuery {
|
||||
return sqlQuery{
|
||||
query: fmt.Sprintf("CREATE INDEX IF NOT EXISTS ON %s %s ", table, column),
|
||||
}
|
||||
}
|
||||
|
||||
// make a createQuery that creates a trigraph index on a table for multiple columns
|
||||
func createTrigraph(table string, columns ...string) sqlQuery {
|
||||
return sqlQuery{
|
||||
query: fmt.Sprintf("CREATE INDEX IF NOT EXISTS ON %s USING gin(%s gin_trgm_ops)", table, strings.Join(columns, ", ")),
|
||||
}
|
||||
}
|
||||
|
||||
// defines table creation info
|
||||
type createTable struct {
|
||||
name string // Table's name
|
||||
columns tableColumns // Table's columns
|
||||
preCreate []sqlQuery // Queries to run before table is ensrued
|
||||
postCreate []sqlQuery // Queries to run after table is ensured
|
||||
}
|
||||
|
||||
func (t createTable) String() string {
|
||||
return fmt.Sprintf("CREATE TABLE %s IF NOT EXISTS ( %s )", t.name, t.columns)
|
||||
}
|
||||
|
||||
func (t createTable) Exec(conn *sql.DB) (err error) {
|
||||
// pre queries
|
||||
for idx := range t.preCreate {
|
||||
err = t.preCreate[idx].Exec(conn)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
// table definition
|
||||
_, err = conn.Exec(t.String())
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// post queries
|
||||
for idx := range t.postCreate {
|
||||
err = t.postCreate[idx].Exec(conn)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// tableColumns is a list of columns for a table to be created
|
||||
type tableColumns []string
|
||||
|
||||
func (def tableColumns) String() string {
|
||||
return strings.Join(def, ", ")
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
package postgres
|
||||
|
||||
func (db *Database) MigrateNext() (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (db *Database) NeedsMigrate() (needs bool, err error) {
|
||||
return
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
package postgres
|
|
@ -1,88 +0,0 @@
|
|||
package postgres
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
|
||||
"github.com/NyaaPantsu/nyaa/util/log"
|
||||
_ "github.com/lib/pq"
|
||||
)
|
||||
|
||||
func New(param string) (db *Database, err error) {
|
||||
db = new(Database)
|
||||
db.conn, err = sql.Open("postgres", param)
|
||||
if err != nil {
|
||||
db = nil
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
type Database struct {
|
||||
conn *sql.DB
|
||||
prepared map[string]*sql.Stmt
|
||||
}
|
||||
|
||||
func (db *Database) getPrepared(name string) *sql.Stmt {
|
||||
return db.prepared[name]
|
||||
}
|
||||
|
||||
func (db *Database) Query(q string, param ...interface{}) (*sql.Rows, error) {
|
||||
return db.conn.Query(q, param...)
|
||||
}
|
||||
|
||||
func (db *Database) Init() (err error) {
|
||||
|
||||
// ensure tables
|
||||
for idx := range tables {
|
||||
log.Debugf("ensure table %s", tables[idx].name)
|
||||
err = tables[idx].Exec(db.conn)
|
||||
if err != nil {
|
||||
log.Errorf("Failed to ensure table %s: %s", tables[idx].name, err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// generate prepared statements
|
||||
for k := range statements {
|
||||
var stmt *sql.Stmt
|
||||
stmt, err = db.conn.Prepare(statements[k])
|
||||
if err != nil {
|
||||
log.Errorf("failed to build prepared statement %s: %s", k, err.Error())
|
||||
return
|
||||
}
|
||||
db.prepared[k] = stmt
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// execute prepared statement with arguments, visit result and autoclose rows after done visiting
|
||||
func (db *Database) queryWithPrepared(name string, visit func(*sql.Rows) error, params ...interface{}) (err error) {
|
||||
var rows *sql.Rows
|
||||
rows, err = db.getPrepared(name).Query(params...)
|
||||
if err == sql.ErrNoRows {
|
||||
err = nil
|
||||
} else if err == nil {
|
||||
err = visit(rows)
|
||||
rows.Close()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// execute prepared statement with arguments, visit single row
|
||||
func (db *Database) queryRowWithPrepared(name string, visit func(*sql.Row) error, params ...interface{}) (err error) {
|
||||
err = visit(db.getPrepared(name).QueryRow(params...))
|
||||
return
|
||||
}
|
||||
|
||||
// execute a query by name and return how many rows were affected
|
||||
func (db *Database) execQuery(name string, p ...interface{}) (affected uint32, err error) {
|
||||
var result sql.Result
|
||||
result, err = db.getPrepared(name).Exec(p...)
|
||||
if err == nil {
|
||||
var d int64
|
||||
d, err = result.RowsAffected()
|
||||
if err == nil {
|
||||
affected = uint32(d)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
|
@ -1,64 +0,0 @@
|
|||
package postgres
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
|
||||
"github.com/NyaaPantsu/nyaa/common"
|
||||
"github.com/NyaaPantsu/nyaa/model"
|
||||
)
|
||||
|
||||
func (db *Database) InsertTorrentReport(report *model.TorrentReport) (err error) {
|
||||
_, err = db.getPrepared(queryInsertTorrentReport).Exec(report.Description, report.TorrentID, report.UserID, report.CreatedAt)
|
||||
return
|
||||
}
|
||||
|
||||
func reportParamToQuery(param *common.ReportParam) (q sqlQuery) {
|
||||
q.query += fmt.Sprintf("SELECT %s FROM %s WHERE created_at IS NOT NULL ", torrentReportSelectColumnsFull, tableTorrentReports)
|
||||
|
||||
counter := 1
|
||||
|
||||
if !param.AllTime {
|
||||
q.query += fmt.Sprintf("AND created_at < $%d AND created_at > $%d", counter, counter+1)
|
||||
q.params = append(q.params, param.Before, param.After)
|
||||
counter += 2
|
||||
}
|
||||
|
||||
if param.Limit > 0 {
|
||||
q.query += fmt.Sprintf("LIMIT $%d ", counter)
|
||||
q.params = append(q.params, param.Limit)
|
||||
counter++
|
||||
}
|
||||
if param.Offset > 0 {
|
||||
q.query += fmt.Sprintf("OFFSET $%d ", counter)
|
||||
q.params = append(q.params, param.Offset)
|
||||
counter++
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (db *Database) GetTorrentReportsWhere(param *common.ReportParam) (reports []model.TorrentReport, err error) {
|
||||
q := reportParamToQuery(param)
|
||||
err = q.Query(db.conn, func(rows *sql.Rows) error {
|
||||
for rows.Next() {
|
||||
var r model.TorrentReport
|
||||
scanTorrentReportColumnsFull(rows, &r)
|
||||
reports = append(reports, r)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
func (db *Database) DeleteTorrentReportByID(id uint32) (err error) {
|
||||
_, err = db.getPrepared(queryDeleteTorrentReportByID).Exec(id)
|
||||
if err == sql.ErrNoRows {
|
||||
err = nil
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (db *Database) DeleteTorrentReportsWhere(param *common.ReportParam) (deleted uint32, err error) {
|
||||
|
||||
return
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
package postgres
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"github.com/NyaaPantsu/nyaa/common"
|
||||
)
|
||||
|
||||
func (db *Database) RecordScrapes(scrape []common.ScrapeResult) (err error) {
|
||||
if len(scrape) > 0 {
|
||||
var tx *sql.Tx
|
||||
tx, err = db.conn.Begin()
|
||||
if err == nil {
|
||||
st := tx.Stmt(db.getPrepared(queryInsertScrape))
|
||||
for idx := range scrape {
|
||||
_, err = st.Exec(scrape[idx].Seeders, scrape[idx].Leechers, scrape[idx].Completed, scrape[idx].Date, scrape[idx].TorrentID)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if err == nil {
|
||||
err = tx.Commit()
|
||||
} else {
|
||||
tx.Rollback()
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
|
@ -1,73 +0,0 @@
|
|||
package postgres
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
|
||||
"github.com/NyaaPantsu/nyaa/model"
|
||||
)
|
||||
|
||||
const queryGetAllTorrents = "GetAllTorrents"
|
||||
const queryGetTorrentByID = "GetTorrentByID"
|
||||
const queryInsertComment = "InsertComment"
|
||||
const queryInsertUser = "InsertUser"
|
||||
const queryInsertTorrentReport = "InsertTorrentReport"
|
||||
const queryUserFollows = "UserFollows"
|
||||
const queryDeleteTorrentReportByID = "DeleteTorrentReportByID"
|
||||
const queryInsertScrape = "InsertScrape"
|
||||
const queryGetUserByApiToken = "GetUserByApiToken"
|
||||
const queryGetUserByEmail = "GetUserByEmail"
|
||||
const queryGetUserByName = "GetUserByName"
|
||||
const queryGetUserByID = "GetUserByID"
|
||||
const queryUpdateUser = "UpdateUser"
|
||||
const queryDeleteUserByID = "DeleteUserByID"
|
||||
const queryDeleteUserByEmail = "DeleteUserByEmail"
|
||||
const queryDeleteUserByToken = "DeleteUserByToken"
|
||||
const queryUserFollowsUpsert = "UserFollowsUpsert"
|
||||
const queryDeleteUserFollowing = "DeleteUserFollowing"
|
||||
|
||||
const torrentSelectColumnsFull = `torrent_id, torrent_name, torrent_hash, category, sub_category, status, date, uploader, downloads, stardom, description, website_link, deleted_at, seeders, leechers, completed, last_scrape`
|
||||
|
||||
func scanTorrentColumnsFull(rows *sql.Rows, t *model.Torrent) {
|
||||
rows.Scan(&t.ID, &t.Name, &t.Hash, &t.Category, &t.SubCategory, &t.Status, &t.Date, &t.UploaderID, &t.Downloads, &t.Stardom, &t.Description, &t.WebsiteLink, &t.DeletedAt, &t.Scrape.Seeders, &t.Scrape.Leechers, &t.Scrape.Completed, &t.Scrape.LastScrape)
|
||||
}
|
||||
|
||||
const commentSelectColumnsFull = `comment_id, torrent_id, user_id, content, created_at, updated_at, deleted_at`
|
||||
|
||||
func scanCommentColumnsFull(rows *sql.Rows, c *model.Comment) {
|
||||
|
||||
}
|
||||
|
||||
const torrentReportSelectColumnsFull = `torrent_report_id, type, torrent_id, user_id, created_at`
|
||||
|
||||
func scanTorrentReportColumnsFull(rows *sql.Rows, r *model.TorrentReport) {
|
||||
rows.Scan(&r.ID, &r.Description, &r.TorrentID, &r.UserID, &r.CreatedAt)
|
||||
}
|
||||
|
||||
const userSelectColumnsFull = `user_id, username, password, email, status, created_at, updated_at, api_token, api_token_expiry, language, md5`
|
||||
|
||||
func scanUserColumnsFull(rows *sql.Rows, u *model.User) {
|
||||
rows.Scan(&u.ID, &u.Username, &u.Password, &u.Email, &u.Status, &u.CreatedAt, &u.UpdatedAt, &u.APIToken, &u.APITokenExpiry, &u.Language, &u.MD5)
|
||||
|
||||
}
|
||||
|
||||
var statements = map[string]string{
|
||||
queryGetTorrentByID: fmt.Sprintf("SELECT %s FROM %s WHERE torrent_id = $1 LIMIT 1", torrentSelectColumnsFull, tableTorrents),
|
||||
queryGetAllTorrents: fmt.Sprintf("SELECT %s FROM %s LIMIT $2 OFFSET $1", torrentSelectColumnsFull, tableTorrents),
|
||||
queryInsertComment: fmt.Sprintf("INSERT INTO %s (comment_id, torrent_id, content, created_at) VALUES ($1, $2, $3, $4)", tableComments),
|
||||
queryInsertTorrentReport: fmt.Sprintf("INSERT INTO %s (type, torrent_id, user_id, created_at) VALUES ($1, $2, $3, $4)", tableTorrentReports),
|
||||
queryUserFollows: fmt.Sprintf("SELECT user_id, following FROM %s WHERE user_id = $1 AND following = $1 LIMIT 1", tableUserFollows),
|
||||
queryDeleteTorrentReportByID: fmt.Sprintf("DELETE FROM %s WHERE torrent_report_id = $1", tableTorrentReports),
|
||||
queryInsertScrape: fmt.Sprintf("UPDATE %s SET (seeders = $1, leechers = $2, completed = $3, last_scrape = $4 ) WHERE torrent_id = $5", tableTorrents),
|
||||
queryGetUserByApiToken: fmt.Sprintf("SELECT %s FROM %s WHERE api_token = $1", userSelectColumnsFull, tableUsers),
|
||||
queryGetUserByEmail: fmt.Sprintf("SELECT %s FROM %s WHERE email = $1", userSelectColumnsFull, tableUsers),
|
||||
queryGetUserByName: fmt.Sprintf("SELECT %s FROM %s WHERE username = $1", userSelectColumnsFull, tableUsers),
|
||||
queryGetUserByID: fmt.Sprintf("SELECT %s FROM %s WHERE user_id = $1", userSelectColumnsFull, tableUsers),
|
||||
queryInsertUser: fmt.Sprintf("INSERT INTO %s (username, password, email, status, created_at, updated_at, last_login_at, api_token, api_token_expires, language, md5 ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)", tableUsers),
|
||||
queryUpdateUser: fmt.Sprintf("UPDATE %s SET (username = $2, password = $3 , email = $4, status = $5, updated_at = $6, last_login_at = $7 , api_token = $8 , api_token_expiry = $9 , language = $10 , md5 = $11 ) WHERE user_id = $1", tableUsers),
|
||||
queryDeleteUserByID: fmt.Sprintf("DELETE FROM %s WHERE user_id = $1", tableUsers),
|
||||
queryDeleteUserByEmail: fmt.Sprintf("DELETE FROM %s WHERE email = $1", tableUsers),
|
||||
queryDeleteUserByToken: fmt.Sprintf("DELETE FROM %s WHERE api_token = $1", tableUsers),
|
||||
queryUserFollowsUpsert: fmt.Sprintf("INSERT INTO %s VALUES(user_id, following) ($1, $2) ON CONFLICT DO UPDATE", tableUserFollows),
|
||||
queryDeleteUserFollowing: fmt.Sprintf("DELETE FROM %s WHERE user_id = $1 AND following = $2", tableUserFollows),
|
||||
}
|
|
@ -1,140 +0,0 @@
|
|||
package postgres
|
||||
|
||||
import "fmt"
|
||||
|
||||
// table name for torrents
|
||||
const tableTorrents = "torrents"
|
||||
|
||||
// table name for users
|
||||
const tableUsers = "users"
|
||||
|
||||
// table for new comments
|
||||
const tableComments = "comments"
|
||||
|
||||
// table for old comments
|
||||
const tableOldComments = "comments_old"
|
||||
|
||||
// table for torrent reports
|
||||
const tableTorrentReports = "torrent_reports"
|
||||
|
||||
// table for user follows
|
||||
const tableUserFollows = "user_follows"
|
||||
|
||||
// table for old user uploads
|
||||
const tableOldUserUploads = "user_uploads_old"
|
||||
|
||||
// all tables that we have in current database schema in the order they are created
|
||||
var tables = []createTable{
|
||||
// users table
|
||||
{
|
||||
name: tableUsers,
|
||||
columns: tableColumns{
|
||||
"user_id SERIAL PRIMARY KEY",
|
||||
"username TEXT NOT NULL",
|
||||
"password TEXT NOT NULL",
|
||||
"email TEXT",
|
||||
"status INTEGER NOT NULL",
|
||||
"created_at TIMESTAMP WITHOUT TIME ZONE NOT NULL",
|
||||
"updated_at TIMESTAMP WITHOUT TIME ZONE",
|
||||
"last_login_at TIMESTAMP WITHOUT TIME ZONE",
|
||||
"api_token TEXT",
|
||||
"api_token_expiry TIMESTAMP WITHOUT TIME ZONE NOT NULL",
|
||||
"language TEXT",
|
||||
"MD5 TEXT",
|
||||
},
|
||||
postCreate: []sqlQuery{
|
||||
createIndex(tableUsers, "username"),
|
||||
},
|
||||
},
|
||||
// torrents table
|
||||
{
|
||||
name: tableTorrents,
|
||||
columns: tableColumns{
|
||||
"torrent_id SERIAL PRIMARY KEY",
|
||||
"torrent_name TEXT",
|
||||
"torrent_hash TEXT NOT NULL",
|
||||
"category INTEGER NOT NULL",
|
||||
"sub_category INTEGER NOT NULL",
|
||||
"status INTEGER NOT NULL",
|
||||
"date TIMESTAMP WITHOUT TIME ZONE",
|
||||
fmt.Sprintf("uploader INTEGER NOT NULL REFERENCES %s (user_id)", tableUsers),
|
||||
"downloads INTEGER",
|
||||
"stardom INTEGER NOT NULL",
|
||||
"filesize BIGINT",
|
||||
"description TEXT NOT NULL",
|
||||
"website_link TEXT",
|
||||
"deleted_at TIMESTAMP WITHOUT TIME ZONE",
|
||||
"seeders INTEGER",
|
||||
"leechers INTEGER",
|
||||
"completed INTEGER",
|
||||
"last_scrape TIMESTAMP WITHOUT TIME ZONE",
|
||||
},
|
||||
postCreate: []sqlQuery{
|
||||
createIndex(tableTorrents, "torrent_id"),
|
||||
createIndex(tableTorrents, "deleted_at"),
|
||||
createIndex(tableTorrents, "uploader"),
|
||||
createTrigraph(tableTorrents, "category", "torrent_name"),
|
||||
createTrigraph(tableTorrents, "sub_category", "torrent_name"),
|
||||
createTrigraph(tableTorrents, "status", "torrent_name"),
|
||||
createTrigraph(tableTorrents, "torrent_name"),
|
||||
},
|
||||
},
|
||||
// new comments table
|
||||
{
|
||||
name: tableComments,
|
||||
columns: tableColumns{
|
||||
"comment_id SERIAL PRIMARY KEY",
|
||||
fmt.Sprintf("torrent_id INTEGER REFERENCES %s (torrent_id)", tableTorrents),
|
||||
fmt.Sprintf("user_id INTEGER REFERENCES %s (user_id)", tableUsers),
|
||||
"content TEXT NOT NULL",
|
||||
"created_at TIMESTAMP WITHOUT TIME ZONE NOT NULL",
|
||||
"updated_at TIMESTAMP WITHOUT TIME ZONE",
|
||||
"deleted_at TIMESTAMP WITH TIME ZONE",
|
||||
},
|
||||
postCreate: []sqlQuery{
|
||||
createIndex(tableComments, "torrent_id"),
|
||||
},
|
||||
},
|
||||
// old comments table
|
||||
{
|
||||
name: tableOldComments,
|
||||
columns: tableColumns{
|
||||
fmt.Sprintf("torrent_id INTEGER NOT NULL REFERENCES %s (torrent_id)", tableTorrents),
|
||||
"username TEXT NOT NULL",
|
||||
"content TEXT NOT NULL",
|
||||
"date TIMESTAMP WITHOUT TIME ZONE NOT NULL",
|
||||
},
|
||||
},
|
||||
// torrent reports table
|
||||
{
|
||||
name: tableTorrentReports,
|
||||
columns: tableColumns{
|
||||
"torrent_report_id SERIAL PRIMARY KEY",
|
||||
"type TEXT",
|
||||
fmt.Sprintf("torrent_id INTEGER REFERENCES %s (torrent_id)", tableTorrents),
|
||||
"user_id INTEGER",
|
||||
"created_at TIMESTAMP WITH TIME ZONE",
|
||||
},
|
||||
postCreate: []sqlQuery{
|
||||
createIndex(tableTorrentReports, "torrent_report_id"),
|
||||
},
|
||||
},
|
||||
// user follows table
|
||||
{
|
||||
name: tableUserFollows,
|
||||
columns: tableColumns{
|
||||
"user_id INTEGER NOT NULL",
|
||||
"following INTEGER NOT NULL",
|
||||
"PRIMARY KEY(user_id, following)",
|
||||
},
|
||||
},
|
||||
// old uploads table
|
||||
{
|
||||
name: tableOldUserUploads,
|
||||
columns: tableColumns{
|
||||
"username TEXT IS NOT NULL",
|
||||
fmt.Sprintf("torrent_id INTEGER IS NOT NULL REFERENCES %s (torrent_id)", tableTorrents),
|
||||
"PRIMARY KEY (torrent_id)",
|
||||
},
|
||||
},
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
package postgres
|
||||
|
||||
import (
|
||||
"github.com/NyaaPantsu/nyaa/model"
|
||||
|
||||
"database/sql"
|
||||
)
|
||||
|
||||
func (db *Database) GetAllTorrents(offset, limit uint32) (torrents []model.Torrent, err error) {
|
||||
err = db.queryWithPrepared(queryGetAllTorrents, func(rows *sql.Rows) error {
|
||||
torrents = make([]model.Torrent, 0, limit)
|
||||
var idx uint64
|
||||
for rows.Next() {
|
||||
rows.Scan(torrents[idx])
|
||||
}
|
||||
return nil
|
||||
}, offset, limit)
|
||||
return
|
||||
}
|
||||
|
||||
func (db *Database) GetTorrentByID(id uint32) (torrent model.Torrent, has bool, err error) {
|
||||
err = db.queryWithPrepared(queryGetTorrentByID, func(rows *sql.Rows) error {
|
||||
rows.Next()
|
||||
scanTorrentColumnsFull(rows, &torrent)
|
||||
has = true
|
||||
return nil
|
||||
}, id)
|
||||
return
|
||||
}
|
||||
|
||||
func (db *Database) UpsertTorrent(t *model.Torrent) (err error) {
|
||||
return
|
||||
}
|
|
@ -1,153 +0,0 @@
|
|||
package postgres
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
|
||||
"github.com/NyaaPantsu/nyaa/common"
|
||||
"github.com/NyaaPantsu/nyaa/model"
|
||||
)
|
||||
|
||||
func userParamToSelectQuery(p *common.UserParam) (q sqlQuery) {
|
||||
q.query = fmt.Sprintf("SELECT %s FROM %s ", userSelectColumnsFull, tableUsers)
|
||||
counter := 1
|
||||
if p.Max > 0 {
|
||||
q.query += fmt.Sprintf("LIMIT $%d ", counter)
|
||||
q.params = append(q.params, p.Max)
|
||||
counter++
|
||||
}
|
||||
if p.Offset > 0 {
|
||||
q.query += fmt.Sprintf("OFFSET $%d ", counter)
|
||||
q.params = append(q.params, p.Offset)
|
||||
counter++
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (db *Database) UserFollows(a, b uint32) (follows bool, err error) {
|
||||
err = db.queryWithPrepared(queryUserFollows, func(rows *sql.Rows) error {
|
||||
follows = true
|
||||
return nil
|
||||
}, a, b)
|
||||
return
|
||||
}
|
||||
|
||||
func (db *Database) AddUserFollowing(a, b uint32) (err error) {
|
||||
_, err = db.getPrepared(queryUserFollowsUpsert).Exec(a, b)
|
||||
return
|
||||
}
|
||||
|
||||
func (db *Database) DeleteUserFollowing(a, b uint32) (deleted bool, err error) {
|
||||
var affected uint32
|
||||
affected, err = db.execQuery(queryDeleteUserFollowing, a, b)
|
||||
deleted = affected > 0
|
||||
return
|
||||
}
|
||||
|
||||
func (db *Database) getUserByQuery(name string, p interface{}) (user model.User, has bool, err error) {
|
||||
err = db.queryWithPrepared(name, func(rows *sql.Rows) error {
|
||||
rows.Next()
|
||||
scanUserColumnsFull(rows, &user)
|
||||
has = true
|
||||
return nil
|
||||
}, p)
|
||||
return
|
||||
}
|
||||
|
||||
func (db *Database) GetUserByAPIToken(token string) (user model.User, has bool, err error) {
|
||||
user, has, err = db.getUserByQuery(queryGetUserByApiToken, token)
|
||||
return
|
||||
}
|
||||
|
||||
func (db *Database) GetUsersByEmail(email string) (users []model.User, err error) {
|
||||
err = db.queryWithPrepared(queryGetUserByEmail, func(rows *sql.Rows) error {
|
||||
for rows.Next() {
|
||||
var user model.User
|
||||
scanUserColumnsFull(rows, &user)
|
||||
users = append(users, user)
|
||||
}
|
||||
return nil
|
||||
}, email)
|
||||
return
|
||||
}
|
||||
|
||||
func (db *Database) GetUserByName(name string) (user model.User, has bool, err error) {
|
||||
user, has, err = db.getUserByQuery(queryGetUserByName, name)
|
||||
return
|
||||
}
|
||||
|
||||
func (db *Database) GetUserByID(id uint32) (user model.User, has bool, err error) {
|
||||
user, has, err = db.getUserByQuery(queryGetUserByID, id)
|
||||
return
|
||||
}
|
||||
|
||||
func (db *Database) InsertUser(u *model.User) (err error) {
|
||||
_, err = db.getPrepared(queryInsertUser).Exec(u.Username, u.Password, u.Email, u.Status, u.CreatedAt, u.UpdatedAt, u.APIToken, u.APITokenExpiry, u.Language, u.MD5)
|
||||
return
|
||||
}
|
||||
|
||||
func (db *Database) UpdateUser(u *model.User) (err error) {
|
||||
_, err = db.getPrepared(queryUpdateUser).Exec(u.ID, u.Username, u.Password, u.Email, u.Status, u.UpdatedAt, u.APIToken, u.APITokenExpiry, u.Language, u.MD5)
|
||||
return
|
||||
}
|
||||
|
||||
func (db *Database) GetUsersWhere(param *common.UserParam) (users []model.User, err error) {
|
||||
var user model.User
|
||||
var has bool
|
||||
if len(param.Email) > 0 {
|
||||
users, err = db.GetUsersByEmail(param.Email)
|
||||
} else if len(param.Name) > 0 {
|
||||
user, has, err = db.GetUserByName(param.Name)
|
||||
if has {
|
||||
users = append(users, user)
|
||||
}
|
||||
} else if len(param.APIToken) > 0 {
|
||||
user, has, err = db.GetUserByAPIToken(param.APIToken)
|
||||
if has {
|
||||
users = append(users, user)
|
||||
}
|
||||
} else if param.ID > 0 {
|
||||
user, has, err = db.GetUserByID(param.ID)
|
||||
if has {
|
||||
users = append(users, user)
|
||||
}
|
||||
} else {
|
||||
q := userParamToSelectQuery(param)
|
||||
if param.Max > 0 {
|
||||
users = make([]model.User, 0, param.Max)
|
||||
} else {
|
||||
users = make([]model.User, 0, 64)
|
||||
}
|
||||
err = q.Query(db.conn, func(rows *sql.Rows) error {
|
||||
|
||||
for rows.Next() {
|
||||
var user model.User
|
||||
scanUserColumnsFull(rows, &user)
|
||||
users = append(users, user)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (db *Database) DeleteUsersWhere(param *common.UserParam) (deleted uint32, err error) {
|
||||
|
||||
var queryName string
|
||||
var p interface{}
|
||||
if param.ID > 0 {
|
||||
queryName = queryDeleteUserByID
|
||||
p = param.ID
|
||||
} else if len(param.Email) > 0 {
|
||||
queryName = queryDeleteUserByEmail
|
||||
p = param.Email
|
||||
} else if len(param.APIToken) > 0 {
|
||||
queryName = queryDeleteUserByToken
|
||||
p = param.APIToken
|
||||
} else {
|
||||
// delete nothing
|
||||
return
|
||||
}
|
||||
deleted, err = db.execQuery(queryName, p)
|
||||
return
|
||||
}
|
|
@ -1,164 +0,0 @@
|
|||
package postgres
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/NyaaPantsu/nyaa/common"
|
||||
"github.com/NyaaPantsu/nyaa/config"
|
||||
"github.com/NyaaPantsu/nyaa/model"
|
||||
)
|
||||
|
||||
// build sql query from SearchParam for torrent search
|
||||
func searchParamToTorrentQuery(param *common.TorrentParam) (q sqlQuery) {
|
||||
counter := 1
|
||||
q.query = fmt.Sprintf("SELECT %s FROM %s ", torrentSelectColumnsFull, tableTorrents)
|
||||
if len(param.Category) > 0 {
|
||||
conditionsOr := make([]string, len(param.Category))
|
||||
for key, val := range param.Category {
|
||||
conditionsOr[key] = fmt.Sprintf("(category = $%d AND sub_category = $%d)", counter, counter+1)
|
||||
q.params = append(q.params, val.Main, val.Sub)
|
||||
counter += 2
|
||||
}
|
||||
q.query += "WHERE " + strings.Join(conditionsOr, " OR ")
|
||||
}
|
||||
|
||||
if counter > 1 {
|
||||
q.query += "AND "
|
||||
} else {
|
||||
q.query += "WHERE "
|
||||
}
|
||||
|
||||
q.query += fmt.Sprintf("status >= $%d ", counter)
|
||||
q.params = append(q.params, param.Status)
|
||||
counter++
|
||||
if param.UserID > 0 {
|
||||
q.query += fmt.Sprintf("AND uploader = $%d ", counter)
|
||||
q.params = append(q.params, param.UserID)
|
||||
counter++
|
||||
}
|
||||
|
||||
notnulls := strings.Split(param.NotNull, ",")
|
||||
for idx := range notnulls {
|
||||
k := strings.ToLower(strings.TrimSpace(notnulls[idx]))
|
||||
switch k {
|
||||
case "date":
|
||||
case "downloads":
|
||||
case "filesize":
|
||||
case "website_link":
|
||||
case "deleted_at":
|
||||
case "seeders":
|
||||
case "leechers":
|
||||
case "completed":
|
||||
case "last_scrape":
|
||||
q.query += fmt.Sprintf("AND %s IS NOT NULL ", k)
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
nulls := strings.Split(param.Null, ",")
|
||||
for idx := range nulls {
|
||||
k := strings.ToLower(strings.TrimSpace(nulls[idx]))
|
||||
switch k {
|
||||
case "date":
|
||||
case "downloads":
|
||||
case "filesize":
|
||||
case "website_link":
|
||||
case "deleted_at":
|
||||
case "seeders":
|
||||
case "leechers":
|
||||
case "completed":
|
||||
case "last_scrape":
|
||||
q.query += fmt.Sprintf("AND %s IS NULL ", k)
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
nameLikes := strings.Split(param.NameLike, ",")
|
||||
for idx := range nameLikes {
|
||||
q.query += fmt.Sprintf("AND torrent_name ILIKE $%d", counter)
|
||||
q.params = append(q.params, strings.TrimSpace(nameLikes[idx]))
|
||||
counter++
|
||||
}
|
||||
|
||||
var sort string
|
||||
switch param.Sort {
|
||||
case common.Name:
|
||||
sort = "torrent_name"
|
||||
case common.Date:
|
||||
sort = "date"
|
||||
case common.Downloads:
|
||||
sort = "downloads"
|
||||
case common.Size:
|
||||
sort = "filesize"
|
||||
case common.Seeders:
|
||||
sort = "seeders"
|
||||
case common.Leechers:
|
||||
sort = "leechers"
|
||||
case common.Completed:
|
||||
sort = "completed"
|
||||
case common.ID:
|
||||
default:
|
||||
sort = config.Conf.Torrents.Order
|
||||
}
|
||||
|
||||
q.query += fmt.Sprintf("ORDER BY %s ", sort)
|
||||
if param.Order {
|
||||
q.query += "ASC "
|
||||
} else {
|
||||
q.query += "DESC "
|
||||
}
|
||||
|
||||
if param.Max > 0 {
|
||||
q.query += fmt.Sprintf("LIMIT $%d ", counter)
|
||||
q.params = append(q.params, param.Max)
|
||||
counter++
|
||||
}
|
||||
if param.Offset > 0 {
|
||||
q.query += fmt.Sprintf("OFFSET $%d ", counter)
|
||||
q.params = append(q.params, param.Offset)
|
||||
counter++
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (db *Database) GetTorrentsWhere(param *common.TorrentParam) (torrents []model.Torrent, err error) {
|
||||
if param.TorrentID > 0 {
|
||||
var torrent model.Torrent
|
||||
var has bool
|
||||
torrent, has, err = db.GetTorrentByID(param.TorrentID)
|
||||
if has {
|
||||
torrents = append(torrents, torrent)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if param.All {
|
||||
torrents, err = db.GetAllTorrents(param.Offset, param.Max)
|
||||
return
|
||||
}
|
||||
|
||||
q := searchParamToTorrentQuery(param)
|
||||
err = q.Query(db.conn, func(rows *sql.Rows) error {
|
||||
if param.Max == 0 {
|
||||
torrents = make([]model.Torrent, 0, 128)
|
||||
} else {
|
||||
torrents = make([]model.Torrent, 0, param.Max)
|
||||
}
|
||||
|
||||
for rows.Next() {
|
||||
var t model.Torrent
|
||||
scanTorrentColumnsFull(rows, &t)
|
||||
torrents = append(torrents, t)
|
||||
// grow as needed
|
||||
if len(torrents) >= cap(torrents) {
|
||||
newtorrents := make([]model.Torrent, cap(torrents), cap(torrents)*3/2) // XXX: adjust as needed
|
||||
copy(newtorrents, torrents)
|
||||
torrents = newtorrents
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
package sqlite
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
|
||||
_ "github.com/mattn/go-sqlite3" // Need for sqlite
|
||||
)
|
||||
|
||||
// queryEvent is a queued event to be executed in a pipeline to ensure that sqlite access is done from 1 goroutine
|
||||
type queryEvent struct {
|
||||
query string
|
||||
param []interface{}
|
||||
handleResult func(*sql.Rows, error)
|
||||
}
|
||||
|
||||
// New : Create a new database
|
||||
func New(param string) (db *Database, err error) {
|
||||
db = new(Database)
|
||||
db.conn, err = sql.Open("sqlite3", param)
|
||||
if err == nil {
|
||||
db.query = make(chan *queryEvent, 128)
|
||||
} else {
|
||||
db = nil
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Database structure
|
||||
type Database struct {
|
||||
conn *sql.DB
|
||||
query chan *queryEvent
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
PANTSU_EXTERNAL_PORT=9999
|
||||
PANTSU_INTERNAL_PORT=9999
|
||||
PANTSU_POSTGRES_DBFILE=nyaa_psql.backup
|
|
@ -1,5 +0,0 @@
|
|||
FROM golang:1.8.1
|
||||
|
||||
RUN mkdir -p /nyaa
|
||||
|
||||
WORKDIR /nyaa
|
170
deploy/README.md
170
deploy/README.md
|
@ -1,170 +0,0 @@
|
|||
# Deployment
|
||||
|
||||
## Docker
|
||||
|
||||
The docker-compose files can be used to quickly deploy the website without
|
||||
needing other dependencies than docker and docker-compose.
|
||||
|
||||
We offer two database back-end (but that might change to only postgresql later).
|
||||
|
||||
> NOTE: Use the *-prod* version to deploy in production. See the section
|
||||
> [production](#production).
|
||||
|
||||
|
||||
### Usage
|
||||
|
||||
The first step depends on the back-end chosen.
|
||||
|
||||
For the **mysql** back-end, you need the database file inside the project's
|
||||
top-level directory and named *nyaa.db*.
|
||||
|
||||
For the **postgresql** back-end, you need the database dump inside the project's
|
||||
top-level directory and named nyaa\_psql.backup.
|
||||
|
||||
You may now start the container as such.
|
||||
|
||||
```
|
||||
$ export GOPATH=$HOME/.go
|
||||
$ mkdir -p $HOME/.go/src/github.com/NyaaPantsu
|
||||
$ cd $HOME/.go/src/github.com/NyaaPantsu
|
||||
$ git clone https://github.com/NyaaPantsu/nyaa
|
||||
$ cd nyaa/deploy
|
||||
$ docker-compose -f <docker_compose_file> up
|
||||
```
|
||||
|
||||
The website will be available at [http://localhost:9999](http://localhost:9999).
|
||||
|
||||
> NOTE: The website might crash if the database takes longer than the amount of
|
||||
> time sleeping in the [init.sh](init.sh) script.
|
||||
|
||||
> NOTE: The docker-compose file uses version 3, but doesn't yet use any feature
|
||||
> from the version 3. If you're getting an error because your version of docker
|
||||
> is too low, you can try changing the version to '2' in the compose file.
|
||||
|
||||
|
||||
### Production
|
||||
|
||||
This is specific to the
|
||||
[docker-compose.postgres-prod.yml](docker-compose.postgres-prod.yml) compose
|
||||
file. This should be used in production.
|
||||
|
||||
This setup uses an external postgresql database configured on the host machine
|
||||
instead of using a container. You must therefore install and configure
|
||||
postgresql in order to use this compose file.
|
||||
|
||||
Set the correct database parameters in [postgres-prod.env](postgres-prod.env).
|
||||
You can then follow the steps above.
|
||||
|
||||
|
||||
### Cleaning docker containers
|
||||
|
||||
Docker can end up taking a lot of space very quickly. The script
|
||||
[prune\_docker.sh](prune_docker.sh) will get rid of unused docker images and
|
||||
volumes.
|
||||
|
||||
|
||||
## Ansible
|
||||
|
||||
> IMPORTANT: Make sure the website connects to pgpool's port. Otherwise, no
|
||||
> caching will be done. Ansible assume you have a user on the remote that has
|
||||
> sudo (no password).
|
||||
|
||||
You'll have to change a few variables in [hosts](host). Replace the host:ip
|
||||
address to the host:ip of the target server. You can also change the user
|
||||
ansible uses to connect to the server. The user needs to have sudo ALL.
|
||||
|
||||
You'll also maybe have to tweak a few variables in
|
||||
[group_vars/all](group_vars/all) such as the database password, etc (but should
|
||||
probably be left like this).
|
||||
|
||||
|
||||
### Setup server playbook
|
||||
|
||||
This playbook installs and configure:
|
||||
|
||||
- postgresql (It also includes pgpool for caching)
|
||||
- firewalld
|
||||
- golang
|
||||
- elasticsearch
|
||||
- backup system (uses cronjob to do daily backup of the database)
|
||||
|
||||
> NOTE: The backup script needs to have access to a GPG key to sign the dumps.
|
||||
> It also needs a file with the passphrase, see
|
||||
> [group_vars/all](group_vars/all).
|
||||
|
||||
```
|
||||
$ ansible-playbook -i hosts setup_server.yml
|
||||
```
|
||||
|
||||
|
||||
### Restore Database Playbook
|
||||
|
||||
This playbook restores a database from dump. The dump has to be named
|
||||
nyaa_psql.backup and needs to be placed in the toplevel project directory *on
|
||||
your local host*. The database will be copied to the remote host and then will
|
||||
be restored.
|
||||
|
||||
```
|
||||
$ ansible-playbook -i hosts restore_database.yml
|
||||
```
|
||||
|
||||
|
||||
### Elasticsearch Index Playbooks
|
||||
|
||||
We are using index aliases for a zero downtime and index hotswapping. You can
|
||||
find more information [here](https://www.elastic.co/guide/en/elasticsearch/guide/current/index-aliases.html).
|
||||
|
||||
I'll assume you already have an index named `nyaapantsu_old` that is aliased to
|
||||
`nyaapantsu` and you want to create a new index to become the new `nyaapantsu`.
|
||||
|
||||
First you'll need to modify the variables in the [group_vars/all](group_vars/all)
|
||||
file.
|
||||
|
||||
The new index will be called `nyaapantsu_new`.
|
||||
|
||||
```yaml
|
||||
nyaapantsu_elasticsearch_alias: nyaapantsu
|
||||
nyaapantsu_elasticsearch_index: nyaapantsu_new
|
||||
nyaapantsu_elasticsearch_old_index: nyaapantsu_old
|
||||
```
|
||||
|
||||
Now you need to run three playbooks.
|
||||
|
||||
```bash
|
||||
# Creates the new index
|
||||
$ ansible-playbook -i hosts create_elasticsearch_index.yml
|
||||
# Populate the new index and disable the reindexing cron job. This avoid
|
||||
# losing new entries.
|
||||
$ ansible-playbook -i hosts populate_elasticsearch_index.yml
|
||||
# Remove the alias nyaapantsu from nyaapantsu_old and adds it to nyaapantsu_new
|
||||
$ ansible-playbook -i hosts swap_elasticsearch_index.yml
|
||||
```
|
||||
|
||||
Nyaa can now access the new index `nyaapantsu_new` by using the alias
|
||||
`nyaapantsu`.
|
||||
|
||||
## Playbook Testing
|
||||
|
||||
You can easily test these playbooks by using vagrant. Once you have vagrant
|
||||
installed:
|
||||
|
||||
```
|
||||
# Download centos/7 image
|
||||
$ vagrant init centos/7
|
||||
|
||||
# Create and boot the vm
|
||||
$ vagrant up
|
||||
$ vagrant ssh
|
||||
```
|
||||
|
||||
Now you have to setup your host to be able to connect to the vm using ssh. One
|
||||
way is to copy your public ssh key to the `~/.ssh/authorized_keys` file. Once
|
||||
that is done, your local host should be able to connect to the vm using ssh.
|
||||
|
||||
You can now tests the playbooks.
|
||||
|
||||
## TODOs
|
||||
- Delete .torrents after X days
|
||||
- Add public keys to db (?)
|
||||
- Show public keys and link to .torrents on the website
|
||||
- Tuning elasticsearch indexing / analyzer
|
|
@ -1,18 +0,0 @@
|
|||
- name: Create elasticsearch index
|
||||
hosts: dbs
|
||||
roles:
|
||||
- common
|
||||
- elasticsearch
|
||||
|
||||
tasks:
|
||||
- name: Read configuration file
|
||||
shell: cat "{{ nyaapantsu_directory }}/elasticsearch_settings.yml"
|
||||
register: config
|
||||
|
||||
- name: Configure elasticsearch index
|
||||
uri:
|
||||
headers:
|
||||
Content-Type: application/yaml
|
||||
url: "http://localhost:9200/{{ nyaapantsu_elasticsearch_index }}"
|
||||
method: PUT
|
||||
body: "{{ config.stdout }}"
|
|
@ -1,17 +0,0 @@
|
|||
nyaapantsu_dbname: nyaapantsu
|
||||
nyaapantsu_user: nyaapantsu
|
||||
nyaapantsu_password: nyaapantsu
|
||||
nyaapantsu_pgpool_port: 9998
|
||||
nyaapantsu_directory: /nyaapantsu/
|
||||
nyaapantsu_gpg_passphrase_file: "{{ nyaapantsu_directory }}/passphrase"
|
||||
nyaapantsu_build_directory: go_nyaa/
|
||||
nyaapantsu_elasticsearch_alias: nyaapantsu
|
||||
# nyaapantsu_elasticsearch_alias: sukebei
|
||||
nyaapantsu_elasticsearch_index: nyaapantsu_v1
|
||||
# nyaapantsu_elasticsearch_index: nyaapantsu_sukebei_v1
|
||||
nyaapantsu_elasticsearch_old_index: CHANGETHIS
|
||||
nyaapantsu_torrent_tablename: torrents
|
||||
# nyaapantsu_torrent_tablename: torrents_sukebei
|
||||
nyaapantsu_max_open_files: 200000
|
||||
nyaapantsu_jvm_heapsize_gb: 8
|
||||
# vim: ft=yaml
|
|
@ -1,5 +0,0 @@
|
|||
[webservers]
|
||||
127.0.0.1:2200 ansible_connection=ssh ansible_ssh_user=vagrant
|
||||
|
||||
[dbs]
|
||||
127.0.0.1:2200 ansible_connection=ssh ansible_ssh_user=vagrant
|
|
@ -1,6 +0,0 @@
|
|||
# Should only be used for the dev machine until we get a nice setup to install
|
||||
# both sukebei AND nyaa.
|
||||
- name: Install nyaa
|
||||
hosts: webservers
|
||||
roles:
|
||||
- nyaapantsu
|
|
@ -1,21 +0,0 @@
|
|||
- name: Populate elasticsearch index from database
|
||||
hosts: dbs
|
||||
roles:
|
||||
- common
|
||||
- postgresql
|
||||
- elasticsearch
|
||||
|
||||
tasks:
|
||||
# Needed otherwise we'll lose information when people upload when we're
|
||||
# populating to the new index.
|
||||
# DONT FORGET TO RE-ENABLE THE CRON JOB AFTER
|
||||
- name: Disable reindex cron job
|
||||
command: mv "/etc/cron.d/reindex_{{ nyaapantsu_torrent_tablename }}" /tmp/
|
||||
become: true
|
||||
|
||||
- name: Index the database into elasticsearch
|
||||
command: python "{{ nyaapantsu_directory }}/index_nyaapantsu.py"
|
||||
environment:
|
||||
PANTSU_DBPARAMS: "host=localhost port={{ nyaapantsu_pgpool_port }} user={{ nyaapantsu_user }} dbname={{ nyaapantsu_dbname }} sslmode=disable password={{ nyaapantsu_password }}"
|
||||
PANTSU_ELASTICSEARCH_INDEX: "{{ nyaapantsu_elasticsearch_index }}"
|
||||
PANTSU_TORRENT_TABLENAME: "{{ nyaapantsu_torrent_tablename }}"
|
|
@ -1,14 +0,0 @@
|
|||
- name: Restore database
|
||||
hosts: dbs
|
||||
roles:
|
||||
- common
|
||||
- postgresql
|
||||
|
||||
tasks:
|
||||
- name: Copy backup database
|
||||
copy:
|
||||
src: ../../nyaa_psql.backup
|
||||
dest: "{{ nyaapantsu_directory }}"
|
||||
|
||||
- name: Restore database from backup
|
||||
command: pg_restore -U "{{ nyaapantsu_user }}" -d "{{ nyaapantsu_dbname }}" "{{ nyaapantsu_directory }}/nyaa_psql.backup"
|
|
@ -1,32 +0,0 @@
|
|||
# Create a backup from the database
|
||||
#!/bin/bash
|
||||
|
||||
set -eu
|
||||
|
||||
NYAAPANTSU_USERNAME="$1"
|
||||
NYAAPANTSU_PASSWORD="$2"
|
||||
NYAAPANTSU_DB="$3"
|
||||
NYAAPANTSU_PASSPHRASE_FILE="$4"
|
||||
NYAAPANTSU_TRACKER="$5"
|
||||
NYAAPANTSU_DOWNLOADED_DIR="$6"
|
||||
NYAAPANTSU_WATCH_DIR="$7"
|
||||
|
||||
dump_file="${NYAAPANTSU_DB}_$(date +'%Y_%m_%d_%H_%M').backup"
|
||||
|
||||
pg_dump -U "${NYAAPANTSU_USERNAME}" -Fc --exclude-table-data=users -f "${dump_file}"
|
||||
|
||||
xz -z "${dump_file}"
|
||||
|
||||
compressed_dump_file="${dump_file}.xz"
|
||||
signature_file="${compressed_dump_file}.sig"
|
||||
|
||||
gpg2 --batch --yes --passphrase-fd 0 \
|
||||
--output "${signature_file}" \
|
||||
--detach-sig "${compressed_dump_file}" < "${NYAAPANTSU_PASSPHRASE_FILE}"
|
||||
|
||||
mktorrent -a "${NYAAPANTSU_TRACKER}" \
|
||||
-c "Official nyaapantsu database release ($(date +'%Y-%m-%d'))" \
|
||||
"${compressed_dump_file}" "${signature_file}"
|
||||
|
||||
mv "${compressed_dump_file}" "${signature_file}" "${NYAAPANTSU_DOWNLOADED_DIR}"
|
||||
mv "${compressed_dump_file}.torrent" "${NYAAPANTSU_WATCH_DIR}/"
|
|
@ -1,72 +0,0 @@
|
|||
# TODO Allow autogenerating of GPG keys
|
||||
- name: Make sure there is a passphrase file
|
||||
stat:
|
||||
path: "{{ nyaapantsu_gpg_passphrase_file }}"
|
||||
register: pass_file
|
||||
|
||||
- name: Copy backup script
|
||||
copy:
|
||||
src: backup.sh
|
||||
dest: "{{ backup_script }}"
|
||||
mode: 0755
|
||||
become: true
|
||||
when: pass_file.stat.exists == true
|
||||
|
||||
- name: Create (if not exists) cronjob
|
||||
file:
|
||||
path: "{{ backup_cron_job }}"
|
||||
state: touch
|
||||
become: true
|
||||
when: pass_file.stat.exists == true
|
||||
|
||||
- name: Add epel repository
|
||||
yum_repository:
|
||||
name: epel
|
||||
description: EPEL YUM repo
|
||||
baseurl: https://download.fedoraproject.org/pub/epel/$releasever/$basearch/
|
||||
gpgcheck: 1
|
||||
gpgkey: https://getfedora.org/static/352C64E5.txt
|
||||
become: true
|
||||
|
||||
- name: Install mktorrent and rtorrent
|
||||
yum:
|
||||
name: "{{ item }}"
|
||||
state: present
|
||||
become: true
|
||||
with_items:
|
||||
- mktorrent
|
||||
- rtorrent
|
||||
|
||||
- name: Create download and watch directory
|
||||
file:
|
||||
path: "{{ item }}"
|
||||
state: directory
|
||||
with_items:
|
||||
- "~/.rtorrent_session/"
|
||||
- "{{ torrent_downloaded_directory }}"
|
||||
- "{{ torrent_watch_directory }}"
|
||||
|
||||
- name: Configure rtorrent
|
||||
template:
|
||||
src: rtorrent.rc.j2
|
||||
dest: ~/.rtorrent.rc
|
||||
|
||||
- name: Copy systemd rtorrent service
|
||||
template:
|
||||
src: rtorrent.service.j2
|
||||
dest: /etc/systemd/system/rtorrent.service
|
||||
become: true
|
||||
|
||||
- name: Enable and start rtorrent service
|
||||
systemd:
|
||||
enabled: yes
|
||||
name: rtorrent
|
||||
state: started
|
||||
become: true
|
||||
|
||||
- name: Setup backup cron
|
||||
template:
|
||||
src: backup_cron.j2
|
||||
dest: "{{ backup_cron_job }}"
|
||||
become: true
|
||||
when: pass_file.stat.exists == true
|
|
@ -1 +0,0 @@
|
|||
0 {{ backup_cron_hours }} * * * {{ backup_script }} {{ nyaapantsu_user }} {{ nyaapantsu_password }} {{ nyaapantsu_dbname }} {{ nyaapantsu_gpg_passphrase_file }} {{ torrent_tracker }} {{ torrent_downloaded_directory }} {{ torrent_watch_directory }}
|
|
@ -1,29 +0,0 @@
|
|||
port_range = {{ torrent_port_range }}
|
||||
min_peers = 40
|
||||
max_peers = 52
|
||||
min_peers_seed = 10
|
||||
max_peers_seed = 52
|
||||
max_uploads = 15
|
||||
upload_rate = 0
|
||||
|
||||
# Default directory to save the downloaded torrents.
|
||||
directory = {{ torrent_downloaded_directory }}
|
||||
|
||||
# Watch a directory for new torrents, and stop those that have been
|
||||
# deleted.
|
||||
schedule = watch_directory,5,5,load_start={{ torrent_watch_directory }}/*.torrent
|
||||
|
||||
#schedule = low_diskspace,5,60,close_low_diskspace=100M
|
||||
|
||||
check_hash = yes
|
||||
|
||||
# Set whether the client should try to connect to UDP trackers.
|
||||
#use_udp_trackers = yes
|
||||
|
||||
# Should be force it ?
|
||||
encryption = allow_incoming,enable_retry,prefer_plaintext
|
||||
|
||||
dht = auto
|
||||
dht_port = 6881
|
||||
peer_exchange = yes
|
||||
# vim: ft=cfg
|
|
@ -1,17 +0,0 @@
|
|||
[Unit]
|
||||
Description=rTorrent
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=forking
|
||||
KillMode=none
|
||||
User={{ ansible_ssh_user }}
|
||||
# FIXME Start-pre gives an 'Operation not supported error'
|
||||
#ExecStartPre=/usr/bin/bash -c "if test -e %h/.rtorrent_session/rtorrent.lock && test -z `pidof rtorrent`; then rm -f %h/.rtorrent_session/rtorrent.lock; fi"
|
||||
ExecStart=/usr/bin/screen -dmfa -S rtorrent /usr/bin/rtorrent
|
||||
ExecStop=/usr/bin/bash -c "test `pidof rtorrent` && killall -w -s 2 /usr/bin/rtorrent"
|
||||
WorkingDirectory=%h
|
||||
Restart=on-failure
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
|
@ -1,8 +0,0 @@
|
|||
# INFO Could probably put backup script in nyaapantsu_directory / bin as well
|
||||
backup_script: /usr/local/bin/nyaapantsu_backup.sh
|
||||
backup_cron_hours: 0
|
||||
backup_cron_job: /etc/cron.d/nyaapantsu_backup
|
||||
torrent_tracker: udp://tracker.doko.moe:6969
|
||||
torrent_downloaded_directory: "{{ nyaapantsu_directory }}/downloaded/"
|
||||
torrent_watch_directory: "{{ nyaapantsu_directory }}/watch/"
|
||||
torrent_port_range: 49164-49164
|
|
@ -1,13 +0,0 @@
|
|||
- name: Create nyaapantsu directory
|
||||
file:
|
||||
path: "{{ nyaapantsu_directory }}"
|
||||
state: directory
|
||||
mode: 0755
|
||||
owner: "{{ ansible_ssh_user }}"
|
||||
become: true
|
||||
|
||||
- name: Install useful stuff
|
||||
yum:
|
||||
name: lsof
|
||||
state: present
|
||||
become: true
|
|
@ -1,31 +0,0 @@
|
|||
# TODO Get from https://download.docker.com/linux/centos/docker-ce.repo instead
|
||||
# of hardcoding information here
|
||||
- name: Add Docker CE repository
|
||||
yum_repository:
|
||||
name: docker-ce-edge
|
||||
enabled: yes
|
||||
description: Docker CE Edge - $basearch
|
||||
baseurl: https://download.docker.com/linux/centos/7/$basearch/edge
|
||||
gpgcheck: 1
|
||||
gpgkey: https://download.docker.com/linux/centos/gpg
|
||||
become: true
|
||||
|
||||
- name: Install Docker CE
|
||||
yum:
|
||||
name: docker-ce
|
||||
state: present
|
||||
become: true
|
||||
|
||||
- name: Install docker-compose
|
||||
get_url:
|
||||
url: "https://github.com/docker/compose/releases/download/{{ release_version }}/docker-compose-{{ ansible_system }}-{{ ansible_architecture }}"
|
||||
dest: /usr/bin/docker-compose
|
||||
mode: 0755
|
||||
become: true
|
||||
|
||||
- name: Start docker and enable at boot
|
||||
systemd:
|
||||
enabled: yes
|
||||
name: docker
|
||||
state: started
|
||||
become: true
|
|
@ -1 +0,0 @@
|
|||
release_version: 1.13.0
|
|
@ -1,88 +0,0 @@
|
|||
---
|
||||
settings:
|
||||
analysis:
|
||||
analyzer:
|
||||
# Don't use ngram for search otherwise 'horribleexample' would match
|
||||
# 'horriblesubs'
|
||||
nyaapantsu_search_analyzer:
|
||||
tokenizer: standard
|
||||
filter:
|
||||
- standard
|
||||
- lowercase
|
||||
char_filter:
|
||||
- underscore_to_space
|
||||
- dash_to_underscore
|
||||
|
||||
nyaapantsu_index_analyzer:
|
||||
tokenizer: standard
|
||||
filter:
|
||||
- standard
|
||||
- lowercase
|
||||
- e_ngram_filter
|
||||
char_filter:
|
||||
- underscore_to_space
|
||||
- dash_to_underscore
|
||||
|
||||
filter:
|
||||
e_ngram_filter:
|
||||
type: edge_ngram
|
||||
min_gram: 1
|
||||
max_gram: 16
|
||||
|
||||
char_filter:
|
||||
dash_to_underscore:
|
||||
type: pattern_replace
|
||||
pattern: "([^\\s]+)-(?=[^\\s]+)"
|
||||
replacement: "$1_"
|
||||
|
||||
underscore_to_space:
|
||||
type: mapping
|
||||
mappings:
|
||||
- "_ => \\u0020"
|
||||
|
||||
index:
|
||||
number_of_shards: 1
|
||||
number_of_replicas: 0
|
||||
max_result_window: 5000000
|
||||
|
||||
mappings:
|
||||
torrents:
|
||||
properties:
|
||||
# TODO Consistent ID's type in TorrentJSON
|
||||
id:
|
||||
type: long
|
||||
name:
|
||||
type: text
|
||||
analyzer: nyaapantsu_index_analyzer
|
||||
fields:
|
||||
raw:
|
||||
type: keyword
|
||||
category:
|
||||
type: text
|
||||
description:
|
||||
type: text
|
||||
sub_category:
|
||||
type: text
|
||||
status:
|
||||
type: long
|
||||
hash:
|
||||
type: text
|
||||
date:
|
||||
type: date
|
||||
uploader_id:
|
||||
type: long
|
||||
downloads:
|
||||
type: long
|
||||
seeders:
|
||||
type: long
|
||||
hidden:
|
||||
type: boolean
|
||||
leechers:
|
||||
type: long
|
||||
completed:
|
||||
type: long
|
||||
filesize:
|
||||
type: long
|
||||
language:
|
||||
type: text
|
||||
analyzer: simple
|
|
@ -1,62 +0,0 @@
|
|||
# coding: utf-8
|
||||
from elasticsearch import Elasticsearch, helpers
|
||||
import psycopg2, pprint, sys, time, os
|
||||
|
||||
CHUNK_SIZE = 10000
|
||||
|
||||
def getEnvOrExit(var):
|
||||
environment = ''
|
||||
try:
|
||||
environment = os.environ[var]
|
||||
except:
|
||||
print('[Error]: Environment variable ' + var + ' not defined.')
|
||||
sys.exit(1)
|
||||
return environment
|
||||
|
||||
dbparams = getEnvOrExit('PANTSU_DBPARAMS')
|
||||
pantsu_index = getEnvOrExit('PANTSU_ELASTICSEARCH_INDEX')
|
||||
torrent_tablename = getEnvOrExit('PANTSU_TORRENT_TABLENAME')
|
||||
|
||||
es = Elasticsearch()
|
||||
pgconn = psycopg2.connect(dbparams)
|
||||
|
||||
cur = pgconn.cursor()
|
||||
cur.execute("""SELECT torrent_id, torrent_name, description, hidden, category, sub_category, status,
|
||||
torrent_hash, date, uploader, downloads, filesize, seeders, leechers, completed, language
|
||||
FROM {torrent_tablename}
|
||||
WHERE deleted_at IS NULL""".format(torrent_tablename=torrent_tablename))
|
||||
|
||||
fetches = cur.fetchmany(CHUNK_SIZE)
|
||||
while fetches:
|
||||
actions = list()
|
||||
for torrent_id, torrent_name, description, hidden, category, sub_category, status, torrent_hash, date, uploader, downloads, filesize, seeders, leechers, completed, language in fetches:
|
||||
doc = {
|
||||
'id': torrent_id,
|
||||
'name': torrent_name.decode('utf-8'),
|
||||
'category': str(category),
|
||||
'sub_category': str(sub_category),
|
||||
'status': status,
|
||||
'hash': torrent_hash,
|
||||
'hidden': hidden,
|
||||
'description': description,
|
||||
'date': date,
|
||||
'uploader_id': uploader,
|
||||
'downloads': downloads,
|
||||
'filesize': filesize,
|
||||
'seeders': seeders,
|
||||
'leechers': leechers,
|
||||
'completed': completed,
|
||||
'language': language
|
||||
}
|
||||
action = {
|
||||
'_index': pantsu_index,
|
||||
'_type': 'torrents',
|
||||
'_id': torrent_id,
|
||||
'_source': doc
|
||||
}
|
||||
actions.append(action)
|
||||
helpers.bulk(es, actions, chunk_size=CHUNK_SIZE, request_timeout=120)
|
||||
del(fetches)
|
||||
fetches = cur.fetchmany(CHUNK_SIZE)
|
||||
cur.close()
|
||||
pgconn.close()
|
|
@ -1,74 +0,0 @@
|
|||
# coding: utf-8
|
||||
from elasticsearch import Elasticsearch, helpers
|
||||
import psycopg2, pprint, sys, time, os
|
||||
|
||||
CHUNK_SIZE = 10000
|
||||
|
||||
def getEnvOrExit(var):
|
||||
environment = ''
|
||||
try:
|
||||
environment = os.environ[var]
|
||||
except:
|
||||
print('[Error]: Environment variable ' + var + ' not defined.')
|
||||
sys.exit(1)
|
||||
return environment
|
||||
|
||||
dbparams = getEnvOrExit('PANTSU_DBPARAMS')
|
||||
pantsu_index = getEnvOrExit('PANTSU_ELASTICSEARCH_INDEX')
|
||||
torrent_tablename = getEnvOrExit('PANTSU_TORRENT_TABLENAME')
|
||||
|
||||
es = Elasticsearch()
|
||||
pgconn = psycopg2.connect(dbparams)
|
||||
|
||||
cur = pgconn.cursor()
|
||||
# We MUST use NO QUERY CACHE because the values are insert on triggers and
|
||||
# not through pgppool.
|
||||
cur.execute('/*NO QUERY CACHE*/ SELECT reindex_torrents_id, torrent_id, action FROM reindex_{torrent_tablename}'.format(torrent_tablename=torrent_tablename))
|
||||
|
||||
fetches = cur.fetchmany(CHUNK_SIZE)
|
||||
while fetches:
|
||||
actions = list()
|
||||
delete_cur = pgconn.cursor()
|
||||
for reindex_id, torrent_id, action in fetches:
|
||||
new_action = {
|
||||
'_op_type': action,
|
||||
'_index': pantsu_index,
|
||||
'_type': 'torrents',
|
||||
'_id': torrent_id
|
||||
}
|
||||
if action == 'index':
|
||||
select_cur = pgconn.cursor()
|
||||
select_cur.execute("""SELECT torrent_id, torrent_name, description, hidden, category, sub_category, status,
|
||||
torrent_hash, date, uploader, downloads, filesize, seeders, leechers, completed, language
|
||||
FROM {torrent_tablename}
|
||||
WHERE torrent_id = {torrent_id}""".format(torrent_id=torrent_id, torrent_tablename=torrent_tablename))
|
||||
torrent_id, torrent_name, description, hidden, category, sub_category, status, torrent_hash, date, uploader, downloads, filesize, seeders, leechers, completed, language = select_cur.fetchone()
|
||||
doc = {
|
||||
'id': torrent_id,
|
||||
'name': torrent_name.decode('utf-8'),
|
||||
'category': str(category),
|
||||
'sub_category': str(sub_category),
|
||||
'status': status,
|
||||
'hidden': hidden,
|
||||
'description': description,
|
||||
'hash': torrent_hash,
|
||||
'date': date,
|
||||
'uploader_id': uploader,
|
||||
'downloads': downloads,
|
||||
'filesize': filesize,
|
||||
'seeders': seeders,
|
||||
'leechers': leechers,
|
||||
'completed': completed,
|
||||
'language': language
|
||||
}
|
||||
new_action['_source'] = doc
|
||||
select_cur.close()
|
||||
delete_cur.execute('DELETE FROM reindex_{torrent_tablename} WHERE reindex_torrents_id = {reindex_id}'.format(reindex_id=reindex_id,torrent_tablename=torrent_tablename))
|
||||
actions.append(new_action)
|
||||
pgconn.commit() # Commit the deletes transaction
|
||||
delete_cur.close()
|
||||
helpers.bulk(es, actions, chunk_size=CHUNK_SIZE, request_timeout=120)
|
||||
del(fetches)
|
||||
fetches = cur.fetchmany(CHUNK_SIZE)
|
||||
cur.close()
|
||||
pgconn.close()
|
|
@ -1,94 +0,0 @@
|
|||
- name: Add elasticsearch key
|
||||
rpm_key:
|
||||
state: present
|
||||
key: https://artifacts.elastic.co/GPG-KEY-elasticsearch
|
||||
become: true
|
||||
|
||||
- name: Add elasticsearch repo
|
||||
yum_repository:
|
||||
name: elasticsearch-5.x
|
||||
baseurl: https://artifacts.elastic.co/packages/5.x/yum
|
||||
gpgcheck: 1
|
||||
gpgkey: https://artifacts.elastic.co/GPG-KEY-elasticsearch
|
||||
enabled: 1
|
||||
description: Elastic search repository for 5.x packages
|
||||
become: true
|
||||
|
||||
- name: Install java and elasticsearch
|
||||
yum:
|
||||
name: "{{ item }}"
|
||||
state: present
|
||||
become: true
|
||||
with_items:
|
||||
- java-1.8.0-openjdk
|
||||
- elasticsearch
|
||||
- python-elasticsearch # INFO Needed for index_nyaapantsu.py script
|
||||
|
||||
- name: Copy files to remote
|
||||
copy:
|
||||
src: "{{ item }}"
|
||||
dest: "{{ nyaapantsu_directory }}"
|
||||
with_items:
|
||||
- elasticsearch_settings.yml
|
||||
- index_nyaapantsu.py
|
||||
|
||||
- name: Increase system max open files
|
||||
lineinfile:
|
||||
path: /etc/sysctl.conf
|
||||
regexp: '^fs.file-max.*'
|
||||
line: 'fs.file-max = {{ nyaapantsu_max_open_files }}'
|
||||
become: true
|
||||
|
||||
- name: Increase JVM heapsize
|
||||
lineinfile:
|
||||
path: /etc/sysconfig/elasticsearch
|
||||
regexp: '^ES_JAVA_OPTS=.*'
|
||||
line: 'ES_JAVA_OPTS="-Xms{{ nyaapantsu_jvm_heapsize_gb }}g -Xmx{{ nyaapantsu_jvm_heapsize_gb }}g"'
|
||||
become: true
|
||||
|
||||
- name: Lock elasticsearch memory
|
||||
lineinfile:
|
||||
path: /etc/elasticsearch/elasticsearch.yml
|
||||
regexp: '^bootstrap.memory_lock: true'
|
||||
line: 'bootstrap.memory_lock: true'
|
||||
become: true
|
||||
|
||||
- name: Create override folder
|
||||
file:
|
||||
path: /etc/systemd/system/elasticsearch.service.d/
|
||||
state: directory
|
||||
mode: 0755
|
||||
become: true
|
||||
|
||||
- name: Add override service file
|
||||
template:
|
||||
src: elasticsearch.override.j2
|
||||
dest: /etc/systemd/system/elasticsearch.service.d/override.conf
|
||||
become: true
|
||||
|
||||
- name: Enable and start elasticsearch
|
||||
systemd:
|
||||
enabled: yes
|
||||
name: elasticsearch
|
||||
state: started
|
||||
daemon_reload: yes
|
||||
become: true
|
||||
|
||||
- name: Copy reindexing triggers
|
||||
template:
|
||||
src: reindex_triggers.sql.j2
|
||||
dest: "{{ nyaapantsu_directory }}/reindex_triggers.sql"
|
||||
|
||||
- name: Apply reindexing triggers
|
||||
shell: psql -U "{{ nyaapantsu_user }}" "{{ nyaapantsu_dbname }}" < "{{ nyaapantsu_directory }}/reindex_triggers.sql"
|
||||
|
||||
- name: Copy reindexing script
|
||||
copy:
|
||||
src: reindex_nyaapantsu.py
|
||||
dest: "{{ elasticsearch_reindex_script }}"
|
||||
|
||||
- name: Setup reindexing cron job
|
||||
template:
|
||||
src: reindex_cron.j2
|
||||
dest: "/etc/cron.d/reindex_{{ nyaapantsu_torrent_tablename }}"
|
||||
become: true
|
|
@ -1,6 +0,0 @@
|
|||
[Service]
|
||||
LimitNOFILE=
|
||||
LimitNOFILE={{ nyaapantsu_max_open_files }}
|
||||
|
||||
LimitMEMLOCK=
|
||||
LimitMEMLOCK=infinity
|
|
@ -1,5 +0,0 @@
|
|||
PANTSU_DBPARAMS="host=localhost port={{ nyaapantsu_pgpool_port }} user={{ nyaapantsu_user }} password={{ nyaapantsu_password }} sslmode=disable"
|
||||
PANTSU_ELASTICSEARCH_INDEX="{{ nyaapantsu_elasticsearch_alias }}"
|
||||
PANTSU_TORRENT_TABLENAME="{{ nyaapantsu_torrent_tablename }}"
|
||||
{{ elasticsearch_cron_minutes }} * * * * {{ ansible_ssh_user }} python {{ elasticsearch_reindex_script }}
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
-- Matches the _op_type values from elasticsearch bulk API
|
||||
-- https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-bulk.html
|
||||
|
||||
CREATE TYPE torrents_action AS ENUM ('index', 'delete');
|
||||
|
||||
CREATE TABLE IF NOT EXISTS reindex_{{ nyaapantsu_torrent_tablename }} (
|
||||
reindex_torrents_id SERIAL,
|
||||
torrent_id int,
|
||||
action torrents_action
|
||||
);
|
||||
|
||||
CREATE OR REPLACE FUNCTION add_reindex_{{ nyaapantsu_torrent_tablename }}_action() RETURNS TRIGGER AS $$
|
||||
BEGIN
|
||||
IF (TG_OP = 'INSERT') THEN
|
||||
INSERT INTO reindex_{{ nyaapantsu_torrent_tablename }} (torrent_id, action) VALUES (NEW.torrent_id, 'index');
|
||||
RETURN NEW;
|
||||
ELSIF (TG_OP = 'UPDATE') THEN
|
||||
IF (NEW.deleted_at IS NOT NULL) THEN
|
||||
INSERT INTO reindex_{{ nyaapantsu_torrent_tablename }} (torrent_id, action) VALUES (OLD.torrent_id, 'delete');
|
||||
RETURN NEW;
|
||||
ELSE
|
||||
INSERT INTO reindex_{{ nyaapantsu_torrent_tablename }} (torrent_id, action) VALUES (NEW.torrent_id, 'index');
|
||||
RETURN NEW;
|
||||
END IF;
|
||||
ELSIF (TG_OP = 'DELETE') THEN
|
||||
INSERT INTO reindex_{{ nyaapantsu_torrent_tablename }} (torrent_id, action) VALUES (OLD.torrent_id, 'delete');
|
||||
RETURN OLD;
|
||||
END IF;
|
||||
RETURN NULL; -- result is ignored since this is an AFTER trigger
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
DROP TRIGGER IF EXISTS trigger_reindex_{{ nyaapantsu_torrent_tablename }} ON {{ nyaapantsu_torrent_tablename }};
|
||||
CREATE TRIGGER trigger_reindex_{{ nyaapantsu_torrent_tablename }}
|
||||
AFTER INSERT OR UPDATE OR DELETE ON {{ nyaapantsu_torrent_tablename }}
|
||||
FOR EACH ROW EXECUTE PROCEDURE add_reindex_{{ nyaapantsu_torrent_tablename }}_action();
|
||||
|
||||
-- vim: ft=sql
|
|
@ -1,3 +0,0 @@
|
|||
# Run job every 5 minutes
|
||||
elasticsearch_cron_minutes: "*/5"
|
||||
elasticsearch_reindex_script: "{{ nyaapantsu_directory }}/reindex_nyaapantsu.py"
|
|
@ -1,23 +0,0 @@
|
|||
- name: Install firewalld
|
||||
yum:
|
||||
name: firewalld
|
||||
state: present
|
||||
|
||||
- name: Start firewalld
|
||||
systemd:
|
||||
name: firewalld
|
||||
enabled: yes
|
||||
state: started
|
||||
become: true
|
||||
|
||||
- name: Add firewalld http and https service
|
||||
firewalld:
|
||||
service: "{{ item }}"
|
||||
permanent: true
|
||||
state: enabled
|
||||
zone: public
|
||||
immediate: true
|
||||
with_items:
|
||||
- http
|
||||
- https
|
||||
become: true
|
|
@ -1,26 +0,0 @@
|
|||
- name: Download Golang
|
||||
get_url:
|
||||
url: "https://storage.googleapis.com/golang/go{{ golang_version }}.linux-amd64.tar.gz"
|
||||
dest: /tmp/golang.tar.gz
|
||||
|
||||
- name: Unzip golang
|
||||
unarchive:
|
||||
src: /tmp/golang.tar.gz
|
||||
dest: /usr/local/
|
||||
remote_src: True
|
||||
become: true
|
||||
|
||||
- name: Add go to PATH
|
||||
lineinfile:
|
||||
path: ~/.bashrc
|
||||
regexp: 'export PATH=.*go.*'
|
||||
line: 'export PATH=$PATH:/usr/local/go/bin'
|
||||
|
||||
- name: Install git for go get command
|
||||
yum:
|
||||
name: "{{ item }}"
|
||||
state: present
|
||||
become: true
|
||||
with_items:
|
||||
- git
|
||||
- gcc
|
|
@ -1 +0,0 @@
|
|||
golang_version: 1.8.1
|
|
@ -1,38 +0,0 @@
|
|||
- name: Make directory
|
||||
file:
|
||||
state: directory
|
||||
path: "{{ nyaapantsu_build_directory }}/src/github.com/NyaaPantsu"
|
||||
|
||||
- name: Register nyaa directory
|
||||
stat:
|
||||
path: "{{ nyaapantsu_build_directory }}/src/github.com/NyaaPantsu/nyaa"
|
||||
register: nyaa_directory
|
||||
|
||||
- name: Register old nyaa directory
|
||||
stat:
|
||||
path: "{{ nyaapantsu_build_directory }}/src/github.com/NyaaPantsu/nyaa_old"
|
||||
register: old_nyaa_directory
|
||||
|
||||
- name: Remove old nyaa directory
|
||||
file:
|
||||
path: "{{ nyaapantsu_build_directory }}/src/github.com/NyaaPantsu/nyaa_old"
|
||||
state: absent
|
||||
when: old_nyaa_directory.stat.exists == true
|
||||
become: true # FIXME Need super user because public/dumps gives permission error
|
||||
|
||||
- name: Backup nyaa to old nyaa directory
|
||||
command: mv -Tf "{{ nyaapantsu_build_directory }}/src/github.com/NyaaPantsu/nyaa/" "{{ nyaapantsu_build_directory }}/src/github.com/NyaaPantsu/nyaa_old/"
|
||||
when: nyaa_directory.stat.exists == true
|
||||
|
||||
# TODO ability to get specify commit
|
||||
- name: Get latest nyaa
|
||||
git:
|
||||
repo: 'https://github.com/NyaaPantsu/nyaa'
|
||||
dest: "{{ nyaapantsu_build_directory }}/src/github.com/NyaaPantsu/nyaa"
|
||||
|
||||
- name: Go build
|
||||
shell: go build
|
||||
args:
|
||||
chdir: "{{ nyaapantsu_build_directory }}/src/github.com/NyaaPantsu/nyaa"
|
||||
environment:
|
||||
GOPATH: "/home/{{ ansible_ssh_user }}/{{ nyaapantsu_build_directory }}"
|
|
@ -1,124 +0,0 @@
|
|||
- name: Download postgresql rpm
|
||||
get_url:
|
||||
url: https://download.postgresql.org/pub/repos/yum/9.6/redhat/rhel-7-x86_64/pgdg-centos96-9.6-3.noarch.rpm
|
||||
dest: /tmp/postgresql.rpm
|
||||
|
||||
- name: Install postgresql.rpm
|
||||
yum:
|
||||
name: "{{ item }}"
|
||||
state: present
|
||||
become: true
|
||||
with_items:
|
||||
- /tmp/postgresql.rpm
|
||||
|
||||
- name: Install postgresql
|
||||
yum:
|
||||
name: "{{ item }}"
|
||||
state: present
|
||||
become: true
|
||||
with_items:
|
||||
- postgresql96-server
|
||||
- postgresql96-contrib # Needed for extensions (ie: btree_gin)
|
||||
- pgpool-II-96
|
||||
|
||||
- name: Add go to PATH
|
||||
lineinfile:
|
||||
path: ~/.bashrc
|
||||
regexp: 'export PATH=.*pgsql.*'
|
||||
line: 'export PATH=$PATH:/usr/pgsql-9.6/bin'
|
||||
|
||||
- name: Initialize postgresql
|
||||
command: /usr/pgsql-9.6/bin/initdb -D /var/lib/pgsql/9.6/data
|
||||
# Will error when database has already been initialized so just ignore it
|
||||
ignore_errors: yes
|
||||
become: true
|
||||
become_user: postgres
|
||||
|
||||
- name: Copy configuration file for postgresql
|
||||
template:
|
||||
src: postgresql.conf.j2
|
||||
dest: /var/lib/pgsql/9.6/data/postgresql.conf
|
||||
become: true
|
||||
become_user: postgres
|
||||
|
||||
|
||||
- name: Install adapter for python
|
||||
yum:
|
||||
name: python-psycopg2
|
||||
state: present
|
||||
become: true
|
||||
|
||||
- name: Configure pgpool
|
||||
template:
|
||||
src: pgpool.conf.j2
|
||||
dest: /etc/pgpool-II-96/pgpool.conf
|
||||
become: true
|
||||
|
||||
- name: Create oiddir for pgpool
|
||||
file:
|
||||
path: "{{ memqcache_oiddir }}"
|
||||
state: directory
|
||||
become: true
|
||||
|
||||
- name: Fix bug where pid is in wrong pool
|
||||
file:
|
||||
src: /var/run/pgpool-II-96
|
||||
path: /var/run/pgpool
|
||||
state: link
|
||||
force: yes
|
||||
become: true
|
||||
|
||||
- name: Start postgresql, pgpool and enable at boot
|
||||
systemd:
|
||||
enabled: yes
|
||||
name: "{{ item }}"
|
||||
state: started
|
||||
become: true
|
||||
with_items:
|
||||
- postgresql-9.6
|
||||
- pgpool-II-96
|
||||
|
||||
- name: Create nyaapantsu database
|
||||
postgresql_db:
|
||||
name: "{{ nyaapantsu_dbname }}"
|
||||
become: true
|
||||
become_user: postgres
|
||||
|
||||
# TODO Probably better idea to not set SUPERUSER
|
||||
- name: Create nyaapantsu user
|
||||
postgresql_user:
|
||||
db: "{{ nyaapantsu_dbname }}"
|
||||
name: "{{ nyaapantsu_user }}"
|
||||
password: "{{ nyaapantsu_password }}"
|
||||
role_attr_flags: SUPERUSER,LOGIN
|
||||
become: true
|
||||
become_user: postgres
|
||||
|
||||
- name: Grant privileges to user
|
||||
postgresql_privs:
|
||||
db: "{{ nyaapantsu_dbname }}"
|
||||
priv: ALL
|
||||
roles: "{{ nyaapantsu_user }}"
|
||||
state: present
|
||||
type: database
|
||||
become: true
|
||||
become_user: postgres
|
||||
|
||||
- name: Add custom pg_hba.conf
|
||||
template:
|
||||
src: pg_hba.conf.j2
|
||||
dest: /var/lib/pgsql/9.6/data/pg_hba.conf
|
||||
become: true
|
||||
become_user: postgres
|
||||
|
||||
- name: Add .pgpass
|
||||
template:
|
||||
src: pgpass.j2
|
||||
dest: ~/.pgpass
|
||||
mode: 0600
|
||||
|
||||
- name: Reload postgres
|
||||
systemd:
|
||||
name: postgresql-9.6
|
||||
state: reloaded
|
||||
become: true
|
|
@ -1,9 +0,0 @@
|
|||
# TYPE DATABASE USER ADDRESS METHOD
|
||||
# For debugging purposes
|
||||
local {{ nyaapantsu_dbname }} {{ nyaapantsu_user }} md5
|
||||
local all all peer
|
||||
# IPv4 local connections:
|
||||
host {{ nyaapantsu_dbname }} {{ nyaapantsu_user }} 127.0.0.1/32 md5
|
||||
# IPv6 local connections:
|
||||
# INFO: For some reason, we need IPv6 for pgpool-ii
|
||||
host {{ nyaapantsu_dbname }} {{ nyaapantsu_user }} ::1/128 md5
|
|
@ -1 +0,0 @@
|
|||
localhost:5432:{{ nyaapantsu_dbname }}:{{ nyaapantsu_user }}:{{ nyaapantsu_password }}
|
|
@ -1,604 +0,0 @@
|
|||
listen_addresses = 'localhost'
|
||||
port = {{ nyaapantsu_pgpool_port }}
|
||||
socket_dir = '/tmp'
|
||||
listen_backlog_multiplier = 2
|
||||
# Set the backlog parameter of listen(2) to
|
||||
# num_init_children * listen_backlog_multiplier.
|
||||
# (change requires restart)
|
||||
|
||||
pcp_listen_addresses = '*'
|
||||
pcp_port = 9898
|
||||
pcp_socket_dir = '/tmp'
|
||||
|
||||
backend_hostname0 = 'localhost'
|
||||
backend_port0 = 5432
|
||||
backend_weight0 = 1
|
||||
backend_data_directory0 = '/var/lib/pgsql/9.6/data'
|
||||
backend_flag0 = 'ALLOW_TO_FAILOVER'
|
||||
# Controls various backend behavior
|
||||
# ALLOW_TO_FAILOVER or DISALLOW_TO_FAILOVER
|
||||
enable_pool_hba = off
|
||||
# Use pool_hba.conf for client authentication
|
||||
pool_passwd = ''
|
||||
# File name of pool_passwd for md5 authentication.
|
||||
# "" disables pool_passwd.
|
||||
# (change requires restart)
|
||||
authentication_timeout = 60
|
||||
# Delay in seconds to complete client authentication
|
||||
# 0 means no timeout.
|
||||
|
||||
# - SSL Connections -
|
||||
|
||||
ssl = off
|
||||
# Enable SSL support
|
||||
# (change requires restart)
|
||||
#ssl_key = './server.key'
|
||||
# Path to the SSL private key file
|
||||
# (change requires restart)
|
||||
#ssl_cert = './server.cert'
|
||||
# Path to the SSL public certificate file
|
||||
# (change requires restart)
|
||||
#ssl_ca_cert = ''
|
||||
# Path to a single PEM format file
|
||||
# containing CA root certificate(s)
|
||||
# (change requires restart)
|
||||
#ssl_ca_cert_dir = ''
|
||||
# Directory containing CA root certificate(s)
|
||||
# (change requires restart)
|
||||
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# POOLS
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
# - Pool size -
|
||||
|
||||
num_init_children = 32
|
||||
# Number of pools
|
||||
# (change requires restart)
|
||||
max_pool = 4
|
||||
# Number of connections per pool
|
||||
# (change requires restart)
|
||||
|
||||
# - Life time -
|
||||
|
||||
child_life_time = {{ child_life_time }}
|
||||
# Pool exits after being idle for this many seconds
|
||||
child_max_connections = 0
|
||||
# Pool exits after receiving that many connections
|
||||
# 0 means no exit
|
||||
connection_life_time = 0
|
||||
# Connection to backend closes after being idle for this many seconds
|
||||
# 0 means no close
|
||||
client_idle_limit = 0
|
||||
# Client is disconnected after being idle for that many seconds
|
||||
# (even inside an explicit transactions!)
|
||||
# 0 means no disconnection
|
||||
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# LOGS
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
# - Where to log -
|
||||
|
||||
log_destination = 'stderr'
|
||||
# Where to log
|
||||
# Valid values are combinations of stderr,
|
||||
# and syslog. Default to stderr.
|
||||
|
||||
# - What to log -
|
||||
|
||||
log_line_prefix = '%t: pid %p: ' # printf-style string to output at beginning of each log line.
|
||||
|
||||
log_connections = off
|
||||
# Log connections
|
||||
log_hostname = off
|
||||
# Hostname will be shown in ps status
|
||||
# and in logs if connections are logged
|
||||
log_statement = off
|
||||
# Log all statements
|
||||
log_per_node_statement = on
|
||||
# Log all statements
|
||||
# with node and backend informations
|
||||
log_standby_delay = 'none'
|
||||
# Log standby delay
|
||||
# Valid values are combinations of always,
|
||||
# if_over_threshold, none
|
||||
|
||||
# - Syslog specific -
|
||||
|
||||
syslog_facility = 'LOCAL0'
|
||||
# Syslog local facility. Default to LOCAL0
|
||||
syslog_ident = 'pgpool'
|
||||
# Syslog program identification string
|
||||
# Default to 'pgpool'
|
||||
|
||||
# - Debug -
|
||||
|
||||
debug_level = 0
|
||||
# Debug message verbosity level
|
||||
# 0 means no message, 1 or more mean verbose
|
||||
|
||||
#log_error_verbosity = default # terse, default, or verbose messages
|
||||
|
||||
#client_min_messages = notice # values in order of decreasing detail:
|
||||
# debug5
|
||||
# debug4
|
||||
# debug3
|
||||
# debug2
|
||||
# debug1
|
||||
# log
|
||||
# notice
|
||||
# warning
|
||||
# error
|
||||
|
||||
#log_min_messages = warning # values in order of decreasing detail:
|
||||
# debug5
|
||||
# debug4
|
||||
# debug3
|
||||
# debug2
|
||||
# debug1
|
||||
# info
|
||||
# notice
|
||||
# warning
|
||||
# error
|
||||
# log
|
||||
# fatal
|
||||
# panic
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# FILE LOCATIONS
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
pid_file_name = '/var/run/pgpool/pgpool.pid'
|
||||
# PID file name
|
||||
# (change requires restart)
|
||||
logdir = '/var/log/pgpool'
|
||||
# Directory of pgPool status file
|
||||
# (change requires restart)
|
||||
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# CONNECTION POOLING
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
connection_cache = on
|
||||
# Activate connection pools
|
||||
# (change requires restart)
|
||||
|
||||
# Semicolon separated list of queries
|
||||
# to be issued at the end of a session
|
||||
# The default is for 8.3 and later
|
||||
reset_query_list = 'ABORT; DISCARD ALL'
|
||||
# The following one is for 8.2 and before
|
||||
#reset_query_list = 'ABORT; RESET ALL; SET SESSION AUTHORIZATION DEFAULT'
|
||||
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# REPLICATION MODE
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
replication_mode = off
|
||||
# Activate replication mode
|
||||
# (change requires restart)
|
||||
replicate_select = off
|
||||
# Replicate SELECT statements
|
||||
# when in replication mode
|
||||
# replicate_select is higher priority than
|
||||
# load_balance_mode.
|
||||
|
||||
insert_lock = on
|
||||
# Automatically locks a dummy row or a table
|
||||
# with INSERT statements to keep SERIAL data
|
||||
# consistency
|
||||
# Without SERIAL, no lock will be issued
|
||||
lobj_lock_table = ''
|
||||
# When rewriting lo_creat command in
|
||||
# replication mode, specify table name to
|
||||
# lock
|
||||
|
||||
# - Degenerate handling -
|
||||
|
||||
replication_stop_on_mismatch = off
|
||||
# On disagreement with the packet kind
|
||||
# sent from backend, degenerate the node
|
||||
# which is most likely "minority"
|
||||
# If off, just force to exit this session
|
||||
|
||||
failover_if_affected_tuples_mismatch = off
|
||||
# On disagreement with the number of affected
|
||||
# tuples in UPDATE/DELETE queries, then
|
||||
# degenerate the node which is most likely
|
||||
# "minority".
|
||||
# If off, just abort the transaction to
|
||||
# keep the consistency
|
||||
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# LOAD BALANCING MODE
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
load_balance_mode = off
|
||||
# Activate load balancing mode
|
||||
# (change requires restart)
|
||||
ignore_leading_white_space = on
|
||||
# Ignore leading white spaces of each query
|
||||
white_function_list = ''
|
||||
# Comma separated list of function names
|
||||
# that don't write to database
|
||||
# Regexp are accepted
|
||||
black_function_list = 'nextval,setval,nextval,setval'
|
||||
# Comma separated list of function names
|
||||
# that write to database
|
||||
# Regexp are accepted
|
||||
|
||||
database_redirect_preference_list = ''
|
||||
# comma separated list of pairs of database and node id.
|
||||
# example: postgres:primary,mydb[0-4]:1,mydb[5-9]:2'
|
||||
# valid for streaming replicaton mode only.
|
||||
|
||||
app_name_redirect_preference_list = ''
|
||||
# comma separated list of pairs of app name and node id.
|
||||
# example: 'psql:primary,myapp[0-4]:1,myapp[5-9]:standby'
|
||||
# valid for streaming replicaton mode only.
|
||||
allow_sql_comments = off
|
||||
# if on, ignore SQL comments when judging if load balance or
|
||||
# query cache is possible.
|
||||
# If off, SQL comments effectively prevent the judgment
|
||||
# (pre 3.4 behavior).
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# MASTER/SLAVE MODE
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
master_slave_mode = off
|
||||
# Activate master/slave mode
|
||||
# (change requires restart)
|
||||
master_slave_sub_mode = 'slony'
|
||||
# Master/slave sub mode
|
||||
# Valid values are combinations slony or
|
||||
# stream. Default is slony.
|
||||
# (change requires restart)
|
||||
|
||||
# - Streaming -
|
||||
|
||||
sr_check_period = 0
|
||||
# Streaming replication check period
|
||||
# Disabled (0) by default
|
||||
sr_check_user = 'nobody'
|
||||
# Streaming replication check user
|
||||
# This is necessary even if you disable
|
||||
# streaming replication delay check with
|
||||
# sr_check_period = 0
|
||||
sr_check_password = ''
|
||||
# Password for streaming replication check user
|
||||
delay_threshold = 0
|
||||
# Threshold before not dispatching query to standby node
|
||||
# Unit is in bytes
|
||||
# Disabled (0) by default
|
||||
|
||||
# - Special commands -
|
||||
|
||||
follow_master_command = ''
|
||||
# Executes this command after master failover
|
||||
# Special values:
|
||||
# %d = node id
|
||||
# %h = host name
|
||||
# %p = port number
|
||||
# %D = database cluster path
|
||||
# %m = new master node id
|
||||
# %H = hostname of the new master node
|
||||
# %M = old master node id
|
||||
# %P = old primary node id
|
||||
# %r = new master port number
|
||||
# %R = new master database cluster path
|
||||
# %% = '%' character
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# HEALTH CHECK
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
health_check_period = 0
|
||||
# Health check period
|
||||
# Disabled (0) by default
|
||||
health_check_timeout = 20
|
||||
# Health check timeout
|
||||
# 0 means no timeout
|
||||
health_check_user = 'nobody'
|
||||
# Health check user
|
||||
health_check_password = ''
|
||||
# Password for health check user
|
||||
health_check_max_retries = 0
|
||||
# Maximum number of times to retry a failed health check before giving up.
|
||||
health_check_retry_delay = 1
|
||||
# Amount of time to wait (in seconds) between retries.
|
||||
connect_timeout = 10000
|
||||
# Timeout value in milliseconds before giving up to connect to backend.
|
||||
# Default is 10000 ms (10 second). Flaky network user may want to increase
|
||||
# the value. 0 means no timeout.
|
||||
# Note that this value is not only used for health check,
|
||||
# but also for ordinary conection to backend.
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# FAILOVER AND FAILBACK
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
failover_command = ''
|
||||
# Executes this command at failover
|
||||
# Special values:
|
||||
# %d = node id
|
||||
# %h = host name
|
||||
# %p = port number
|
||||
# %D = database cluster path
|
||||
# %m = new master node id
|
||||
# %H = hostname of the new master node
|
||||
# %M = old master node id
|
||||
# %P = old primary node id
|
||||
# %r = new master port number
|
||||
# %R = new master database cluster path
|
||||
# %% = '%' character
|
||||
failback_command = ''
|
||||
# Executes this command at failback.
|
||||
# Special values:
|
||||
# %d = node id
|
||||
# %h = host name
|
||||
# %p = port number
|
||||
# %D = database cluster path
|
||||
# %m = new master node id
|
||||
# %H = hostname of the new master node
|
||||
# %M = old master node id
|
||||
# %P = old primary node id
|
||||
# %r = new master port number
|
||||
# %R = new master database cluster path
|
||||
# %% = '%' character
|
||||
|
||||
fail_over_on_backend_error = on
|
||||
# Initiates failover when reading/writing to the
|
||||
# backend communication socket fails
|
||||
# If set to off, pgpool will report an
|
||||
# error and disconnect the session.
|
||||
|
||||
search_primary_node_timeout = 10
|
||||
# Timeout in seconds to search for the
|
||||
# primary node when a failover occurs.
|
||||
# 0 means no timeout, keep searching
|
||||
# for a primary node forever.
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# ONLINE RECOVERY
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
recovery_user = 'nobody'
|
||||
# Online recovery user
|
||||
recovery_password = ''
|
||||
# Online recovery password
|
||||
recovery_1st_stage_command = ''
|
||||
# Executes a command in first stage
|
||||
recovery_2nd_stage_command = ''
|
||||
# Executes a command in second stage
|
||||
recovery_timeout = 90
|
||||
# Timeout in seconds to wait for the
|
||||
# recovering node's postmaster to start up
|
||||
# 0 means no wait
|
||||
client_idle_limit_in_recovery = 0
|
||||
# Client is disconnected after being idle
|
||||
# for that many seconds in the second stage
|
||||
# of online recovery
|
||||
# 0 means no disconnection
|
||||
# -1 means immediate disconnection
|
||||
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# WATCHDOG
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
# - Enabling -
|
||||
|
||||
use_watchdog = off
|
||||
# Activates watchdog
|
||||
# (change requires restart)
|
||||
|
||||
# -Connection to up stream servers -
|
||||
|
||||
trusted_servers = ''
|
||||
# trusted server list which are used
|
||||
# to confirm network connection
|
||||
# (hostA,hostB,hostC,...)
|
||||
# (change requires restart)
|
||||
ping_path = '/bin'
|
||||
# ping command path
|
||||
# (change requires restart)
|
||||
|
||||
# - Watchdog communication Settings -
|
||||
|
||||
wd_hostname = ''
|
||||
# Host name or IP address of this watchdog
|
||||
# (change requires restart)
|
||||
wd_port = 9000
|
||||
# port number for watchdog service
|
||||
# (change requires restart)
|
||||
wd_authkey = ''
|
||||
# Authentication key for watchdog communication
|
||||
# (change requires restart)
|
||||
|
||||
# - Virtual IP control Setting -
|
||||
|
||||
delegate_IP = ''
|
||||
# delegate IP address
|
||||
# If this is empty, virtual IP never bring up.
|
||||
# (change requires restart)
|
||||
ifconfig_path = '/sbin'
|
||||
# ifconfig command path
|
||||
# (change requires restart)
|
||||
if_up_cmd = 'ifconfig eth0:0 inet $_IP_$ netmask 255.255.255.0'
|
||||
# startup delegate IP command
|
||||
# (change requires restart)
|
||||
if_down_cmd = 'ifconfig eth0:0 down'
|
||||
# shutdown delegate IP command
|
||||
# (change requires restart)
|
||||
|
||||
arping_path = '/usr/sbin' # arping command path
|
||||
# (change requires restart)
|
||||
|
||||
arping_cmd = 'arping -U $_IP_$ -w 1'
|
||||
# arping command
|
||||
# (change requires restart)
|
||||
|
||||
# - Behaivor on escalation Setting -
|
||||
|
||||
clear_memqcache_on_escalation = on
|
||||
# Clear all the query cache on shared memory
|
||||
# when standby pgpool escalate to active pgpool
|
||||
# (= virtual IP holder).
|
||||
# This should be off if client connects to pgpool
|
||||
# not using virtual IP.
|
||||
# (change requires restart)
|
||||
wd_escalation_command = ''
|
||||
# Executes this command at escalation on new active pgpool.
|
||||
# (change requires restart)
|
||||
|
||||
# - Lifecheck Setting -
|
||||
|
||||
# -- common --
|
||||
|
||||
wd_lifecheck_method = 'heartbeat'
|
||||
# Method of watchdog lifecheck ('heartbeat' or 'query')
|
||||
# (change requires restart)
|
||||
wd_interval = 10
|
||||
# lifecheck interval (sec) > 0
|
||||
# (change requires restart)
|
||||
|
||||
# -- heartbeat mode --
|
||||
|
||||
wd_heartbeat_port = 9694
|
||||
# Port number for receiving heartbeat signal
|
||||
# (change requires restart)
|
||||
wd_heartbeat_keepalive = 2
|
||||
# Interval time of sending heartbeat signal (sec)
|
||||
# (change requires restart)
|
||||
wd_heartbeat_deadtime = 30
|
||||
# Deadtime interval for heartbeat signal (sec)
|
||||
# (change requires restart)
|
||||
heartbeat_destination0 = 'host0_ip1'
|
||||
# Host name or IP address of destination 0
|
||||
# for sending heartbeat signal.
|
||||
# (change requires restart)
|
||||
heartbeat_destination_port0 = 9694
|
||||
# Port number of destination 0 for sending
|
||||
# heartbeat signal. Usually this is the
|
||||
# same as wd_heartbeat_port.
|
||||
# (change requires restart)
|
||||
heartbeat_device0 = ''
|
||||
# Name of NIC device (such like 'eth0')
|
||||
# used for sending/receiving heartbeat
|
||||
# signal to/from destination 0.
|
||||
# This works only when this is not empty
|
||||
# and pgpool has root privilege.
|
||||
# (change requires restart)
|
||||
|
||||
#heartbeat_destination1 = 'host0_ip2'
|
||||
#heartbeat_destination_port1 = 9694
|
||||
#heartbeat_device1 = ''
|
||||
|
||||
# -- query mode --
|
||||
|
||||
wd_life_point = 3
|
||||
# lifecheck retry times
|
||||
# (change requires restart)
|
||||
wd_lifecheck_query = 'SELECT 1'
|
||||
# lifecheck query to pgpool from watchdog
|
||||
# (change requires restart)
|
||||
wd_lifecheck_dbname = 'template1'
|
||||
# Database name connected for lifecheck
|
||||
# (change requires restart)
|
||||
wd_lifecheck_user = 'nobody'
|
||||
# watchdog user monitoring pgpools in lifecheck
|
||||
# (change requires restart)
|
||||
wd_lifecheck_password = ''
|
||||
# Password for watchdog user in lifecheck
|
||||
# (change requires restart)
|
||||
|
||||
# - Other pgpool Connection Settings -
|
||||
|
||||
#other_pgpool_hostname0 = 'host0'
|
||||
# Host name or IP address to connect to for other pgpool 0
|
||||
# (change requires restart)
|
||||
#other_pgpool_port0 = 5432
|
||||
# Port number for othet pgpool 0
|
||||
# (change requires restart)
|
||||
#other_wd_port0 = 9000
|
||||
# Port number for othet watchdog 0
|
||||
# (change requires restart)
|
||||
#other_pgpool_hostname1 = 'host1'
|
||||
#other_pgpool_port1 = 5432
|
||||
#other_wd_port1 = 9000
|
||||
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# OTHERS
|
||||
#------------------------------------------------------------------------------
|
||||
relcache_expire = 0
|
||||
# Life time of relation cache in seconds.
|
||||
# 0 means no cache expiration(the default).
|
||||
# The relation cache is used for cache the
|
||||
# query result against PostgreSQL system
|
||||
# catalog to obtain various information
|
||||
# including table structures or if it's a
|
||||
# temporary table or not. The cache is
|
||||
# maintained in a pgpool child local memory
|
||||
# and being kept as long as it survives.
|
||||
# If someone modify the table by using
|
||||
# ALTER TABLE or some such, the relcache is
|
||||
# not consistent anymore.
|
||||
# For this purpose, cache_expiration
|
||||
# controls the life time of the cache.
|
||||
|
||||
relcache_size = 256
|
||||
# Number of relation cache
|
||||
# entry. If you see frequently:
|
||||
# "pool_search_relcache: cache replacement happend"
|
||||
# in the pgpool log, you might want to increate this number.
|
||||
|
||||
check_temp_table = on
|
||||
# If on, enable temporary table check in SELECT statements.
|
||||
# This initiates queries against system catalog of primary/master
|
||||
# thus increases load of master.
|
||||
# If you are absolutely sure that your system never uses temporary tables
|
||||
# and you want to save access to primary/master, you could turn this off.
|
||||
# Default is on.
|
||||
|
||||
check_unlogged_table = on
|
||||
# If on, enable unlogged table check in SELECT statements.
|
||||
# This initiates queries against system catalog of primary/master
|
||||
# thus increases load of master.
|
||||
# If you are absolutely sure that your system never uses unlogged tables
|
||||
# and you want to save access to primary/master, you could turn this off.
|
||||
# Default is on.
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# IN MEMORY QUERY MEMORY CACHE
|
||||
#------------------------------------------------------------------------------
|
||||
memory_cache_enabled = on
|
||||
memqcache_method = 'shmem'
|
||||
memqcache_memcached_host = 'localhost'
|
||||
memqcache_memcached_port = 11211
|
||||
# In bytes
|
||||
memqcache_total_size = {{ memqcache_total_size_byte }}
|
||||
memqcache_max_num_cache = 1000000
|
||||
# Total number of cache entries. Mandatory
|
||||
# if memqcache_method = 'shmem'.
|
||||
# Each cache entry consumes 48 bytes on shared memory.
|
||||
# Defaults to 1,000,000(45.8MB).
|
||||
# (change requires restart)
|
||||
# Never expire cache entries
|
||||
memqcache_expire = 0
|
||||
memqcache_auto_cache_invalidation = on
|
||||
# Max size of each query
|
||||
memqcache_maxcache = {{ memqcache_maxcache_byte }}
|
||||
# TODO Assert cache_block_size > maxcache
|
||||
memqcache_cache_block_size = {{ memqcache_cache_block_size_byte }}
|
||||
memqcache_oiddir = '{{ memqcache_oiddir }}'
|
||||
white_memqcache_table_list = ''
|
||||
black_memqcache_table_list = ''
|
||||
# vim: ft=cfg
|
|
@ -1,641 +0,0 @@
|
|||
# -----------------------------
|
||||
# PostgreSQL configuration file
|
||||
# -----------------------------
|
||||
#
|
||||
# This file consists of lines of the form:
|
||||
#
|
||||
# name = value
|
||||
#
|
||||
# (The "=" is optional.) Whitespace may be used. Comments are introduced with
|
||||
# "#" anywhere on a line. The complete list of parameter names and allowed
|
||||
# values can be found in the PostgreSQL documentation.
|
||||
#
|
||||
# The commented-out settings shown in this file represent the default values.
|
||||
# Re-commenting a setting is NOT sufficient to revert it to the default value;
|
||||
# you need to reload the server.
|
||||
#
|
||||
# This file is read on server startup and when the server receives a SIGHUP
|
||||
# signal. If you edit the file on a running system, you have to SIGHUP the
|
||||
# server for the changes to take effect, or use "pg_ctl reload". Some
|
||||
# parameters, which are marked below, require a server shutdown and restart to
|
||||
# take effect.
|
||||
#
|
||||
# Any parameter can also be given as a command-line option to the server, e.g.,
|
||||
# "postgres -c log_connections=on". Some parameters can be changed at run time
|
||||
# with the "SET" SQL command.
|
||||
#
|
||||
# Memory units: kB = kilobytes Time units: ms = milliseconds
|
||||
# MB = megabytes s = seconds
|
||||
# GB = gigabytes min = minutes
|
||||
# TB = terabytes h = hours
|
||||
# d = days
|
||||
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# FILE LOCATIONS
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
# The default values of these variables are driven from the -D command-line
|
||||
# option or PGDATA environment variable, represented here as ConfigDir.
|
||||
|
||||
#data_directory = 'ConfigDir' # use data in another directory
|
||||
# (change requires restart)
|
||||
#hba_file = 'ConfigDir/pg_hba.conf' # host-based authentication file
|
||||
# (change requires restart)
|
||||
#ident_file = 'ConfigDir/pg_ident.conf' # ident configuration file
|
||||
# (change requires restart)
|
||||
|
||||
# If external_pid_file is not explicitly set, no extra PID file is written.
|
||||
#external_pid_file = '' # write an extra PID file
|
||||
# (change requires restart)
|
||||
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# CONNECTIONS AND AUTHENTICATION
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
# - Connection Settings -
|
||||
|
||||
#listen_addresses = 'localhost' # what IP address(es) to listen on;
|
||||
# comma-separated list of addresses;
|
||||
# defaults to 'localhost'; use '*' for all
|
||||
# (change requires restart)
|
||||
#port = 5432 # (change requires restart)
|
||||
max_connections = 100 # (change requires restart)
|
||||
#superuser_reserved_connections = 3 # (change requires restart)
|
||||
#unix_socket_directories = '/var/run/postgresql, /tmp' # comma-separated list of directories
|
||||
# (change requires restart)
|
||||
#unix_socket_group = '' # (change requires restart)
|
||||
#unix_socket_permissions = 0777 # begin with 0 to use octal notation
|
||||
# (change requires restart)
|
||||
#bonjour = off # advertise server via Bonjour
|
||||
# (change requires restart)
|
||||
#bonjour_name = '' # defaults to the computer name
|
||||
# (change requires restart)
|
||||
|
||||
# - Security and Authentication -
|
||||
|
||||
#authentication_timeout = 1min # 1s-600s
|
||||
#ssl = off # (change requires restart)
|
||||
#ssl_ciphers = 'HIGH:MEDIUM:+3DES:!aNULL' # allowed SSL ciphers
|
||||
# (change requires restart)
|
||||
#ssl_prefer_server_ciphers = on # (change requires restart)
|
||||
#ssl_ecdh_curve = 'prime256v1' # (change requires restart)
|
||||
#ssl_cert_file = 'server.crt' # (change requires restart)
|
||||
#ssl_key_file = 'server.key' # (change requires restart)
|
||||
#ssl_ca_file = '' # (change requires restart)
|
||||
#ssl_crl_file = '' # (change requires restart)
|
||||
#password_encryption = on
|
||||
#db_user_namespace = off
|
||||
#row_security = on
|
||||
|
||||
# GSSAPI using Kerberos
|
||||
#krb_server_keyfile = ''
|
||||
#krb_caseins_users = off
|
||||
|
||||
# - TCP Keepalives -
|
||||
# see "man 7 tcp" for details
|
||||
|
||||
#tcp_keepalives_idle = 0 # TCP_KEEPIDLE, in seconds;
|
||||
# 0 selects the system default
|
||||
#tcp_keepalives_interval = 0 # TCP_KEEPINTVL, in seconds;
|
||||
# 0 selects the system default
|
||||
#tcp_keepalives_count = 0 # TCP_KEEPCNT;
|
||||
# 0 selects the system default
|
||||
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# RESOURCE USAGE (except WAL)
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
# - Memory -
|
||||
|
||||
shared_buffers = 128MB # min 128kB
|
||||
# (change requires restart)
|
||||
#huge_pages = try # on, off, or try
|
||||
# (change requires restart)
|
||||
#temp_buffers = 8MB # min 800kB
|
||||
#max_prepared_transactions = 0 # zero disables the feature
|
||||
# (change requires restart)
|
||||
# Caution: it is not advisable to set max_prepared_transactions nonzero unless
|
||||
# you actively intend to use prepared transactions.
|
||||
#work_mem = 4MB # min 64kB
|
||||
#maintenance_work_mem = 64MB # min 1MB
|
||||
#replacement_sort_tuples = 150000 # limits use of replacement selection sort
|
||||
#autovacuum_work_mem = -1 # min 1MB, or -1 to use maintenance_work_mem
|
||||
#max_stack_depth = 2MB # min 100kB
|
||||
dynamic_shared_memory_type = posix # the default is the first option
|
||||
# supported by the operating system:
|
||||
# posix
|
||||
# sysv
|
||||
# windows
|
||||
# mmap
|
||||
# use none to disable dynamic shared memory
|
||||
|
||||
# - Disk -
|
||||
|
||||
#temp_file_limit = -1 # limits per-process temp file space
|
||||
# in kB, or -1 for no limit
|
||||
|
||||
# - Kernel Resource Usage -
|
||||
|
||||
#max_files_per_process = 1000 # min 25
|
||||
# (change requires restart)
|
||||
#shared_preload_libraries = '' # (change requires restart)
|
||||
|
||||
# - Cost-Based Vacuum Delay -
|
||||
|
||||
#vacuum_cost_delay = 0 # 0-100 milliseconds
|
||||
#vacuum_cost_page_hit = 1 # 0-10000 credits
|
||||
#vacuum_cost_page_miss = 10 # 0-10000 credits
|
||||
#vacuum_cost_page_dirty = 20 # 0-10000 credits
|
||||
#vacuum_cost_limit = 200 # 1-10000 credits
|
||||
|
||||
# - Background Writer -
|
||||
|
||||
#bgwriter_delay = 200ms # 10-10000ms between rounds
|
||||
#bgwriter_lru_maxpages = 100 # 0-1000 max buffers written/round
|
||||
#bgwriter_lru_multiplier = 2.0 # 0-10.0 multiplier on buffers scanned/round
|
||||
#bgwriter_flush_after = 512kB # measured in pages, 0 disables
|
||||
|
||||
# - Asynchronous Behavior -
|
||||
|
||||
#effective_io_concurrency = 1 # 1-1000; 0 disables prefetching
|
||||
#max_worker_processes = 8 # (change requires restart)
|
||||
#max_parallel_workers_per_gather = 0 # taken from max_worker_processes
|
||||
#old_snapshot_threshold = -1 # 1min-60d; -1 disables; 0 is immediate
|
||||
# (change requires restart)
|
||||
#backend_flush_after = 0 # measured in pages, 0 disables
|
||||
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# WRITE AHEAD LOG
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
# - Settings -
|
||||
|
||||
#wal_level = minimal # minimal, replica, or logical
|
||||
# (change requires restart)
|
||||
#fsync = on # flush data to disk for crash safety
|
||||
# (turning this off can cause
|
||||
# unrecoverable data corruption)
|
||||
#synchronous_commit = on # synchronization level;
|
||||
# off, local, remote_write, remote_apply, or on
|
||||
#wal_sync_method = fsync # the default is the first option
|
||||
# supported by the operating system:
|
||||
# open_datasync
|
||||
# fdatasync (default on Linux)
|
||||
# fsync
|
||||
# fsync_writethrough
|
||||
# open_sync
|
||||
#full_page_writes = on # recover from partial page writes
|
||||
#wal_compression = off # enable compression of full-page writes
|
||||
#wal_log_hints = off # also do full page writes of non-critical updates
|
||||
# (change requires restart)
|
||||
#wal_buffers = -1 # min 32kB, -1 sets based on shared_buffers
|
||||
# (change requires restart)
|
||||
#wal_writer_delay = 200ms # 1-10000 milliseconds
|
||||
#wal_writer_flush_after = 1MB # measured in pages, 0 disables
|
||||
|
||||
#commit_delay = 0 # range 0-100000, in microseconds
|
||||
#commit_siblings = 5 # range 1-1000
|
||||
|
||||
# - Checkpoints -
|
||||
|
||||
#checkpoint_timeout = 5min # range 30s-1d
|
||||
#max_wal_size = 1GB
|
||||
#min_wal_size = 80MB
|
||||
#checkpoint_completion_target = 0.5 # checkpoint target duration, 0.0 - 1.0
|
||||
#checkpoint_flush_after = 256kB # measured in pages, 0 disables
|
||||
#checkpoint_warning = 30s # 0 disables
|
||||
|
||||
# - Archiving -
|
||||
|
||||
#archive_mode = off # enables archiving; off, on, or always
|
||||
# (change requires restart)
|
||||
#archive_command = '' # command to use to archive a logfile segment
|
||||
# placeholders: %p = path of file to archive
|
||||
# %f = file name only
|
||||
# e.g. 'test ! -f /mnt/server/archivedir/%f && cp %p /mnt/server/archivedir/%f'
|
||||
#archive_timeout = 0 # force a logfile segment switch after this
|
||||
# number of seconds; 0 disables
|
||||
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# REPLICATION
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
# - Sending Server(s) -
|
||||
|
||||
# Set these on the master and on any standby that will send replication data.
|
||||
|
||||
#max_wal_senders = 0 # max number of walsender processes
|
||||
# (change requires restart)
|
||||
#wal_keep_segments = 0 # in logfile segments, 16MB each; 0 disables
|
||||
#wal_sender_timeout = 60s # in milliseconds; 0 disables
|
||||
|
||||
#max_replication_slots = 0 # max number of replication slots
|
||||
# (change requires restart)
|
||||
#track_commit_timestamp = off # collect timestamp of transaction commit
|
||||
# (change requires restart)
|
||||
|
||||
# - Master Server -
|
||||
|
||||
# These settings are ignored on a standby server.
|
||||
|
||||
#synchronous_standby_names = '' # standby servers that provide sync rep
|
||||
# number of sync standbys and comma-separated list of application_name
|
||||
# from standby(s); '*' = all
|
||||
#vacuum_defer_cleanup_age = 0 # number of xacts by which cleanup is delayed
|
||||
|
||||
# - Standby Servers -
|
||||
|
||||
# These settings are ignored on a master server.
|
||||
|
||||
#hot_standby = off # "on" allows queries during recovery
|
||||
# (change requires restart)
|
||||
#max_standby_archive_delay = 30s # max delay before canceling queries
|
||||
# when reading WAL from archive;
|
||||
# -1 allows indefinite delay
|
||||
#max_standby_streaming_delay = 30s # max delay before canceling queries
|
||||
# when reading streaming WAL;
|
||||
# -1 allows indefinite delay
|
||||
#wal_receiver_status_interval = 10s # send replies at least this often
|
||||
# 0 disables
|
||||
#hot_standby_feedback = off # send info from standby to prevent
|
||||
# query conflicts
|
||||
#wal_receiver_timeout = 60s # time that receiver waits for
|
||||
# communication from master
|
||||
# in milliseconds; 0 disables
|
||||
#wal_retrieve_retry_interval = 5s # time to wait before retrying to
|
||||
# retrieve WAL after a failed attempt
|
||||
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# QUERY TUNING
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
# - Planner Method Configuration -
|
||||
|
||||
#enable_bitmapscan = on
|
||||
#enable_hashagg = on
|
||||
#enable_hashjoin = on
|
||||
#enable_indexscan = on
|
||||
#enable_indexonlyscan = on
|
||||
#enable_material = on
|
||||
#enable_mergejoin = on
|
||||
#enable_nestloop = on
|
||||
#enable_seqscan = on
|
||||
#enable_sort = on
|
||||
#enable_tidscan = on
|
||||
|
||||
# - Planner Cost Constants -
|
||||
|
||||
#seq_page_cost = 1.0 # measured on an arbitrary scale
|
||||
#random_page_cost = 4.0 # same scale as above
|
||||
#cpu_tuple_cost = 0.01 # same scale as above
|
||||
#cpu_index_tuple_cost = 0.005 # same scale as above
|
||||
#cpu_operator_cost = 0.0025 # same scale as above
|
||||
#parallel_tuple_cost = 0.1 # same scale as above
|
||||
#parallel_setup_cost = 1000.0 # same scale as above
|
||||
#min_parallel_relation_size = 8MB
|
||||
#effective_cache_size = 4GB
|
||||
|
||||
# - Genetic Query Optimizer -
|
||||
|
||||
#geqo = on
|
||||
#geqo_threshold = 12
|
||||
#geqo_effort = 5 # range 1-10
|
||||
#geqo_pool_size = 0 # selects default based on effort
|
||||
#geqo_generations = 0 # selects default based on effort
|
||||
#geqo_selection_bias = 2.0 # range 1.5-2.0
|
||||
#geqo_seed = 0.0 # range 0.0-1.0
|
||||
|
||||
# - Other Planner Options -
|
||||
|
||||
#default_statistics_target = 100 # range 1-10000
|
||||
#constraint_exclusion = partition # on, off, or partition
|
||||
#cursor_tuple_fraction = 0.1 # range 0.0-1.0
|
||||
#from_collapse_limit = 8
|
||||
#join_collapse_limit = 8 # 1 disables collapsing of explicit
|
||||
# JOIN clauses
|
||||
#force_parallel_mode = off
|
||||
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# ERROR REPORTING AND LOGGING
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
# - Where to Log -
|
||||
|
||||
log_destination = 'stderr' # Valid values are combinations of
|
||||
# stderr, csvlog, syslog, and eventlog,
|
||||
# depending on platform. csvlog
|
||||
# requires logging_collector to be on.
|
||||
|
||||
# This is used when logging to stderr:
|
||||
logging_collector = on # Enable capturing of stderr and csvlog
|
||||
# into log files. Required to be on for
|
||||
# csvlogs.
|
||||
# (change requires restart)
|
||||
|
||||
# These are only used if logging_collector is on:
|
||||
log_directory = 'pg_log' # directory where log files are written,
|
||||
# can be absolute or relative to PGDATA
|
||||
log_filename = 'postgresql-%a.log' # log file name pattern,
|
||||
# can include strftime() escapes
|
||||
#log_file_mode = 0600 # creation mode for log files,
|
||||
# begin with 0 to use octal notation
|
||||
log_truncate_on_rotation = on # If on, an existing log file with the
|
||||
# same name as the new log file will be
|
||||
# truncated rather than appended to.
|
||||
# But such truncation only occurs on
|
||||
# time-driven rotation, not on restarts
|
||||
# or size-driven rotation. Default is
|
||||
# off, meaning append to existing files
|
||||
# in all cases.
|
||||
log_rotation_age = 1d # Automatic rotation of logfiles will
|
||||
# happen after that time. 0 disables.
|
||||
log_rotation_size = 0 # Automatic rotation of logfiles will
|
||||
# happen after that much log output.
|
||||
# 0 disables.
|
||||
|
||||
# These are relevant when logging to syslog:
|
||||
#syslog_facility = 'LOCAL0'
|
||||
#syslog_ident = 'postgres'
|
||||
#syslog_sequence_numbers = on
|
||||
#syslog_split_messages = on
|
||||
|
||||
# This is only relevant when logging to eventlog (win32):
|
||||
#event_source = 'PostgreSQL'
|
||||
|
||||
# - When to Log -
|
||||
|
||||
#client_min_messages = notice # values in order of decreasing detail:
|
||||
# debug5
|
||||
# debug4
|
||||
# debug3
|
||||
# debug2
|
||||
# debug1
|
||||
# log
|
||||
# notice
|
||||
# warning
|
||||
# error
|
||||
|
||||
#log_min_messages = warning # values in order of decreasing detail:
|
||||
# debug5
|
||||
# debug4
|
||||
# debug3
|
||||
# debug2
|
||||
# debug1
|
||||
# info
|
||||
# notice
|
||||
# warning
|
||||
# error
|
||||
# log
|
||||
# fatal
|
||||
# panic
|
||||
|
||||
#log_min_error_statement = error # values in order of decreasing detail:
|
||||
# debug5
|
||||
# debug4
|
||||
# debug3
|
||||
# debug2
|
||||
# debug1
|
||||
# info
|
||||
# notice
|
||||
# warning
|
||||
# error
|
||||
# log
|
||||
# fatal
|
||||
# panic (effectively off)
|
||||
|
||||
#log_min_duration_statement = -1 # -1 is disabled, 0 logs all statements
|
||||
# and their durations, > 0 logs only
|
||||
# statements running at least this number
|
||||
# of milliseconds
|
||||
|
||||
|
||||
# - What to Log -
|
||||
|
||||
#debug_print_parse = off
|
||||
#debug_print_rewritten = off
|
||||
#debug_print_plan = off
|
||||
#debug_pretty_print = on
|
||||
#log_checkpoints = off
|
||||
#log_connections = off
|
||||
#log_disconnections = off
|
||||
#log_duration = off
|
||||
#log_error_verbosity = default # terse, default, or verbose messages
|
||||
#log_hostname = off
|
||||
log_line_prefix = '< %m > ' # special values:
|
||||
# %a = application name
|
||||
# %u = user name
|
||||
# %d = database name
|
||||
# %r = remote host and port
|
||||
# %h = remote host
|
||||
# %p = process ID
|
||||
# %t = timestamp without milliseconds
|
||||
# %m = timestamp with milliseconds
|
||||
# %n = timestamp with milliseconds (as a Unix epoch)
|
||||
# %i = command tag
|
||||
# %e = SQL state
|
||||
# %c = session ID
|
||||
# %l = session line number
|
||||
# %s = session start timestamp
|
||||
# %v = virtual transaction ID
|
||||
# %x = transaction ID (0 if none)
|
||||
# %q = stop here in non-session
|
||||
# processes
|
||||
# %% = '%'
|
||||
# e.g. '<%u%%%d> '
|
||||
#log_lock_waits = off # log lock waits >= deadlock_timeout
|
||||
#log_statement = 'none' # none, ddl, mod, all
|
||||
#log_replication_commands = off
|
||||
#log_temp_files = -1 # log temporary files equal or larger
|
||||
# than the specified size in kilobytes;
|
||||
# -1 disables, 0 logs all temp files
|
||||
log_timezone = 'UTC'
|
||||
|
||||
|
||||
# - Process Title -
|
||||
|
||||
#cluster_name = '' # added to process titles if nonempty
|
||||
# (change requires restart)
|
||||
#update_process_title = on
|
||||
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# RUNTIME STATISTICS
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
# - Query/Index Statistics Collector -
|
||||
|
||||
#track_activities = on
|
||||
#track_counts = on
|
||||
#track_io_timing = off
|
||||
#track_functions = none # none, pl, all
|
||||
#track_activity_query_size = 1024 # (change requires restart)
|
||||
#stats_temp_directory = 'pg_stat_tmp'
|
||||
|
||||
|
||||
# - Statistics Monitoring -
|
||||
|
||||
#log_parser_stats = off
|
||||
#log_planner_stats = off
|
||||
#log_executor_stats = off
|
||||
#log_statement_stats = off
|
||||
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# AUTOVACUUM PARAMETERS
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
#autovacuum = on # Enable autovacuum subprocess? 'on'
|
||||
# requires track_counts to also be on.
|
||||
#log_autovacuum_min_duration = -1 # -1 disables, 0 logs all actions and
|
||||
# their durations, > 0 logs only
|
||||
# actions running at least this number
|
||||
# of milliseconds.
|
||||
#autovacuum_max_workers = 3 # max number of autovacuum subprocesses
|
||||
# (change requires restart)
|
||||
#autovacuum_naptime = 1min # time between autovacuum runs
|
||||
#autovacuum_vacuum_threshold = 50 # min number of row updates before
|
||||
# vacuum
|
||||
#autovacuum_analyze_threshold = 50 # min number of row updates before
|
||||
# analyze
|
||||
#autovacuum_vacuum_scale_factor = 0.2 # fraction of table size before vacuum
|
||||
#autovacuum_analyze_scale_factor = 0.1 # fraction of table size before analyze
|
||||
#autovacuum_freeze_max_age = 200000000 # maximum XID age before forced vacuum
|
||||
# (change requires restart)
|
||||
#autovacuum_multixact_freeze_max_age = 400000000 # maximum multixact age
|
||||
# before forced vacuum
|
||||
# (change requires restart)
|
||||
#autovacuum_vacuum_cost_delay = 20ms # default vacuum cost delay for
|
||||
# autovacuum, in milliseconds;
|
||||
# -1 means use vacuum_cost_delay
|
||||
#autovacuum_vacuum_cost_limit = -1 # default vacuum cost limit for
|
||||
# autovacuum, -1 means use
|
||||
# vacuum_cost_limit
|
||||
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# CLIENT CONNECTION DEFAULTS
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
# - Statement Behavior -
|
||||
|
||||
#search_path = '"$user", public' # schema names
|
||||
#default_tablespace = '' # a tablespace name, '' uses the default
|
||||
#temp_tablespaces = '' # a list of tablespace names, '' uses
|
||||
# only default tablespace
|
||||
#check_function_bodies = on
|
||||
#default_transaction_isolation = 'read committed'
|
||||
#default_transaction_read_only = off
|
||||
#default_transaction_deferrable = off
|
||||
#session_replication_role = 'origin'
|
||||
#statement_timeout = 0 # in milliseconds, 0 is disabled
|
||||
#lock_timeout = 0 # in milliseconds, 0 is disabled
|
||||
#idle_in_transaction_session_timeout = 0 # in milliseconds, 0 is disabled
|
||||
#vacuum_freeze_min_age = 50000000
|
||||
#vacuum_freeze_table_age = 150000000
|
||||
#vacuum_multixact_freeze_min_age = 5000000
|
||||
#vacuum_multixact_freeze_table_age = 150000000
|
||||
#bytea_output = 'hex' # hex, escape
|
||||
#xmlbinary = 'base64'
|
||||
#xmloption = 'content'
|
||||
#gin_fuzzy_search_limit = 0
|
||||
#gin_pending_list_limit = 4MB
|
||||
|
||||
# - Locale and Formatting -
|
||||
|
||||
datestyle = 'iso, mdy'
|
||||
#intervalstyle = 'postgres'
|
||||
timezone = 'UTC'
|
||||
#timezone_abbreviations = 'Default' # Select the set of available time zone
|
||||
# abbreviations. Currently, there are
|
||||
# Default
|
||||
# Australia (historical usage)
|
||||
# India
|
||||
# You can create your own file in
|
||||
# share/timezonesets/.
|
||||
#extra_float_digits = 0 # min -15, max 3
|
||||
#client_encoding = sql_ascii # actually, defaults to database
|
||||
# encoding
|
||||
|
||||
# These settings are initialized by initdb, but they can be changed.
|
||||
lc_messages = 'en_US.UTF-8' # locale for system error message
|
||||
# strings
|
||||
lc_monetary = 'en_US.UTF-8' # locale for monetary formatting
|
||||
lc_numeric = 'en_US.UTF-8' # locale for number formatting
|
||||
lc_time = 'en_US.UTF-8' # locale for time formatting
|
||||
|
||||
# default configuration for text search
|
||||
default_text_search_config = 'pg_catalog.english'
|
||||
|
||||
# - Other Defaults -
|
||||
|
||||
#dynamic_library_path = '$libdir'
|
||||
#local_preload_libraries = ''
|
||||
#session_preload_libraries = ''
|
||||
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# LOCK MANAGEMENT
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
#deadlock_timeout = 1s
|
||||
#max_locks_per_transaction = 64 # min 10
|
||||
# (change requires restart)
|
||||
#max_pred_locks_per_transaction = 64 # min 10
|
||||
# (change requires restart)
|
||||
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# VERSION/PLATFORM COMPATIBILITY
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
# - Previous PostgreSQL Versions -
|
||||
|
||||
#array_nulls = on
|
||||
#backslash_quote = safe_encoding # on, off, or safe_encoding
|
||||
#default_with_oids = off
|
||||
#escape_string_warning = on
|
||||
#lo_compat_privileges = off
|
||||
#operator_precedence_warning = off
|
||||
#quote_all_identifiers = off
|
||||
#sql_inheritance = on
|
||||
#standard_conforming_strings = on
|
||||
#synchronize_seqscans = on
|
||||
|
||||
# - Other Platforms and Clients -
|
||||
|
||||
#transform_null_equals = off
|
||||
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# ERROR HANDLING
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
#exit_on_error = off # terminate session on any error?
|
||||
#restart_after_crash = on # reinitialize after backend crash?
|
||||
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# CONFIG FILE INCLUDES
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
# These options allow settings to be loaded from files other than the
|
||||
# default postgresql.conf.
|
||||
|
||||
#include_dir = 'conf.d' # include files ending in '.conf' from
|
||||
# directory 'conf.d'
|
||||
#include_if_exists = 'exists.conf' # include file only if it exists
|
||||
#include = 'special.conf' # include file
|
||||
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# CUSTOMIZED OPTIONS
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
# Add settings for extensions here
|
|
@ -1,10 +0,0 @@
|
|||
memqcache_oiddir: '/var/log/pgpool/oiddir'
|
||||
# TODO Check the machine has enough RAM
|
||||
# ~10 GB
|
||||
memqcache_total_size_byte: 10737418240
|
||||
# 131 mb
|
||||
memqcache_maxcache_byte: 131072000
|
||||
# Has to be bigger or equal to maxcache_byte
|
||||
memqcache_cache_block_size_byte: 131072000
|
||||
# 20 seconds idle max (application shouldn't even make idle connections)
|
||||
child_life_time: 20
|
|
@ -1,15 +0,0 @@
|
|||
- name: Set up webserver
|
||||
hosts: webservers
|
||||
roles:
|
||||
- common
|
||||
- firewalld
|
||||
#- docker
|
||||
- golang
|
||||
|
||||
- name: Set up databases
|
||||
hosts: dbs
|
||||
roles:
|
||||
- common
|
||||
- backup
|
||||
- postgresql
|
||||
- elasticsearch
|
|
@ -1,28 +0,0 @@
|
|||
# We're not putting elasticsearch role because we don't want to re-enable the
|
||||
# reindexing cron job before we've actually made the swap
|
||||
- name: Populate elasticsearch index from database
|
||||
hosts: dbs
|
||||
roles:
|
||||
- common
|
||||
- postgresql
|
||||
|
||||
tasks:
|
||||
- name: Swap elasticsearch index
|
||||
uri:
|
||||
url: "http://localhost:9200/_aliases"
|
||||
method: POST
|
||||
body_format: json
|
||||
body:
|
||||
actions:
|
||||
- remove:
|
||||
index: "{{ nyaapantsu_elasticsearch_old_index }}"
|
||||
alias: "{{ nyaapantsu_elasticsearch_alias }}"
|
||||
- add:
|
||||
index: "{{ nyaapantsu_elasticsearch_index }}"
|
||||
alias: "{{ nyaapantsu_elasticsearch_alias }}"
|
||||
|
||||
- name: Re-enable reindex cron job
|
||||
command: mv "/tmp/reindex_{{ nyaapantsu_torrent_tablename }}" /etc/cron.d/
|
||||
become: true
|
||||
ignore_errors: yes # Can ignore error here if the file had previously been
|
||||
# moved.
|
|
@ -1,20 +0,0 @@
|
|||
version: '3'
|
||||
services:
|
||||
pantsu:
|
||||
build:
|
||||
context: ..
|
||||
dockerfile: deploy/Dockerfile
|
||||
command: ./deploy/init.sh
|
||||
env_file:
|
||||
- postgres-prod.env
|
||||
environment:
|
||||
- PANTSU_INTERNAL_PORT=${PANTSU_INTERNAL_PORT}
|
||||
network_mode: "host"
|
||||
ports:
|
||||
# 0.0.0.0 makes it accessible to the network
|
||||
# You may want to remove it to make pantsu available only
|
||||
# to localhost
|
||||
- 0.0.0.0:${PANTSU_EXTERNAL_PORT}:${PANTSU_INTERNAL_PORT}
|
||||
volumes:
|
||||
- "${GOPATH}:/go/"
|
||||
- "./..:/nyaa"
|
|
@ -1,34 +0,0 @@
|
|||
version: '3'
|
||||
services:
|
||||
pantsu:
|
||||
build:
|
||||
context: ..
|
||||
dockerfile: deploy/Dockerfile
|
||||
command: ./deploy/init.sh
|
||||
depends_on:
|
||||
- pantsu_db
|
||||
env_file:
|
||||
- postgres.env
|
||||
environment:
|
||||
- PANTSU_INTERNAL_PORT=${PANTSU_INTERNAL_PORT}
|
||||
links:
|
||||
- pantsu_db
|
||||
ports:
|
||||
# 0.0.0.0 makes it accessible to the network
|
||||
# You may want to remove it to make pantsu available only
|
||||
# to localhost
|
||||
- 0.0.0.0:${PANTSU_EXTERNAL_PORT}:${PANTSU_INTERNAL_PORT}
|
||||
volumes:
|
||||
- "${GOPATH}:/go/"
|
||||
- "./..:/nyaa"
|
||||
|
||||
pantsu_db:
|
||||
env_file:
|
||||
- postgres.env
|
||||
environment:
|
||||
- PANTSU_POSTGRES_DBFILE=${PANTSU_POSTGRES_DBFILE}
|
||||
image: postgres:9.6.2
|
||||
volumes:
|
||||
# restore.sh will be sourced after initial initdb
|
||||
- "./restore.sh:/docker-entrypoint-initdb.d/restore.sh"
|
||||
- "./../${PANTSU_POSTGRES_DBFILE}:/${PANTSU_POSTGRES_DBFILE}"
|
|
@ -1,19 +0,0 @@
|
|||
version: '3'
|
||||
services:
|
||||
pantsu:
|
||||
build:
|
||||
context: ..
|
||||
dockerfile: deploy/Dockerfile
|
||||
command: ./deploy/init.sh
|
||||
env_file:
|
||||
- sqlite.env
|
||||
environment:
|
||||
- PANTSU_INTERNAL_PORT=${PANTSU_INTERNAL_PORT}
|
||||
ports:
|
||||
# 0.0.0.0 makes it accessible to the network
|
||||
# You may want to remove it to make pantsu available only
|
||||
# to localhost
|
||||
- 0.0.0.0:${PANTSU_EXTERNAL_PORT}:${PANTSU_INTERNAL_PORT}
|
||||
volumes:
|
||||
- "${GOPATH}:/go/"
|
||||
- "./..:/nyaa"
|
|
@ -1,16 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -eux
|
||||
|
||||
# TODO Doesn't scale, find another way to wait until db is ready
|
||||
if [[ "${PANTSU_DBTYPE}" = "postgres" ]]; then
|
||||
echo 'Waiting for the database to be ready...'
|
||||
sleep 40
|
||||
fi
|
||||
|
||||
go get github.com/NyaaPantsu/nyaa
|
||||
go build
|
||||
./nyaa -host 0.0.0.0 \
|
||||
-port "${PANTSU_INTERNAL_PORT}" \
|
||||
-dbtype "${PANTSU_DBTYPE}" \
|
||||
-dbparams "${PANTSU_DBPARAMS}"
|
|
@ -1,9 +0,0 @@
|
|||
POSTGRES_USER=nyaapantsu
|
||||
POSTGRES_PASSWORD=nyaapantsu
|
||||
POSTGRES_DB=nyaapantsu
|
||||
|
||||
PANTSU_DBTYPE=postgres
|
||||
# TODO Would prefer to use the line below but docker doesn't seem to accept
|
||||
# that.
|
||||
#PANTSU_DBPARAMS=host=pantsu_db user=${POSTGRES_USER} dbname=${POSTGRES_DB} sslmode=disable password=${POSTGRES_PASSWORD}
|
||||
PANTSU_DBPARAMS=host=localhost port=9998 user=nyaapantsu dbname=nyaapantsu sslmode=disable password=nyaapantsu
|
|
@ -1,9 +0,0 @@
|
|||
POSTGRES_USER=nyaapantsu
|
||||
POSTGRES_PASSWORD=nyaapantsu
|
||||
POSTGRES_DB=nyaapantsu
|
||||
|
||||
PANTSU_DBTYPE=postgres
|
||||
# TODO Would prefer to use the line below but docker doesn't seem to accept
|
||||
# that.
|
||||
#PANTSU_DBPARAMS=host=pantsu_db user=${POSTGRES_USER} dbname=${POSTGRES_DB} sslmode=disable password=${POSTGRES_PASSWORD}
|
||||
PANTSU_DBPARAMS=host=pantsu_db user=nyaapantsu dbname=nyaapantsu sslmode=disable password=nyaapantsu
|
|
@ -1,11 +0,0 @@
|
|||
# Prune images and volumes
|
||||
#
|
||||
# Docker tends to take a lot of space. This will remove dangling images and
|
||||
# volumes not used by at least container.
|
||||
# WARNING: You might not want to run this if you have stuff that are dangling
|
||||
# that you want to keep.
|
||||
#
|
||||
#!/bin/bash
|
||||
|
||||
docker image prune -f
|
||||
docker volume prune -f
|
|
@ -1,12 +0,0 @@
|
|||
#!/bin/bash
|
||||
# Restore the database from a postgres dump
|
||||
|
||||
|
||||
pg_restore --username "${POSTGRES_USER}" -d ${POSTGRES_DB} "/${PANTSU_POSTGRES_DBFILE}"
|
||||
|
||||
last_nyaa_torrent_id=923001
|
||||
# Setting the sequence to start from after the latest nyaa torrent.
|
||||
psql -U postgres "${POSTGRES_DB}" <<EOF
|
||||
alter sequence torrents_torrent_id_seq start
|
||||
${last_nyaa_torrent_id} restart
|
||||
EOF
|
|
@ -1,2 +0,0 @@
|
|||
PANTSU_DBTYPE=sqlite3
|
||||
PANTSU_DBPARAMS=./nyaa.db?cache_size=50
|
|
@ -1,11 +0,0 @@
|
|||
<!--[if IE]><meta http-equiv="X-UA-Compatible" content="IE=5,IE=9" ><![endif]-->
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Nyaapantsu_models</title>
|
||||
<meta charset="utf-8"/>
|
||||
</head>
|
||||
<body><div class="mxgraph" style="max-width:100%;border:1px solid transparent;" data-mxgraph="{"highlight":"#0000ff","nav":true,"resize":true,"toolbar":"zoom layers lightbox","edit":"_blank","xml":"<mxfile userAgent=\"Mozilla/5.0 (X11; Linux x86_64; rv:38.0) Gecko/20100101 Firefox/38.0\" version=\"6.6.3\" editor=\"www.draw.io\" type=\"google\"><diagram name=\"Page-1\">7V1rc6M6Ev01qdrdqqR4GIw/JnGys7uZSTaPuvd+2pKNbGsHIxbkJL6/fiUkGYTEw7GJ40xcUzUgGj36HLW6W0BO3Mvl699TkCy+4xBGJ44Vvp644xPHsQeuRf9jJWte4g0CXjBPUSiEioIH9CcUheK++QqFMFMECcYRQYlaOMVxDKdEKQNpil9UsRmO1FYTMIdawcMURHrpbygkC14aeFZR/g2i+UK2bFviyhJIYVGQLUCIX0pF7tWJe5liTPjR8vUSRkx5Ui/8vuuaq5uOpTAmnW6YOCPP9kAwdAN/OrFOmTCr4hlEKzHaE8ePaGUXIXpmPSZroQb/fyvWzYsIxfB0IcZ7TkVs1qhXCDCtR2geK3dNaQ9hWhby5+L/vLUZpiMwNccunGY5J1hjdLSvei3/fLj9QS/m1MtklZO02oheQlXFW9aK8+HLUkfpmvOyQAQ+JGDKzl8o6anQgiwjembTw4yk+Ce8xBFOc3nXyn9sMCiKSuXX+Y+Wz1MQIqoheS3GMa364hmmBFEengt1EpxsusOuwddaHtgbdtFpCfESknRNReQNgWSkmJLukJ++FPy2rZGQWZTIPRy6YmKJSTXfVF7wjh4I6plp6AMrmExmvg9GLpxNhqfDWhbuxosHAuIQRFSbWS3iB8KWdUKYOtun53LKiInSK/ieCr7nWxr6o4EBfEda8l3A12zQYPCF/vuh7w9V8Ie2a5j67ruhb2vgX+LlEuYYVYz2afmnX/7HmJNhhXLS/OXuX3/VhR5xyjSlylaFnjKYNktcUvxyhZ/n/ElRPDcIpRAQGJ4LsUe0hIa2krBdaAwjWBL6m1mqdrTyLnFGdXNt0g0bthDND6XcgebIPsjuuArZN65oieyOZeC6HfTBdd3Zuo3Ct9K9M5NjsIQtRO3C5jGlaRNHt2Xf8bLKVS3oINCdJzOpnD2QSvOdRl+k+hSksiumKuhqqvbBKt0p01hFoQITkMHxaplszasfrXQRSN6g+Gez4DWKYOH5UYL6g3ZeHS8v7A3o0mEL3DO/9HtP46PRxGukCQ/L+6fK0/3NzvZHShwxU0a2yhS/s7fTCzd8jRts6h7Qrb+A8RSHMLzL03ItNkYzMcdLjOrSMvSsM7f08w7JkkBjyQ2I5yuWkt2NKe125XgR9UeVNWEUKIjqIb0R0VEvAb2lIfoDEzRDU0AQjveMaicrfw9ByCUmGEeGJkJaBe2hDH/r6nlKoxYBLXFwvByzXSdQSOY5A8Xx8DuaDa8Xlul5I7EG3MMEpz1lj8Ywm6YoyXncxUXZOc3UJYP0leRRlzfH6bqg9cNMPcujMPNNTrGkSa0fuyUxBZ/4iblHBVHYEZc5XpLYga8ume5hAyfpkpW9YwjDNxOjo8tTlfgO5jFsWT2/gazFXWZ2KSNgmXwW/2rkfuCY29YDq43R72PRa2dRO0Mu6TI2x3Tg9WR9WE26SBFAVlmDQFtG8SmJMAjbFt4xfomZXFNLtCtpiJcNEt1SVVXT/VCjw9/gJKMzqEh71Am+dbdIqsbkHlRlb6NQFa9DvkhGC12eeBcn3rico65pwnRb2z0GlKhVhWlWgG3C4AbC6aJVijae5JptqQxk5GFK7VsjDxk3blBGyqPj+ZGjd8iq+QbqaHWzl4N+dpj1FEOj43Na/W3vjrWbzFY71m5T9dwl1Z6fr8IX8STjzwtY+7JKBFLy0xbPvj1+N2ZbayerWcuaue+2dNQqo4PB7mb6dR32fW7ASHa1IJJZ7ZoZNotpS4cxY152Bo0C3RLvHWyw63SxwSYpgw02VraTDT72YIdaYNV/DZyDGmB9i7rRNLQY327bz+XkSm325fwZUCdui31s8/Ta9y7258/ZaM8gdt7t7ufBHD1nfZ6ge5itordxVCCqLIeNTse/VzBd38MpTqlfvJLMMBL3ERMQmUWPlxDFZqUghG13ZUQvQbaj55eLlWFLMvxq+42O99aN6H4mt55q41a0j2RJt8XpDmTZC52/zVJXS4BaNpxaw4j9PYNKDeIjpVhLfllKXb0mSPrs5vo227yty/gDJIRezJolTSXX+T/rcQEzFliTF8zIlbLjJMUTMIkYbZf4mYdPKGZCC3Y5hoCts7MVWaWmzqOfRY+4eTdzigpKX7VJzOCMj71OmXzTElPrSJQ3YpUb1R3azsmVp5jSKzTUak6YKTgqyB6xtRtp208djZ3bj7XTn9wr9m/2uvXezdS17b1va8Hq2uEzss13yqfjJ/Kaqs8i+529pl72Ph19a4Kx5BpHEXsL8y2RXjMHec2f6KELJ1AfunCtjoD28iyPo7+YxzDhKafsNtp+v7Kb0TA+PnG8qLrqCuF2naT9LBB6OlxdirdEVF3V5fUsAXHVb6BdNRWXy5YgqZP2jDeoDNLuGZvuKS9EWp+Ol2X2wFd5FtiWsmvdcRdGyu2XdXoOUELQ9SVP1zG95LkhZLVgt2p/rAGgvCDZKg8QxCcNEKDwLUvcqXl5XOtM23unFHXSxCz52miJVKKo9c3RJQpD1syFicql91BdR56Lbll74GQ1qeNoFByYXjR2gx4o6OopHQnPKqoCFqHNWrRAWYE9O8wWuTNjgbw9SY4URjwCWrDvUjiXTCAOWSiJSR5QTqcwAynKQ85QvCVBD3/CdfXuM1pwl6IlyFXJa7nGKWSAyhtmCEZhtglnqSwLNJlqqWZldkLcy8M52kaWwClBzzBan5WYWYy1bfRsLc7Y29QiSr5MuSZmmI8Rk5pnfN/aWn465RGADNDDFLycIbwZ3ZSZb2vC+gNDxAUnTEU4gTEP7HlvZ3x7vZja/8mxy87yaSdqR6SratgeE1MIT57Qo5yc3paDp4Vl9u3dLkRwRnawCvZgTy5Q5ZMDgWYIhp4pTJEWY7+WwNUUDcM5lIYPp2SB5zgG0VVRepHSqDFkuZyxpSICXxH5nRWfeeLsD3klpj0tXWKnf4gKMgJScs6+TkMLru6XlMu3OXD5hWvERpMLwjhUxNa8rCTxX+qBrQVeYEUwLSqGcIPZlwPy7phhZSNvBpUqCq/SKazRpnwejfZ7DkmNkG9mBzd7z2oH9ou11wfWdgnpEri/bzCTSJ85ng72nzDFj/g7x7KMt23AW9DiQ0Eu48JGyO3DYe73Mr/rMbd/AczlGxcfFfPhYTEffkrMPzbkwWFN+y8LOd/xOAjko6/V/DCW/XCYywTBMa7mIhj7UHA7Xfz1A8Ktp2muXsGU5HkTR6OCHiGn7OlmMBE5LPciwSjfJh/zrW4WG1OlZ0Kx7aEy//RaRkNkFM8fc3ROB/1EyTTcVbd/Nts65UDZ9G22Xr4Bo2v7y6Xa2dhaH2n2aV+TsvuH3FEXWA7zfnIjewPc3yPgo/dwovNbqS7AuiQgLF9R8x3mz64JcxPY1fS8VyZPu/zQapSvbkhV5OkB73FB1c3Q38be9zZYX+Q9rLXqJ4/bYK0qK5RhgeqIt7KOFZDbHwDyoIu9Gh0Kcv3J6IMHA0cPudPFJ+G8OATkvWTw1d0a60Sx6opRtz+dUXc+9AzvJXm/W1bvV8D7YNPb7iXmOMY07j5N+nsEHTWQ09PiT5pwt774wzDu1f8B</diagram></mxfile>"}"></div>
|
||||
<script type="text/javascript" src="https://www.draw.io/embed2.js?s=er&"></script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,2 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<mxfile userAgent="Mozilla/5.0 (X11; Linux x86_64; rv:38.0) Gecko/20100101 Firefox/38.0" version="6.6.3" editor="www.draw.io" type="google"><diagram name="Page-1">7V1tc6M4Ev41qdq7qqR4Mdj+mMTJzt1lZrJ5qd39tCWDYusGI07ISby//iSEzIsEyLGJ7UxcUzUgGiT186jV3RLkxL1cvP5KQDL/ikMYnThW+HriTk4cxx64FvuPl6xEiTcYiYIZQWEuVBTco79hXpjfN1uiEKYVQYpxRFFSLQxwHMOAVsoAIfilKvaEo2qtCZhBpeA+AJFa+jsK6VyUjjyrKP8C0Wwua7at/MoCSOG8IJ2DEL+UityrE/eSYEzF0eL1EkZceVIv4r7rhqvrhhEYU6Mbps7Ysz0wGrojP5hap1yYP+IZRMu8tyeOH7GHXYTombeYrnI1+P9b8mZeRCiGp/O8v+dMxOaVeoUA13qEZnHlroC1EJKykD/L/89qe8KsB7rq+IXTNOMEr4z19lV9yr/vv39jFzPqpfKRU1KvRC1hqhI1K8VZ92WpU2ma8zJHFN4nIODnL4z0TGhOFxE7s9lhSgn+AS9xhEkm71rZj3cGRVGp/Dr7sfIZASFiGpLXYhyzR188Q0IR4+F5rk6Kk3Vz+DX42sgDe80uNiwhXkBKVkxE3jCUFM2HpDsUpy8Fv8fjXGRe4vZw6ObjKh9Ts/WzC9qxg5x5ehb6wBpNp0++D8YufJoOT4eNJNyOFvcUxCGImDLTRsD3BC1vRG7pbJ+dyxGTj5MesXdst4q951sK+K6jAd+RN24DvmKCBoNP9N8PfW9YBX9ouwr4tuW+G/q2Av4lXixghlHNZp+Wf+rlf00EGZYoI80vt//5hyr0gAnXVFW2LvSYQtIuccnwyxR+nvGHoHimESIQUBie52IPaAE1dSVht9AERrAk9E+9VGNv5V35GdPNtU43vNu5aHYo5fY0RnZAdt9xK2QfeKqlcywN1+1RH1xXfa3vUfhWuhszOQYL2EFUEzZPGE3bOLop+46XVbXpczBSfSc9qZwdkErxncafpPoQpLJrpmpkaqp2wSrVKVNYxaACU5DCyXKRbMyrb510yZG8QfGPdsFrFMHC82ME9QfdvDpeXhTJBOmwjdwzv/R7T+Oj0MRrpYmIyvunyuPdzdb2R0ocL1Mce1xliu/u1YT4Cjf40N2jW38B4wCHMLzNsnIdNkYxMcdLjPrUMvSsM7f08/bJkpHCkhsQz5Y8I7sdU7rtyvEi6tVG+nA8qiCqhvRaRMe9BPSWgug3TNETCgBFON4xqkZW/g6CUEhMMY40VYTsEayFMvxtes4jiToElMTB8XLMdp1RhWSeM6g4Hr6h2fB6YZmaN8rngDuYYNJT9mgC04CgJOOxiYuydZrJJIP0meSpTm+OYzqh9cNMNctTYeabnGJJk0Y/dkNi5nwSJ/oWFUThR0LmeEliDwe1Ba/9Bk7SJSt7xxCGbyaGoctTl/gKZjHsmD2/gLTDXeZ2KaVgkXwU/2rkHnDMbauB1dro9zHpdbOomyGXbBqbYdbxZrLeL6cmUhTQZdoi0JVRfEwiDMKuiXeCX2Iu11YTawoJ8aJFwixVVTfd9w06/B1OUzaCirRHk+BbV4ukanTuQV32exRWxZuQL5LRuS5PvIsTb1LOUTdUobut6x4NSsyqQpIWYOswuIEwmHdKscqTTLMdDwMpvQ+YfWvlIefGDUppuXciP3L0Dlk938AcLTN7OehnhVlNMbQ6Pqf13+buWLfJ7LRj3TZVzV0y7fnZLHwRT1OxX8DalVWikJGf1Xj25eGrNtvaOFj1WlbMvdnU0agMA4NtZvpVHfZ9rsFINrUgkl7tihnWiylThzZjXnYGtQJmiXcDG+w6JjZYJ6WxwdqHbWWDjz3Y4YtGFQs82q8BVpeoW01Dh/E1W34uJ1casy/nz4A5cRusY+uH165XsT9+zsYe1iIs49XufjbmqDnr8wTdwXQZvY2jOaKV6bDV6fhtCcnqDgaYML94KZmhJe4DpiDSix4vIZxBLT+zNmH7CbIdNb9czAwbkuFnW28sttnJvSzOwAzLfga3mmoTVrSPZInZ5HQL0vSFjd92qasFQB0LTp1hxO72oDKD+MAo1pFfllJXrwmSPrv+eetl3s5p/B5Syi6m7ZK6kuvsn/UwhykPrOkL5uQi/DgheAqmEaftAj+L8AnFXGjOL8cQ8Hn2aUmXRNd49KNokTDvek4xQemrtolpnPGJZ5TJ100xjY5EeSG2cmN1hdY4ufIYM3qFmqfqE2YVHCvIHrG1GyvLT4YTl9uPtVN37hXrNztdejczdV1r75tasKZ6xIjs8p2y4fhxvCZlVcvzDbd+9LP26ahLE5wl1ziK+EuYb4n02jkonvyBNl04o+qmC9cytCa97OVx1BfzOCYi5ZR+jzZfrzQzGtrtE8eLqludIVzT0KafCUJNh1en4g0Rrc7q8nqagLjuN7Cm6orLZQuQNEl72huqDFLumejuKU9ESpuOl2W261d5NrKtyqq1YRJQyu2WdWoOUEJg+pKn6+he8lwTsl6w3WO/rQBgvKDpMgsQ8i8aIMDgW5S40/DuuNKYrvdOGeq0jVnytdESqfKizjdHFygMeTUXOiqX3kN1HXmeN8vaASdrWT65N6pEwXXep+oa90BBV03pSHiWUR2wCK3nojlKC+z5YTrPnBkLZPVJchAYiQhozj9L4VxygTjkoSSmWUAZBDAFBGUhZ5i/JcEOf8BV/e4zVnBL0AJkqhRPucYEckDlDU8IRmG6DmeZLA80uWqZZmV2Ir9XhHOsjjSBAUXPMFqdlZhZ9LWr93wuTvnb1HmUfEmEJp6w6COmDXt831pbdhqICEAG6CEBL2cIr3sXcPNtTXl7YIiE4JSrCCcwFoG9aO2TWF4vhvZfGXbpXylekgCeZaMvrwRRUw3xpSauF5FDYUcZR5kNvbaHGyqCFZaZuHMbEcEnuoWFsAc7codqMctIMQpDTxeySOuxW6vgKoqG4QxKI4gJneMZjkF0VZReEBZBhjyvM7GqiMBXRP/gxWdefvanvBKzlpYu8dM/8wekFBB6zj9Uwwqu7haM198z4LIL14j3JhOEcViIMWwf8FcQr8SFkth/mUu2ykEDS4pZUdGPG8w/JZC1SY8t7347skxb2YhpUKncoMYaP4O0QcjXU0TYwedqA3YLuNcH4HYJ7hLCf6yBk3CfOZ6K+N+Q4DWWZdDtOugFNw4KchkotkJu7w9zv5dB3oy5/RNgLl/BOFTMh/vFfPghMT9syEf7Ne0/LeRiCWQvkI8/Z/P9WPb9YS4zBsc4m+cR2UHB7Zj463uEW83bXL2CgGaJFEehghomE77dGUzzpJZ7kWCUrZtPxNo3D5CZ0tNcsd3xsvgWW8riZBTPHjJ0Tgf9hMos5q2uB63XecrRsu5jbb18FEbV9qdLtbWxtQ5p9Cmfl7L7h9ypTrCd+REBuZoh6RVxf4eIj9/Di85uZboAq5JAbvqKJ99isZtNvvho1xP2Xpk93fJDq1V+UHs1qCbPDkSLC66uu/42+r63xfpk727s1ZvYa1vOO9Orn+Rxi3WszYiaCdEwe1yZNwuC2QdAsJGJeRzva0JUt2YfTfBxyKg7Jm6QoMY+UO8lgXyMmaVdDnTnoCG3e3F9f3LMjSB/rwSyAwaB57shCLwpCKxxP96iOeIfEXCjxeD9uIt+7cuq8u3XpuBFkbd3610qdNyzq6EzQOVNB63+5YHScf33gw5izlEQ72VvwlabUY7fAJlMOeKtmd0jzk6LP+4kTELxJ7Lcq/8D</diagram></mxfile>
|
BIN
doc/api.dia
BIN
doc/api.dia
Fichier binaire non affiché.
91
doc/api.svg
91
doc/api.svg
|
@ -1,91 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/PR-SVG-20010719/DTD/svg10.dtd">
|
||||
<svg width="54cm" height="22cm" viewBox="9 44 1077 424" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g>
|
||||
<rect style="fill: #ffffff" x="10" y="50" width="248.7" height="44"/>
|
||||
<rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x="10" y="50" width="248.7" height="44"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:middle;font-family:monospace;font-style:normal;font-weight:normal" x="134.35" y="66"><<object>></text>
|
||||
<text font-size="16" style="fill: #000000;text-anchor:middle;font-family:sans-serif;font-style:normal;font-weight:700" x="134.35" y="85">API</text>
|
||||
<rect style="fill: #ffffff" x="10" y="94" width="248.7" height="52"/>
|
||||
<rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x="10" y="94" width="248.7" height="52"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="13" y="108">+torrents: list</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="13" y="124">+queryRecordCount: number = int</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="13" y="140">+totalRecordCount: number = int</text>
|
||||
<rect style="fill: #ffffff" x="10" y="146" width="248.7" height="8"/>
|
||||
<rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x="10" y="146" width="248.7" height="8"/>
|
||||
</g>
|
||||
<g>
|
||||
<rect style="fill: #ffffff" x="330" y="45" width="341.1" height="44"/>
|
||||
<rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x="330" y="45" width="341.1" height="44"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:middle;font-family:monospace;font-style:normal;font-weight:normal" x="500.55" y="61"><<object>></text>
|
||||
<text font-size="16" style="fill: #000000;text-anchor:middle;font-family:sans-serif;font-style:normal;font-weight:700" x="500.55" y="80">Torrent</text>
|
||||
<rect style="fill: #ffffff" x="330" y="89" width="341.1" height="356"/>
|
||||
<rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x="330" y="89" width="341.1" height="356"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="333" y="103">+id: string = int</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="333" y="119">+name: string</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="333" y="135">+status: number = int</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="333" y="151">+hash: string = SHA-1 Hex Digest</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="333" y="167">+date: string = ISO 8601 Date + Time</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="333" y="183">+filesize: number = int</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="333" y="199">+description: string = HTML</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="333" y="215">+comments: list</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="333" y="231">+sub_category: string = int</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="333" y="247">+category: string = int</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="333" y="263">+downloads: number = int</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="333" y="279">+uploader_id: number = int</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="333" y="295">+uploader_name: string</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="333" y="311">+uploader_old: string</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="333" y="327">+website_link: string = URL</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="333" y="343">+magnet: string = magnet URI</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="333" y="359">+torrent: string = URL</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="333" y="375">+seeders: number = int</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="333" y="391">+leechers: number = int</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="333" y="407">+completed: number = int</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="333" y="423">+last_scrape: string = ISO 8601 Date + Time</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="333" y="439">+file_list: list</text>
|
||||
<rect style="fill: #ffffff" x="330" y="445" width="341.1" height="8"/>
|
||||
<rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x="330" y="445" width="341.1" height="8"/>
|
||||
</g>
|
||||
<g>
|
||||
<polyline style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="284.879,102 301.854,102 301.854,67 330,67 "/>
|
||||
<polygon style="fill: #ffffff" points="259.708,102 273.708,97.2 287.708,102 273.708,106.8 "/>
|
||||
<polygon style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="259.708,102 273.708,97.2 287.708,102 273.708,106.8 "/>
|
||||
</g>
|
||||
<g>
|
||||
<rect style="fill: #ffffff" x="797" y="97" width="287.2" height="44"/>
|
||||
<rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x="797" y="97" width="287.2" height="44"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:middle;font-family:monospace;font-style:normal;font-weight:normal" x="940.6" y="113"><<object>></text>
|
||||
<text font-size="16" style="fill: #000000;text-anchor:middle;font-family:sans-serif;font-style:normal;font-weight:700" x="940.6" y="132">Comment</text>
|
||||
<rect style="fill: #ffffff" x="797" y="141" width="287.2" height="84"/>
|
||||
<rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x="797" y="141" width="287.2" height="84"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="800" y="155">+username: string</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="800" y="171">+user_id: number = int</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="800" y="187">+user_avatar: string = URL</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="800" y="203">+content: string = HTML</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="800" y="219">+date: string = ISO 8601 Date + Time</text>
|
||||
<rect style="fill: #ffffff" x="797" y="225" width="287.2" height="8"/>
|
||||
<rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x="797" y="225" width="287.2" height="8"/>
|
||||
</g>
|
||||
<g>
|
||||
<polyline style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="696.272,211 741.05,211 741.05,119 797,119 "/>
|
||||
<polygon style="fill: #ffffff" points="671.1,211 685.1,206.2 699.1,211 685.1,215.8 "/>
|
||||
<polygon style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="671.1,211 685.1,206.2 699.1,211 685.1,215.8 "/>
|
||||
</g>
|
||||
<g>
|
||||
<rect style="fill: #ffffff" x="781" y="352" width="117.8" height="44"/>
|
||||
<rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x="781" y="352" width="117.8" height="44"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:middle;font-family:monospace;font-style:normal;font-weight:normal" x="839.9" y="368"><<object>></text>
|
||||
<text font-size="16" style="fill: #000000;text-anchor:middle;font-family:sans-serif;font-style:normal;font-weight:700" x="839.9" y="387">File</text>
|
||||
<rect style="fill: #ffffff" x="781" y="396" width="117.8" height="36"/>
|
||||
<rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x="781" y="396" width="117.8" height="36"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="784" y="410">+path: string</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="784" y="426">+filesize: int</text>
|
||||
<rect style="fill: #ffffff" x="781" y="432" width="117.8" height="8"/>
|
||||
<rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x="781" y="432" width="117.8" height="8"/>
|
||||
</g>
|
||||
<g>
|
||||
<polyline style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="696.272,435 733.05,435 733.05,374 781,374 "/>
|
||||
<polygon style="fill: #ffffff" points="671.1,435 685.1,430.2 699.1,435 685.1,439.8 "/>
|
||||
<polygon style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="671.1,435 685.1,430.2 699.1,435 685.1,439.8 "/>
|
||||
</g>
|
||||
</svg>
|
Avant Largeur: | Hauteur: | Taille: 10 KiB |
BIN
doc/model.dia
BIN
doc/model.dia
Fichier binaire non affiché.
428
doc/model.svg
428
doc/model.svg
|
@ -1,428 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/PR-SVG-20010719/DTD/svg10.dtd">
|
||||
<svg width="59cm" height="35cm" viewBox="14 -53 1174 688" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g>
|
||||
<rect style="fill: #ffffff" x="472" y="63" width="203.1" height="18"/>
|
||||
<rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x="472" y="63" width="203.1" height="18"/>
|
||||
<text font-size="11.2" style="fill: #000000;text-anchor:middle;font-family:sans-serif;font-style:normal;font-weight:700" x="573.55" y="77">torrents</text>
|
||||
<rect style="fill: #ffffff" x="472" y="81" width="203.1" height="292"/>
|
||||
<rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x="472" y="81" width="203.1" height="292"/>
|
||||
<polygon style="fill: #000000" points="475,91 477,94 479,91 477,88 "/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="481" y="97">torrent_id</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="583.4" y="97">int</text>
|
||||
<line style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" x1="481" y1="98.6" x2="606.5" y2="98.6"/>
|
||||
<ellipse style="fill: none; fill-opacity:0; stroke-width: 0.2; stroke: #000000" cx="477" cy="107" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="481" y="113">torrent_name</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="583.4" y="113">text</text>
|
||||
<ellipse style="fill: #000000" cx="477" cy="123" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="481" y="129">torrent_hash</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="583.4" y="129">text</text>
|
||||
<ellipse style="fill: #000000" cx="477" cy="139" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="481" y="145">category</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="583.4" y="145">int</text>
|
||||
<ellipse style="fill: #000000" cx="477" cy="155" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="481" y="161">sub_category</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="583.4" y="161">int</text>
|
||||
<ellipse style="fill: #000000" cx="477" cy="171" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="481" y="177">status</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="583.4" y="177">int</text>
|
||||
<ellipse style="fill: none; fill-opacity:0; stroke-width: 0.2; stroke: #000000" cx="477" cy="187" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="481" y="193">date</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="583.4" y="193">timestamp</text>
|
||||
<ellipse style="fill: #000000" cx="477" cy="203" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="481" y="209">uploader</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="583.4" y="209">int</text>
|
||||
<ellipse style="fill: none; fill-opacity:0; stroke-width: 0.2; stroke: #000000" cx="477" cy="219" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="481" y="225">downloads</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="583.4" y="225">int</text>
|
||||
<ellipse style="fill: #000000" cx="477" cy="235" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="481" y="241">stardom</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="583.4" y="241">int</text>
|
||||
<ellipse style="fill: none; fill-opacity:0; stroke-width: 0.2; stroke: #000000" cx="477" cy="251" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="481" y="257">filesize</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="583.4" y="257">bigint</text>
|
||||
<ellipse style="fill: #000000" cx="477" cy="267" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="481" y="273">description</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="583.4" y="273">text</text>
|
||||
<ellipse style="fill: none; fill-opacity:0; stroke-width: 0.2; stroke: #000000" cx="477" cy="283" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="481" y="289">website_link</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="583.4" y="289">text</text>
|
||||
<ellipse style="fill: none; fill-opacity:0; stroke-width: 0.2; stroke: #000000" cx="477" cy="299" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="481" y="305">deleted_at</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="583.4" y="305">timestamp</text>
|
||||
<ellipse style="fill: none; fill-opacity:0; stroke-width: 0.2; stroke: #000000" cx="477" cy="315" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="481" y="321">seeders</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="583.4" y="321">int</text>
|
||||
<ellipse style="fill: none; fill-opacity:0; stroke-width: 0.2; stroke: #000000" cx="477" cy="331" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="481" y="337">leechers</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="583.4" y="337">int</text>
|
||||
<ellipse style="fill: none; fill-opacity:0; stroke-width: 0.2; stroke: #000000" cx="477" cy="347" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="481" y="353">completed</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="583.4" y="353">int</text>
|
||||
<ellipse style="fill: none; fill-opacity:0; stroke-width: 0.2; stroke: #000000" cx="477" cy="363" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="481" y="369">last_scrape</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="583.4" y="369">timestamptz</text>
|
||||
</g>
|
||||
<g>
|
||||
<rect style="fill: #ffffff" x="16" y="-52" width="187.7" height="18"/>
|
||||
<rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x="16" y="-52" width="187.7" height="18"/>
|
||||
<text font-size="11.2" style="fill: #000000;text-anchor:middle;font-family:sans-serif;font-style:normal;font-weight:700" x="109.85" y="-38">comments</text>
|
||||
<rect style="fill: #ffffff" x="16" y="-34" width="187.7" height="116"/>
|
||||
<rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x="16" y="-34" width="187.7" height="116"/>
|
||||
<polygon style="fill: #000000" points="19,-24 21,-21 23,-24 21,-27 "/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="25" y="-18">comment_id</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="112" y="-18">int</text>
|
||||
<line style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" x1="25" y1="-16.4" x2="135.1" y2="-16.4"/>
|
||||
<ellipse style="fill: #000000" cx="21" cy="-8" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="25" y="-2">torrent_id</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="112" y="-2">int</text>
|
||||
<ellipse style="fill: #000000" cx="21" cy="8" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="25" y="14">user_id</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="112" y="14">int</text>
|
||||
<ellipse style="fill: #000000" cx="21" cy="24" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="25" y="30">content</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="112" y="30">text</text>
|
||||
<ellipse style="fill: #000000" cx="21" cy="40" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="25" y="46">created_at</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="112" y="46">timestamp</text>
|
||||
<ellipse style="fill: none; fill-opacity:0; stroke-width: 0.2; stroke: #000000" cx="21" cy="56" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="25" y="62">updated_at</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="112" y="62">timestamp</text>
|
||||
<ellipse style="fill: none; fill-opacity:0; stroke-width: 0.2; stroke: #000000" cx="21" cy="72" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="25" y="78">deleted_at</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="112" y="78">timestamptz</text>
|
||||
</g>
|
||||
<g>
|
||||
<polyline style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="203.7,-8 337.85,-8 337.85,91 467.528,91 "/>
|
||||
<polyline style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="459.764,96 469.764,91 459.764,86 "/>
|
||||
<text font-size="9.6" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="207.7" y="-12">n</text>
|
||||
<text font-size="9.6" style="fill: #000000;text-anchor:end;font-family:monospace;font-style:normal;font-weight:normal" x="468" y="87">1</text>
|
||||
</g>
|
||||
<g>
|
||||
<rect style="fill: #ffffff" x="35" y="529" width="149.2" height="18"/>
|
||||
<rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x="35" y="529" width="149.2" height="18"/>
|
||||
<text font-size="11.2" style="fill: #000000;text-anchor:middle;font-family:sans-serif;font-style:normal;font-weight:700" x="109.6" y="543">files</text>
|
||||
<rect style="fill: #ffffff" x="35" y="547" width="149.2" height="68"/>
|
||||
<rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x="35" y="547" width="149.2" height="68"/>
|
||||
<polygon style="fill: #000000" points="38,557 40,560 42,557 40,554 "/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="44" y="563">file_id</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="131" y="563">int</text>
|
||||
<line style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" x1="44" y1="564.6" x2="154.1" y2="564.6"/>
|
||||
<ellipse style="fill: none; fill-opacity:0; stroke-width: 0.2; stroke: #000000" cx="40" cy="573" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="44" y="579">torrent_id</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="131" y="579">int</text>
|
||||
<ellipse style="fill: none; fill-opacity:0; stroke-width: 0.2; stroke: #000000" cx="40" cy="589" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="44" y="595">path</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="131" y="595">text</text>
|
||||
<ellipse style="fill: none; fill-opacity:0; stroke-width: 0.2; stroke: #000000" cx="40" cy="605" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="44" y="611">filesize</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="131" y="611">bigint</text>
|
||||
</g>
|
||||
<g>
|
||||
<rect style="fill: #ffffff" x="361" y="390" width="218.5" height="18"/>
|
||||
<rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x="361" y="390" width="218.5" height="18"/>
|
||||
<text font-size="11.2" style="fill: #000000;text-anchor:middle;font-family:sans-serif;font-style:normal;font-weight:700" x="470.25" y="404">users</text>
|
||||
<rect style="fill: #ffffff" x="361" y="408" width="218.5" height="228"/>
|
||||
<rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x="361" y="408" width="218.5" height="228"/>
|
||||
<polygon style="fill: #000000" points="364,418 366,421 368,418 366,415 "/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="370" y="424">user_id</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="503.2" y="424">int</text>
|
||||
<line style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" x1="370" y1="425.6" x2="526.3" y2="425.6"/>
|
||||
<ellipse style="fill: #000000" cx="366" cy="434" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="370" y="440">username</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="503.2" y="440">text</text>
|
||||
<ellipse style="fill: #000000" cx="366" cy="450" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="370" y="456">password</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="503.2" y="456">text</text>
|
||||
<ellipse style="fill: none; fill-opacity:0; stroke-width: 0.2; stroke: #000000" cx="366" cy="466" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="370" y="472">email</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="503.2" y="472">text</text>
|
||||
<ellipse style="fill: #000000" cx="366" cy="482" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="370" y="488">status</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="503.2" y="488">int</text>
|
||||
<ellipse style="fill: #000000" cx="366" cy="498" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="370" y="504">created_at</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="503.2" y="504">timestamp</text>
|
||||
<ellipse style="fill: none; fill-opacity:0; stroke-width: 0.2; stroke: #000000" cx="366" cy="514" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="370" y="520">updated_at</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="503.2" y="520">timestamp</text>
|
||||
<ellipse style="fill: none; fill-opacity:0; stroke-width: 0.2; stroke: #000000" cx="366" cy="530" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="370" y="536">last_login_at</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="503.2" y="536">timestamp</text>
|
||||
<ellipse style="fill: none; fill-opacity:0; stroke-width: 0.2; stroke: #000000" cx="366" cy="546" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="370" y="552">last_login_ip</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="503.2" y="552">text</text>
|
||||
<ellipse style="fill: none; fill-opacity:0; stroke-width: 0.2; stroke: #000000" cx="366" cy="562" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="370" y="568">api_token</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="503.2" y="568">text</text>
|
||||
<ellipse style="fill: #000000" cx="366" cy="578" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="370" y="584">api_token_expiry</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="503.2" y="584">timestamp</text>
|
||||
<ellipse style="fill: none; fill-opacity:0; stroke-width: 0.2; stroke: #000000" cx="366" cy="594" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="370" y="600">language</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="503.2" y="600">text</text>
|
||||
<ellipse style="fill: none; fill-opacity:0; stroke-width: 0.2; stroke: #000000" cx="366" cy="610" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="370" y="616">md5</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="503.2" y="616">text</text>
|
||||
<ellipse style="fill: none; fill-opacity:0; stroke-width: 0.2; stroke: #000000" cx="366" cy="626" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="370" y="632">settings</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="503.2" y="632">text</text>
|
||||
</g>
|
||||
<g>
|
||||
<rect style="fill: #ffffff" x="209" y="439.5" width="133.8" height="18"/>
|
||||
<rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x="209" y="439.5" width="133.8" height="18"/>
|
||||
<text font-size="11.2" style="fill: #000000;text-anchor:middle;font-family:sans-serif;font-style:normal;font-weight:700" x="275.9" y="453.5">notifications</text>
|
||||
<rect style="fill: #ffffff" x="209" y="457.5" width="133.8" height="100"/>
|
||||
<rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x="209" y="457.5" width="133.8" height="100"/>
|
||||
<polygon style="fill: #000000" points="212,467.5 214,470.5 216,467.5 214,464.5 "/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="218" y="473.5">id</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="305" y="473.5">int</text>
|
||||
<line style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" x1="218" y1="475.1" x2="328.1" y2="475.1"/>
|
||||
<ellipse style="fill: none; fill-opacity:0; stroke-width: 0.2; stroke: #000000" cx="214" cy="483.5" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="218" y="489.5">content</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="305" y="489.5">text</text>
|
||||
<ellipse style="fill: none; fill-opacity:0; stroke-width: 0.2; stroke: #000000" cx="214" cy="499.5" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="218" y="505.5">read</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="305" y="505.5">bool</text>
|
||||
<ellipse style="fill: none; fill-opacity:0; stroke-width: 0.2; stroke: #000000" cx="214" cy="515.5" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="218" y="521.5">identifier</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="305" y="521.5">text</text>
|
||||
<ellipse style="fill: none; fill-opacity:0; stroke-width: 0.2; stroke: #000000" cx="214" cy="531.5" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="218" y="537.5">url</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="305" y="537.5">text</text>
|
||||
<ellipse style="fill: none; fill-opacity:0; stroke-width: 0.2; stroke: #000000" cx="214" cy="547.5" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="218" y="553.5">user_id</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="305" y="553.5">int</text>
|
||||
</g>
|
||||
<g>
|
||||
<rect style="fill: #ffffff" x="14.7" y="103.5" width="187.7" height="18"/>
|
||||
<rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x="14.7" y="103.5" width="187.7" height="18"/>
|
||||
<text font-size="11.2" style="fill: #000000;text-anchor:middle;font-family:sans-serif;font-style:normal;font-weight:700" x="108.55" y="117.5">sukebei_comments</text>
|
||||
<rect style="fill: #ffffff" x="14.7" y="121.5" width="187.7" height="116"/>
|
||||
<rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x="14.7" y="121.5" width="187.7" height="116"/>
|
||||
<polygon style="fill: #000000" points="17.7,131.5 19.7,134.5 21.7,131.5 19.7,128.5 "/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="23.7" y="137.5">comment_id</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="110.7" y="137.5">int</text>
|
||||
<line style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" x1="23.7" y1="139.1" x2="133.8" y2="139.1"/>
|
||||
<ellipse style="fill: #000000" cx="19.7" cy="147.5" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="23.7" y="153.5">torrent_id</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="110.7" y="153.5">int</text>
|
||||
<ellipse style="fill: #000000" cx="19.7" cy="163.5" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="23.7" y="169.5">user_id</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="110.7" y="169.5">int</text>
|
||||
<ellipse style="fill: #000000" cx="19.7" cy="179.5" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="23.7" y="185.5">content</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="110.7" y="185.5">text</text>
|
||||
<ellipse style="fill: #000000" cx="19.7" cy="195.5" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="23.7" y="201.5">created_at</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="110.7" y="201.5">timestamp</text>
|
||||
<ellipse style="fill: none; fill-opacity:0; stroke-width: 0.2; stroke: #000000" cx="19.7" cy="211.5" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="23.7" y="217.5">updated_at</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="110.7" y="217.5">timestamp</text>
|
||||
<ellipse style="fill: none; fill-opacity:0; stroke-width: 0.2; stroke: #000000" cx="19.7" cy="227.5" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="23.7" y="233.5">deleted_at</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="110.7" y="233.5">timestamptz</text>
|
||||
</g>
|
||||
<g>
|
||||
<polyline style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="202.4,147.5 338,147.5 338,91 472,91 "/>
|
||||
<text font-size="9.59961" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="206.4" y="143.5">n</text>
|
||||
<text font-size="9.59961" style="fill: #000000;text-anchor:end;font-family:monospace;font-style:normal;font-weight:normal" x="468" y="87">1</text>
|
||||
</g>
|
||||
<g>
|
||||
<rect style="fill: #ffffff" x="595" y="402.75" width="226.2" height="18"/>
|
||||
<rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x="595" y="402.75" width="226.2" height="18"/>
|
||||
<text font-size="11.2" style="fill: #000000;text-anchor:middle;font-family:sans-serif;font-style:normal;font-weight:700" x="708.1" y="416.75">torrent_reports</text>
|
||||
<rect style="fill: #ffffff" x="595" y="420.75" width="226.2" height="84"/>
|
||||
<rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x="595" y="420.75" width="226.2" height="84"/>
|
||||
<polygon style="fill: #000000" points="598,430.75 600,433.75 602,430.75 600,427.75 "/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="604" y="436.75">torrent_report_id</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="744.9" y="436.75">int</text>
|
||||
<line style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" x1="604" y1="438.35" x2="768" y2="438.35"/>
|
||||
<ellipse style="fill: none; fill-opacity:0; stroke-width: 0.2; stroke: #000000" cx="600" cy="446.75" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="604" y="452.75">type</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="744.9" y="452.75">text</text>
|
||||
<ellipse style="fill: none; fill-opacity:0; stroke-width: 0.2; stroke: #000000" cx="600" cy="462.75" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="604" y="468.75">torrent_id</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="744.9" y="468.75">int</text>
|
||||
<ellipse style="fill: none; fill-opacity:0; stroke-width: 0.2; stroke: #000000" cx="600" cy="478.75" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="604" y="484.75">user_id</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="744.9" y="484.75">int</text>
|
||||
<ellipse style="fill: none; fill-opacity:0; stroke-width: 0.2; stroke: #000000" cx="600" cy="494.75" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="604" y="500.75">created_at</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="744.9" y="500.75">timestamp</text>
|
||||
</g>
|
||||
<g>
|
||||
<rect style="fill: #ffffff" x="35" y="452.25" width="118.4" height="18"/>
|
||||
<rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x="35" y="452.25" width="118.4" height="18"/>
|
||||
<text font-size="11.2" style="fill: #000000;text-anchor:middle;font-family:sans-serif;font-style:normal;font-weight:700" x="94.2" y="466.25">user_follows</text>
|
||||
<rect style="fill: #ffffff" x="35" y="470.25" width="118.4" height="36"/>
|
||||
<rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x="35" y="470.25" width="118.4" height="36"/>
|
||||
<polygon style="fill: #000000" points="38,480.25 40,483.25 42,480.25 40,477.25 "/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="44" y="486.25">user_id</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="123.3" y="486.25">int</text>
|
||||
<line style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" x1="44" y1="487.85" x2="146.4" y2="487.85"/>
|
||||
<ellipse style="fill: #000000" cx="40" cy="496.25" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="44" y="502.25">following</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="123.3" y="502.25">int</text>
|
||||
</g>
|
||||
<g>
|
||||
<rect style="fill: #ffffff" x="18" y="259.25" width="133.8" height="18"/>
|
||||
<rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x="18" y="259.25" width="133.8" height="18"/>
|
||||
<text font-size="11.2" style="fill: #000000;text-anchor:middle;font-family:sans-serif;font-style:normal;font-weight:700" x="84.9" y="273.25">user_uploads_old</text>
|
||||
<rect style="fill: #ffffff" x="18" y="277.25" width="133.8" height="36"/>
|
||||
<rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x="18" y="277.25" width="133.8" height="36"/>
|
||||
<ellipse style="fill: #000000" cx="23" cy="287.25" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="27" y="293.25">username</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="114" y="293.25">text</text>
|
||||
<ellipse style="fill: #000000" cx="23" cy="303.25" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="27" y="309.25">torrent_id</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="114" y="309.25">int</text>
|
||||
</g>
|
||||
<g>
|
||||
<polyline style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="151.8,303.25 338,303.25 338,91 472,91 "/>
|
||||
<text font-size="9.59961" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="155.8" y="299.25">n</text>
|
||||
<text font-size="9.59961" style="fill: #000000;text-anchor:end;font-family:monospace;font-style:normal;font-weight:normal" x="468" y="87">1</text>
|
||||
</g>
|
||||
<g>
|
||||
<rect style="fill: #ffffff" x="734.7" y="63.5" width="203.1" height="18"/>
|
||||
<rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x="734.7" y="63.5" width="203.1" height="18"/>
|
||||
<text font-size="11.2" style="fill: #000000;text-anchor:middle;font-family:sans-serif;font-style:normal;font-weight:700" x="836.25" y="77.5">sukebei_torrents</text>
|
||||
<rect style="fill: #ffffff" x="734.7" y="81.5" width="203.1" height="292"/>
|
||||
<rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x="734.7" y="81.5" width="203.1" height="292"/>
|
||||
<polygon style="fill: #000000" points="737.7,91.5 739.7,94.5 741.7,91.5 739.7,88.5 "/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="743.7" y="97.5">torrent_id</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="846.1" y="97.5">int</text>
|
||||
<line style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" x1="743.7" y1="99.1" x2="869.2" y2="99.1"/>
|
||||
<ellipse style="fill: none; fill-opacity:0; stroke-width: 0.2; stroke: #000000" cx="739.7" cy="107.5" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="743.7" y="113.5">torrent_name</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="846.1" y="113.5">text</text>
|
||||
<ellipse style="fill: #000000" cx="739.7" cy="123.5" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="743.7" y="129.5">torrent_hash</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="846.1" y="129.5">text</text>
|
||||
<ellipse style="fill: #000000" cx="739.7" cy="139.5" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="743.7" y="145.5">category</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="846.1" y="145.5">int</text>
|
||||
<ellipse style="fill: #000000" cx="739.7" cy="155.5" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="743.7" y="161.5">sub_category</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="846.1" y="161.5">int</text>
|
||||
<ellipse style="fill: #000000" cx="739.7" cy="171.5" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="743.7" y="177.5">status</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="846.1" y="177.5">int</text>
|
||||
<ellipse style="fill: none; fill-opacity:0; stroke-width: 0.2; stroke: #000000" cx="739.7" cy="187.5" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="743.7" y="193.5">date</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="846.1" y="193.5">timestamp</text>
|
||||
<ellipse style="fill: #000000" cx="739.7" cy="203.5" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="743.7" y="209.5">uploader</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="846.1" y="209.5">int</text>
|
||||
<ellipse style="fill: none; fill-opacity:0; stroke-width: 0.2; stroke: #000000" cx="739.7" cy="219.5" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="743.7" y="225.5">downloads</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="846.1" y="225.5">int</text>
|
||||
<ellipse style="fill: #000000" cx="739.7" cy="235.5" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="743.7" y="241.5">stardom</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="846.1" y="241.5">int</text>
|
||||
<ellipse style="fill: none; fill-opacity:0; stroke-width: 0.2; stroke: #000000" cx="739.7" cy="251.5" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="743.7" y="257.5">filesize</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="846.1" y="257.5">bigint</text>
|
||||
<ellipse style="fill: #000000" cx="739.7" cy="267.5" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="743.7" y="273.5">description</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="846.1" y="273.5">text</text>
|
||||
<ellipse style="fill: none; fill-opacity:0; stroke-width: 0.2; stroke: #000000" cx="739.7" cy="283.5" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="743.7" y="289.5">website_link</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="846.1" y="289.5">text</text>
|
||||
<ellipse style="fill: none; fill-opacity:0; stroke-width: 0.2; stroke: #000000" cx="739.7" cy="299.5" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="743.7" y="305.5">deleted_at</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="846.1" y="305.5">timestamp</text>
|
||||
<ellipse style="fill: none; fill-opacity:0; stroke-width: 0.2; stroke: #000000" cx="739.7" cy="315.5" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="743.7" y="321.5">seeders</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="846.1" y="321.5">int</text>
|
||||
<ellipse style="fill: none; fill-opacity:0; stroke-width: 0.2; stroke: #000000" cx="739.7" cy="331.5" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="743.7" y="337.5">leechers</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="846.1" y="337.5">int</text>
|
||||
<ellipse style="fill: none; fill-opacity:0; stroke-width: 0.2; stroke: #000000" cx="739.7" cy="347.5" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="743.7" y="353.5">completed</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="846.1" y="353.5">int</text>
|
||||
<ellipse style="fill: none; fill-opacity:0; stroke-width: 0.2; stroke: #000000" cx="739.7" cy="363.5" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="743.7" y="369.5">last_scrape</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="846.1" y="369.5">timestamptz</text>
|
||||
</g>
|
||||
<g>
|
||||
<rect style="fill: #ffffff" x="843.7" y="395.75" width="149.2" height="18"/>
|
||||
<rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x="843.7" y="395.75" width="149.2" height="18"/>
|
||||
<text font-size="11.2" style="fill: #000000;text-anchor:middle;font-family:sans-serif;font-style:normal;font-weight:700" x="918.3" y="409.75">sukebei_files</text>
|
||||
<rect style="fill: #ffffff" x="843.7" y="413.75" width="149.2" height="68"/>
|
||||
<rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x="843.7" y="413.75" width="149.2" height="68"/>
|
||||
<polygon style="fill: #000000" points="846.7,423.75 848.7,426.75 850.7,423.75 848.7,420.75 "/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="852.7" y="429.75">file_id</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="939.7" y="429.75">int</text>
|
||||
<line style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" x1="852.7" y1="431.35" x2="962.8" y2="431.35"/>
|
||||
<ellipse style="fill: none; fill-opacity:0; stroke-width: 0.2; stroke: #000000" cx="848.7" cy="439.75" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="852.7" y="445.75">torrent_id</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="939.7" y="445.75">int</text>
|
||||
<ellipse style="fill: none; fill-opacity:0; stroke-width: 0.2; stroke: #000000" cx="848.7" cy="455.75" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="852.7" y="461.75">path</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="939.7" y="461.75">text</text>
|
||||
<ellipse style="fill: none; fill-opacity:0; stroke-width: 0.2; stroke: #000000" cx="848.7" cy="471.75" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="852.7" y="477.75">filesize</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="939.7" y="477.75">bigint</text>
|
||||
</g>
|
||||
<g>
|
||||
<rect style="fill: #ffffff" x="857.7" y="516" width="226.2" height="18"/>
|
||||
<rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x="857.7" y="516" width="226.2" height="18"/>
|
||||
<text font-size="11.2" style="fill: #000000;text-anchor:middle;font-family:sans-serif;font-style:normal;font-weight:700" x="970.8" y="530">sukebei_torrent_reports</text>
|
||||
<rect style="fill: #ffffff" x="857.7" y="534" width="226.2" height="84"/>
|
||||
<rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x="857.7" y="534" width="226.2" height="84"/>
|
||||
<polygon style="fill: #000000" points="860.7,544 862.7,547 864.7,544 862.7,541 "/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="866.7" y="550">torrent_report_id</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="1007.6" y="550">int</text>
|
||||
<line style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" x1="866.7" y1="551.6" x2="1030.7" y2="551.6"/>
|
||||
<ellipse style="fill: none; fill-opacity:0; stroke-width: 0.2; stroke: #000000" cx="862.7" cy="560" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="866.7" y="566">type</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="1007.6" y="566">text</text>
|
||||
<ellipse style="fill: none; fill-opacity:0; stroke-width: 0.2; stroke: #000000" cx="862.7" cy="576" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="866.7" y="582">torrent_id</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="1007.6" y="582">int</text>
|
||||
<ellipse style="fill: none; fill-opacity:0; stroke-width: 0.2; stroke: #000000" cx="862.7" cy="592" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="866.7" y="598">user_id</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="1007.6" y="598">int</text>
|
||||
<ellipse style="fill: none; fill-opacity:0; stroke-width: 0.2; stroke: #000000" cx="862.7" cy="608" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="866.7" y="614">created_at</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="1007.6" y="614">timestamp</text>
|
||||
</g>
|
||||
<g>
|
||||
<rect style="fill: #ffffff" x="16.006" y="352.25" width="172.3" height="18"/>
|
||||
<rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x="16.006" y="352.25" width="172.3" height="18"/>
|
||||
<text font-size="11.2" style="fill: #000000;text-anchor:middle;font-family:sans-serif;font-style:normal;font-weight:700" x="102.156" y="366.25">comments_old</text>
|
||||
<rect style="fill: #ffffff" x="16.006" y="370.25" width="172.3" height="68"/>
|
||||
<rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x="16.006" y="370.25" width="172.3" height="68"/>
|
||||
<ellipse style="fill: #000000" cx="21.006" cy="380.25" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="25.006" y="386.25">torrent_id</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="112.006" y="386.25">int</text>
|
||||
<ellipse style="fill: #000000" cx="21.006" cy="396.25" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="25.006" y="402.25">username</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="112.006" y="402.25">text</text>
|
||||
<ellipse style="fill: #000000" cx="21.006" cy="412.25" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="25.006" y="418.25">content</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="112.006" y="418.25">text</text>
|
||||
<ellipse style="fill: #000000" cx="21.006" cy="428.25" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="25.006" y="434.25">date</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="112.006" y="434.25">timestamp</text>
|
||||
</g>
|
||||
<g>
|
||||
<polyline style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="188.306,380.25 338.006,380.25 338.006,91 472,91 "/>
|
||||
<text font-size="9.59961" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="192.306" y="376.25">n</text>
|
||||
<text font-size="9.59961" style="fill: #000000;text-anchor:end;font-family:monospace;font-style:normal;font-weight:normal" x="468" y="87">1</text>
|
||||
</g>
|
||||
<g>
|
||||
<rect style="fill: #ffffff" x="1015.71" y="405.75" width="172.55" height="18"/>
|
||||
<rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x="1015.71" y="405.75" width="172.55" height="18"/>
|
||||
<text font-size="11.2" style="fill: #000000;text-anchor:middle;font-family:sans-serif;font-style:normal;font-weight:700" x="1101.98" y="419.75">sukebei_user_uploads_old</text>
|
||||
<rect style="fill: #ffffff" x="1015.71" y="423.75" width="172.55" height="36"/>
|
||||
<rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x="1015.71" y="423.75" width="172.55" height="36"/>
|
||||
<ellipse style="fill: #000000" cx="1020.71" cy="433.75" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="1024.71" y="439.75">username</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="1111.71" y="439.75">text</text>
|
||||
<ellipse style="fill: #000000" cx="1020.71" cy="449.75" rx="2" ry="2"/>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="1024.71" y="455.75">torrent_id</text>
|
||||
<text font-size="12.8" style="fill: #000000;text-anchor:start;font-family:monospace;font-style:normal;font-weight:normal" x="1111.71" y="455.75">int</text>
|
||||
</g>
|
||||
</svg>
|
Avant Largeur: | Hauteur: | Taille: 51 KiB |
6
main.go
6
main.go
|
@ -9,7 +9,6 @@ import (
|
|||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/NyaaPantsu/nyaa/cache"
|
||||
"github.com/NyaaPantsu/nyaa/config"
|
||||
"github.com/NyaaPantsu/nyaa/db"
|
||||
"github.com/NyaaPantsu/nyaa/network"
|
||||
|
@ -122,7 +121,6 @@ func main() {
|
|||
processFlags := conf.BindFlags()
|
||||
defaults := flag.Bool("print-defaults", false, "print the default configuration file on stdout")
|
||||
mode := flag.String("mode", "webapp", "which mode to run daemon in, either webapp, scraper or metainfo_fetcher")
|
||||
flag.Float64Var(&conf.Cache.Size, "c", config.Conf.Cache.Size, "size of the search cache in MB")
|
||||
|
||||
flag.Parse()
|
||||
if *defaults {
|
||||
|
@ -150,10 +148,6 @@ func main() {
|
|||
if err != nil {
|
||||
log.Fatal(err.Error())
|
||||
}
|
||||
err = cache.Configure(&conf.Cache)
|
||||
if err != nil {
|
||||
log.Fatal(err.Error())
|
||||
}
|
||||
err = search.Configure(&conf.Search)
|
||||
if err != nil {
|
||||
log.Fatal(err.Error())
|
||||
|
|
|
@ -17,7 +17,6 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/NyaaPantsu/nyaa/cache"
|
||||
"github.com/NyaaPantsu/nyaa/config"
|
||||
"github.com/NyaaPantsu/nyaa/model"
|
||||
"github.com/NyaaPantsu/nyaa/service"
|
||||
|
@ -348,7 +347,6 @@ func (r *TorrentRequest) ExtractInfo(req *http.Request) error {
|
|||
return err
|
||||
}
|
||||
|
||||
cache.Impl.ClearAll()
|
||||
defer req.Body.Close()
|
||||
|
||||
err = r.ExtractCategory(req)
|
||||
|
|
|
@ -8,7 +8,6 @@ import (
|
|||
"unicode"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/NyaaPantsu/nyaa/cache"
|
||||
"github.com/NyaaPantsu/nyaa/common"
|
||||
"github.com/NyaaPantsu/nyaa/config"
|
||||
"github.com/NyaaPantsu/nyaa/db"
|
||||
|
@ -258,17 +257,14 @@ func searchByQueryPostgres(r *http.Request, pagenum int, countAll bool, withUser
|
|||
|
||||
log.Infof("SQL query is :: %s\n", parameters.Conditions)
|
||||
|
||||
tor, count, err = cache.Impl.Get(search, func() (tor []model.Torrent, count int, err error) {
|
||||
if deleted {
|
||||
tor, count, err = torrentService.GetDeletedTorrents(¶meters, orderBy, int(search.Max), int(search.Max)*(search.Page-1))
|
||||
} else if countAll && !withUser {
|
||||
tor, count, err = torrentService.GetTorrentsOrderBy(¶meters, orderBy, int(search.Max), int(search.Max)*(search.Page-1))
|
||||
} else if withUser {
|
||||
tor, count, err = torrentService.GetTorrentsWithUserOrderBy(¶meters, orderBy, int(search.Max), int(search.Max)*(search.Page-1))
|
||||
} else {
|
||||
tor, err = torrentService.GetTorrentsOrderByNoCount(¶meters, orderBy, int(search.Max), int(search.Max)*(search.Page-1))
|
||||
}
|
||||
return
|
||||
})
|
||||
if deleted {
|
||||
tor, count, err = torrentService.GetDeletedTorrents(¶meters, orderBy, int(search.Max), int(search.Max)*(search.Page-1))
|
||||
} else if countAll && !withUser {
|
||||
tor, count, err = torrentService.GetTorrentsOrderBy(¶meters, orderBy, int(search.Max), int(search.Max)*(search.Page-1))
|
||||
} else if withUser {
|
||||
tor, count, err = torrentService.GetTorrentsWithUserOrderBy(¶meters, orderBy, int(search.Max), int(search.Max)*(search.Page-1))
|
||||
} else {
|
||||
tor, err = torrentService.GetTorrentsOrderByNoCount(¶meters, orderBy, int(search.Max), int(search.Max)*(search.Page-1))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
Référencer dans un nouveau ticket