User support in MurmurDB import and freezer.

This commit is contained in:
Mikkel Krautz 2011-04-08 17:26:52 +02:00
parent 73478072d0
commit 47bb4d0025
6 changed files with 223 additions and 16 deletions

View file

@ -33,6 +33,7 @@ GOFILES = \
channel.go \ channel.go \
acl.go \ acl.go \
group.go \ group.go \
user.go \
murmurdb.go \ murmurdb.go \
freeze.go freeze.go

View file

@ -1,3 +1,7 @@
// Copyright (c) 2011 The Grumble Authors
// The use of this source code is goverened by a BSD-style
// license that can be found in the LICENSE-file.
package main package main
import ( import (
@ -7,9 +11,22 @@ import (
) )
type frozenServer struct { type frozenServer struct {
Id int "id" Id int "id"
MaxUsers int "max_user" MaxUsers int "max_user"
Channels []frozenChannel "channels" SuperUserPassword string "super_user_password"
Channels []frozenChannel "channels"
Users []frozenUser "users"
}
type frozenUser struct {
Id uint32 "id"
Name string "name"
CertHash string "cert_hash"
Email string "email"
TextureBlob string "texture_blob"
CommentBlob string "comment_blob"
LastChannelId int "last_channel_id"
LastActive uint64 "last_active"
} }
type frozenChannel struct { type frozenChannel struct {
@ -21,8 +38,7 @@ type frozenChannel struct {
Links []int "links" Links []int "links"
ACL []frozenACL "acl" ACL []frozenACL "acl"
Groups []frozenGroup "groups" Groups []frozenGroup "groups"
Description string "description" DescriptionBlob string "description_blob"
DescriptionHash []byte "description_hash"
} }
type frozenACL struct { type frozenACL struct {
@ -45,6 +61,7 @@ type frozenGroup struct {
// Freeze a server // Freeze a server
func (server *Server) Freeze() (fs frozenServer, err os.Error) { func (server *Server) Freeze() (fs frozenServer, err os.Error) {
fs.Id = int(server.Id) fs.Id = int(server.Id)
fs.SuperUserPassword = server.superUserPassword
fs.MaxUsers = server.MaxUsers fs.MaxUsers = server.MaxUsers
channels := []frozenChannel{} channels := []frozenChannel{}
@ -57,6 +74,16 @@ func (server *Server) Freeze() (fs frozenServer, err os.Error) {
} }
fs.Channels = channels fs.Channels = channels
users := []frozenUser{}
for _, u := range server.Users {
fu, err := u.Freeze()
if err != nil {
return
}
users = append(users, fu)
}
fs.Users = users
return return
} }
@ -71,8 +98,6 @@ func (channel *Channel) Freeze() (fc frozenChannel, err os.Error) {
} }
fc.Position = int64(channel.Position) fc.Position = int64(channel.Position)
fc.InheritACL = channel.InheritACL fc.InheritACL = channel.InheritACL
fc.Description = channel.Description
fc.DescriptionHash = channel.DescriptionHash
acls := []frozenACL{} acls := []frozenACL{}
for _, acl := range channel.ACL { for _, acl := range channel.ACL {
@ -103,6 +128,20 @@ func (channel *Channel) Freeze() (fc frozenChannel, err os.Error) {
return return
} }
// Freeze a User
func (user *User) Freeze() (fu frozenUser, err os.Error) {
fu.Id = user.Id
fu.Name = user.Name
fu.CertHash = user.CertHash
fu.Email = user.Email
fu.TextureBlob = user.TextureBlob
fu.CommentBlob = user.CommentBlob
fu.LastChannelId = user.LastChannelId
fu.LastActive = user.LastActive
return
}
// Freeze a ChannelACL // Freeze a ChannelACL
func (acl *ChannelACL) Freeze() (facl frozenACL, err os.Error) { func (acl *ChannelACL) Freeze() (facl frozenACL, err os.Error) {
facl.UserId = acl.UserId facl.UserId = acl.UserId
@ -148,14 +187,15 @@ func NewServerFromFrozen(filename string) (s *Server, err os.Error) {
return nil, err return nil, err
} }
s.superUserPassword = fs.SuperUserPassword
// Add all channels, but don't hook up parent/child relationships // Add all channels, but don't hook up parent/child relationships
// until all of them are loaded. // until all of them are loaded.
for _, jc := range fs.Channels { for _, jc := range fs.Channels {
c := NewChannel(jc.Id, jc.Name) c := NewChannel(jc.Id, jc.Name)
c.Position = int(jc.Position) c.Position = int(jc.Position)
c.InheritACL = jc.InheritACL c.InheritACL = jc.InheritACL
c.Description = jc.Description c.DescriptionHash = []byte{} // fixme
c.DescriptionHash = jc.DescriptionHash
for _, jacl := range jc.ACL { for _, jacl := range jc.ACL {
acl := NewChannelACL(c) acl := NewChannelACL(c)
@ -201,5 +241,24 @@ func NewServerFromFrozen(filename string) (s *Server, err os.Error) {
s.root = s.Channels[0] s.root = s.Channels[0]
// Add all users
for _, ju := range fs.Users {
u, err := NewUser(ju.Id, ju.Name)
if err != nil {
return nil, err
}
u.CertHash = ju.CertHash
u.Email = ju.Email
u.TextureBlob = ju.TextureBlob
u.CommentBlob = ju.CommentBlob
u.LastChannelId = ju.LastChannelId
u.LastActive = ju.LastActive
s.Users[u.Id] = u
s.UserNameMap[u.Name] = u
s.UserCertMap[u.CertHash] = u
}
return s, nil return s, nil
} }

View file

@ -51,28 +51,25 @@ func MurmurImport(filename string) (err os.Error) {
for _, sid := range servers { for _, sid := range servers {
m, err := NewServerFromSQLite(sid, db) m, err := NewServerFromSQLite(sid, db)
if err != nil { if err != nil {
log.Printf("Unable to create server: %s", err.String()) return err
return
} }
f, err := os.Create(filepath.Join(*datadir, fmt.Sprintf("%v", sid))) f, err := os.Create(filepath.Join(*datadir, fmt.Sprintf("%v", sid)))
if err != nil { if err != nil {
log.Printf("%s", err.String()) return err
return
} }
zf, err := gzip.NewWriterLevel(f, gzip.BestCompression) zf, err := gzip.NewWriterLevel(f, gzip.BestCompression)
fz, err := m.Freeze() fz, err := m.Freeze()
if err != nil { if err != nil {
log.Fatalf("Unable to freeze server: %s", err.String()) return err
} }
enc := gob.NewEncoder(zf) enc := gob.NewEncoder(zf)
err = enc.Encode(fz) err = enc.Encode(fz)
if err != nil { if err != nil {
log.Printf("%s", err.String()) return err
return
} }
zf.Close() zf.Close()

View file

@ -1,3 +1,7 @@
// Copyright (c) 2011 The Grumble Authors
// The use of this source code is goverened by a BSD-style
// license that can be found in the LICENSE-file.
package main package main
// This file implements a Server that can be created from a Murmur SQLite file. // This file implements a Server that can be created from a Murmur SQLite file.
@ -42,6 +46,11 @@ func NewServerFromSQLite(id int64, db *sqlite.Conn) (s *Server, err os.Error) {
return nil, err return nil, err
} }
err = populateUsers(s, db)
if err != nil {
return nil, err
}
return return
} }
@ -268,3 +277,96 @@ func populateChannelLinkInfo(server *Server, db *sqlite.Conn) (err os.Error) {
return nil return nil
} }
func populateUsers(server *Server, db *sqlite.Conn) (err os.Error) {
// Populate the server with regular user data
stmt, err := db.Prepare("SELECT user_id, name, pw, lastchannel, texture, strftime('%s', last_active) FROM users WHERE server_id=?")
if err != nil {
return
}
err = stmt.Exec(server.Id)
if err != nil {
return
}
for stmt.Next() {
var (
UserId int64
UserName string
SHA1Password string
LastChannel int
Texture []byte
LastActive int64
)
err = stmt.Scan(&UserId, &UserName, &SHA1Password, &LastChannel, &Texture, &LastActive)
if err != nil {
continue
}
if UserId == 0 {
server.superUserPassword = "sha1" + SHA1Password
continue
}
user, err := NewUser(uint32(UserId), UserName)
if err != nil {
return err
}
user.LastActive = uint64(LastActive)
user.LastChannelId = LastChannel
server.Users[user.Id] = user
}
stmt, err = db.Prepare("SELECT key, value FROM user_info WHERE server_id=? AND user_id=?")
if err != nil {
return
}
// Populate users with any new-style UserInfo records
for uid, user := range server.Users {
err = stmt.Reset()
if err != nil {
return err
}
err = stmt.Exec(server.Id, uid)
if err != nil {
return err
}
for stmt.Next() {
var (
Key int
Value string
)
err = stmt.Scan(&Key, &Value)
if err != nil {
return err
}
switch Key {
case UserInfoEmail:
user.Email = Value
case UserInfoComment:
// unhandled
case UserInfoHash:
user.CertHash = "sha1-" + Value
case UserInfoLastActive:
// not a kv-pair (trigger)
case UserInfoPassword:
// not a kv-pair
case UserInfoName:
// not a kv-pair
}
}
}
return
}

View file

@ -68,6 +68,12 @@ type Server struct {
root *Channel root *Channel
Channels map[int]*Channel Channels map[int]*Channel
// Users
superUserPassword string
Users map[uint32]*User
UserCertMap map[string]*User
UserNameMap map[string]*User
// ACL cache // ACL cache
aclcache ACLCache aclcache ACLCache
} }
@ -81,6 +87,9 @@ func NewServer(id int64, addr string, port int) (s *Server, err os.Error) {
s.port = port s.port = port
s.clients = make(map[uint32]*Client) s.clients = make(map[uint32]*Client)
s.Users = make(map[uint32]*User)
s.UserCertMap = make(map[string]*User)
s.UserNameMap = make(map[string]*User)
s.hclients = make(map[string][]*Client) s.hclients = make(map[string][]*Client)
s.hpclients = make(map[string]*Client) s.hpclients = make(map[string]*Client)

39
user.go Normal file
View file

@ -0,0 +1,39 @@
// Copyright (c) 2011 The Grumble Authors
// The use of this source code is goverened by a BSD-style
// license that can be found in the LICENSE-file.
package main
import (
"os"
)
// This file implements Server's handling of Users.
//
// Users are registered clients on the server.
type User struct {
Id uint32
Name string
CertHash string
Email string
TextureBlob string
CommentBlob string
LastChannelId int
LastActive uint64
}
// Create a new User
func NewUser(id uint32, name string) (user *User, err os.Error) {
if id < 0 {
return nil, os.NewError("Invalid user id")
}
if len(name) == 0 || name == "SuperUser" {
return nil, os.NewError("Invalid username")
}
return &User{
Id: id,
Name: name,
}, nil
}