-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathuser.go
148 lines (111 loc) · 3.29 KB
/
user.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
package database
import (
"errors"
"fmt"
"log"
"github.com/willeponken/go-cjdns/key"
)
// usersBucket defines the namespace for the user bucket.
const usersBucket = "Users"
// userExists takes a identifier and tries to type cast it into either a public key or a uint64, and then lookups that identifier in the database.
func (db *Database) userExists(identifier interface{}) (pos []byte, exists bool) {
err := db.View(func(tx *Tx) error {
bucket := tx.Bucket([]byte(usersBucket))
pubkey, isPubkey := identifier.(*key.Public)
if isPubkey {
strPubkey := pubkey.String()
cursor := bucket.Cursor()
for k, pk := cursor.First(); pk != nil; k, pk = cursor.Next() {
if string(pk) == strPubkey {
pos = k
exists = true
return nil
}
}
exists = false
return nil
}
id, isID := identifier.(uint64)
if isID {
p := uint64ToBin(id)
if user := bucket.Get(p); user != nil {
pos = p
exists = true
return nil
}
exists = false
return nil
}
return errors.New("Unknown identifier specified")
})
if err != nil {
exists = false
}
return
}
// nextUserID iterates over all users and tries to find a available slot between users, if there is no available it will return the next sequence available after all users.
func (db *Database) nextUserID() (id uint64, err error) {
err = db.View(func(tx *Tx) error {
bucket := tx.Bucket([]byte(usersBucket))
cursor := bucket.Cursor()
lastID := uint64(0)
for currentID, _ := cursor.First(); currentID != nil; currentID, _ = cursor.Next() {
// The current ID is larger than the last found ID, this means that there is a "gap" that can be filled,
// so we'll stop the iteration and use the last ID + 1 as it's available.
if binToUint64(currentID) > lastID+1 {
break
}
lastID = binToUint64(currentID)
}
id = lastID + 1
return nil
})
return
}
// AddUser inserts a new user into the UserBucket with public key and ID (used as seed for lease).
func (db *Database) AddUser(pubkey *key.Public) (id uint64, err error) {
k := pubkey.String()
_, exists := db.userExists(pubkey)
if exists {
err = fmt.Errorf("User with public key: %s already exists", k)
log.Println(err)
return
}
err = db.Update(func(tx *Tx) error {
bucket := tx.Bucket([]byte(usersBucket))
id, err = db.nextUserID()
if err != nil {
return err
}
log.Printf("Adding new user with key: %s and ID: %d", k, id)
return bucket.Put(uint64ToBin(id), []byte(k)) // End of transaction after data is put
})
return
}
// GetID returns the ID for a registered user.
func (db *Database) GetID(pubkey *key.Public) (id uint64, err error) {
pos, exists := db.userExists(pubkey)
if !exists {
err = fmt.Errorf("User with public key: %s does not exist", pubkey.String())
log.Println(err)
return
}
id = binToUint64(pos)
return
}
// DelUser removes a registered user using the pubkey as identifier.
func (db *Database) DelUser(identifier interface{}) (err error) {
pos, exists := db.userExists(identifier)
if !exists {
err = fmt.Errorf("User identified as: %v does not exist", identifier)
log.Println(err)
return
}
err = db.Update(func(tx *Tx) error {
bucket := tx.Bucket([]byte(usersBucket))
log.Printf("Deleting user identified as: %v", identifier)
err = bucket.Delete(pos)
return nil
})
return
}