1
0
Fork 0
forked from External/ergo

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

This commit is contained in:
Daniel Oaks 2016-09-17 21:23:04 +10:00
parent 969eed394f
commit ae69ef5cd6
7 changed files with 98 additions and 197 deletions

View file

@ -4,33 +4,23 @@
package irc
import (
"database/sql"
"errors"
"log"
"regexp"
"strings"
"github.com/DanielOaks/girc-go/ircmatch"
)
var (
ErrNickMissing = errors.New("nick missing")
ErrNicknameInUse = errors.New("nickname in use")
ErrNicknameMismatch = errors.New("nickname mismatch")
wildMaskExpr = regexp.MustCompile(`\*|\?`)
likeQuoter = strings.NewReplacer(
`\`, `\\`,
`%`, `\%`,
`_`, `\_`,
`*`, `%`,
`?`, `_`)
)
func HasWildcards(mask string) bool {
return wildMaskExpr.MatchString(mask)
}
func ExpandUserHost(userhost Name) (expanded Name) {
expanded = userhost
// fill in missing wildcards for nicks
//TODO(dan): this would fail with dan@lol, do we want to accommodate that?
if !strings.Contains(expanded.String(), "!") {
expanded += "!*"
}
@ -40,19 +30,13 @@ func ExpandUserHost(userhost Name) (expanded Name) {
return
}
func QuoteLike(userhost Name) string {
return likeQuoter.Replace(userhost.String())
}
type ClientLookupSet struct {
byNick map[Name]*Client
db *ClientDB
}
func NewClientLookupSet() *ClientLookupSet {
return &ClientLookupSet{
byNick: make(map[Name]*Client),
db: NewClientDB(),
}
}
@ -68,7 +52,6 @@ func (clients *ClientLookupSet) Add(client *Client) error {
return ErrNicknameInUse
}
clients.byNick[client.Nick().ToLower()] = client
clients.db.Add(client)
return nil
}
@ -80,101 +63,47 @@ func (clients *ClientLookupSet) Remove(client *Client) error {
return ErrNicknameMismatch
}
delete(clients.byNick, client.nick.ToLower())
clients.db.Remove(client)
return nil
}
func (clients *ClientLookupSet) FindAll(userhost Name) (set ClientSet) {
userhost = ExpandUserHost(userhost)
set = make(ClientSet)
rows, err := clients.db.db.Query(
`SELECT nickname FROM client WHERE userhost LIKE ? ESCAPE '\'`,
QuoteLike(userhost))
if err != nil {
Log.error.Println("ClientLookupSet.FindAll.Query:", err)
return
}
for rows.Next() {
var sqlNickname string
err := rows.Scan(&sqlNickname)
if err != nil {
Log.error.Println("ClientLookupSet.FindAll.Scan:", err)
return
userhost = ExpandUserHost(userhost)
matcher := ircmatch.MakeMatch(userhost.String())
var casemappedNickMask string
for _, client := range clients.byNick {
casemappedNickMask = NewName(client.nickMaskString).String()
if matcher.Match(casemappedNickMask) {
set.Add(client)
}
nickname := Name(sqlNickname)
client := clients.Get(nickname)
if client == nil {
Log.error.Println("ClientLookupSet.FindAll: missing client:", nickname)
continue
}
set.Add(client)
}
return
return set
}
func (clients *ClientLookupSet) Find(userhost Name) *Client {
userhost = ExpandUserHost(userhost)
row := clients.db.db.QueryRow(
`SELECT nickname FROM client WHERE userhost LIKE ? ESCAPE '\' LIMIT 1`,
QuoteLike(userhost))
var nickname Name
err := row.Scan(&nickname)
if err != nil {
Log.error.Println("ClientLookupSet.Find:", err)
return nil
}
return clients.Get(nickname)
}
matcher := ircmatch.MakeMatch(userhost.String())
//
// client db
//
type ClientDB struct {
db *sql.DB
}
func NewClientDB() *ClientDB {
db := &ClientDB{
db: OpenDB(":memory:"),
}
stmts := []string{
`CREATE TABLE client (
nickname TEXT NOT NULL COLLATE NOCASE UNIQUE,
userhost TEXT NOT NULL COLLATE NOCASE,
UNIQUE (nickname, userhost) ON CONFLICT REPLACE)`,
`CREATE UNIQUE INDEX idx_nick ON client (nickname COLLATE NOCASE)`,
`CREATE UNIQUE INDEX idx_uh ON client (userhost COLLATE NOCASE)`,
}
for _, stmt := range stmts {
_, err := db.db.Exec(stmt)
if err != nil {
log.Fatal("NewClientDB: ", stmt, err)
var casemappedNickMask string
for _, client := range clients.byNick {
casemappedNickMask = NewName(client.nickMaskString).String()
if matcher.Match(casemappedNickMask) {
return client
}
}
return db
}
func (db *ClientDB) Add(client *Client) {
_, err := db.db.Exec(`INSERT INTO client (nickname, userhost) VALUES (?, ?)`,
client.Nick().String(), client.UserHost().String())
if err != nil {
Log.error.Println("ClientDB.Add:", err)
}
}
func (db *ClientDB) Remove(client *Client) {
_, err := db.db.Exec(`DELETE FROM client WHERE nickname = ?`,
client.Nick().String())
if err != nil {
Log.error.Println("ClientDB.Remove:", err)
}
return nil
}
//
// usermask to regexp
//
//TODO(dan): move this over to generally using glob syntax instead?
// kinda more expected in normal ban/etc masks, though regex is useful (probably as an extban?)
type UserMaskSet struct {
masks map[Name]bool
regexp *regexp.Regexp