Browse Source

db: Remove SQLite db, hopefully looking up clients still works.Channel persistence is broken by this, will fix it later.

tags/v0.1.0
Daniel Oaks 7 years ago
parent
commit
ae69ef5cd6
7 changed files with 98 additions and 197 deletions
  1. 2
    0
      CHANGELOG.md
  2. 24
    19
      irc/channel.go
  3. 23
    94
      irc/client_lookup_set.go
  4. 1
    5
      irc/config.go
  5. 13
    40
      irc/database.go
  6. 31
    35
      irc/server.go
  7. 4
    4
      oragono.go

+ 2
- 0
CHANGELOG.md View File

@@ -14,6 +14,7 @@ Initial release of Oragono!
14 14
 
15 15
 ### Added
16 16
 * Added YAML config file format.
17
+* Added buntdb key-value store for persistent data.
17 18
 * Added native SSL/TLS support (thanks to @edmand).
18 19
 * Added ability to generate testing certificates from the command line.
19 20
 * Added support for looking up usernames with [ident](https://tools.ietf.org/html/rfc1413) on client connection.
@@ -35,6 +36,7 @@ Initial release of Oragono!
35 36
 
36 37
 ### Removed
37 38
 * Removed gitconfig configuration format [replaced with YAML].
39
+* Removed sqlite database [replaced with buntdb key-value store].
38 40
 * Removed `THEATER` command (it broke and I'm not that interested in putting the work in to get it working again with the aim of this project. PRs accepted).
39 41
 
40 42
 ### Fixed

+ 24
- 19
irc/channel.go View File

@@ -424,26 +424,31 @@ func (channel *Channel) applyModeMask(client *Client, mode ChannelMode, op ModeO
424 424
 }
425 425
 
426 426
 func (channel *Channel) Persist() (err error) {
427
-	if channel.flags[Persistent] {
428
-		//TODO(dan): Save topicSetBy/topicSetTime and createdTime
429
-		_, err = channel.server.db.Exec(`
430
-            INSERT OR REPLACE INTO channel
431
-              (name, flags, key, topic, user_limit, ban_list, except_list,
432
-               invite_list)
433
-              VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
434
-			channel.name.String(), channel.flags.String(), channel.key,
435
-			channel.topic, channel.userLimit, channel.lists[BanMask].String(),
436
-			channel.lists[ExceptMask].String(), channel.lists[InviteMask].String())
437
-	} else {
438
-		_, err = channel.server.db.Exec(`
439
-            DELETE FROM channel WHERE name = ?`, channel.name.String())
440
-	}
441
-
442
-	if err != nil {
443
-		Log.error.Println("Channel.Persist:", channel, err)
444
-	}
445
-
446 427
 	return
428
+
429
+	//TODO(dan): Fix persistence
430
+	/*
431
+			if channel.flags[Persistent] {
432
+				//TODO(dan): Save topicSetBy/topicSetTime and createdTime
433
+				_, err = channel.server.db.Exec(`
434
+		            INSERT OR REPLACE INTO channel
435
+		              (name, flags, key, topic, user_limit, ban_list, except_list,
436
+		               invite_list)
437
+		              VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
438
+					channel.name.String(), channel.flags.String(), channel.key,
439
+					channel.topic, channel.userLimit, channel.lists[BanMask].String(),
440
+					channel.lists[ExceptMask].String(), channel.lists[InviteMask].String())
441
+			} else {
442
+				_, err = channel.server.db.Exec(`
443
+		            DELETE FROM channel WHERE name = ?`, channel.name.String())
444
+			}
445
+
446
+			if err != nil {
447
+				Log.error.Println("Channel.Persist:", channel, err)
448
+			}
449
+
450
+			return
451
+	*/
447 452
 }
448 453
 
449 454
 func (channel *Channel) Notice(client *Client, message string) {

+ 23
- 94
irc/client_lookup_set.go View File

@@ -4,33 +4,23 @@
4 4
 package irc
5 5
 
6 6
 import (
7
-	"database/sql"
8 7
 	"errors"
9
-	"log"
10 8
 	"regexp"
11 9
 	"strings"
10
+
11
+	"github.com/DanielOaks/girc-go/ircmatch"
12 12
 )
13 13
 
14 14
 var (
15 15
 	ErrNickMissing      = errors.New("nick missing")
16 16
 	ErrNicknameInUse    = errors.New("nickname in use")
17 17
 	ErrNicknameMismatch = errors.New("nickname mismatch")
18
-	wildMaskExpr        = regexp.MustCompile(`\*|\?`)
19
-	likeQuoter          = strings.NewReplacer(
20
-		`\`, `\\`,
21
-		`%`, `\%`,
22
-		`_`, `\_`,
23
-		`*`, `%`,
24
-		`?`, `_`)
25 18
 )
26 19
 
27
-func HasWildcards(mask string) bool {
28
-	return wildMaskExpr.MatchString(mask)
29
-}
30
-
31 20
 func ExpandUserHost(userhost Name) (expanded Name) {
32 21
 	expanded = userhost
33 22
 	// fill in missing wildcards for nicks
23
+	//TODO(dan): this would fail with dan@lol, do we want to accommodate that?
34 24
 	if !strings.Contains(expanded.String(), "!") {
35 25
 		expanded += "!*"
36 26
 	}
@@ -40,19 +30,13 @@ func ExpandUserHost(userhost Name) (expanded Name) {
40 30
 	return
41 31
 }
42 32
 
43
-func QuoteLike(userhost Name) string {
44
-	return likeQuoter.Replace(userhost.String())
45
-}
46
-
47 33
 type ClientLookupSet struct {
48 34
 	byNick map[Name]*Client
49
-	db     *ClientDB
50 35
 }
51 36
 
52 37
 func NewClientLookupSet() *ClientLookupSet {
53 38
 	return &ClientLookupSet{
54 39
 		byNick: make(map[Name]*Client),
55
-		db:     NewClientDB(),
56 40
 	}
57 41
 }
58 42
 
@@ -68,7 +52,6 @@ func (clients *ClientLookupSet) Add(client *Client) error {
68 52
 		return ErrNicknameInUse
69 53
 	}
70 54
 	clients.byNick[client.Nick().ToLower()] = client
71
-	clients.db.Add(client)
72 55
 	return nil
73 56
 }
74 57
 
@@ -80,101 +63,47 @@ func (clients *ClientLookupSet) Remove(client *Client) error {
80 63
 		return ErrNicknameMismatch
81 64
 	}
82 65
 	delete(clients.byNick, client.nick.ToLower())
83
-	clients.db.Remove(client)
84 66
 	return nil
85 67
 }
86 68
 
87 69
 func (clients *ClientLookupSet) FindAll(userhost Name) (set ClientSet) {
88
-	userhost = ExpandUserHost(userhost)
89 70
 	set = make(ClientSet)
90
-	rows, err := clients.db.db.Query(
91
-		`SELECT nickname FROM client WHERE userhost LIKE ? ESCAPE '\'`,
92
-		QuoteLike(userhost))
93
-	if err != nil {
94
-		Log.error.Println("ClientLookupSet.FindAll.Query:", err)
95
-		return
96
-	}
97
-	for rows.Next() {
98
-		var sqlNickname string
99
-		err := rows.Scan(&sqlNickname)
100
-		if err != nil {
101
-			Log.error.Println("ClientLookupSet.FindAll.Scan:", err)
102
-			return
103
-		}
104
-		nickname := Name(sqlNickname)
105
-		client := clients.Get(nickname)
106
-		if client == nil {
107
-			Log.error.Println("ClientLookupSet.FindAll: missing client:", nickname)
108
-			continue
71
+
72
+	userhost = ExpandUserHost(userhost)
73
+	matcher := ircmatch.MakeMatch(userhost.String())
74
+
75
+	var casemappedNickMask string
76
+	for _, client := range clients.byNick {
77
+		casemappedNickMask = NewName(client.nickMaskString).String()
78
+		if matcher.Match(casemappedNickMask) {
79
+			set.Add(client)
109 80
 		}
110
-		set.Add(client)
111 81
 	}
112
-	return
82
+
83
+	return set
113 84
 }
114 85
 
115 86
 func (clients *ClientLookupSet) Find(userhost Name) *Client {
116 87
 	userhost = ExpandUserHost(userhost)
117
-	row := clients.db.db.QueryRow(
118
-		`SELECT nickname FROM client WHERE userhost LIKE ? ESCAPE '\' LIMIT 1`,
119
-		QuoteLike(userhost))
120
-	var nickname Name
121
-	err := row.Scan(&nickname)
122
-	if err != nil {
123
-		Log.error.Println("ClientLookupSet.Find:", err)
124
-		return nil
125
-	}
126
-	return clients.Get(nickname)
127
-}
128
-
129
-//
130
-// client db
131
-//
88
+	matcher := ircmatch.MakeMatch(userhost.String())
132 89
 
133
-type ClientDB struct {
134
-	db *sql.DB
135
-}
136
-
137
-func NewClientDB() *ClientDB {
138
-	db := &ClientDB{
139
-		db: OpenDB(":memory:"),
140
-	}
141
-	stmts := []string{
142
-		`CREATE TABLE client (
143
-          nickname TEXT NOT NULL COLLATE NOCASE UNIQUE,
144
-          userhost TEXT NOT NULL COLLATE NOCASE,
145
-          UNIQUE (nickname, userhost) ON CONFLICT REPLACE)`,
146
-		`CREATE UNIQUE INDEX idx_nick ON client (nickname COLLATE NOCASE)`,
147
-		`CREATE UNIQUE INDEX idx_uh ON client (userhost COLLATE NOCASE)`,
148
-	}
149
-	for _, stmt := range stmts {
150
-		_, err := db.db.Exec(stmt)
151
-		if err != nil {
152
-			log.Fatal("NewClientDB: ", stmt, err)
90
+	var casemappedNickMask string
91
+	for _, client := range clients.byNick {
92
+		casemappedNickMask = NewName(client.nickMaskString).String()
93
+		if matcher.Match(casemappedNickMask) {
94
+			return client
153 95
 		}
154 96
 	}
155
-	return db
156
-}
157 97
 
158
-func (db *ClientDB) Add(client *Client) {
159
-	_, err := db.db.Exec(`INSERT INTO client (nickname, userhost) VALUES (?, ?)`,
160
-		client.Nick().String(), client.UserHost().String())
161
-	if err != nil {
162
-		Log.error.Println("ClientDB.Add:", err)
163
-	}
164
-}
165
-
166
-func (db *ClientDB) Remove(client *Client) {
167
-	_, err := db.db.Exec(`DELETE FROM client WHERE nickname = ?`,
168
-		client.Nick().String())
169
-	if err != nil {
170
-		Log.error.Println("ClientDB.Remove:", err)
171
-	}
98
+	return nil
172 99
 }
173 100
 
174 101
 //
175 102
 // usermask to regexp
176 103
 //
177 104
 
105
+//TODO(dan): move this over to generally using glob syntax instead?
106
+// kinda more expected in normal ban/etc masks, though regex is useful (probably as an extban?)
178 107
 type UserMaskSet struct {
179 108
 	masks  map[Name]bool
180 109
 	regexp *regexp.Regexp

+ 1
- 5
irc/config.go View File

@@ -84,8 +84,7 @@ type Config struct {
84 84
 	}
85 85
 
86 86
 	Datastore struct {
87
-		Path       string
88
-		SQLitePath string `yaml:"sqlite-path"`
87
+		Path string
89 88
 	}
90 89
 
91 90
 	Registration struct {
@@ -152,9 +151,6 @@ func LoadConfig(filename string) (config *Config, err error) {
152 151
 	if config.Datastore.Path == "" {
153 152
 		return nil, errors.New("Datastore path missing")
154 153
 	}
155
-	if config.Datastore.SQLitePath == "" {
156
-		return nil, errors.New("SQLite database path missing")
157
-	}
158 154
 	if len(config.Server.Listen) == 0 {
159 155
 		return nil, errors.New("Server listening addresses missing")
160 156
 	}

+ 13
- 40
irc/database.go View File

@@ -4,79 +4,52 @@
4 4
 package irc
5 5
 
6 6
 import (
7
-	"database/sql"
8 7
 	"encoding/base64"
9 8
 	"fmt"
10 9
 	"log"
11 10
 	"os"
12 11
 
13
-	_ "github.com/mattn/go-sqlite3"
14 12
 	"github.com/tidwall/buntdb"
15 13
 )
16 14
 
17 15
 const (
16
+	// 'version' of the database schema
17
+	keySchemaVersion = "db.version"
18 18
 	// key for the primary salt used by the ircd
19 19
 	keySalt = "crypto.salt"
20 20
 )
21 21
 
22
-func InitDB(buntpath string, path string) {
22
+// InitDB creates the database.
23
+func InitDB(path string) {
23 24
 	// prepare kvstore db
24
-	os.Remove(buntpath)
25
-	store, err := buntdb.Open(buntpath)
25
+	//TODO(dan): fail if already exists instead? don't want to overwrite good data
26
+	os.Remove(path)
27
+	store, err := buntdb.Open(path)
26 28
 	if err != nil {
27 29
 		log.Fatal(fmt.Sprintf("Failed to open datastore: %s", err.Error()))
28 30
 	}
29 31
 	defer store.Close()
30 32
 
31 33
 	err = store.Update(func(tx *buntdb.Tx) error {
34
+		// set base db salt
32 35
 		salt, err := NewSalt()
33 36
 		encodedSalt := base64.StdEncoding.EncodeToString(salt)
34 37
 		if err != nil {
35 38
 			log.Fatal("Could not generate cryptographically-secure salt for the user:", err.Error())
36 39
 		}
37 40
 		tx.Set(keySalt, encodedSalt, nil)
41
+
42
+		// set schema version
43
+		tx.Set(keySchemaVersion, "1", nil)
38 44
 		return nil
39 45
 	})
40 46
 
41 47
 	if err != nil {
42 48
 		log.Fatal("Could not save bunt store:", err.Error())
43 49
 	}
44
-
45
-	// prepare SQLite db
46
-	os.Remove(path)
47
-	db := OpenDB(path)
48
-	defer db.Close()
49
-	_, err = db.Exec(`
50
-        CREATE TABLE channel (
51
-          name TEXT NOT NULL UNIQUE,
52
-          flags TEXT DEFAULT '',
53
-          key TEXT DEFAULT '',
54
-          topic TEXT DEFAULT '',
55
-          user_limit INTEGER DEFAULT 0,
56
-          ban_list TEXT DEFAULT '',
57
-          except_list TEXT DEFAULT '',
58
-          invite_list TEXT DEFAULT '')`)
59
-	if err != nil {
60
-		log.Fatal("initdb error: ", err)
61
-	}
62 50
 }
63 51
 
52
+// UpgradeDB upgrades the datastore to the latest schema.
64 53
 func UpgradeDB(path string) {
65
-	db := OpenDB(path)
66
-	alter := `ALTER TABLE channel ADD COLUMN %s TEXT DEFAULT ''`
67
-	cols := []string{"ban_list", "except_list", "invite_list"}
68
-	for _, col := range cols {
69
-		_, err := db.Exec(fmt.Sprintf(alter, col))
70
-		if err != nil {
71
-			log.Fatal("updatedb error: ", err)
72
-		}
73
-	}
74
-}
75
-
76
-func OpenDB(path string) *sql.DB {
77
-	db, err := sql.Open("sqlite3", path)
78
-	if err != nil {
79
-		log.Fatal("open db error: ", err)
80
-	}
81
-	return db
54
+	return
82 55
 }

+ 31
- 35
irc/server.go View File

@@ -8,7 +8,6 @@ package irc
8 8
 import (
9 9
 	"bufio"
10 10
 	"crypto/tls"
11
-	"database/sql"
12 11
 	"encoding/base64"
13 12
 	"fmt"
14 13
 	"log"
@@ -39,7 +38,6 @@ type Server struct {
39 38
 	clients             *ClientLookupSet
40 39
 	commands            chan Command
41 40
 	ctime               time.Time
42
-	db                  *sql.DB
43 41
 	store               buntdb.DB
44 42
 	idle                chan *Client
45 43
 	limits              Limits
@@ -79,7 +77,6 @@ func NewServer(config *Config) *Server {
79 77
 		clients:  NewClientLookupSet(),
80 78
 		commands: make(chan Command),
81 79
 		ctime:    time.Now(),
82
-		db:       OpenDB(config.Datastore.SQLitePath),
83 80
 		idle:     make(chan *Client),
84 81
 		limits: Limits{
85 82
 			AwayLen:  config.Limits.AwayLen,
@@ -216,35 +213,38 @@ func loadChannelList(channel *Channel, list string, maskMode ChannelMode) {
216 213
 }
217 214
 
218 215
 func (server *Server) loadChannels() {
219
-	rows, err := server.db.Query(`
220
-        SELECT name, flags, key, topic, user_limit, ban_list, except_list,
221
-               invite_list
222
-          FROM channel`)
223
-	if err != nil {
224
-		log.Fatal("error loading channels: ", err)
225
-	}
226
-	for rows.Next() {
227
-		var name, flags, key, topic string
228
-		var userLimit uint64
229
-		var banList, exceptList, inviteList string
230
-		err = rows.Scan(&name, &flags, &key, &topic, &userLimit, &banList,
231
-			&exceptList, &inviteList)
232
-		if err != nil {
233
-			log.Println("Server.loadChannels:", err)
234
-			continue
235
-		}
216
+	//TODO(dan): Fix channel persistence
217
+	/*
218
+			rows, err := server.db.Query(`
219
+		        SELECT name, flags, key, topic, user_limit, ban_list, except_list,
220
+		               invite_list
221
+		          FROM channel`)
222
+			if err != nil {
223
+				log.Fatal("error loading channels: ", err)
224
+			}
225
+			for rows.Next() {
226
+				var name, flags, key, topic string
227
+				var userLimit uint64
228
+				var banList, exceptList, inviteList string
229
+				err = rows.Scan(&name, &flags, &key, &topic, &userLimit, &banList,
230
+					&exceptList, &inviteList)
231
+				if err != nil {
232
+					log.Println("Server.loadChannels:", err)
233
+					continue
234
+				}
236 235
 
237
-		channel := NewChannel(server, NewName(name), false)
238
-		for _, flag := range flags {
239
-			channel.flags[ChannelMode(flag)] = true
240
-		}
241
-		channel.key = key
242
-		channel.topic = topic
243
-		channel.userLimit = userLimit
244
-		loadChannelList(channel, banList, BanMask)
245
-		loadChannelList(channel, exceptList, ExceptMask)
246
-		loadChannelList(channel, inviteList, InviteMask)
247
-	}
236
+				channel := NewChannel(server, NewName(name), false)
237
+				for _, flag := range flags {
238
+					channel.flags[ChannelMode(flag)] = true
239
+				}
240
+				channel.key = key
241
+				channel.topic = topic
242
+				channel.userLimit = userLimit
243
+				loadChannelList(channel, banList, BanMask)
244
+				loadChannelList(channel, exceptList, ExceptMask)
245
+				loadChannelList(channel, inviteList, InviteMask)
246
+			}
247
+	*/
248 248
 }
249 249
 
250 250
 func (server *Server) Shutdown() {
@@ -253,9 +253,6 @@ func (server *Server) Shutdown() {
253 253
 		client.Notice("Server is shutting down")
254 254
 	}
255 255
 
256
-	if err := server.db.Close(); err != nil {
257
-		Log.error.Println("Server.Shutdown db.Close: error:", err)
258
-	}
259 256
 	if err := server.store.Close(); err != nil {
260 257
 		Log.error.Println("Server.Shutdown store.Close: error:", err)
261 258
 	}
@@ -263,7 +260,6 @@ func (server *Server) Shutdown() {
263 260
 
264 261
 func (server *Server) Run() {
265 262
 	// defer closing db/store
266
-	defer server.db.Close()
267 263
 	defer server.store.Close()
268 264
 
269 265
 	done := false

+ 4
- 4
oragono.go View File

@@ -54,11 +54,11 @@ Options:
54 54
 		fmt.Print("\n")
55 55
 		fmt.Println(encoded)
56 56
 	} else if arguments["initdb"].(bool) {
57
-		irc.InitDB(config.Datastore.Path, config.Datastore.SQLitePath)
58
-		log.Println("databases initialized: ", config.Datastore.Path, config.Datastore.SQLitePath)
57
+		irc.InitDB(config.Datastore.Path)
58
+		log.Println("database initialized: ", config.Datastore.Path)
59 59
 	} else if arguments["upgradedb"].(bool) {
60
-		irc.UpgradeDB(config.Datastore.SQLitePath)
61
-		log.Println("database upgraded: ", config.Datastore.SQLitePath)
60
+		irc.UpgradeDB(config.Datastore.Path)
61
+		log.Println("database upgraded: ", config.Datastore.Path)
62 62
 	} else if arguments["mkcerts"].(bool) {
63 63
 		log.Println("making self-signed certificates")
64 64
 

Loading…
Cancel
Save