forked from External/grumble
User support in MurmurDB import and freezer.
This commit is contained in:
parent
73478072d0
commit
47bb4d0025
6 changed files with 223 additions and 16 deletions
1
Makefile
1
Makefile
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
77
freeze.go
77
freeze.go
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
11
grumble.go
11
grumble.go
|
|
@ -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()
|
||||||
|
|
|
||||||
102
murmurdb.go
102
murmurdb.go
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
39
user.go
Normal 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
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue