@@ -2,8 +2,11 @@ package session
2
2
3
3
import (
4
4
"bytes"
5
+ "encoding/binary"
5
6
"errors"
6
7
"fmt"
8
+ "os"
9
+ "path/filepath"
7
10
"time"
8
11
9
12
"github.com/btcsuite/btcd/btcec/v2"
@@ -53,8 +56,122 @@ var (
53
56
// ErrDBInitErr is returned when a bucket that we expect to have been
54
57
// set up during DB initialisation is not found.
55
58
ErrDBInitErr = errors .New ("db did not initialise properly" )
59
+
60
+ // byteOrder is the default byte order we'll use for serialization
61
+ // within the database.
62
+ byteOrder = binary .BigEndian
63
+ )
64
+
65
+ const (
66
+ // DBFilename is the default filename of the session database.
67
+ DBFilename = "session.db"
68
+
69
+ // dbFilePermission is the default permission the session database file
70
+ // is created with.
71
+ dbFilePermission = 0600
72
+
73
+ // DefaultSessionDBTimeout is the default maximum time we wait for the
74
+ // session bbolt database to be opened. If the database is already
75
+ // opened by another process, the unique lock cannot be obtained. With
76
+ // the timeout we error out after the given time instead of just
77
+ // blocking for forever.
78
+ DefaultSessionDBTimeout = 5 * time .Second
56
79
)
57
80
81
+ // DB is a bolt-backed persistent store.
82
+ type DB struct {
83
+ * bbolt.DB
84
+ }
85
+
86
+ // A compile-time check to ensure that DB implements the Store interface.
87
+ var _ Store = (* DB )(nil )
88
+
89
+ // NewDB creates a new bolt database that can be found at the given directory.
90
+ func NewDB (dir , fileName string ) (* DB , error ) {
91
+ firstInit := false
92
+ path := filepath .Join (dir , fileName )
93
+
94
+ // If the database file does not exist yet, create its directory.
95
+ if ! fileExists (path ) {
96
+ if err := os .MkdirAll (dir , 0700 ); err != nil {
97
+ return nil , err
98
+ }
99
+ firstInit = true
100
+ }
101
+
102
+ db , err := initDB (path , firstInit )
103
+ if err != nil {
104
+ return nil , err
105
+ }
106
+
107
+ // Attempt to sync the database's current version with the latest known
108
+ // version available.
109
+ if err := syncVersions (db ); err != nil {
110
+ return nil , err
111
+ }
112
+
113
+ return & DB {DB : db }, nil
114
+ }
115
+
116
+ // fileExists reports whether the named file or directory exists.
117
+ func fileExists (path string ) bool {
118
+ if _ , err := os .Stat (path ); err != nil {
119
+ if os .IsNotExist (err ) {
120
+ return false
121
+ }
122
+ }
123
+ return true
124
+ }
125
+
126
+ // initDB initializes all the required top-level buckets for the database.
127
+ func initDB (filepath string , firstInit bool ) (* bbolt.DB , error ) {
128
+ db , err := bbolt .Open (filepath , dbFilePermission , & bbolt.Options {
129
+ Timeout : DefaultSessionDBTimeout ,
130
+ })
131
+ if err == bbolt .ErrTimeout {
132
+ return nil , fmt .Errorf ("error while trying to open %s: timed " +
133
+ "out after %v when trying to obtain exclusive lock" ,
134
+ filepath , DefaultSessionDBTimeout )
135
+ }
136
+ if err != nil {
137
+ return nil , err
138
+ }
139
+
140
+ err = db .Update (func (tx * bbolt.Tx ) error {
141
+ if firstInit {
142
+ metadataBucket , err := tx .CreateBucketIfNotExists (
143
+ metadataBucketKey ,
144
+ )
145
+ if err != nil {
146
+ return err
147
+ }
148
+ err = setDBVersion (metadataBucket , latestDBVersion )
149
+ if err != nil {
150
+ return err
151
+ }
152
+ }
153
+
154
+ sessionBkt , err := tx .CreateBucketIfNotExists (sessionBucketKey )
155
+ if err != nil {
156
+ return err
157
+ }
158
+
159
+ _ , err = sessionBkt .CreateBucketIfNotExists (idIndexKey )
160
+ if err != nil {
161
+ return err
162
+ }
163
+
164
+ _ , err = sessionBkt .CreateBucketIfNotExists (groupIDIndexKey )
165
+
166
+ return err
167
+ })
168
+ if err != nil {
169
+ return nil , err
170
+ }
171
+
172
+ return db , nil
173
+ }
174
+
58
175
// getSessionKey returns the key for a session.
59
176
func getSessionKey (session * Session ) []byte {
60
177
return session .LocalPublicKey .SerializeCompressed ()
0 commit comments