@@ -108,8 +108,8 @@ func NewDefaultSessionStorage(
108
108
if err != nil {
109
109
ds .logger .ErrorContext (ctx , "opening db %q: %w" , dbFilename , err )
110
110
if errors .Is (err , berrors .ErrInvalid ) {
111
- const s = ` AdGuard Home cannot be initialized due to an incompatible file system.
112
- Please read the explanation here: https://github.com/AdguardTeam/AdGuardHome/wiki/Getting-Started #limitations`
111
+ const s = " AdGuard Home cannot be initialized due to an incompatible file system.\n " +
112
+ " Please read the explanation here: https://adguard-dns.io/kb/adguard-home/getting-started/ #limitations"
113
113
slogutil .PrintLines (ctx , ds .logger , slog .LevelError , "" , s )
114
114
}
115
115
@@ -133,11 +133,9 @@ func (ds *DefaultSessionStorage) loadSessions(ctx context.Context) (err error) {
133
133
134
134
needRollback := true
135
135
defer func () {
136
- if ! needRollback {
137
- return
136
+ if needRollback {
137
+ err = errors . WithDeferred ( err , tx . Rollback ())
138
138
}
139
-
140
- err = errors .Join (err , tx .Rollback ())
141
139
}()
142
140
143
141
bkt := tx .Bucket ([]byte (bboltBucketSessions ))
@@ -178,21 +176,61 @@ func (ds *DefaultSessionStorage) processSessions(
178
176
ctx context.Context ,
179
177
bkt * bbolt.Bucket ,
180
178
) (removed int , err error ) {
181
- now := ds .clock .Now ()
182
179
invalidSessions := [][]byte {}
183
180
184
- err = bkt .ForEach (func ( k , v [] byte ) ( txErr error ) {
185
- s , txErr := deserialize ( v )
186
- if txErr != nil || now . After ( s . Expire ) {
187
- invalidSessions = append ( invalidSessions , k )
181
+ err = bkt .ForEach (ds . bboltSessionHandler ( ctx , & invalidSessions ))
182
+ if err != nil {
183
+ return 0 , fmt . Errorf ( "iterating over sessions: %w" , err )
184
+ }
188
185
189
- return txErr
186
+ var errs []error
187
+ for _ , s := range invalidSessions {
188
+ if err = bkt .Delete (s ); err != nil {
189
+ errs = append (errs , err )
190
190
}
191
+ }
192
+
193
+ if err = errors .Join (errs ... ); err != nil {
194
+ return 0 , fmt .Errorf ("deleting sessions: %w" , err )
195
+ }
196
+
197
+ return len (invalidSessions ), nil
198
+ }
199
+
200
+ // bboltSessionHandler returns a function for [bbolt.Bucket.ForEach] that
201
+ // iterates over stored sessions, deserializes them, and logs any errors
202
+ // encountered. The returned error is always nil, as these errors are
203
+ // considered non-critical to stop the iteration process.
204
+ func (ds * DefaultSessionStorage ) bboltSessionHandler (
205
+ ctx context.Context ,
206
+ invalidSessions * [][]byte ,
207
+ ) (fn func (k , v []byte ) (err error )) {
208
+ now := ds .clock .Now ()
191
209
192
- var u * User
193
- u , txErr = ds .userDB .ByLogin (ctx , s .UserLogin )
194
- if txErr != nil {
195
- invalidSessions = append (invalidSessions , k )
210
+ return func (k , v []byte ) (err error ) {
211
+ s , err := bboltDecode (v )
212
+ if err != nil {
213
+ * invalidSessions = append (* invalidSessions , k )
214
+ ds .logger .DebugContext (ctx , "deserializing session" , slogutil .KeyError , err )
215
+
216
+ return nil
217
+ }
218
+
219
+ if now .After (s .Expire ) {
220
+ * invalidSessions = append (* invalidSessions , k )
221
+
222
+ return nil
223
+ }
224
+
225
+ u , err := ds .userDB .ByLogin (ctx , s .UserLogin )
226
+ if err != nil {
227
+ // Should not happen, as it currently always returns nil for error.
228
+ panic (err )
229
+ }
230
+
231
+ if u == nil {
232
+ ds .logger .DebugContext (ctx , "no saved user by name" , "name" , s .UserLogin )
233
+ * invalidSessions = append (* invalidSessions , k )
196
234
197
235
return nil
198
236
}
@@ -203,19 +241,7 @@ func (ds *DefaultSessionStorage) processSessions(
203
241
ds .sessions [t ] = s
204
242
205
243
return nil
206
- })
207
- if err != nil {
208
- // Don't wrap the error because it's informative enough as is.
209
- return 0 , err
210
244
}
211
-
212
- for _ , s := range invalidSessions {
213
- if err = bkt .Delete (s ); err != nil {
214
- return 0 , fmt .Errorf ("deleting session: %w" , err )
215
- }
216
- }
217
-
218
- return len (invalidSessions ), nil
219
245
}
220
246
221
247
// bboltBucketSessions is the name of the bucket storing web user sessions in
@@ -232,12 +258,8 @@ const (
232
258
bboltSessionNameLen = 2
233
259
)
234
260
235
- // deserialize decodes a binary data into a session.
236
- //
237
- // TODO(s.chzhen): !! Improve naming.
238
- func deserialize (data []byte ) (s * Session , err error ) {
239
- defer func () { err = errors .Annotate (err , "deserializing session: %w" ) }()
240
-
261
+ // bboltDecode deserializes decodes a binary data into a session.
262
+ func bboltDecode (data []byte ) (s * Session , err error ) {
241
263
if len (data ) < bboltSessionExpireLen + bboltSessionNameLen {
242
264
return nil , fmt .Errorf ("length of the data is less than expected: got %d" , len (data ))
243
265
}
@@ -259,8 +281,8 @@ func deserialize(data []byte) (s *Session, err error) {
259
281
}, nil
260
282
}
261
283
262
- // serialize encodes a session properties into a binary data.
263
- func serialize (s * Session ) (data []byte ) {
284
+ // bboltEncode serializes a session properties into a binary data.
285
+ func bboltEncode (s * Session ) (data []byte ) {
264
286
data = make ([]byte , bboltSessionExpireLen + bboltSessionNameLen + len (s .UserLogin ))
265
287
266
288
expireData := data [:bboltSessionExpireLen ]
@@ -319,7 +341,7 @@ func (ds *DefaultSessionStorage) store(s *Session) (err error) {
319
341
return fmt .Errorf ("creating bucket: %w" , err )
320
342
}
321
343
322
- err = bkt .Put (s .Token [:], serialize (s ))
344
+ err = bkt .Put (s .Token [:], bboltEncode (s ))
323
345
if err != nil {
324
346
return fmt .Errorf ("putting data: %w" , err )
325
347
}
0 commit comments