You've already forked nyx
mirror of
https://github.com/rls-moe/nyx
synced 2025-08-19 06:18:38 +00:00
MVP, no mod tools or anything but it works
This commit is contained in:
67
resources/adminpass.go
Normal file
67
resources/adminpass.go
Normal file
@@ -0,0 +1,67 @@
|
||||
package resources
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/hlandau/passlib"
|
||||
"github.com/tidwall/buntdb"
|
||||
)
|
||||
|
||||
type AdminPass struct {
|
||||
ID string `json:"id"`
|
||||
Password string `json:"password"`
|
||||
}
|
||||
|
||||
func (a *AdminPass) HashLogin(pass string) error {
|
||||
var err error
|
||||
a.Password, err = passlib.Hash(pass)
|
||||
return err
|
||||
}
|
||||
|
||||
func (a *AdminPass) VerifyLogin(pass string) error {
|
||||
var err error
|
||||
err = passlib.VerifyNoUpgrade(pass, a.Password)
|
||||
return err
|
||||
}
|
||||
|
||||
func NewAdmin(tx *buntdb.Tx, in *AdminPass) error {
|
||||
dat, err := json.Marshal(in)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, replaced, err := tx.Set(
|
||||
fmt.Sprintf(adminPassPath, escapeString(in.ID)),
|
||||
string(dat),
|
||||
nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if replaced {
|
||||
return errors.New("Admin already exists")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetAdmin(tx *buntdb.Tx, id string) (*AdminPass, error) {
|
||||
var ret = &AdminPass{}
|
||||
dat, err := tx.Get(
|
||||
fmt.Sprintf(adminPassPath, escapeString(id)),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = json.Unmarshal([]byte(dat), ret); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func DelAdmin(tx *buntdb.Tx, id string) error {
|
||||
if _, err := tx.Delete(
|
||||
fmt.Sprintf(adminPassPath, escapeString(id)),
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
78
resources/board.go
Normal file
78
resources/board.go
Normal file
@@ -0,0 +1,78 @@
|
||||
package resources
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/tidwall/buntdb"
|
||||
)
|
||||
|
||||
type Board struct {
|
||||
ShortName string `json:"short"`
|
||||
LongName string `json:"long"`
|
||||
Metadata Metadata `json:"meta"`
|
||||
}
|
||||
|
||||
func NewBoard(tx *buntdb.Tx, hostname string, in *Board) error {
|
||||
dat, err := json.Marshal(in)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, replaced, err := tx.Set(
|
||||
fmt.Sprintf(boardPath, escapeString(hostname), escapeString(in.ShortName)),
|
||||
string(dat),
|
||||
nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if replaced {
|
||||
return errors.New("Board " + escapeString(in.ShortName) + " already exists")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestBoard(tx *buntdb.Tx, hostname, shortname string) (error) {
|
||||
_, err := tx.Get(
|
||||
fmt.Sprintf(boardPath, escapeString(hostname), escapeString(shortname)),
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
func GetBoard(tx *buntdb.Tx, hostname, shortname string) (*Board, error) {
|
||||
var ret = &Board{}
|
||||
dat, err := tx.Get(
|
||||
fmt.Sprintf(boardPath, escapeString(hostname), escapeString(shortname)),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = json.Unmarshal([]byte(dat), ret); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func DelBoard(tx *buntdb.Tx, hostname, shortname string) error {
|
||||
if _, err := tx.Delete(
|
||||
fmt.Sprintf(boardPath, escapeString(hostname), escapeString(shortname)),
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func ListBoards(tx *buntdb.Tx, hostname string) ([]*Board, error) {
|
||||
var boardList = []*Board{}
|
||||
var err error
|
||||
tx.AscendKeys(fmt.Sprintf(boardPath, escapeString(hostname), "*"),
|
||||
func(key, value string) bool {
|
||||
var board = &Board{}
|
||||
err = json.Unmarshal([]byte(value), board)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
boardList = append(boardList, board)
|
||||
return true
|
||||
})
|
||||
return boardList, err
|
||||
}
|
114
resources/db.go
Normal file
114
resources/db.go
Normal file
@@ -0,0 +1,114 @@
|
||||
package resources
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/tidwall/buntdb"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
setup = "/jack/setup"
|
||||
hostEnable = "/jack/%s/enabled"
|
||||
boardPath = "/jack/%s/board/%s/board-data"
|
||||
threadPath = "/jack/%s/board/%s/thread/%032d/thread-data"
|
||||
threadSPath = "/jack/%s/board/%s/thread/*/thread-data"
|
||||
replyPath = "/jack/%s/board/%s/thread/%032d/reply/%032d/reply-data"
|
||||
replySPath = "/jack/%s/board/%s/thread/%032d/reply/*/reply-data"
|
||||
modPassPath = "/jack/%s/pass/mod/%s/mod-data"
|
||||
adminPassPath = "/jack/./pass/admin/%s/admin-data"
|
||||
)
|
||||
|
||||
func InitialSetup(db *buntdb.DB) error {
|
||||
return db.Update(func(tx *buntdb.Tx) error {
|
||||
if _, err := tx.Get(setup); err != nil {
|
||||
fmt.Println("")
|
||||
if err != buntdb.ErrNotFound {
|
||||
fmt.Println("DB setup not known.")
|
||||
return err
|
||||
}
|
||||
fmt.Println("DB not setup.")
|
||||
tx.Set(setup, "yes", nil)
|
||||
} else {
|
||||
fmt.Println("DB setup.")
|
||||
return nil
|
||||
}
|
||||
|
||||
fmt.Println("Creating Indices")
|
||||
err := tx.CreateIndex("board/short", "/jack/*/board/*/board-data", buntdb.IndexJSON("short"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = tx.CreateIndex("replies", "/jack/*/board/*/thread/*/reply/*/reply-data", buntdb.IndexJSON("thread"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = tx.CreateIndex("board/thread", "/jack/*/board/*/thread/*/thread-data", buntdb.IndexJSON("board"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println("Creating default admin")
|
||||
admin := &AdminPass{
|
||||
ID: "admin",
|
||||
}
|
||||
err = admin.HashLogin("admin")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println("Saving default admin to DB")
|
||||
err = NewAdmin(tx, admin)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println("Committing setup...")
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func CreateHost(db *buntdb.DB, hostname string) error {
|
||||
return db.Update(func(tx *buntdb.Tx) error {
|
||||
hostname = escapeString(hostname)
|
||||
_, replaced, err := tx.Set(fmt.Sprintf(hostEnable, "hostname"), "", nil)
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
if replaced {
|
||||
tx.Rollback()
|
||||
return errors.New("Hostname already enabled")
|
||||
}
|
||||
|
||||
board := &Board{
|
||||
ShortName: "d",
|
||||
LongName: "default",
|
||||
Metadata: map[string]string{
|
||||
"locked": "true",
|
||||
"description": "Default Board",
|
||||
},
|
||||
}
|
||||
err = NewBoard(tx, hostname, board)
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func escapeString(in string) string {
|
||||
in = strings.Replace(in, ".", ".dot.", -1)
|
||||
in = strings.Replace(in, "-", ".minus.", -1)
|
||||
in = strings.Replace(in, "\\", ".backslash.", -1)
|
||||
in = strings.Replace(in, "*", ".star.", -1)
|
||||
in = strings.Replace(in, "?", ".ask.", -1)
|
||||
in = strings.Replace(in, "/", ".slash.", -1)
|
||||
in = strings.Replace(in, "@", ".at.", -1)
|
||||
in = strings.Replace(in, ">>", ".quote.", -1)
|
||||
in = strings.Replace(in, ">", ".arrow-left.", -1)
|
||||
in = strings.Replace(in, "<", ".arrow-right.", -1)
|
||||
return in
|
||||
}
|
17
resources/ids.go
Normal file
17
resources/ids.go
Normal file
@@ -0,0 +1,17 @@
|
||||
package resources
|
||||
|
||||
import (
|
||||
"go.rls.moe/nyx/resources/snowflakes"
|
||||
"time"
|
||||
)
|
||||
|
||||
var fountain = snowflakes.Generator{
|
||||
StartTime: time.Date(
|
||||
2017, 03, 11,
|
||||
11, 12, 29,
|
||||
0, time.UTC).Unix(),
|
||||
}
|
||||
|
||||
func getID() (int64, error) {
|
||||
return fountain.NewID()
|
||||
}
|
3
resources/metadata.go
Normal file
3
resources/metadata.go
Normal file
@@ -0,0 +1,3 @@
|
||||
package resources
|
||||
|
||||
type Metadata map[string]string
|
72
resources/modpass.go
Normal file
72
resources/modpass.go
Normal file
@@ -0,0 +1,72 @@
|
||||
package resources
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/hlandau/passlib"
|
||||
"github.com/tidwall/buntdb"
|
||||
)
|
||||
|
||||
type ModPass struct {
|
||||
ID string `json:"id"`
|
||||
Password string `json:"password"`
|
||||
Board string `json:"board"`
|
||||
}
|
||||
|
||||
func (m *ModPass) HashLogin(pass string) error {
|
||||
var err error
|
||||
m.Password, err = passlib.Hash(pass)
|
||||
return err
|
||||
}
|
||||
|
||||
func (m *ModPass) VerifyLogin(pass string) error {
|
||||
var err error
|
||||
err = passlib.VerifyNoUpgrade(pass, m.Password)
|
||||
return err
|
||||
}
|
||||
|
||||
func NewMod(tx *buntdb.Tx, host string, in *ModPass) error {
|
||||
dat, err := json.Marshal(in)
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
_, replaced, err := tx.Set(
|
||||
fmt.Sprintf(modPassPath, escapeString(host), escapeString(in.ID)),
|
||||
string(dat),
|
||||
nil)
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
if replaced {
|
||||
tx.Rollback()
|
||||
return errors.New("Admin already exists")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetMod(tx *buntdb.Tx, host, id string) (*ModPass, error) {
|
||||
var ret = &ModPass{}
|
||||
dat, err := tx.Get(
|
||||
fmt.Sprintf(modPassPath, escapeString(host), escapeString(id)),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = json.Unmarshal([]byte(dat), ret); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func DelMod(tx *buntdb.Tx, host, id string) error {
|
||||
if _, err := tx.Delete(
|
||||
fmt.Sprintf(modPassPath, escapeString(host), escapeString(id)),
|
||||
); err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
113
resources/reply.go
Normal file
113
resources/reply.go
Normal file
@@ -0,0 +1,113 @@
|
||||
package resources
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/tidwall/buntdb"
|
||||
"golang.org/x/crypto/blake2b"
|
||||
)
|
||||
|
||||
type Reply struct {
|
||||
ID int64 `json:"id"`
|
||||
Text string `json:"text"`
|
||||
Image []byte `json:"image"`
|
||||
Thread int64 `json:"thread"`
|
||||
Board string `json:"board"`
|
||||
Metadata Metadata `json:"meta"`
|
||||
}
|
||||
|
||||
func NewReply(tx *buntdb.Tx, host, board string, thread *Thread, in *Reply, noId bool) error {
|
||||
var err error
|
||||
|
||||
if !noId {
|
||||
in.ID, err = getID()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
}
|
||||
|
||||
dat, err := json.Marshal(in)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = TestThread(tx, host, in.Board, in.Thread)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, replaced, err := tx.Set(
|
||||
fmt.Sprintf(replyPath, escapeString(host), escapeString(board), thread.ID, in.ID),
|
||||
string(dat),
|
||||
nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if replaced {
|
||||
return errors.New("Admin already exists")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetReply(tx *buntdb.Tx, host, board string, thread, id int64) (*Reply, error) {
|
||||
var ret = &Reply{}
|
||||
dat, err := tx.Get(
|
||||
fmt.Sprintf(replyPath, escapeString(host), escapeString(board), thread, id),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = json.Unmarshal([]byte(dat), ret); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func DelReply(tx *buntdb.Tx, host, board string, thread, id int64) error {
|
||||
if _, err := tx.Delete(
|
||||
fmt.Sprintf(replyPath, escapeString(host), escapeString(board), thread, id),
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func ListReplies(tx *buntdb.Tx, host, board string, thread int64) ([]*Reply, error) {
|
||||
var replyList = []*Reply{}
|
||||
var err error
|
||||
|
||||
err = TestThread(tx, host, board, thread)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tx.DescendKeys(
|
||||
fmt.Sprintf(
|
||||
replySPath,
|
||||
escapeString(host),
|
||||
escapeString(board),
|
||||
thread,
|
||||
),
|
||||
func(key, value string) bool {
|
||||
var reply = &Reply{}
|
||||
err = json.Unmarshal([]byte(value), reply)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
replyList = append(replyList, reply)
|
||||
if len(replyList) >= 100 {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
|
||||
return replyList, err
|
||||
}
|
||||
|
||||
func CalcTripCode(trip string) string {
|
||||
fullTrip := blake2b.Sum256([]byte(trip))
|
||||
return base64.RawStdEncoding.EncodeToString(fullTrip[:8])
|
||||
}
|
20
resources/snowflakes/LICENSE
Normal file
20
resources/snowflakes/LICENSE
Normal file
@@ -0,0 +1,20 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2017 Arke Works
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
1
resources/snowflakes/NOTICE
Normal file
1
resources/snowflakes/NOTICE
Normal file
@@ -0,0 +1 @@
|
||||
You can find the original generator at https://github.com/arke-works/arke/blob/master/snowflakes/generator.go
|
75
resources/snowflakes/generator.go
Normal file
75
resources/snowflakes/generator.go
Normal file
@@ -0,0 +1,75 @@
|
||||
package snowflakes
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
counterLen = 10
|
||||
counterMask = -1 ^ (-1 << counterLen)
|
||||
)
|
||||
|
||||
var (
|
||||
errNoFuture = errors.New("Start Time cannot be set in the future")
|
||||
)
|
||||
|
||||
// Generator is a fountain for new snowflakes. StartTime must be
|
||||
// initialized to a past point in time and Instance ID can be any
|
||||
// positive value or 0.
|
||||
//
|
||||
// If any value is not correctly set, new IDs cannot be produced.
|
||||
type Generator struct {
|
||||
StartTime int64
|
||||
mutex *sync.Mutex
|
||||
sequence int32
|
||||
now int64
|
||||
}
|
||||
|
||||
// NewID generates a new, unique snowflake value
|
||||
//
|
||||
// Up to 8192 snowflakes per second can be requested
|
||||
// If exhausted, it blocks and sleeps until a new second
|
||||
// of unix time starts.
|
||||
//
|
||||
// The return value is signed but always positive.
|
||||
//
|
||||
// Additionally, the return value is monotonic for a single
|
||||
// instance and weakly monotonic for many instances.
|
||||
func (g *Generator) NewID() (int64, error) {
|
||||
if g.mutex == nil {
|
||||
g.mutex = new(sync.Mutex)
|
||||
}
|
||||
if g.StartTime > time.Now().Unix() {
|
||||
return 0, errNoFuture
|
||||
}
|
||||
g.mutex.Lock()
|
||||
defer g.mutex.Unlock()
|
||||
|
||||
var (
|
||||
now int64
|
||||
flake int64
|
||||
)
|
||||
now = int64(time.Now().Unix())
|
||||
|
||||
if now == g.now {
|
||||
g.sequence = (g.sequence + 1) & counterMask
|
||||
if g.sequence == 0 {
|
||||
for now <= g.now {
|
||||
now = int64(time.Now().Unix())
|
||||
time.Sleep(time.Microsecond * 100)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
g.sequence = 0
|
||||
}
|
||||
|
||||
g.now = now
|
||||
|
||||
flake = int64(
|
||||
((now - g.StartTime) << counterLen) |
|
||||
int64(g.sequence))
|
||||
|
||||
return flake, nil
|
||||
}
|
12
resources/text.go
Normal file
12
resources/text.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package resources
|
||||
|
||||
import (
|
||||
"html/template"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func OperateReplyText(unsafe string) template.HTML {
|
||||
unsafe = template.HTMLEscapeString(unsafe)
|
||||
unsafe = strings.Replace(unsafe, "\n", "<br />", -1)
|
||||
return template.HTML(unsafe)
|
||||
}
|
145
resources/thread.go
Normal file
145
resources/thread.go
Normal file
@@ -0,0 +1,145 @@
|
||||
package resources
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/tidwall/buntdb"
|
||||
)
|
||||
|
||||
type Thread struct {
|
||||
ID int64 `json:"id"`
|
||||
StartReply int64 `json:"start"`
|
||||
Board string `json:"board"`
|
||||
Metadata Metadata `json:"-"`
|
||||
|
||||
intReply *Reply
|
||||
|
||||
intReplies []*Reply
|
||||
}
|
||||
|
||||
func (t *Thread) GetReplies() []*Reply {
|
||||
return t.intReplies
|
||||
}
|
||||
|
||||
func (t *Thread) GetReply() *Reply {
|
||||
return t.intReply
|
||||
}
|
||||
|
||||
func NewThread(tx *buntdb.Tx, host, board string, in *Thread, in2 *Reply) error {
|
||||
var err error
|
||||
|
||||
err = TestBoard(tx, host, in.Board)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
in.ID, err = getID()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
in2.Thread = in.ID
|
||||
|
||||
in2.ID, err = getID()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
in.StartReply = in2.ID
|
||||
|
||||
dat, err := json.Marshal(in)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, replaced, err := tx.Set(
|
||||
fmt.Sprintf(threadPath, escapeString(host), escapeString(board), in.ID),
|
||||
string(dat),
|
||||
nil)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if replaced {
|
||||
return errors.New("Thread already exists")
|
||||
}
|
||||
|
||||
return NewReply(tx, host, board, in, in2, true)
|
||||
}
|
||||
|
||||
func TestThread(tx *buntdb.Tx, host, board string, id int64) error {
|
||||
err := TestBoard(tx, host, board)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = tx.Get(
|
||||
fmt.Sprintf(threadPath, escapeString(host), escapeString(board), id),
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
func GetThread(tx *buntdb.Tx, host, board string, id int64) (*Thread, error) {
|
||||
var ret = &Thread{}
|
||||
dat, err := tx.Get(
|
||||
fmt.Sprintf(threadPath, escapeString(host), escapeString(board), id),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = json.Unmarshal([]byte(dat), ret); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ret.intReply, err = GetReply(tx, host, board, id, ret.StartReply)
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func DelThread(tx *buntdb.Tx, host, board string, id int64) error {
|
||||
if _, err := tx.Delete(
|
||||
fmt.Sprintf(threadPath, escapeString(host), escapeString(board), id),
|
||||
); err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func FillReplies(tx *buntdb.Tx, host string, thread *Thread) (err error) {
|
||||
thread.intReplies, err = ListReplies(tx, host, thread.Board, thread.ID)
|
||||
return
|
||||
}
|
||||
|
||||
func ListThreads(tx *buntdb.Tx, host, board string) ([]*Thread, error) {
|
||||
var threadList = []*Thread{}
|
||||
var err error
|
||||
|
||||
err = TestBoard(tx, host, board)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tx.DescendKeys(
|
||||
fmt.Sprintf(
|
||||
threadSPath,
|
||||
escapeString(host),
|
||||
escapeString(board),
|
||||
),
|
||||
func(key, value string) bool {
|
||||
var thread = &Thread{}
|
||||
err = json.Unmarshal([]byte(value), thread)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
thread.intReply, err = GetReply(tx, host, board, thread.ID, thread.StartReply)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
threadList = append(threadList, thread)
|
||||
if len(threadList) >= 25 {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
return threadList, err
|
||||
}
|
Reference in New Issue
Block a user