Browse Source

User persistence to sqlite.

tags/v0.1.0
Jeremy Latt 11 years ago
parent
commit
ccdf7779a5
12 changed files with 170 additions and 113 deletions
  1. 1
    0
      .gitignore
  2. 8
    8
      sql/drop.sql
  3. 18
    8
      sql/init.sql
  4. 1
    12
      src/ergonomadicdb/ergonomadicdb.go
  5. 26
    29
      src/irc/channel.go
  6. 2
    2
      src/irc/client.go
  7. 2
    2
      src/irc/net.go
  8. 2
    1
      src/irc/nickserv.go
  9. 77
    37
      src/irc/persistence.go
  10. 15
    3
      src/irc/server.go
  11. 1
    1
      src/irc/service.go
  12. 17
    10
      src/irc/user.go

+ 1
- 0
.gitignore View File

1
 pkg
1
 pkg
2
 bin
2
 bin
3
 src/code.google.com/
3
 src/code.google.com/
4
+src/github.com/
4
 ergonomadic.db
5
 ergonomadic.db

+ 8
- 8
sql/drop.sql View File

1
-DROP INDEX user_id_channel_id
2
-DROP TABLE user_channel
1
+DROP INDEX IF EXISTS index_user_id_channel_id;
2
+DROP TABLE IF EXISTS user_channel;
3
 
3
 
4
-DROP INDEX channel_name
5
-DROP INDEX channel_id
6
-DROP TABLE channel
4
+DROP INDEX IF EXISTS index_channel_name;
5
+DROP INDEX IF EXISTS index_channel_id;
6
+DROP TABLE IF EXISTS channel;
7
 
7
 
8
-DROP INDEX user_nick
9
-DROP INDEX user_id
10
-DROP TABLE user
8
+DROP INDEX IF EXISTS index_user_nick;
9
+DROP INDEX IF EXISTS index_user_id;
10
+DROP TABLE IF EXISTS user;

+ 18
- 8
sql/init.sql View File

1
-CREATE TABLE user (id integer not null primary key autoincrement, nick text not null, hash blob not null)
2
-CREATE UNIQUE INDEX user_id ON user (id)
3
-CREATE UNIQUE INDEX user_nick ON user (nick)
1
+CREATE TABLE user (
2
+  id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
3
+  nick TEXT NOT NULL UNIQUE,
4
+  hash BLOB NOT NULL
5
+);
6
+CREATE INDEX index_user_id ON user(id);
7
+CREATE INDEX index_user_nick ON user(nick);
4
 
8
 
5
-CREATE TABLE channel (id integer not null primary key autoincrement, name text not  null)
6
-CREATE UNIQUE INDEX channel_id ON channel (id)
7
-CREATE UNIQUE INDEX channel_name ON channel (name)
9
+CREATE TABLE channel (
10
+  id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
11
+  name TEXT NOT NULL UNIQUE
12
+);
13
+CREATE INDEX index_channel_id ON channel(id);
8
 
14
 
9
-CREATE_TABLE user_channel (id integer not null primary key autoincrement, user_id integer not null, channel_id integer not null)
10
-CREATE UNIQUE INDEX user_id_channel_id ON user_channel (user_id, channel_id)
15
+CREATE TABLE user_channel (
16
+  id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
17
+  user_id INTEGER NOT NULL,
18
+  channel_id INTEGER NOT NULL
19
+);
20
+CREATE UNIQUE INDEX index_user_id_channel_id ON user_channel (user_id, channel_id);

+ 1
- 12
src/ergonomadicdb/ergonomadicdb.go View File

5
 	"irc"
5
 	"irc"
6
 )
6
 )
7
 
7
 
8
-var (
9
-	actions = map[string]func(*irc.Database){
10
-		"init": func(db *irc.Database) {
11
-			db.InitTables()
12
-		},
13
-		"drop": func(db *irc.Database) {
14
-			db.DropTables()
15
-		},
16
-	}
17
-)
18
-
19
 func main() {
8
 func main() {
20
 	flag.Parse()
9
 	flag.Parse()
21
-	actions[flag.Arg(0)](irc.NewDatabase())
10
+	irc.NewDatabase().ExecSqlFile(flag.Arg(0) + ".sql").Close()
22
 }
11
 }

+ 26
- 29
src/irc/channel.go View File

49
 // NewChannel creates a new channel from a `Server` and a `name` string, which
49
 // NewChannel creates a new channel from a `Server` and a `name` string, which
50
 // must be unique on the server.
50
 // must be unique on the server.
51
 func NewChannel(s *Server, name string) *Channel {
51
 func NewChannel(s *Server, name string) *Channel {
52
-	replies := make(chan Reply)
53
-	commands := make(chan ChannelCommand)
52
+	commands := make(chan ChannelCommand, 1)
53
+	replies := make(chan Reply, 1)
54
 	channel := &Channel{
54
 	channel := &Channel{
55
 		name:     name,
55
 		name:     name,
56
 		members:  make(UserSet),
56
 		members:  make(UserSet),
58
 		commands: commands,
58
 		commands: commands,
59
 		replies:  replies,
59
 		replies:  replies,
60
 	}
60
 	}
61
-	go channel.receiveReplies(replies)
62
 	go channel.receiveCommands(commands)
61
 	go channel.receiveCommands(commands)
62
+	go channel.receiveReplies(replies)
63
 	return channel
63
 	return channel
64
 }
64
 }
65
 
65
 
81
 	return true
81
 	return true
82
 }
82
 }
83
 
83
 
84
-// Forward `Reply`s to all `User`s of the `Channel`.
84
+func (channel *Channel) receiveCommands(commands <-chan ChannelCommand) {
85
+	for command := range commands {
86
+		if DEBUG_CHANNEL {
87
+			log.Printf("%s → %s : %s", command.Source(), channel, command)
88
+		}
89
+		command.HandleChannel(channel)
90
+	}
91
+}
92
+
85
 func (channel *Channel) receiveReplies(replies <-chan Reply) {
93
 func (channel *Channel) receiveReplies(replies <-chan Reply) {
86
 	for reply := range replies {
94
 	for reply := range replies {
87
 		if DEBUG_CHANNEL {
95
 		if DEBUG_CHANNEL {
88
-			log.Printf("%s → %s", channel, reply)
96
+			log.Printf("%s ← %s : %s", channel, reply.Source(), reply)
89
 		}
97
 		}
90
 		for user := range channel.members {
98
 		for user := range channel.members {
91
 			if user != reply.Source() {
99
 			if user != reply.Source() {
92
-				user.replies <- reply
100
+				user.Replies() <- reply
93
 			}
101
 			}
94
 		}
102
 		}
95
 	}
103
 	}
96
 }
104
 }
97
-
98
-func (channel *Channel) receiveCommands(commands <-chan ChannelCommand) {
99
-	for command := range commands {
100
-		if DEBUG_CHANNEL {
101
-			log.Printf("%s ← %s %s", channel, command.Source(), command)
102
-		}
103
-		command.HandleChannel(channel)
104
-	}
105
-}
106
-
107
 func (channel *Channel) Nicks() []string {
105
 func (channel *Channel) Nicks() []string {
108
 	return channel.members.Nicks()
106
 	return channel.members.Nicks()
109
 }
107
 }
121
 	replier.Replies() <- RplTopic(channel)
119
 	replier.Replies() <- RplTopic(channel)
122
 }
120
 }
123
 
121
 
122
+func (channel *Channel) Replies() chan<- Reply {
123
+	return channel.replies
124
+}
125
+
124
 func (channel *Channel) Id() string {
126
 func (channel *Channel) Id() string {
125
 	return channel.name
127
 	return channel.name
126
 }
128
 }
133
 	return channel.commands
135
 	return channel.commands
134
 }
136
 }
135
 
137
 
136
-func (channel *Channel) Replies() chan<- Reply {
137
-	return channel.replies
138
-}
139
-
140
 func (channel *Channel) String() string {
138
 func (channel *Channel) String() string {
141
 	return channel.Id()
139
 	return channel.Id()
142
 }
140
 }
150
 	user := client.user
148
 	user := client.user
151
 
149
 
152
 	if channel.key != m.channels[channel.name] {
150
 	if channel.key != m.channels[channel.name] {
153
-		client.user.replies <- ErrBadChannelKey(channel)
151
+		client.user.Replies() <- ErrBadChannelKey(channel)
154
 		return
152
 		return
155
 	}
153
 	}
156
 
154
 
157
 	channel.members.Add(user)
155
 	channel.members.Add(user)
158
 	user.channels.Add(channel)
156
 	user.channels.Add(channel)
159
 
157
 
160
-	channel.replies <- RplJoin(channel, user)
158
+	channel.Replies() <- RplJoin(channel, user)
161
 	channel.GetTopic(user)
159
 	channel.GetTopic(user)
162
-	user.replies <- RplNamReply(channel)
163
-	user.replies <- RplEndOfNames(channel.server)
160
+	user.Replies() <- RplNamReply(channel)
161
+	user.Replies() <- RplEndOfNames(channel.server)
164
 }
162
 }
165
 
163
 
166
 func (m *PartCommand) HandleChannel(channel *Channel) {
164
 func (m *PartCommand) HandleChannel(channel *Channel) {
176
 		msg = user.Nick()
174
 		msg = user.Nick()
177
 	}
175
 	}
178
 
176
 
179
-	channel.replies <- RplPart(channel, user, msg)
177
+	channel.Replies() <- RplPart(channel, user, msg)
180
 
178
 
181
 	channel.members.Remove(user)
179
 	channel.members.Remove(user)
182
 	user.channels.Remove(channel)
180
 	user.channels.Remove(channel)
190
 	user := m.User()
188
 	user := m.User()
191
 
189
 
192
 	if !channel.members[user] {
190
 	if !channel.members[user] {
193
-		user.replies <- ErrNotOnChannel(channel)
191
+		user.Replies() <- ErrNotOnChannel(channel)
194
 		return
192
 		return
195
 	}
193
 	}
196
 
194
 
202
 	channel.topic = m.topic
200
 	channel.topic = m.topic
203
 
201
 
204
 	if channel.topic == "" {
202
 	if channel.topic == "" {
205
-		channel.replies <- RplNoTopic(channel)
203
+		channel.Replies() <- RplNoTopic(channel)
206
 		return
204
 		return
207
 	}
205
 	}
208
-
209
-	channel.replies <- RplTopic(channel)
206
+	channel.Replies() <- RplTopic(channel)
210
 }
207
 }
211
 
208
 
212
 func (m *PrivMsgCommand) HandleChannel(channel *Channel) {
209
 func (m *PrivMsgCommand) HandleChannel(channel *Channel) {

+ 2
- 2
src/irc/client.go View File

31
 func NewClient(server *Server, conn net.Conn) *Client {
31
 func NewClient(server *Server, conn net.Conn) *Client {
32
 	read := StringReadChan(conn)
32
 	read := StringReadChan(conn)
33
 	write := StringWriteChan(conn)
33
 	write := StringWriteChan(conn)
34
-	replies := make(chan Reply)
34
+	replies := make(chan Reply, 1)
35
 
35
 
36
 	client := &Client{
36
 	client := &Client{
37
 		conn:     conn,
37
 		conn:     conn,
67
 func (c *Client) writeConn(write chan<- string, replies <-chan Reply) {
67
 func (c *Client) writeConn(write chan<- string, replies <-chan Reply) {
68
 	for reply := range replies {
68
 	for reply := range replies {
69
 		if DEBUG_CLIENT {
69
 		if DEBUG_CLIENT {
70
-			log.Printf("%s ← %s", c, reply)
70
+			log.Printf("%s ← %s : %s", c, reply.Source(), reply)
71
 		}
71
 		}
72
 		write <- reply.Format(c)
72
 		write <- reply.Format(c)
73
 	}
73
 	}

+ 2
- 2
src/irc/net.go View File

30
 				break
30
 				break
31
 			}
31
 			}
32
 			if DEBUG_NET {
32
 			if DEBUG_NET {
33
-				log.Printf("%s → %s", conn.RemoteAddr(), line)
33
+				log.Printf("%s → %s : %s", conn.RemoteAddr(), conn.LocalAddr(), line)
34
 			}
34
 			}
35
 			ch <- line
35
 			ch <- line
36
 		}
36
 		}
45
 	go func() {
45
 	go func() {
46
 		for str := range ch {
46
 		for str := range ch {
47
 			if DEBUG_NET {
47
 			if DEBUG_NET {
48
-				log.Printf("%s ← %s", conn.RemoteAddr(), str)
48
+				log.Printf("%s ← %s : %s", conn.RemoteAddr(), conn.LocalAddr(), str)
49
 			}
49
 			}
50
 			if _, err := writer.WriteString(str + "\r\n"); err != nil {
50
 			if _, err := writer.WriteString(str + "\r\n"); err != nil {
51
 				break
51
 				break

+ 2
- 1
src/irc/nickserv.go View File

106
 		return
106
 		return
107
 	}
107
 	}
108
 
108
 
109
-	user := NewUser(client.nick, m.password, ns.server)
109
+	user := NewUser(client.nick, ns.server).SetPassword(m.password)
110
+	ns.server.db.Save(user)
110
 	ns.Reply(client, "You have registered.")
111
 	ns.Reply(client, "You have registered.")
111
 
112
 
112
 	if !user.Login(client, client.nick, m.password) {
113
 	if !user.Login(client, client.nick, m.password) {

+ 77
- 37
src/irc/persistence.go View File

27
 	QueryRow(string, ...interface{}) *sql.Row
27
 	QueryRow(string, ...interface{}) *sql.Row
28
 }
28
 }
29
 
29
 
30
-type TransactionFunc func(Queryable) bool
30
+type Savable interface {
31
+	Save(q Queryable) bool
32
+}
31
 
33
 
32
 //
34
 //
33
 // general
35
 // general
36
 func NewDatabase() *Database {
38
 func NewDatabase() *Database {
37
 	db, err := sql.Open("sqlite3", "ergonomadic.db")
39
 	db, err := sql.Open("sqlite3", "ergonomadic.db")
38
 	if err != nil {
40
 	if err != nil {
39
-		panic("cannot open database")
41
+		log.Fatalln("cannot open database")
40
 	}
42
 	}
41
 	return &Database{db}
43
 	return &Database{db}
42
 }
44
 }
48
 func readLines(filename string) <-chan string {
50
 func readLines(filename string) <-chan string {
49
 	file, err := os.Open(filename)
51
 	file, err := os.Open(filename)
50
 	if err != nil {
52
 	if err != nil {
51
-		panic(err)
53
+		log.Fatalln(err)
52
 	}
54
 	}
53
 	reader := bufio.NewReader(file)
55
 	reader := bufio.NewReader(file)
54
 	lines := make(chan string)
56
 	lines := make(chan string)
56
 		defer file.Close()
58
 		defer file.Close()
57
 		defer close(lines)
59
 		defer close(lines)
58
 		for {
60
 		for {
59
-			line, err := reader.ReadString('\n')
61
+			line, err := reader.ReadString(';')
60
 			if err != nil {
62
 			if err != nil {
61
 				break
63
 				break
62
 			}
64
 			}
70
 	return lines
72
 	return lines
71
 }
73
 }
72
 
74
 
73
-func (db *Database) execSqlFile(filename string) {
75
+func (db *Database) ExecSqlFile(filename string) *Database {
74
 	db.Transact(func(q Queryable) bool {
76
 	db.Transact(func(q Queryable) bool {
75
 		for line := range readLines(filepath.Join("sql", filename)) {
77
 		for line := range readLines(filepath.Join("sql", filename)) {
76
 			log.Println(line)
78
 			log.Println(line)
77
-			q.Exec(line)
79
+			_, err := q.Exec(line)
80
+			if err != nil {
81
+				log.Fatalln(err)
82
+			}
78
 		}
83
 		}
79
 		return true
84
 		return true
80
 	})
85
 	})
86
+	return db
81
 }
87
 }
82
 
88
 
83
-func (db *Database) InitTables() {
84
-	db.execSqlFile("init.sql")
85
-}
86
-
87
-func (db *Database) DropTables() {
88
-	db.execSqlFile("drop.sql")
89
-}
90
-
91
-func (db *Database) Transact(txf TransactionFunc) {
89
+func (db *Database) Transact(txf func(Queryable) bool) {
92
 	tx, err := db.Begin()
90
 	tx, err := db.Begin()
93
 	if err != nil {
91
 	if err != nil {
94
-		panic(err)
92
+		log.Panicln(err)
95
 	}
93
 	}
96
 	if txf(tx) {
94
 	if txf(tx) {
97
 		tx.Commit()
95
 		tx.Commit()
100
 	}
98
 	}
101
 }
99
 }
102
 
100
 
101
+func (db *Database) Save(s Savable) {
102
+	db.Transact(func(tx Queryable) bool {
103
+		return s.Save(tx)
104
+	})
105
+}
106
+
107
+//
108
+// general purpose sql
109
+//
110
+
111
+func FindId(q Queryable, sql string, args ...interface{}) (rowId RowId, err error) {
112
+	row := q.QueryRow(sql, args...)
113
+	err = row.Scan(&rowId)
114
+	return
115
+}
116
+
117
+func Count(q Queryable, sql string, args ...interface{}) (count uint, err error) {
118
+	row := q.QueryRow(sql, args...)
119
+	err = row.Scan(&count)
120
+	return
121
+}
122
+
103
 //
123
 //
104
 // data
124
 // data
105
 //
125
 //
117
 
137
 
118
 // user
138
 // user
119
 
139
 
120
-func FindUserByNick(q Queryable, nick string) (ur *UserRow) {
121
-	ur = new(UserRow)
122
-	row := q.QueryRow("SELECT * FROM user LIMIT 1 WHERE nick = ?", nick)
123
-	err := row.Scan(&ur.id, &ur.nick, &ur.hash)
140
+func FindAllUsers(q Queryable) (urs []UserRow, err error) {
141
+	var rows *sql.Rows
142
+	rows, err = q.Query("SELECT id, nick, hash FROM user")
124
 	if err != nil {
143
 	if err != nil {
125
-		ur = nil
144
+		return
145
+	}
146
+	urs = make([]UserRow, 0)
147
+	for rows.Next() {
148
+		ur := UserRow{}
149
+		err = rows.Scan(&(ur.id), &(ur.nick), &(ur.hash))
150
+		if err != nil {
151
+			return
152
+		}
153
+		urs = append(urs, ur)
126
 	}
154
 	}
127
 	return
155
 	return
128
 }
156
 }
129
 
157
 
130
-func FindUserIdByNick(q Queryable, nick string) (rowId RowId, err error) {
131
-	row := q.QueryRow("SELECT id FROM user WHERE nick = ?", nick)
132
-	err = row.Scan(&rowId)
158
+func FindUserByNick(q Queryable, nick string) (ur *UserRow, err error) {
159
+	ur = &UserRow{}
160
+	row := q.QueryRow("SELECT id, nick, hash FROM user LIMIT 1 WHERE nick = ?",
161
+		nick)
162
+	err = row.Scan(&(ur.id), &(ur.nick), &(ur.hash))
133
 	return
163
 	return
134
 }
164
 }
135
 
165
 
166
+func FindUserIdByNick(q Queryable, nick string) (RowId, error) {
167
+	return FindId(q, "SELECT id FROM user WHERE nick = ?", nick)
168
+}
169
+
136
 func FindChannelByName(q Queryable, name string) (cr *ChannelRow) {
170
 func FindChannelByName(q Queryable, name string) (cr *ChannelRow) {
137
 	cr = new(ChannelRow)
171
 	cr = new(ChannelRow)
138
-	row := q.QueryRow("SELECT * FROM channel LIMIT 1 WHERE name = ?", name)
172
+	row := q.QueryRow("SELECT id, name FROM channel LIMIT 1 WHERE name = ?", name)
139
 	err := row.Scan(&(cr.id), &(cr.name))
173
 	err := row.Scan(&(cr.id), &(cr.name))
140
 	if err != nil {
174
 	if err != nil {
141
 		cr = nil
175
 		cr = nil
185
 
219
 
186
 // channel
220
 // channel
187
 
221
 
188
-func FindChannelIdByName(q Queryable, name string) (channelId RowId, err error) {
189
-	row := q.QueryRow("SELECT id FROM channel WHERE name = ?", name)
190
-	err = row.Scan(&channelId)
191
-	return
222
+func FindChannelIdByName(q Queryable, name string) (RowId, error) {
223
+	return FindId(q, "SELECT id FROM channel WHERE name = ?", name)
192
 }
224
 }
193
 
225
 
194
-func FindChannelsForUser(q Queryable, userId RowId) (crs []ChannelRow) {
195
-	rows, err := q.Query(`SELECT * FROM channel WHERE id IN
196
-(SELECT channel_id from user_channel WHERE user_id = ?)`, userId)
226
+func FindChannelsForUser(q Queryable, userId RowId) (crs []ChannelRow, err error) {
227
+	query := ` FROM channel WHERE id IN
228
+(SELECT channel_id from user_channel WHERE user_id = ?)`
229
+	count, err := Count(q, "SELECT COUNT(id)"+query, userId)
197
 	if err != nil {
230
 	if err != nil {
198
-		panic(err)
231
+		return
199
 	}
232
 	}
200
-	crs = make([]ChannelRow, 0)
233
+	rows, err := q.Query("SELECT id, name"+query, userId)
234
+	if err != nil {
235
+		return
236
+	}
237
+	crs = make([]ChannelRow, count)
238
+	var i = 0
201
 	for rows.Next() {
239
 	for rows.Next() {
202
 		cr := ChannelRow{}
240
 		cr := ChannelRow{}
203
-		if err := rows.Scan(&(cr.id), &(cr.name)); err != nil {
204
-			panic(err)
241
+		err = rows.Scan(&(cr.id), &(cr.name))
242
+		if err != nil {
243
+			return
205
 		}
244
 		}
206
-		crs = append(crs, cr)
245
+		crs[i] = cr
246
+		i++
207
 	}
247
 	}
208
 	return
248
 	return
209
 }
249
 }

+ 15
- 3
src/irc/server.go View File

24
 	channels ChannelNameMap
24
 	channels ChannelNameMap
25
 	services ServiceNameMap
25
 	services ServiceNameMap
26
 	commands chan<- Command
26
 	commands chan<- Command
27
+	db       *Database
27
 }
28
 }
28
 
29
 
29
 func NewServer(name string) *Server {
30
 func NewServer(name string) *Server {
30
-	commands := make(chan Command)
31
+	commands := make(chan Command, 1)
31
 	server := &Server{
32
 	server := &Server{
32
 		ctime:    time.Now(),
33
 		ctime:    time.Now(),
33
 		name:     name,
34
 		name:     name,
35
 		users:    make(UserNameMap),
36
 		users:    make(UserNameMap),
36
 		channels: make(ChannelNameMap),
37
 		channels: make(ChannelNameMap),
37
 		services: make(ServiceNameMap),
38
 		services: make(ServiceNameMap),
39
+		db:       NewDatabase(),
38
 	}
40
 	}
39
 	go server.receiveCommands(commands)
41
 	go server.receiveCommands(commands)
40
 	NewNickServ(server)
42
 	NewNickServ(server)
43
+	server.db.Transact(func(q Queryable) bool {
44
+		urs, err := FindAllUsers(server.db)
45
+		if err != nil {
46
+			return false
47
+		}
48
+		for _, ur := range urs {
49
+			NewUser(ur.nick, server).SetHash(ur.hash)
50
+		}
51
+		return false
52
+	})
41
 	return server
53
 	return server
42
 }
54
 }
43
 
55
 
44
 func (server *Server) receiveCommands(commands <-chan Command) {
56
 func (server *Server) receiveCommands(commands <-chan Command) {
45
 	for command := range commands {
57
 	for command := range commands {
46
 		if DEBUG_SERVER {
58
 		if DEBUG_SERVER {
47
-			log.Printf("%s ← %s %s", server, command.Client(), command)
59
+			log.Printf("%s → %s : %s", command.Client(), server, command)
48
 		}
60
 		}
49
 		command.Client().atime = time.Now()
61
 		command.Client().atime = time.Now()
50
 		command.HandleServer(server)
62
 		command.HandleServer(server)
278
 
290
 
279
 	channel := s.channels[m.channel]
291
 	channel := s.channels[m.channel]
280
 	if channel == nil {
292
 	if channel == nil {
281
-		user.Replies() <- ErrNoSuchChannel(s, m.channel)
293
+		m.Client().Replies() <- ErrNoSuchChannel(s, m.channel)
282
 		return
294
 		return
283
 	}
295
 	}
284
 
296
 

+ 1
- 1
src/irc/service.go View File

29
 }
29
 }
30
 
30
 
31
 func NewService(service EditableService, s *Server, name string) Service {
31
 func NewService(service EditableService, s *Server, name string) Service {
32
-	commands := make(chan ServiceCommand)
32
+	commands := make(chan ServiceCommand, 1)
33
 	base := &BaseService{
33
 	base := &BaseService{
34
 		server:   s,
34
 		server:   s,
35
 		name:     name,
35
 		name:     name,

+ 17
- 10
src/irc/user.go View File

46
 	return nicks
46
 	return nicks
47
 }
47
 }
48
 
48
 
49
-func NewUser(nick string, password string, server *Server) *User {
50
-	commands := make(chan UserCommand)
51
-	replies := make(chan Reply)
49
+func NewUser(nick string, server *Server) *User {
50
+	commands := make(chan UserCommand, 1)
51
+	replies := make(chan Reply, 1)
52
 	user := &User{
52
 	user := &User{
53
 		nick:     nick,
53
 		nick:     nick,
54
 		server:   server,
54
 		server:   server,
56
 		channels: make(ChannelSet),
56
 		channels: make(ChannelSet),
57
 		replies:  replies,
57
 		replies:  replies,
58
 	}
58
 	}
59
-	user.SetPassword(password)
60
 
59
 
61
 	go user.receiveCommands(commands)
60
 	go user.receiveCommands(commands)
62
 	go user.receiveReplies(replies)
61
 	go user.receiveReplies(replies)
81
 		}
80
 		}
82
 	}
81
 	}
83
 
82
 
83
+	userId := *(user.id)
84
 	channelIds := user.channels.Ids()
84
 	channelIds := user.channels.Ids()
85
 	if len(channelIds) == 0 {
85
 	if len(channelIds) == 0 {
86
-		if err := DeleteAllUserChannels(q, *(user.id)); err != nil {
86
+		if err := DeleteAllUserChannels(q, userId); err != nil {
87
 			return false
87
 			return false
88
 		}
88
 		}
89
 	} else {
89
 	} else {
90
-		if err := DeleteOtherUserChannels(q, *(user.id), channelIds); err != nil {
90
+		if err := DeleteOtherUserChannels(q, userId, channelIds); err != nil {
91
 			return false
91
 			return false
92
 		}
92
 		}
93
-		if err := InsertUserChannels(q, *(user.id), channelIds); err != nil {
93
+		if err := InsertUserChannels(q, userId, channelIds); err != nil {
94
 			return false
94
 			return false
95
 		}
95
 		}
96
 	}
96
 	}
97
 	return true
97
 	return true
98
 }
98
 }
99
 
99
 
100
-func (user *User) SetPassword(password string) {
100
+func (user *User) SetPassword(password string) *User {
101
 	hash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
101
 	hash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
102
 	if err != nil {
102
 	if err != nil {
103
 		panic("bcrypt failed; cannot generate password hash")
103
 		panic("bcrypt failed; cannot generate password hash")
104
 	}
104
 	}
105
+	return user.SetHash(hash)
106
+}
107
+
108
+func (user *User) SetHash(hash []byte) *User {
105
 	user.hash = hash
109
 	user.hash = hash
110
+	return user
106
 }
111
 }
107
 
112
 
108
 func (user *User) receiveCommands(commands <-chan UserCommand) {
113
 func (user *User) receiveCommands(commands <-chan UserCommand) {
109
 	for command := range commands {
114
 	for command := range commands {
110
 		if DEBUG_USER {
115
 		if DEBUG_USER {
111
-			log.Printf("%s ← %s %s", user, command.Client(), command)
116
+			log.Printf("%s → %s : %s", command.Client(), user, command)
112
 		}
117
 		}
113
 		command.HandleUser(user)
118
 		command.HandleUser(user)
114
 	}
119
 	}
117
 // Distribute replies to clients.
122
 // Distribute replies to clients.
118
 func (user *User) receiveReplies(replies <-chan Reply) {
123
 func (user *User) receiveReplies(replies <-chan Reply) {
119
 	for reply := range replies {
124
 	for reply := range replies {
120
-		log.Printf("%s ← %s", user, reply)
125
+		if DEBUG_USER {
126
+			log.Printf("%s ← %s : %s", user, reply.Source(), reply)
127
+		}
121
 		for client := range user.clients {
128
 		for client := range user.clients {
122
 			client.Replies() <- reply
129
 			client.Replies() <- reply
123
 		}
130
 		}

Loading…
Cancel
Save