Browse Source

get rid of user abstraction, services

tags/v0.1.0
Jeremy Latt 10 years ago
parent
commit
f04dd7c5d5
11 changed files with 145 additions and 983 deletions
  1. 3
    3
      build.sh
  2. 49
    85
      src/irc/channel.go
  3. 41
    18
      src/irc/client.go
  4. 0
    5
      src/irc/commands.go
  5. 2
    2
      src/irc/net.go
  6. 0
    158
      src/irc/nickserv.go
  7. 0
    270
      src/irc/persistence.go
  8. 5
    4
      src/irc/reply.go
  9. 45
    127
      src/irc/server.go
  10. 0
    83
      src/irc/service.go
  11. 0
    228
      src/irc/user.go

+ 3
- 3
build.sh View File

@@ -1,5 +1,5 @@
1 1
 #!/bin/bash
2 2
 export GOPATH="$PWD"
3
-go get "code.google.com/p/go.crypto/bcrypt"
4
-go get "github.com/mattn/go-sqlite3"
5
-go install ergonomadic genpasswd ergonomadicdb
3
+#go get "code.google.com/p/go.crypto/bcrypt"
4
+#go get "github.com/mattn/go-sqlite3"
5
+go install ergonomadic genpasswd

+ 49
- 85
src/irc/channel.go View File

@@ -9,82 +9,41 @@ const (
9 9
 )
10 10
 
11 11
 type Channel struct {
12
-	id        *RowId
13
-	server    *Server
14 12
 	commands  chan<- ChannelCommand
15
-	replies   chan<- Reply
16
-	name      string
17 13
 	key       string
18
-	topic     string
19
-	members   UserSet
14
+	members   ClientSet
15
+	name      string
20 16
 	noOutside bool
21 17
 	password  string
18
+	replies   chan<- Reply
19
+	server    *Server
20
+	topic     string
22 21
 }
23 22
 
24 23
 type ChannelSet map[*Channel]bool
25 24
 
26
-func (set ChannelSet) Add(channel *Channel) {
27
-	set[channel] = true
28
-}
29
-
30
-func (set ChannelSet) Remove(channel *Channel) {
31
-	delete(set, channel)
32
-}
33
-
34
-func (set ChannelSet) Ids() (ids []RowId) {
35
-	ids = make([]RowId, len(set))
36
-	var i = 0
37
-	for channel := range set {
38
-		ids[i] = *(channel.id)
39
-		i++
40
-	}
41
-	return ids
42
-}
43
-
44 25
 type ChannelCommand interface {
45 26
 	Command
46 27
 	HandleChannel(channel *Channel)
47 28
 }
48 29
 
49
-// NewChannel creates a new channel from a `Server` and a `name` string, which
50
-// must be unique on the server.
30
+// NewChannel creates a new channel from a `Server` and a `name`
31
+// string, which must be unique on the server.
51 32
 func NewChannel(s *Server, name string) *Channel {
52 33
 	commands := make(chan ChannelCommand)
53 34
 	replies := make(chan Reply)
54 35
 	channel := &Channel{
55 36
 		name:     name,
56
-		members:  make(UserSet),
37
+		members:  make(ClientSet),
57 38
 		server:   s,
58 39
 		commands: commands,
59 40
 		replies:  replies,
60 41
 	}
61 42
 	go channel.receiveCommands(commands)
62 43
 	go channel.receiveReplies(replies)
63
-	Save(s.db, channel)
64 44
 	return channel
65 45
 }
66 46
 
67
-func (channel *Channel) Save(q Queryable) bool {
68
-	if channel.id == nil {
69
-		if err := InsertChannel(q, channel); err != nil {
70
-			log.Println(err)
71
-			return false
72
-		}
73
-		channelId, err := FindChannelIdByName(q, channel.name)
74
-		if err != nil {
75
-			log.Println(err)
76
-			return false
77
-		}
78
-		channel.id = &channelId
79
-	} else {
80
-		if err := UpdateChannel(q, channel); err != nil {
81
-			log.Println(err)
82
-			return false
83
-		}
84
-	}
85
-	return true
86
-}
87
-
88 47
 func (channel *Channel) receiveCommands(commands <-chan ChannelCommand) {
89 48
 	for command := range commands {
90 49
 		if DEBUG_CHANNEL {
@@ -99,16 +58,13 @@ func (channel *Channel) receiveReplies(replies <-chan Reply) {
99 58
 		if DEBUG_CHANNEL {
100 59
 			log.Printf("%s ← %s : %s", channel, reply.Source(), reply)
101 60
 		}
102
-		for user := range channel.members {
103
-			if user != reply.Source() {
104
-				user.Replies() <- reply
61
+		for client := range channel.members {
62
+			if client != reply.Source() {
63
+				client.replies <- reply
105 64
 			}
106 65
 		}
107 66
 	}
108 67
 }
109
-func (channel *Channel) Nicks() []string {
110
-	return channel.members.Nicks()
111
-}
112 68
 
113 69
 func (channel *Channel) IsEmpty() bool {
114 70
 	return len(channel.members) == 0
@@ -127,6 +83,16 @@ func (channel *Channel) GetUsers(replier Replier) {
127 83
 	replier.Replies() <- NewNamesReply(channel)
128 84
 }
129 85
 
86
+func (channel *Channel) Nicks() []string {
87
+	nicks := make([]string, len(channel.members))
88
+	i := 0
89
+	for client := range channel.members {
90
+		nicks[i] = client.Nick()
91
+		i += 1
92
+	}
93
+	return nicks
94
+}
95
+
130 96
 func (channel *Channel) Replies() chan<- Reply {
131 97
 	return channel.replies
132 98
 }
@@ -143,20 +109,22 @@ func (channel *Channel) PublicId() string {
143 109
 	return channel.name
144 110
 }
145 111
 
146
-func (channel *Channel) Commands() chan<- ChannelCommand {
147
-	return channel.commands
148
-}
149
-
150 112
 func (channel *Channel) String() string {
151 113
 	return channel.Id()
152 114
 }
153 115
 
154
-func (channel *Channel) Join(user *User) {
155
-	channel.members.Add(user)
156
-	user.channels.Add(channel)
157
-	channel.Replies() <- RplJoin(channel, user)
158
-	channel.GetTopic(user)
159
-	channel.GetUsers(user)
116
+func (channel *Channel) Join(client *Client) {
117
+	channel.members[client] = true
118
+	client.channels[channel] = true
119
+	reply := RplJoin(channel, client)
120
+	client.replies <- reply
121
+	channel.replies <- reply
122
+	channel.GetTopic(client)
123
+	channel.GetUsers(client)
124
+}
125
+
126
+func (channel *Channel) HasMember(client *Client) bool {
127
+	return channel.members[client]
160 128
 }
161 129
 
162 130
 //
@@ -166,58 +134,54 @@ func (channel *Channel) Join(user *User) {
166 134
 func (m *JoinCommand) HandleChannel(channel *Channel) {
167 135
 	client := m.Client()
168 136
 	if channel.key != m.channels[channel.name] {
169
-		client.Replies() <- ErrBadChannelKey(channel)
137
+		client.replies <- ErrBadChannelKey(channel)
170 138
 		return
171 139
 	}
172 140
 
173
-	channel.Join(client.user)
141
+	channel.Join(client)
174 142
 }
175 143
 
176 144
 func (m *PartCommand) HandleChannel(channel *Channel) {
177
-	user := m.Client().user
145
+	c := m.Client()
178 146
 
179
-	if !channel.members[user] {
180
-		user.Replies() <- ErrNotOnChannel(channel)
147
+	if !channel.HasMember(c) {
148
+		c.replies <- ErrNotOnChannel(channel)
181 149
 		return
182 150
 	}
183 151
 
184 152
 	msg := m.message
185 153
 	if msg == "" {
186
-		msg = user.Nick()
154
+		msg = c.Nick()
187 155
 	}
188 156
 
189
-	channel.Replies() <- RplPart(channel, user, msg)
157
+	channel.replies <- RplPart(channel, c, msg)
190 158
 
191
-	channel.members.Remove(user)
192
-	user.channels.Remove(channel)
159
+	delete(channel.members, c)
160
+	delete(c.channels, channel)
193 161
 
194
-	if channel.IsEmpty() {
162
+	if channel.IsEmpty() { // TODO persistent channels
195 163
 		channel.server.DeleteChannel(channel)
196 164
 	}
197 165
 }
198 166
 
199 167
 func (m *TopicCommand) HandleChannel(channel *Channel) {
200
-	user := m.User()
168
+	client := m.Client()
201 169
 
202
-	if !channel.members[user] {
203
-		user.Replies() <- ErrNotOnChannel(channel)
170
+	if !channel.HasMember(client) {
171
+		client.replies <- ErrNotOnChannel(channel)
204 172
 		return
205 173
 	}
206 174
 
207 175
 	if m.topic == "" {
208
-		channel.GetTopic(user)
176
+		channel.GetTopic(client)
209 177
 		return
210 178
 	}
211 179
 
212 180
 	channel.topic = m.topic
213 181
 
214
-	if channel.topic == "" {
215
-		channel.Replies() <- RplNoTopic(channel)
216
-		return
217
-	}
218
-	channel.Replies() <- RplTopic(channel)
182
+	channel.GetTopic(channel)
219 183
 }
220 184
 
221 185
 func (m *PrivMsgCommand) HandleChannel(channel *Channel) {
222
-	channel.Replies() <- RplPrivMsgChannel(channel, m.User(), m.message)
186
+	channel.replies <- RplPrivMsgChannel(channel, m.Client(), m.message)
223 187
 }

+ 41
- 18
src/irc/client.go View File

@@ -8,22 +8,28 @@ import (
8 8
 )
9 9
 
10 10
 const (
11
-	DEBUG_CLIENT = true
11
+	DEBUG_CLIENT = false
12 12
 )
13 13
 
14
+type ClientCommand interface {
15
+	Command
16
+	HandleClient(*Client)
17
+}
18
+
14 19
 type Client struct {
20
+	atime      time.Time
21
+	away       bool
22
+	channels   ChannelSet
23
+	commands   chan<- ClientCommand
15 24
 	conn       net.Conn
16
-	username   string
17
-	realname   string
18 25
 	hostname   string
19 26
 	nick       string
20
-	serverPass bool
27
+	realname   string
21 28
 	registered bool
22
-	away       bool
23
-	server     *Server
24
-	atime      time.Time
25
-	user       *User
26 29
 	replies    chan<- Reply
30
+	server     *Server
31
+	serverPass bool
32
+	username   string
27 33
 }
28 34
 
29 35
 type ClientSet map[*Client]bool
@@ -31,17 +37,21 @@ type ClientSet map[*Client]bool
31 37
 func NewClient(server *Server, conn net.Conn) *Client {
32 38
 	read := StringReadChan(conn)
33 39
 	write := StringWriteChan(conn)
40
+	commands := make(chan ClientCommand)
34 41
 	replies := make(chan Reply)
35 42
 
36 43
 	client := &Client{
44
+		channels: make(ChannelSet),
45
+		commands: commands,
37 46
 		conn:     conn,
38
-		hostname: conn.RemoteAddr().String(),
39
-		server:   server,
47
+		hostname: LookupHostname(conn.RemoteAddr()),
40 48
 		replies:  replies,
49
+		server:   server,
41 50
 	}
42 51
 
43 52
 	go client.readConn(read)
44 53
 	go client.writeConn(write, replies)
54
+	go client.receiveCommands(commands)
45 55
 
46 56
 	return client
47 57
 }
@@ -51,9 +61,9 @@ func (c *Client) readConn(recv <-chan string) {
51 61
 		m, err := ParseCommand(str)
52 62
 		if err != nil {
53 63
 			if err == NotEnoughArgsError {
54
-				c.Replies() <- ErrNeedMoreParams(c.server, str)
64
+				c.replies <- ErrNeedMoreParams(c.server, str)
55 65
 			} else {
56
-				c.Replies() <- ErrUnknownCommand(c.server, str)
66
+				c.replies <- ErrUnknownCommand(c.server, str)
57 67
 			}
58 68
 			continue
59 69
 		}
@@ -72,6 +82,15 @@ func (c *Client) writeConn(write chan<- string, replies <-chan Reply) {
72 82
 	}
73 83
 }
74 84
 
85
+func (client *Client) receiveCommands(commands <-chan ClientCommand) {
86
+	for command := range commands {
87
+		if DEBUG_CLIENT {
88
+			log.Printf("%s → %s : %s", command.Client(), client, command)
89
+		}
90
+		command.HandleClient(client)
91
+	}
92
+}
93
+
75 94
 func (c *Client) Replies() chan<- Reply {
76 95
 	return c.replies
77 96
 }
@@ -81,11 +100,7 @@ func (c *Client) Server() *Server {
81 100
 }
82 101
 
83 102
 func (c *Client) Nick() string {
84
-	if c.user != nil {
85
-		return c.user.Nick()
86
-	}
87
-
88
-	if c.nick != "" {
103
+	if c.HasNick() {
89 104
 		return c.nick
90 105
 	}
91 106
 
@@ -97,7 +112,7 @@ func (c *Client) UModeString() string {
97 112
 }
98 113
 
99 114
 func (c *Client) HasNick() bool {
100
-	return c.Nick() != ""
115
+	return c.nick != ""
101 116
 }
102 117
 
103 118
 func (c *Client) HasUsername() bool {
@@ -126,3 +141,11 @@ func (c *Client) String() string {
126 141
 func (c *Client) PublicId() string {
127 142
 	return fmt.Sprintf("%s!%s@%s", c.Nick(), c.Nick(), c.server.Id())
128 143
 }
144
+
145
+//
146
+// commands
147
+//
148
+
149
+func (m *PrivMsgCommand) HandleClient(client *Client) {
150
+	client.replies <- RplPrivMsg(m.Client(), client, m.message)
151
+}

+ 0
- 5
src/irc/commands.go View File

@@ -9,7 +9,6 @@ import (
9 9
 
10 10
 type Command interface {
11 11
 	Client() *Client
12
-	User() *User
13 12
 	Source() Identifier
14 13
 	Reply(Reply)
15 14
 	HandleServer(*Server)
@@ -46,10 +45,6 @@ func (command *BaseCommand) Client() *Client {
46 45
 	return command.client
47 46
 }
48 47
 
49
-func (command *BaseCommand) User() *User {
50
-	return command.Client().user
51
-}
52
-
53 48
 func (command *BaseCommand) SetBase(c *Client) {
54 49
 	*command = BaseCommand{c}
55 50
 }

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

@@ -8,7 +8,7 @@ import (
8 8
 )
9 9
 
10 10
 const (
11
-	DEBUG_NET = true
11
+	DEBUG_NET = false
12 12
 )
13 13
 
14 14
 func readTrimmedLine(reader *bufio.Reader) (string, error) {
@@ -64,7 +64,7 @@ func LookupHostname(addr net.Addr) string {
64 64
 	if err != nil {
65 65
 		return addrStr
66 66
 	}
67
-	names, err := net.LookupAddr(ipaddr)
67
+	names, err := net.LookupHost(ipaddr)
68 68
 	if err != nil {
69 69
 		return ipaddr
70 70
 	}

+ 0
- 158
src/irc/nickserv.go View File

@@ -1,158 +0,0 @@
1
-package irc
2
-
3
-import (
4
-	"fmt"
5
-	"log"
6
-)
7
-
8
-const (
9
-	DEBUG_NICKSERV = true
10
-)
11
-
12
-type NickServCommand interface {
13
-	HandleNickServ(*NickServ)
14
-	Client() *Client
15
-	SetBase(*Client)
16
-}
17
-
18
-type NickServ struct {
19
-	BaseService
20
-}
21
-
22
-func NewNickServ(s *Server) Service {
23
-	return NewService(new(NickServ), s, "NickServ")
24
-}
25
-
26
-func (ns *NickServ) SetBase(base *BaseService) {
27
-	ns.BaseService = *base
28
-}
29
-
30
-func (ns *NickServ) Debug() bool {
31
-	return DEBUG_NICKSERV
32
-}
33
-
34
-var (
35
-	parseNickServCommandFuncs = map[string]func([]string) (NickServCommand, error){
36
-		"REGISTER": NewRegisterCommand,
37
-		"IDENTIFY": NewIdentifyCommand,
38
-	}
39
-)
40
-
41
-//
42
-// commands
43
-//
44
-
45
-func (ns *NickServ) HandlePrivMsg(m *PrivMsgCommand) {
46
-	command, args := parseLine(m.message)
47
-	constructor := parseNickServCommandFuncs[command]
48
-	if constructor == nil {
49
-		ns.Reply(m.Client(), "Unknown command.")
50
-		return
51
-	}
52
-
53
-	cmd, err := constructor(args)
54
-	if err != nil {
55
-		ns.Reply(m.Client(), "Not enough parameters.")
56
-		return
57
-	}
58
-
59
-	cmd.SetBase(m.Client())
60
-	if ns.Debug() {
61
-		log.Printf("%s ← %s %s", ns, cmd.Client(), cmd)
62
-	}
63
-
64
-	cmd.HandleNickServ(ns)
65
-}
66
-
67
-//
68
-// sub-commands
69
-//
70
-
71
-type RegisterCommand struct {
72
-	BaseCommand
73
-	password string
74
-	email    string
75
-}
76
-
77
-func (m *RegisterCommand) String() string {
78
-	return fmt.Sprintf("REGISTER(email=%s, password=%s)", m.email, m.password)
79
-}
80
-
81
-func NewRegisterCommand(args []string) (NickServCommand, error) {
82
-	if len(args) == 0 {
83
-		return nil, NotEnoughArgsError
84
-	}
85
-
86
-	cmd := &RegisterCommand{
87
-		BaseCommand: BaseCommand{},
88
-		password:    args[0],
89
-	}
90
-	if len(args) > 1 {
91
-		cmd.email = args[1]
92
-	}
93
-	return cmd, nil
94
-}
95
-
96
-func (m *RegisterCommand) HandleNickServ(ns *NickServ) {
97
-	client := m.Client()
98
-
99
-	if client.user != nil {
100
-		ns.Reply(client, "You are already registered.")
101
-		return
102
-	}
103
-
104
-	if ns.server.users[client.nick] != nil {
105
-		ns.Reply(client, "That nick is already registered.")
106
-		return
107
-	}
108
-
109
-	user := NewUser(client.nick, ns.server)
110
-	user.SetPassword(m.password)
111
-	Save(ns.server.db, user)
112
-	ns.Reply(client, "You have registered.")
113
-
114
-	if !user.Login(client, client.nick, m.password) {
115
-		ns.Reply(client, "Login failed.")
116
-		return
117
-	}
118
-	ns.Reply(client, "Logged in.")
119
-}
120
-
121
-type IdentifyCommand struct {
122
-	BaseCommand
123
-	password string
124
-}
125
-
126
-func (m *IdentifyCommand) String() string {
127
-	return fmt.Sprintf("IDENTIFY(password=%s)", m.password)
128
-}
129
-
130
-func NewIdentifyCommand(args []string) (NickServCommand, error) {
131
-	if len(args) == 0 {
132
-		return nil, NotEnoughArgsError
133
-	}
134
-
135
-	return &IdentifyCommand{
136
-		BaseCommand: BaseCommand{},
137
-		password:    args[0],
138
-	}, nil
139
-}
140
-
141
-func (m *IdentifyCommand) HandleNickServ(ns *NickServ) {
142
-	client := m.Client()
143
-	if client.user != nil {
144
-		ns.Reply(client, "That nick is already registered.")
145
-		return
146
-	}
147
-
148
-	user := ns.server.users[client.nick]
149
-	if user == nil {
150
-		ns.Reply(client, "No such nick.")
151
-		return
152
-	}
153
-
154
-	if !user.Login(client, client.nick, m.password) {
155
-		ns.Reply(client, "Login failed.")
156
-	}
157
-	ns.Reply(client, "Logged in.")
158
-}

+ 0
- 270
src/irc/persistence.go View File

@@ -1,270 +0,0 @@
1
-package irc
2
-
3
-import (
4
-	"database/sql"
5
-	//"fmt"
6
-	"bufio"
7
-	_ "github.com/mattn/go-sqlite3"
8
-	"log"
9
-	"os"
10
-	"path/filepath"
11
-	"strings"
12
-)
13
-
14
-type RowId uint64
15
-
16
-type Queryable interface {
17
-	Exec(string, ...interface{}) (sql.Result, error)
18
-	Query(string, ...interface{}) (*sql.Rows, error)
19
-	QueryRow(string, ...interface{}) *sql.Row
20
-}
21
-
22
-type Savable interface {
23
-	Save(q Queryable) bool
24
-}
25
-
26
-type Loadable interface {
27
-	Load(q Queryable) bool
28
-}
29
-
30
-//
31
-// general
32
-//
33
-
34
-func NewDatabase() (db *sql.DB) {
35
-	db, err := sql.Open("sqlite3", "ergonomadic.db")
36
-	if err != nil {
37
-		log.Fatalln("cannot open database")
38
-	}
39
-	return
40
-}
41
-
42
-func readLines(filename string) <-chan string {
43
-	file, err := os.Open(filename)
44
-	if err != nil {
45
-		log.Fatalln(err)
46
-	}
47
-	reader := bufio.NewReader(file)
48
-	lines := make(chan string)
49
-	go func(lines chan<- string) {
50
-		defer file.Close()
51
-		defer close(lines)
52
-		for {
53
-			line, err := reader.ReadString(';')
54
-			if err != nil {
55
-				break
56
-			}
57
-			line = strings.TrimSpace(line)
58
-			if line == "" {
59
-				continue
60
-			}
61
-			lines <- line
62
-		}
63
-	}(lines)
64
-	return lines
65
-}
66
-
67
-func ExecSqlFile(db *sql.DB, filename string) {
68
-	Transact(db, func(q Queryable) bool {
69
-		for line := range readLines(filepath.Join("sql", filename)) {
70
-			log.Println(line)
71
-			_, err := q.Exec(line)
72
-			if err != nil {
73
-				log.Fatalln(err)
74
-			}
75
-		}
76
-		return true
77
-	})
78
-}
79
-
80
-func Transact(db *sql.DB, txf func(Queryable) bool) {
81
-	tx, err := db.Begin()
82
-	if err != nil {
83
-		log.Panicln(err)
84
-	}
85
-	if txf(tx) {
86
-		tx.Commit()
87
-	} else {
88
-		tx.Rollback()
89
-	}
90
-}
91
-
92
-func Save(db *sql.DB, s Savable) {
93
-	Transact(db, s.Save)
94
-}
95
-
96
-func Load(db *sql.DB, l Loadable) {
97
-	Transact(db, l.Load)
98
-}
99
-
100
-//
101
-// general purpose sql
102
-//
103
-
104
-func findId(q Queryable, sql string, args ...interface{}) (rowId RowId, err error) {
105
-	row := q.QueryRow(sql, args...)
106
-	err = row.Scan(&rowId)
107
-	return
108
-}
109
-
110
-func countRows(q Queryable, sql string, args ...interface{}) (count uint, err error) {
111
-	row := q.QueryRow(sql, args...)
112
-	err = row.Scan(&count)
113
-	return
114
-}
115
-
116
-//
117
-// data
118
-//
119
-
120
-type UserRow struct {
121
-	id   RowId
122
-	nick string
123
-	hash []byte
124
-}
125
-
126
-type ChannelRow struct {
127
-	id   RowId
128
-	name string
129
-}
130
-
131
-// user
132
-
133
-func FindAllUsers(q Queryable) (urs []*UserRow, err error) {
134
-	var rows *sql.Rows
135
-	rows, err = q.Query("SELECT id, nick, hash FROM user")
136
-	if err != nil {
137
-		return
138
-	}
139
-	urs = make([]*UserRow, 0)
140
-	for rows.Next() {
141
-		ur := &UserRow{}
142
-		err = rows.Scan(&(ur.id), &(ur.nick), &(ur.hash))
143
-		if err != nil {
144
-			return
145
-		}
146
-		urs = append(urs, ur)
147
-	}
148
-	return
149
-}
150
-
151
-func FindUserByNick(q Queryable, nick string) (ur *UserRow, err error) {
152
-	ur = &UserRow{}
153
-	row := q.QueryRow("SELECT id, nick, hash FROM user LIMIT 1 WHERE nick = ?",
154
-		nick)
155
-	err = row.Scan(&(ur.id), &(ur.nick), &(ur.hash))
156
-	return
157
-}
158
-
159
-func FindUserIdByNick(q Queryable, nick string) (RowId, error) {
160
-	return findId(q, "SELECT id FROM user WHERE nick = ?", nick)
161
-}
162
-
163
-func FindChannelByName(q Queryable, name string) (cr *ChannelRow) {
164
-	cr = new(ChannelRow)
165
-	row := q.QueryRow("SELECT id, name FROM channel LIMIT 1 WHERE name = ?", name)
166
-	err := row.Scan(&(cr.id), &(cr.name))
167
-	if err != nil {
168
-		cr = nil
169
-	}
170
-	return
171
-}
172
-
173
-func InsertUser(q Queryable, row *UserRow) (err error) {
174
-	_, err = q.Exec("INSERT INTO user (nick, hash) VALUES (?, ?)",
175
-		row.nick, row.hash)
176
-	return
177
-}
178
-
179
-func UpdateUser(q Queryable, row *UserRow) (err error) {
180
-	_, err = q.Exec("UPDATE user SET nick = ?, hash = ? WHERE id = ?",
181
-		row.nick, row.hash, row.id)
182
-	return
183
-}
184
-
185
-func DeleteUser(q Queryable, id RowId) (err error) {
186
-	_, err = q.Exec("DELETE FROM user WHERE id = ?", id)
187
-	return
188
-}
189
-
190
-// user-channel
191
-
192
-func DeleteAllUserChannels(q Queryable, rowId RowId) (err error) {
193
-	_, err = q.Exec("DELETE FROM user_channel WHERE user_id = ?", rowId)
194
-	return
195
-}
196
-
197
-func DeleteOtherUserChannels(q Queryable, userId RowId, channelIds []RowId) (err error) {
198
-	_, err = q.Exec(`DELETE FROM user_channel WHERE
199
-user_id = ? AND channel_id NOT IN ?`, userId, channelIds)
200
-	return
201
-}
202
-
203
-func InsertUserChannels(q Queryable, userId RowId, channelIds []RowId) (err error) {
204
-	ins := "INSERT OR IGNORE INTO user_channel (user_id, channel_id) VALUES "
205
-	vals := strings.Repeat("(?, ?), ", len(channelIds))
206
-	vals = vals[0 : len(vals)-2]
207
-	args := make([]RowId, 2*len(channelIds))
208
-	for i, channelId := range channelIds {
209
-		args[i] = userId
210
-		args[i+1] = channelId
211
-	}
212
-	_, err = q.Exec(ins+vals, args)
213
-	return
214
-}
215
-
216
-// channel
217
-
218
-func FindChannelIdByName(q Queryable, name string) (RowId, error) {
219
-	return findId(q, "SELECT id FROM channel WHERE name = ?", name)
220
-}
221
-
222
-func findChannels(q Queryable, where string, args ...interface{}) (crs []*ChannelRow, err error) {
223
-	count, err := countRows(q, "SELECT COUNT(id) FROM channel "+where, args...)
224
-	if err != nil {
225
-		return
226
-	}
227
-	rows, err := q.Query("SELECT id, name FROM channel "+where, args...)
228
-	if err != nil {
229
-		return
230
-	}
231
-	crs = make([]*ChannelRow, count)
232
-	var i = 0
233
-	for rows.Next() {
234
-		cr := &ChannelRow{}
235
-		err = rows.Scan(&(cr.id), &(cr.name))
236
-		if err != nil {
237
-			return
238
-		}
239
-		crs[i] = cr
240
-		i++
241
-	}
242
-	return
243
-}
244
-
245
-func FindChannelsForUser(q Queryable, userId RowId) (crs []*ChannelRow, err error) {
246
-	crs, err = findChannels(q,
247
-		"WHERE id IN (SELECT channel_id from user_channel WHERE user_id = ?)", userId)
248
-	return
249
-}
250
-
251
-func FindAllChannels(q Queryable) (crs []*ChannelRow, err error) {
252
-	crs, err = findChannels(q, "")
253
-	return
254
-}
255
-
256
-func InsertChannel(q Queryable, channel *Channel) (err error) {
257
-	_, err = q.Exec("INSERT INTO channel (name) VALUES (?)", channel.name)
258
-	return
259
-}
260
-
261
-func UpdateChannel(q Queryable, channel *Channel) (err error) {
262
-	_, err = q.Exec("UPDATE channel SET name = ? WHERE id = ?",
263
-		channel.name, *(channel.id))
264
-	return
265
-}
266
-
267
-func DeleteChannel(q Queryable, channel *Channel) (err error) {
268
-	_, err = q.Exec("DELETE FROM channel WHERE id = ?", *(channel.id))
269
-	return
270
-}

+ 5
- 4
src/irc/reply.go View File

@@ -93,6 +93,7 @@ func NewNamesReply(channel *Channel) Reply {
93 93
 		BaseReply: &BaseReply{
94 94
 			source: channel,
95 95
 		},
96
+		channel: channel,
96 97
 	}
97 98
 }
98 99
 
@@ -142,12 +143,12 @@ func RplPrivMsgChannel(channel *Channel, source Identifier, message string) Repl
142 143
 	return NewStringReply(source, RPL_PRIVMSG, "%s :%s", channel.name, message)
143 144
 }
144 145
 
145
-func RplJoin(channel *Channel, user *User) Reply {
146
-	return NewStringReply(user, RPL_JOIN, channel.name)
146
+func RplJoin(channel *Channel, client *Client) Reply {
147
+	return NewStringReply(client, RPL_JOIN, channel.name)
147 148
 }
148 149
 
149
-func RplPart(channel *Channel, user *User, message string) Reply {
150
-	return NewStringReply(user, RPL_PART, "%s :%s", channel.name, message)
150
+func RplPart(channel *Channel, client *Client, message string) Reply {
151
+	return NewStringReply(client, RPL_PART, "%s :%s", channel.name, message)
151 152
 }
152 153
 
153 154
 func RplPong(server *Server) Reply {

+ 45
- 127
src/irc/server.go View File

@@ -2,7 +2,6 @@ package irc
2 2
 
3 3
 import (
4 4
 	"code.google.com/p/go.crypto/bcrypt"
5
-	"database/sql"
6 5
 	"log"
7 6
 	"net"
8 7
 	"time"
@@ -13,19 +12,16 @@ const (
13 12
 )
14 13
 
15 14
 type ChannelNameMap map[string]*Channel
16
-type UserNameMap map[string]*User
17
-type ServiceNameMap map[string]Service
15
+type ClientNameMap map[string]*Client
18 16
 
19 17
 type Server struct {
20
-	hostname string
18
+	channels ChannelNameMap
19
+	commands chan<- Command
21 20
 	ctime    time.Time
21
+	hostname string
22 22
 	name     string
23 23
 	password []byte
24
-	users    UserNameMap
25
-	channels ChannelNameMap
26
-	services ServiceNameMap
27
-	commands chan<- Command
28
-	db       *sql.DB
24
+	clients  ClientNameMap
29 25
 }
30 26
 
31 27
 func NewServer(name string) *Server {
@@ -34,43 +30,13 @@ func NewServer(name string) *Server {
34 30
 		ctime:    time.Now(),
35 31
 		name:     name,
36 32
 		commands: commands,
37
-		users:    make(UserNameMap),
33
+		clients:  make(ClientNameMap),
38 34
 		channels: make(ChannelNameMap),
39
-		services: make(ServiceNameMap),
40
-		db:       NewDatabase(),
41 35
 	}
42 36
 	go server.receiveCommands(commands)
43
-	NewNickServ(server)
44
-	Load(server.db, server)
45 37
 	return server
46 38
 }
47 39
 
48
-func (server *Server) Load(q Queryable) bool {
49
-	crs, err := FindAllChannels(q)
50
-	if err != nil {
51
-		log.Println(err)
52
-		return false
53
-	}
54
-	for _, cr := range crs {
55
-		channel := server.GetOrMakeChannel(cr.name)
56
-		channel.id = &(cr.id)
57
-	}
58
-
59
-	urs, err := FindAllUsers(q)
60
-	if err != nil {
61
-		log.Println(err)
62
-		return false
63
-	}
64
-	for _, ur := range urs {
65
-		user := NewUser(ur.nick, server)
66
-		user.SetHash(ur.hash)
67
-		if !user.Load(q) {
68
-			return false
69
-		}
70
-	}
71
-	return true
72
-}
73
-
74 40
 func (server *Server) receiveCommands(commands <-chan Command) {
75 41
 	for command := range commands {
76 42
 		if DEBUG_SERVER {
@@ -113,16 +79,16 @@ func (s *Server) GetOrMakeChannel(name string) *Channel {
113 79
 }
114 80
 
115 81
 // Send a message to clients of channels fromClient is a member.
116
-func (s *Server) InterestedUsers(fromUser *User) UserSet {
117
-	users := make(UserSet)
118
-	users.Add(fromUser)
119
-	for channel := range fromUser.channels {
120
-		for user := range channel.members {
121
-			users.Add(user)
82
+func (s *Server) interestedClients(fromClient *Client) ClientSet {
83
+	clients := make(ClientSet)
84
+	clients[fromClient] = true
85
+	for channel := range fromClient.channels {
86
+		for client := range channel.members {
87
+			clients[client] = true
122 88
 		}
123 89
 	}
124 90
 
125
-	return users
91
+	return clients
126 92
 }
127 93
 
128 94
 // server functionality
@@ -164,9 +130,6 @@ func (s *Server) Nick() string {
164 130
 
165 131
 func (s *Server) DeleteChannel(channel *Channel) {
166 132
 	delete(s.channels, channel.name)
167
-	if err := DeleteChannel(s.db, channel); err != nil {
168
-		log.Println(err)
169
-	}
170 133
 }
171 134
 
172 135
 //
@@ -198,32 +161,30 @@ func (m *PassCommand) HandleServer(s *Server) {
198 161
 
199 162
 func (m *NickCommand) HandleServer(s *Server) {
200 163
 	c := m.Client()
201
-	if c.user == nil {
202
-		c.Replies() <- RplNick(c, m.nickname)
203
-		c.nick = m.nickname
204
-		s.tryRegister(c)
164
+
165
+	if s.clients[m.nickname] != nil {
166
+		c.replies <- ErrNickNameInUse(s, m.nickname)
205 167
 		return
206 168
 	}
207 169
 
208
-	user := c.user
209
-	if s.users[m.nickname] != nil {
210
-		user.Replies() <- ErrNickNameInUse(s, m.nickname)
211
-		return
170
+	reply := RplNick(c, m.nickname)
171
+	for iclient := range s.interestedClients(c) {
172
+		iclient.replies <- reply
212 173
 	}
213 174
 
214
-	delete(s.users, user.nick)
215
-	s.users[m.nickname] = user
216
-	reply := RplNick(user, m.nickname)
217
-	for iuser := range s.InterestedUsers(user) {
218
-		iuser.Replies() <- reply
175
+	if c.HasNick() {
176
+		delete(s.clients, c.nick)
219 177
 	}
220
-	user.nick = m.nickname
178
+	s.clients[m.nickname] = c
179
+	c.nick = m.nickname
180
+
181
+	s.tryRegister(c)
221 182
 }
222 183
 
223 184
 func (m *UserMsgCommand) HandleServer(s *Server) {
224 185
 	c := m.Client()
225
-	if c.username != "" {
226
-		c.Replies() <- ErrAlreadyRegistered(s)
186
+	if c.registered {
187
+		c.replies <- ErrAlreadyRegistered(s)
227 188
 		return
228 189
 	}
229 190
 
@@ -234,108 +195,65 @@ func (m *UserMsgCommand) HandleServer(s *Server) {
234 195
 func (m *QuitCommand) HandleServer(s *Server) {
235 196
 	c := m.Client()
236 197
 
237
-	user := c.user
238
-	if user != nil {
239
-		reply := RplQuit(c, m.message)
240
-		for user := range s.InterestedUsers(c.user) {
241
-			user.Replies() <- reply
242
-		}
198
+	reply := RplQuit(c, m.message)
199
+	for client := range s.interestedClients(c) {
200
+		client.replies <- reply
243 201
 	}
244 202
 	c.conn.Close()
245
-	if user == nil {
246
-		return
203
+	cmd := &PartCommand{
204
+		BaseCommand: BaseCommand{c},
247 205
 	}
248
-
249
-	user.LogoutClient(c)
250
-	if !user.HasClients() {
251
-		cmd := &PartCommand{
252
-			BaseCommand: BaseCommand{c},
253
-		}
254
-		for channel := range user.channels {
255
-			channel.Commands() <- cmd
256
-		}
206
+	for channel := range c.channels {
207
+		channel.commands <- cmd
257 208
 	}
258 209
 }
259 210
 
260 211
 func (m *JoinCommand) HandleServer(s *Server) {
261 212
 	c := m.Client()
262 213
 
263
-	if c.user == nil {
264
-		c.Replies() <- ErrNoPrivileges(s)
265
-		return
266
-	}
267
-
268 214
 	if m.zero {
269 215
 		cmd := &PartCommand{
270 216
 			BaseCommand: BaseCommand{c},
271 217
 		}
272
-		for channel := range c.user.channels {
273
-			channel.Commands() <- cmd
218
+		for channel := range c.channels {
219
+			channel.commands <- cmd
274 220
 		}
275 221
 		return
276 222
 	}
277 223
 
278 224
 	for name := range m.channels {
279
-		s.GetOrMakeChannel(name).Commands() <- m
225
+		s.GetOrMakeChannel(name).commands <- m
280 226
 	}
281 227
 }
282 228
 
283 229
 func (m *PartCommand) HandleServer(s *Server) {
284
-	user := m.User()
285
-
286
-	if user == nil {
287
-		m.Client().Replies() <- ErrNoPrivileges(s)
288
-		return
289
-	}
290
-
291 230
 	for _, chname := range m.channels {
292 231
 		channel := s.channels[chname]
293 232
 
294 233
 		if channel == nil {
295
-			user.Replies() <- ErrNoSuchChannel(s, channel.name)
234
+			m.Client().replies <- ErrNoSuchChannel(s, channel.name)
296 235
 			continue
297 236
 		}
298 237
 
299
-		channel.Commands() <- m
238
+		channel.commands <- m
300 239
 	}
301 240
 }
302 241
 
303 242
 func (m *TopicCommand) HandleServer(s *Server) {
304
-	user := m.User()
305
-
306
-	// Hide all channels from logged-out clients.
307
-	if user == nil {
308
-		m.Client().Replies() <- ErrNoPrivileges(s)
309
-		return
310
-	}
311
-
312 243
 	channel := s.channels[m.channel]
313 244
 	if channel == nil {
314
-		m.Client().Replies() <- ErrNoSuchChannel(s, m.channel)
245
+		m.Client().replies <- ErrNoSuchChannel(s, m.channel)
315 246
 		return
316 247
 	}
317 248
 
318
-	channel.Commands() <- m
249
+	channel.commands <- m
319 250
 }
320 251
 
321 252
 func (m *PrivMsgCommand) HandleServer(s *Server) {
322
-	service := s.services[m.target]
323
-	if service != nil {
324
-		service.Commands() <- m
325
-		return
326
-	}
327
-
328
-	user := m.User()
329
-	// Hide all users from logged-out clients.
330
-	if user == nil {
331
-		m.Client().Replies() <- ErrNoPrivileges(s)
332
-		return
333
-	}
334
-
335 253
 	if m.TargetIsChannel() {
336 254
 		channel := s.channels[m.target]
337 255
 		if channel == nil {
338
-			m.Client().Replies() <- ErrNoSuchChannel(s, m.target)
256
+			m.Client().replies <- ErrNoSuchChannel(s, m.target)
339 257
 			return
340 258
 		}
341 259
 
@@ -343,9 +261,9 @@ func (m *PrivMsgCommand) HandleServer(s *Server) {
343 261
 		return
344 262
 	}
345 263
 
346
-	target := s.users[m.target]
264
+	target := s.clients[m.target]
347 265
 	if target == nil {
348
-		m.Client().Replies() <- ErrNoSuchNick(s, m.target)
266
+		m.Client().replies <- ErrNoSuchNick(s, m.target)
349 267
 		return
350 268
 	}
351 269
 
@@ -353,5 +271,5 @@ func (m *PrivMsgCommand) HandleServer(s *Server) {
353 271
 }
354 272
 
355 273
 func (m *ModeCommand) HandleServer(s *Server) {
356
-	m.Client().Replies() <- RplUModeIs(s, m.Client())
274
+	m.Client().replies <- RplUModeIs(s, m.Client())
357 275
 }

+ 0
- 83
src/irc/service.go View File

@@ -1,83 +0,0 @@
1
-package irc
2
-
3
-import (
4
-	"fmt"
5
-	"log"
6
-)
7
-
8
-type ServiceCommand interface {
9
-	Command
10
-	HandleService(Service)
11
-}
12
-
13
-type Service interface {
14
-	Identifier
15
-	Commands() chan<- ServiceCommand
16
-	HandlePrivMsg(*PrivMsgCommand)
17
-	Debug() bool
18
-}
19
-
20
-type EditableService interface {
21
-	Service
22
-	SetBase(*BaseService)
23
-}
24
-
25
-type BaseService struct {
26
-	server   *Server
27
-	name     string
28
-	commands chan<- ServiceCommand
29
-}
30
-
31
-func NewService(service EditableService, s *Server, name string) Service {
32
-	commands := make(chan ServiceCommand)
33
-	base := &BaseService{
34
-		server:   s,
35
-		name:     name,
36
-		commands: commands,
37
-	}
38
-	go receiveCommands(service, commands)
39
-	service.SetBase(base)
40
-	s.services[service.Nick()] = service
41
-	return service
42
-}
43
-
44
-func receiveCommands(service Service, commands <-chan ServiceCommand) {
45
-	for command := range commands {
46
-		if service.Debug() {
47
-			log.Printf("%s ← %s %s", service.Id(), command.Client(), command)
48
-		}
49
-		command.HandleService(service)
50
-	}
51
-}
52
-
53
-func (service *BaseService) Id() string {
54
-	return fmt.Sprintf("%s!%s@%s", service.name, service.name, service.server.name)
55
-}
56
-
57
-func (service *BaseService) String() string {
58
-	return service.Id()
59
-}
60
-
61
-func (service *BaseService) PublicId() string {
62
-	return service.Id()
63
-}
64
-
65
-func (service *BaseService) Nick() string {
66
-	return service.name
67
-}
68
-
69
-func (service *BaseService) Reply(client *Client, message string) {
70
-	client.Replies() <- RplPrivMsg(service, client, message)
71
-}
72
-
73
-func (service *BaseService) Commands() chan<- ServiceCommand {
74
-	return service.commands
75
-}
76
-
77
-//
78
-// commands
79
-//
80
-
81
-func (m *PrivMsgCommand) HandleService(service Service) {
82
-	service.HandlePrivMsg(m)
83
-}

+ 0
- 228
src/irc/user.go View File

@@ -1,228 +0,0 @@
1
-package irc
2
-
3
-import (
4
-	"code.google.com/p/go.crypto/bcrypt"
5
-	"fmt"
6
-	"log"
7
-)
8
-
9
-const (
10
-	DEBUG_USER = true
11
-)
12
-
13
-type UserCommand interface {
14
-	Command
15
-	HandleUser(*User)
16
-}
17
-
18
-type User struct {
19
-	id       RowId
20
-	nick     string
21
-	hash     []byte
22
-	server   *Server
23
-	clients  ClientSet
24
-	channels ChannelSet
25
-	commands chan<- UserCommand
26
-	replies  chan<- Reply
27
-}
28
-
29
-type UserSet map[*User]bool
30
-
31
-func (set UserSet) Add(user *User) {
32
-	set[user] = true
33
-}
34
-
35
-func (set UserSet) Remove(user *User) {
36
-	delete(set, user)
37
-}
38
-
39
-func (set UserSet) Nicks() []string {
40
-	nicks := make([]string, len(set))
41
-	i := 0
42
-	for member := range set {
43
-		nicks[i] = member.Nick()
44
-		i++
45
-	}
46
-	return nicks
47
-}
48
-
49
-func NewUser(nick string, server *Server) *User {
50
-	commands := make(chan UserCommand)
51
-	replies := make(chan Reply)
52
-	user := &User{
53
-		nick:     nick,
54
-		server:   server,
55
-		clients:  make(ClientSet),
56
-		channels: make(ChannelSet),
57
-		replies:  replies,
58
-	}
59
-
60
-	go user.receiveCommands(commands)
61
-	go user.receiveReplies(replies)
62
-	server.users[nick] = user
63
-
64
-	return user
65
-}
66
-
67
-func (user *User) Row() *UserRow {
68
-	return &UserRow{user.id, user.nick, user.hash}
69
-}
70
-
71
-func (user *User) Create(q Queryable) bool {
72
-	var err error
73
-	if err := InsertUser(q, user.Row()); err != nil {
74
-		log.Println(err)
75
-		return false
76
-	}
77
-	user.id, err = FindUserIdByNick(q, user.nick)
78
-	if err != nil {
79
-		log.Println(err)
80
-		return false
81
-	}
82
-	return true
83
-}
84
-
85
-func (user *User) Save(q Queryable) bool {
86
-	if err := UpdateUser(q, user.Row()); err != nil {
87
-		log.Println(err)
88
-		return false
89
-	}
90
-
91
-	channelIds := user.channels.Ids()
92
-	if len(channelIds) == 0 {
93
-		if err := DeleteAllUserChannels(q, user.id); err != nil {
94
-			log.Println(err)
95
-			return false
96
-		}
97
-	} else {
98
-		if err := DeleteOtherUserChannels(q, user.id, channelIds); err != nil {
99
-			log.Println(err)
100
-			return false
101
-		}
102
-		if err := InsertUserChannels(q, user.id, channelIds); err != nil {
103
-			log.Println(err)
104
-			return false
105
-		}
106
-	}
107
-	return true
108
-}
109
-
110
-func (user *User) Delete(q Queryable) bool {
111
-	err := DeleteUser(q, user.id)
112
-	if err != nil {
113
-		log.Println(err)
114
-		return false
115
-	}
116
-	return true
117
-}
118
-
119
-func (user *User) Load(q Queryable) bool {
120
-	crs, err := FindChannelsForUser(q, user.id)
121
-	if err != nil {
122
-		log.Println(err)
123
-		return false
124
-	}
125
-	for _, cr := range crs {
126
-		user.server.GetOrMakeChannel(cr.name).Join(user)
127
-	}
128
-	return true
129
-}
130
-
131
-func (user *User) SetPassword(password string) {
132
-	hash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
133
-	if err != nil {
134
-		log.Panicln(err)
135
-	}
136
-	user.SetHash(hash)
137
-}
138
-
139
-func (user *User) SetHash(hash []byte) {
140
-	user.hash = hash
141
-}
142
-
143
-func (user *User) receiveCommands(commands <-chan UserCommand) {
144
-	for command := range commands {
145
-		if DEBUG_USER {
146
-			log.Printf("%s → %s : %s", command.Client(), user, command)
147
-		}
148
-		command.HandleUser(user)
149
-	}
150
-}
151
-
152
-// Distribute replies to clients.
153
-func (user *User) receiveReplies(replies <-chan Reply) {
154
-	for reply := range replies {
155
-		if DEBUG_USER {
156
-			log.Printf("%s ← %s : %s", user, reply.Source(), reply)
157
-		}
158
-		for client := range user.clients {
159
-			client.Replies() <- reply
160
-		}
161
-	}
162
-}
163
-
164
-// Identifier
165
-
166
-func (user *User) Id() string {
167
-	return fmt.Sprintf("%s!%s@%s", user.nick, user.nick, user.server.Id())
168
-}
169
-
170
-func (user *User) PublicId() string {
171
-	return user.Id()
172
-}
173
-
174
-func (user *User) Nick() string {
175
-	return user.nick
176
-}
177
-
178
-func (user *User) String() string {
179
-	return user.Id()
180
-}
181
-
182
-func (user *User) Login(c *Client, nick string, password string) bool {
183
-	if nick != c.nick {
184
-		return false
185
-	}
186
-
187
-	if user.hash == nil {
188
-		return false
189
-	}
190
-
191
-	err := bcrypt.CompareHashAndPassword(user.hash, []byte(password))
192
-	if err != nil {
193
-		c.Replies() <- ErrNoPrivileges(user.server)
194
-		return false
195
-	}
196
-
197
-	user.clients[c] = true
198
-	c.user = user
199
-	for channel := range user.channels {
200
-		channel.GetTopic(c)
201
-		channel.GetUsers(c)
202
-	}
203
-	return true
204
-}
205
-
206
-func (user *User) LogoutClient(c *Client) bool {
207
-	if user.clients[c] {
208
-		delete(user.clients, c)
209
-		return true
210
-	}
211
-	return false
212
-}
213
-
214
-func (user *User) HasClients() bool {
215
-	return len(user.clients) > 0
216
-}
217
-
218
-func (user *User) Replies() chan<- Reply {
219
-	return user.replies
220
-}
221
-
222
-//
223
-// commands
224
-//
225
-
226
-func (m *PrivMsgCommand) HandleUser(user *User) {
227
-	user.Replies() <- RplPrivMsg(m.Client(), user, m.message)
228
-}

Loading…
Cancel
Save