-
Notifications
You must be signed in to change notification settings - Fork 1
/
db.go
194 lines (173 loc) · 4.47 KB
/
db.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
/* Contains functions for manipulating the BoltDB file */
package main
import (
"encoding/json"
"errors"
"path/filepath"
"strings"
"time"
"github.com/anacrolix/torrent"
"go.etcd.io/bbolt"
)
func openDB() (*bbolt.DB, error) {
return bbolt.Open(
filepath.Join(btEngine.ClientConfig.DataDir, ".torrserve.db"),
0660,
&bbolt.Options{
Timeout: time.Second,
})
}
func createSpecBucket() error {
/* Opens DB file */
db, dberr := openDB()
if dberr != nil {
return dberr
}
defer db.Close()
/* Create TorrSpec bucket */
return db.Update(func(tx *bbolt.Tx) error {
tx.CreateBucketIfNotExists([]byte("TorrSpecs"))
return nil
})
}
// Saves torrent spec to database file
func saveSpec(spec *torrent.TorrentSpec) error {
/* Marshal torrent spec to JSON persistentSpec */
json, err := json.Marshal(persistentSpec{
Trackers: spec.Trackers,
InfoHash: spec.InfoHash.String(),
DisplayName: spec.DisplayName,
Webseeds: spec.Webseeds,
DhtNodes: spec.DhtNodes,
PeerAddrs: spec.PeerAddrs,
Sources: spec.Sources,
DisableInitialPieceCheck: spec.DisableInitialPieceCheck,
DisallowDataUpload: spec.DisallowDataUpload,
DisallowDataDownload: spec.DisallowDataDownload,
})
if err != nil {
return err
}
return specToDB(spec.InfoHash.String(), json)
}
// Commit a persistentSpec to DB
func specToDB(infohash string, json []byte) error {
/* Opens DB file */
db, dberr := openDB()
if dberr != nil {
return dberr
}
defer db.Close()
/* Adds marshal'd spec to DB file */
return db.Update(func(tx *bbolt.Tx) error {
b := tx.Bucket([]byte("TorrSpecs"))
return b.Put([]byte(strings.ToLower(infohash)), json)
})
}
// Loads all persistentSpec to BitTorrent client
func loadPersist() {
/* Get all specs from DB */
specs, err := getSpecs()
if err != nil {
Warn.Printf("Cannot get persistent specs: %s\n", err)
return
}
/* Iterates over all specs */
for _, spec := range specs {
/* Add spec to BitTorrent client */
t, terr := btEngine.addTorrent(persistSpecToTorrentSpec(spec), true)
if terr != nil {
Warn.Printf("Cannot load spec \"%s\": %s\n", spec.InfoHash, terr)
rmerr := removeSpec(spec.InfoHash)
if rmerr != nil {
Warn.Printf("Cannot remove spec \"%s\": %s\n", spec.InfoHash, rmerr)
}
continue
}
/* Start download of files in persistent spec */
for _, f := range spec.Files {
tf, tferr := getTorrentFile(t, f.File)
if tferr != nil {
Warn.Printf("Cannot load file \"%s\": %s\n", f.File, tferr)
continue
}
tf.SetPriority(f.Priority)
}
}
}
// Returns all persistentSpec in DB
func getSpecs() ([]persistentSpec, error) {
/* Opens DB file */
db, dberr := openDB()
if dberr != nil {
return []persistentSpec{}, dberr
}
defer db.Close()
/* Iterates over all specs in DB to make array of specs */
specs := []persistentSpec{}
verr := db.View(func(tx *bbolt.Tx) error {
b := tx.Bucket([]byte("TorrSpecs"))
c := b.Cursor()
for k, v := c.First(); k != nil; k, v = c.Next() {
spec := persistentSpec{}
derr := json.Unmarshal(v, &spec)
if derr != nil {
return derr
}
specs = append(specs, spec)
}
return nil
})
return specs, verr
}
// Get specific persistentSpec from infohash
func getSpec(infohash string) (persistentSpec, error) {
/* Get all specs from DB */
specs, err := getSpecs()
if err != nil {
return persistentSpec{}, err
}
/* Returns specified spec */
for _, spec := range specs {
if spec.InfoHash == infohash {
return spec, nil
}
}
return persistentSpec{}, errors.New("torrent spec not found")
}
func removeSpec(infohash string) error {
/* Opens DB file */
db, dberr := openDB()
if dberr != nil {
return dberr
}
defer db.Close()
/* Deletes spec */
return db.Update(func(tx *bbolt.Tx) error {
b := tx.Bucket([]byte("TorrSpecs"))
return b.Delete([]byte(strings.ToLower(infohash)))
})
}
// Adds file of torrent to DB for persistence
func saveSpecFile(infohash string, filename string, filepriority torrent.PiecePriority) error {
/* Get persistence spec from infohash */
spec, err := getSpec(infohash)
if err != nil {
return err
}
/* Remove unmodified spec */
rmerr := removeSpec(infohash)
if rmerr != nil {
return rmerr
}
/* Create new spec with file */
spec.Files = append(spec.Files, persistentSpecFiles{
File: filename,
Priority: filepriority,
})
json, jerr := json.Marshal(&spec)
if jerr != nil {
return jerr
}
return specToDB(infohash, json)
}