Bläddra i källkod

Merge pull request #35 from jlatt/fix-goroutine-leak

fix two bugs
tags/v0.1.0
Jeremy Latt 10 år sedan
förälder
incheckning
2e212e3692
9 ändrade filer med 122 tillägg och 209 borttagningar
  1. 4
    2
      irc/channel.go
  2. 4
    9
      irc/client.go
  3. 3
    2
      irc/client_lookup_set.go
  4. 80
    151
      irc/commands.go
  5. 9
    8
      irc/nickname.go
  6. 1
    1
      irc/reply.go
  7. 7
    4
      irc/server.go
  8. 10
    14
      irc/socket.go
  9. 4
    18
      irc/theater.go

+ 4
- 2
irc/channel.go Visa fil

@@ -244,11 +244,12 @@ func (channel *Channel) PrivMsg(client *Client, message Text) {
244 244
 		client.ErrCannotSendToChan(channel)
245 245
 		return
246 246
 	}
247
+	reply := RplPrivMsg(client, channel, message)
247 248
 	for member := range channel.members {
248 249
 		if member == client {
249 250
 			continue
250 251
 		}
251
-		member.Reply(RplPrivMsg(client, channel, message))
252
+		member.Reply(reply)
252 253
 	}
253 254
 }
254 255
 
@@ -458,11 +459,12 @@ func (channel *Channel) Notice(client *Client, message Text) {
458 459
 		client.ErrCannotSendToChan(channel)
459 460
 		return
460 461
 	}
462
+	reply := RplNotice(client, channel, message)
461 463
 	for member := range channel.members {
462 464
 		if member == client {
463 465
 			continue
464 466
 		}
465
-		member.Reply(RplNotice(client, channel, message))
467
+		member.Reply(reply)
466 468
 	}
467 469
 }
468 470
 

+ 4
- 9
irc/client.go Visa fil

@@ -62,10 +62,7 @@ func NewClient(server *Server, conn net.Conn) *Client {
62 62
 
63 63
 func (client *Client) run() {
64 64
 	for command := range client.commands {
65
-		command.SetClient(client)
66
-
67
-		checkPass, ok := command.(checkPasswordCommand)
68
-		if ok {
65
+		if checkPass, ok := command.(checkPasswordCommand); ok {
69 66
 			checkPass.LoadPassword(client.server)
70 67
 			// Block the client thread while handling a potentially expensive
71 68
 			// password bcrypt operation. Since the server is single-threaded
@@ -74,15 +71,13 @@ func (client *Client) run() {
74 71
 			// completes. This could be a form of DoS if handled naively.
75 72
 			checkPass.CheckPassword()
76 73
 		}
77
-
74
+		command.SetClient(client)
78 75
 		client.server.commands <- command
79 76
 	}
80 77
 }
81 78
 
82 79
 func (client *Client) connectionTimeout() {
83
-	client.commands <- &QuitCommand{
84
-		message: "connection timeout",
85
-	}
80
+	client.commands <- NewQuitCommand("connection timeout")
86 81
 }
87 82
 
88 83
 //
@@ -259,8 +254,8 @@ func (client *Client) Quit(message Text) {
259 254
 		return
260 255
 	}
261 256
 
262
-	client.Reply(RplError("connection closed"))
263 257
 	client.hasQuit = true
258
+	client.Reply(RplError("quit"))
264 259
 	client.server.whoWas.Append(client)
265 260
 	friends := client.Friends()
266 261
 	friends.Remove(client)

+ 3
- 2
irc/client_lookup_set.go Visa fil

@@ -92,12 +92,13 @@ func (clients *ClientLookupSet) FindAll(userhost Name) (set ClientSet) {
92 92
 		return
93 93
 	}
94 94
 	for rows.Next() {
95
-		var nickname Name
96
-		err := rows.Scan(&nickname)
95
+		var sqlNickname string
96
+		err := rows.Scan(&sqlNickname)
97 97
 		if err != nil {
98 98
 			Log.error.Println("ClientLookupSet.FindAll.Scan:", err)
99 99
 			return
100 100
 		}
101
+		nickname := Name(sqlNickname)
101 102
 		client := clients.Get(nickname)
102 103
 		if client == nil {
103 104
 			Log.error.Println("ClientLookupSet.FindAll: missing client:", nickname)

+ 80
- 151
irc/commands.go Visa fil

@@ -26,37 +26,37 @@ var (
26 26
 	NotEnoughArgsError = errors.New("not enough arguments")
27 27
 	ErrParseCommand    = errors.New("failed to parse message")
28 28
 	parseCommandFuncs  = map[StringCode]parseCommandFunc{
29
-		AWAY:    NewAwayCommand,
30
-		CAP:     NewCapCommand,
31
-		DEBUG:   NewDebugCommand,
32
-		INVITE:  NewInviteCommand,
33
-		ISON:    NewIsOnCommand,
34
-		JOIN:    NewJoinCommand,
35
-		KICK:    NewKickCommand,
36
-		KILL:    NewKillCommand,
37
-		LIST:    NewListCommand,
38
-		MODE:    NewModeCommand,
39
-		MOTD:    NewMOTDCommand,
40
-		NAMES:   NewNamesCommand,
41
-		NICK:    NewNickCommand,
42
-		NOTICE:  NewNoticeCommand,
43
-		ONICK:   NewOperNickCommand,
44
-		OPER:    NewOperCommand,
45
-		PART:    NewPartCommand,
46
-		PASS:    NewPassCommand,
47
-		PING:    NewPingCommand,
48
-		PONG:    NewPongCommand,
49
-		PRIVMSG: NewPrivMsgCommand,
50
-		PROXY:   NewProxyCommand,
51
-		QUIT:    NewQuitCommand,
52
-		THEATER: NewTheaterCommand, // nonstandard
53
-		TIME:    NewTimeCommand,
54
-		TOPIC:   NewTopicCommand,
55
-		USER:    NewUserCommand,
56
-		VERSION: NewVersionCommand,
57
-		WHO:     NewWhoCommand,
58
-		WHOIS:   NewWhoisCommand,
59
-		WHOWAS:  NewWhoWasCommand,
29
+		AWAY:    ParseAwayCommand,
30
+		CAP:     ParseCapCommand,
31
+		DEBUG:   ParseDebugCommand,
32
+		INVITE:  ParseInviteCommand,
33
+		ISON:    ParseIsOnCommand,
34
+		JOIN:    ParseJoinCommand,
35
+		KICK:    ParseKickCommand,
36
+		KILL:    ParseKillCommand,
37
+		LIST:    ParseListCommand,
38
+		MODE:    ParseModeCommand,
39
+		MOTD:    ParseMOTDCommand,
40
+		NAMES:   ParseNamesCommand,
41
+		NICK:    ParseNickCommand,
42
+		NOTICE:  ParseNoticeCommand,
43
+		ONICK:   ParseOperNickCommand,
44
+		OPER:    ParseOperCommand,
45
+		PART:    ParsePartCommand,
46
+		PASS:    ParsePassCommand,
47
+		PING:    ParsePingCommand,
48
+		PONG:    ParsePongCommand,
49
+		PRIVMSG: ParsePrivMsgCommand,
50
+		PROXY:   ParseProxyCommand,
51
+		QUIT:    ParseQuitCommand,
52
+		THEATER: ParseTheaterCommand, // nonstandard
53
+		TIME:    ParseTimeCommand,
54
+		TOPIC:   ParseTopicCommand,
55
+		USER:    ParseUserCommand,
56
+		VERSION: ParseVersionCommand,
57
+		WHO:     ParseWhoCommand,
58
+		WHOIS:   ParseWhoisCommand,
59
+		WHOWAS:  ParseWhoWasCommand,
60 60
 	}
61 61
 )
62 62
 
@@ -85,7 +85,7 @@ func ParseCommand(line string) (cmd Command, err error) {
85 85
 	code, args := ParseLine(line)
86 86
 	constructor := parseCommandFuncs[code]
87 87
 	if constructor == nil {
88
-		cmd = NewUnknownCommand(args)
88
+		cmd = ParseUnknownCommand(args)
89 89
 	} else {
90 90
 		cmd, err = constructor(args)
91 91
 	}
@@ -135,11 +135,7 @@ type UnknownCommand struct {
135 135
 	args []string
136 136
 }
137 137
 
138
-func (cmd *UnknownCommand) String() string {
139
-	return fmt.Sprintf("UNKNOWN(command=%s, args=%s)", cmd.Code(), cmd.args)
140
-}
141
-
142
-func NewUnknownCommand(args []string) *UnknownCommand {
138
+func ParseUnknownCommand(args []string) *UnknownCommand {
143 139
 	return &UnknownCommand{
144 140
 		args: args,
145 141
 	}
@@ -153,11 +149,7 @@ type PingCommand struct {
153 149
 	server2 Name
154 150
 }
155 151
 
156
-func (cmd *PingCommand) String() string {
157
-	return fmt.Sprintf("PING(server=%s, server2=%s)", cmd.server, cmd.server2)
158
-}
159
-
160
-func NewPingCommand(args []string) (Command, error) {
152
+func ParsePingCommand(args []string) (Command, error) {
161 153
 	if len(args) < 1 {
162 154
 		return nil, NotEnoughArgsError
163 155
 	}
@@ -178,11 +170,7 @@ type PongCommand struct {
178 170
 	server2 Name
179 171
 }
180 172
 
181
-func (cmd *PongCommand) String() string {
182
-	return fmt.Sprintf("PONG(server1=%s, server2=%s)", cmd.server1, cmd.server2)
183
-}
184
-
185
-func NewPongCommand(args []string) (Command, error) {
173
+func ParsePongCommand(args []string) (Command, error) {
186 174
 	if len(args) < 1 {
187 175
 		return nil, NotEnoughArgsError
188 176
 	}
@@ -204,10 +192,6 @@ type PassCommand struct {
204 192
 	err      error
205 193
 }
206 194
 
207
-func (cmd *PassCommand) String() string {
208
-	return fmt.Sprintf("PASS(password=%s)", cmd.password)
209
-}
210
-
211 195
 func (cmd *PassCommand) LoadPassword(server *Server) {
212 196
 	cmd.hash = server.password
213 197
 }
@@ -219,7 +203,7 @@ func (cmd *PassCommand) CheckPassword() {
219 203
 	cmd.err = ComparePassword(cmd.hash, cmd.password)
220 204
 }
221 205
 
222
-func NewPassCommand(args []string) (Command, error) {
206
+func ParsePassCommand(args []string) (Command, error) {
223 207
 	if len(args) < 1 {
224 208
 		return nil, NotEnoughArgsError
225 209
 	}
@@ -230,7 +214,7 @@ func NewPassCommand(args []string) (Command, error) {
230 214
 
231 215
 // NICK <nickname>
232 216
 
233
-func NewNickCommand(args []string) (Command, error) {
217
+func ParseNickCommand(args []string) (Command, error) {
234 218
 	if len(args) != 1 {
235 219
 		return nil, NotEnoughArgsError
236 220
 	}
@@ -252,11 +236,6 @@ type RFC1459UserCommand struct {
252 236
 	servername Name
253 237
 }
254 238
 
255
-func (cmd *RFC1459UserCommand) String() string {
256
-	return fmt.Sprintf("USER(username=%s, hostname=%s, servername=%s, realname=%s)",
257
-		cmd.username, cmd.hostname, cmd.servername, cmd.realname)
258
-}
259
-
260 239
 // USER <user> <mode> <unused> <realname>
261 240
 type RFC2812UserCommand struct {
262 241
 	UserCommand
@@ -264,11 +243,6 @@ type RFC2812UserCommand struct {
264 243
 	unused string
265 244
 }
266 245
 
267
-func (cmd *RFC2812UserCommand) String() string {
268
-	return fmt.Sprintf("USER(username=%s, mode=%d, unused=%s, realname=%s)",
269
-		cmd.username, cmd.mode, cmd.unused, cmd.realname)
270
-}
271
-
272 246
 func (cmd *RFC2812UserCommand) Flags() []UserMode {
273 247
 	flags := make([]UserMode, 0)
274 248
 	if (cmd.mode & 4) == 4 {
@@ -280,7 +254,7 @@ func (cmd *RFC2812UserCommand) Flags() []UserMode {
280 254
 	return flags
281 255
 }
282 256
 
283
-func NewUserCommand(args []string) (Command, error) {
257
+func ParseUserCommand(args []string) (Command, error) {
284 258
 	if len(args) != 4 {
285 259
 		return nil, NotEnoughArgsError
286 260
 	}
@@ -311,11 +285,15 @@ type QuitCommand struct {
311 285
 	message Text
312 286
 }
313 287
 
314
-func (cmd *QuitCommand) String() string {
315
-	return fmt.Sprintf("QUIT(message=%s)", cmd.message)
288
+func NewQuitCommand(message Text) *QuitCommand {
289
+	cmd := &QuitCommand{
290
+		message: message,
291
+	}
292
+	cmd.code = QUIT
293
+	return cmd
316 294
 }
317 295
 
318
-func NewQuitCommand(args []string) (Command, error) {
296
+func ParseQuitCommand(args []string) (Command, error) {
319 297
 	msg := &QuitCommand{}
320 298
 	if len(args) > 0 {
321 299
 		msg.message = NewText(args[0])
@@ -331,11 +309,7 @@ type JoinCommand struct {
331 309
 	zero     bool
332 310
 }
333 311
 
334
-func (cmd *JoinCommand) String() string {
335
-	return fmt.Sprintf("JOIN(channels=%s, zero=%t)", cmd.channels, cmd.zero)
336
-}
337
-
338
-func NewJoinCommand(args []string) (Command, error) {
312
+func ParseJoinCommand(args []string) (Command, error) {
339 313
 	msg := &JoinCommand{
340 314
 		channels: make(map[Name]Text),
341 315
 	}
@@ -378,11 +352,7 @@ func (cmd *PartCommand) Message() Text {
378 352
 	return cmd.message
379 353
 }
380 354
 
381
-func (cmd *PartCommand) String() string {
382
-	return fmt.Sprintf("PART(channels=%s, message=%s)", cmd.channels, cmd.message)
383
-}
384
-
385
-func NewPartCommand(args []string) (Command, error) {
355
+func ParsePartCommand(args []string) (Command, error) {
386 356
 	if len(args) < 1 {
387 357
 		return nil, NotEnoughArgsError
388 358
 	}
@@ -403,11 +373,7 @@ type PrivMsgCommand struct {
403 373
 	message Text
404 374
 }
405 375
 
406
-func (cmd *PrivMsgCommand) String() string {
407
-	return fmt.Sprintf("PRIVMSG(target=%s, message=%s)", cmd.target, cmd.message)
408
-}
409
-
410
-func NewPrivMsgCommand(args []string) (Command, error) {
376
+func ParsePrivMsgCommand(args []string) (Command, error) {
411 377
 	if len(args) < 2 {
412 378
 		return nil, NotEnoughArgsError
413 379
 	}
@@ -426,11 +392,7 @@ type TopicCommand struct {
426 392
 	topic    Text
427 393
 }
428 394
 
429
-func (cmd *TopicCommand) String() string {
430
-	return fmt.Sprintf("TOPIC(channel=%s, topic=%s)", cmd.channel, cmd.topic)
431
-}
432
-
433
-func NewTopicCommand(args []string) (Command, error) {
395
+func ParseTopicCommand(args []string) (Command, error) {
434 396
 	if len(args) < 1 {
435 397
 		return nil, NotEnoughArgsError
436 398
 	}
@@ -480,7 +442,7 @@ type ModeCommand struct {
480 442
 }
481 443
 
482 444
 // MODE <nickname> *( ( "+" / "-" ) *( "i" / "w" / "o" / "O" / "r" ) )
483
-func NewUserModeCommand(nickname Name, args []string) (Command, error) {
445
+func ParseUserModeCommand(nickname Name, args []string) (Command, error) {
484 446
 	cmd := &ModeCommand{
485 447
 		nickname: nickname,
486 448
 		changes:  make(ModeChanges, 0),
@@ -506,10 +468,6 @@ func NewUserModeCommand(nickname Name, args []string) (Command, error) {
506 468
 	return cmd, nil
507 469
 }
508 470
 
509
-func (cmd *ModeCommand) String() string {
510
-	return fmt.Sprintf("MODE(nickname=%s, changes=%s)", cmd.nickname, cmd.changes)
511
-}
512
-
513 471
 type ChannelModeChange struct {
514 472
 	mode ChannelMode
515 473
 	op   ModeOp
@@ -557,7 +515,7 @@ type ChannelModeCommand struct {
557 515
 }
558 516
 
559 517
 // MODE <channel> *( ( "-" / "+" ) *<modes> *<modeparams> )
560
-func NewChannelModeCommand(channel Name, args []string) (Command, error) {
518
+func ParseChannelModeCommand(channel Name, args []string) (Command, error) {
561 519
 	cmd := &ChannelModeCommand{
562 520
 		channel: channel,
563 521
 		changes: make(ChannelModeChanges, 0),
@@ -599,20 +557,16 @@ func NewChannelModeCommand(channel Name, args []string) (Command, error) {
599 557
 	return cmd, nil
600 558
 }
601 559
 
602
-func (msg *ChannelModeCommand) String() string {
603
-	return fmt.Sprintf("MODE(channel=%s, changes=%s)", msg.channel, msg.changes)
604
-}
605
-
606
-func NewModeCommand(args []string) (Command, error) {
560
+func ParseModeCommand(args []string) (Command, error) {
607 561
 	if len(args) == 0 {
608 562
 		return nil, NotEnoughArgsError
609 563
 	}
610 564
 
611 565
 	name := NewName(args[0])
612 566
 	if name.IsChannel() {
613
-		return NewChannelModeCommand(name, args[1:])
567
+		return ParseChannelModeCommand(name, args[1:])
614 568
 	} else {
615
-		return NewUserModeCommand(name, args[1:])
569
+		return ParseUserModeCommand(name, args[1:])
616 570
 	}
617 571
 }
618 572
 
@@ -623,7 +577,7 @@ type WhoisCommand struct {
623 577
 }
624 578
 
625 579
 // WHOIS [ <target> ] <mask> *( "," <mask> )
626
-func NewWhoisCommand(args []string) (Command, error) {
580
+func ParseWhoisCommand(args []string) (Command, error) {
627 581
 	if len(args) < 1 {
628 582
 		return nil, NotEnoughArgsError
629 583
 	}
@@ -644,10 +598,6 @@ func NewWhoisCommand(args []string) (Command, error) {
644 598
 	}, nil
645 599
 }
646 600
 
647
-func (msg *WhoisCommand) String() string {
648
-	return fmt.Sprintf("WHOIS(target=%s, masks=%s)", msg.target, msg.masks)
649
-}
650
-
651 601
 type WhoCommand struct {
652 602
 	BaseCommand
653 603
 	mask         Name
@@ -655,7 +605,7 @@ type WhoCommand struct {
655 605
 }
656 606
 
657 607
 // WHO [ <mask> [ "o" ] ]
658
-func NewWhoCommand(args []string) (Command, error) {
608
+func ParseWhoCommand(args []string) (Command, error) {
659 609
 	cmd := &WhoCommand{}
660 610
 
661 611
 	if len(args) > 0 {
@@ -669,25 +619,17 @@ func NewWhoCommand(args []string) (Command, error) {
669 619
 	return cmd, nil
670 620
 }
671 621
 
672
-func (msg *WhoCommand) String() string {
673
-	return fmt.Sprintf("WHO(mask=%s, operatorOnly=%t)", msg.mask, msg.operatorOnly)
674
-}
675
-
676 622
 type OperCommand struct {
677 623
 	PassCommand
678 624
 	name Name
679 625
 }
680 626
 
681
-func (msg *OperCommand) String() string {
682
-	return fmt.Sprintf("OPER(name=%s, password=%s)", msg.name, msg.password)
683
-}
684
-
685 627
 func (msg *OperCommand) LoadPassword(server *Server) {
686 628
 	msg.hash = server.operators[msg.name]
687 629
 }
688 630
 
689 631
 // OPER <name> <password>
690
-func NewOperCommand(args []string) (Command, error) {
632
+func ParseOperCommand(args []string) (Command, error) {
691 633
 	if len(args) < 2 {
692 634
 		return nil, NotEnoughArgsError
693 635
 	}
@@ -705,12 +647,7 @@ type CapCommand struct {
705 647
 	capabilities CapabilitySet
706 648
 }
707 649
 
708
-func (msg *CapCommand) String() string {
709
-	return fmt.Sprintf("CAP(subCommand=%s, capabilities=%s)",
710
-		msg.subCommand, msg.capabilities)
711
-}
712
-
713
-func NewCapCommand(args []string) (Command, error) {
650
+func ParseCapCommand(args []string) (Command, error) {
714 651
 	if len(args) < 1 {
715 652
 		return nil, NotEnoughArgsError
716 653
 	}
@@ -740,11 +677,15 @@ type ProxyCommand struct {
740 677
 	hostname   Name // looked up in socket thread
741 678
 }
742 679
 
743
-func (msg *ProxyCommand) String() string {
744
-	return fmt.Sprintf("PROXY(sourceIP=%s, sourcePort=%s)", msg.sourceIP, msg.sourcePort)
680
+func NewProxyCommand(hostname Name) *ProxyCommand {
681
+	cmd := &ProxyCommand{
682
+		hostname: hostname,
683
+	}
684
+	cmd.code = PROXY
685
+	return cmd
745 686
 }
746 687
 
747
-func NewProxyCommand(args []string) (Command, error) {
688
+func ParseProxyCommand(args []string) (Command, error) {
748 689
 	if len(args) < 5 {
749 690
 		return nil, NotEnoughArgsError
750 691
 	}
@@ -764,11 +705,7 @@ type AwayCommand struct {
764 705
 	away bool
765 706
 }
766 707
 
767
-func (msg *AwayCommand) String() string {
768
-	return fmt.Sprintf("AWAY(%s)", msg.text)
769
-}
770
-
771
-func NewAwayCommand(args []string) (Command, error) {
708
+func ParseAwayCommand(args []string) (Command, error) {
772 709
 	cmd := &AwayCommand{}
773 710
 
774 711
 	if len(args) > 0 {
@@ -784,11 +721,7 @@ type IsOnCommand struct {
784 721
 	nicks []Name
785 722
 }
786 723
 
787
-func (msg *IsOnCommand) String() string {
788
-	return fmt.Sprintf("ISON(nicks=%s)", msg.nicks)
789
-}
790
-
791
-func NewIsOnCommand(args []string) (Command, error) {
724
+func ParseIsOnCommand(args []string) (Command, error) {
792 725
 	if len(args) == 0 {
793 726
 		return nil, NotEnoughArgsError
794 727
 	}
@@ -803,7 +736,7 @@ type MOTDCommand struct {
803 736
 	target Name
804 737
 }
805 738
 
806
-func NewMOTDCommand(args []string) (Command, error) {
739
+func ParseMOTDCommand(args []string) (Command, error) {
807 740
 	cmd := &MOTDCommand{}
808 741
 	if len(args) > 0 {
809 742
 		cmd.target = NewName(args[0])
@@ -817,11 +750,7 @@ type NoticeCommand struct {
817 750
 	message Text
818 751
 }
819 752
 
820
-func (cmd *NoticeCommand) String() string {
821
-	return fmt.Sprintf("NOTICE(target=%s, message=%s)", cmd.target, cmd.message)
822
-}
823
-
824
-func NewNoticeCommand(args []string) (Command, error) {
753
+func ParseNoticeCommand(args []string) (Command, error) {
825 754
 	if len(args) < 2 {
826 755
 		return nil, NotEnoughArgsError
827 756
 	}
@@ -844,7 +773,7 @@ func (msg *KickCommand) Comment() Text {
844 773
 	return msg.comment
845 774
 }
846 775
 
847
-func NewKickCommand(args []string) (Command, error) {
776
+func ParseKickCommand(args []string) (Command, error) {
848 777
 	if len(args) < 2 {
849 778
 		return nil, NotEnoughArgsError
850 779
 	}
@@ -875,7 +804,7 @@ type ListCommand struct {
875 804
 	target   Name
876 805
 }
877 806
 
878
-func NewListCommand(args []string) (Command, error) {
807
+func ParseListCommand(args []string) (Command, error) {
879 808
 	cmd := &ListCommand{}
880 809
 	if len(args) > 0 {
881 810
 		cmd.channels = NewNames(strings.Split(args[0], ","))
@@ -892,7 +821,7 @@ type NamesCommand struct {
892 821
 	target   Name
893 822
 }
894 823
 
895
-func NewNamesCommand(args []string) (Command, error) {
824
+func ParseNamesCommand(args []string) (Command, error) {
896 825
 	cmd := &NamesCommand{}
897 826
 	if len(args) > 0 {
898 827
 		cmd.channels = NewNames(strings.Split(args[0], ","))
@@ -908,7 +837,7 @@ type DebugCommand struct {
908 837
 	subCommand Name
909 838
 }
910 839
 
911
-func NewDebugCommand(args []string) (Command, error) {
840
+func ParseDebugCommand(args []string) (Command, error) {
912 841
 	if len(args) == 0 {
913 842
 		return nil, NotEnoughArgsError
914 843
 	}
@@ -923,7 +852,7 @@ type VersionCommand struct {
923 852
 	target Name
924 853
 }
925 854
 
926
-func NewVersionCommand(args []string) (Command, error) {
855
+func ParseVersionCommand(args []string) (Command, error) {
927 856
 	cmd := &VersionCommand{}
928 857
 	if len(args) > 0 {
929 858
 		cmd.target = NewName(args[0])
@@ -937,7 +866,7 @@ type InviteCommand struct {
937 866
 	channel  Name
938 867
 }
939 868
 
940
-func NewInviteCommand(args []string) (Command, error) {
869
+func ParseInviteCommand(args []string) (Command, error) {
941 870
 	if len(args) < 2 {
942 871
 		return nil, NotEnoughArgsError
943 872
 	}
@@ -948,7 +877,7 @@ func NewInviteCommand(args []string) (Command, error) {
948 877
 	}, nil
949 878
 }
950 879
 
951
-func NewTheaterCommand(args []string) (Command, error) {
880
+func ParseTheaterCommand(args []string) (Command, error) {
952 881
 	if len(args) < 1 {
953 882
 		return nil, NotEnoughArgsError
954 883
 	} else if upperSubCmd := strings.ToUpper(args[0]); upperSubCmd == "IDENTIFY" && len(args) == 3 {
@@ -978,7 +907,7 @@ type TimeCommand struct {
978 907
 	target Name
979 908
 }
980 909
 
981
-func NewTimeCommand(args []string) (Command, error) {
910
+func ParseTimeCommand(args []string) (Command, error) {
982 911
 	cmd := &TimeCommand{}
983 912
 	if len(args) > 0 {
984 913
 		cmd.target = NewName(args[0])
@@ -992,7 +921,7 @@ type KillCommand struct {
992 921
 	comment  Text
993 922
 }
994 923
 
995
-func NewKillCommand(args []string) (Command, error) {
924
+func ParseKillCommand(args []string) (Command, error) {
996 925
 	if len(args) < 2 {
997 926
 		return nil, NotEnoughArgsError
998 927
 	}
@@ -1009,7 +938,7 @@ type WhoWasCommand struct {
1009 938
 	target    Name
1010 939
 }
1011 940
 
1012
-func NewWhoWasCommand(args []string) (Command, error) {
941
+func ParseWhoWasCommand(args []string) (Command, error) {
1013 942
 	if len(args) < 1 {
1014 943
 		return nil, NotEnoughArgsError
1015 944
 	}
@@ -1025,7 +954,7 @@ func NewWhoWasCommand(args []string) (Command, error) {
1025 954
 	return cmd, nil
1026 955
 }
1027 956
 
1028
-func NewOperNickCommand(args []string) (Command, error) {
957
+func ParseOperNickCommand(args []string) (Command, error) {
1029 958
 	if len(args) < 2 {
1030 959
 		return nil, NotEnoughArgsError
1031 960
 	}

+ 9
- 8
irc/nickname.go Visa fil

@@ -1,18 +1,10 @@
1 1
 package irc
2 2
 
3
-import (
4
-	"fmt"
5
-)
6
-
7 3
 type NickCommand struct {
8 4
 	BaseCommand
9 5
 	nickname Name
10 6
 }
11 7
 
12
-func (m *NickCommand) String() string {
13
-	return fmt.Sprintf("NICK(nickname=%s)", m.nickname)
14
-}
15
-
16 8
 func (m *NickCommand) HandleRegServer(s *Server) {
17 9
 	client := m.Client()
18 10
 	if !client.authorized {
@@ -89,11 +81,20 @@ func (msg *OperNickCommand) HandleServer(server *Server) {
89 81
 		return
90 82
 	}
91 83
 
84
+	if msg.nick == client.nick {
85
+		return
86
+	}
87
+
92 88
 	target := server.clients.Get(msg.target)
93 89
 	if target == nil {
94 90
 		client.ErrNoSuchNick(msg.target)
95 91
 		return
96 92
 	}
97 93
 
94
+	if server.clients.Get(msg.nick) != nil {
95
+		client.ErrNickNameInUse(msg.nick)
96
+		return
97
+	}
98
+
98 99
 	target.ChangeNickname(msg.nick)
99 100
 }

+ 1
- 1
irc/reply.go Visa fil

@@ -81,7 +81,7 @@ func (target *Client) MultilineReply(names []string, code NumericCode, format st
81 81
 	for to < len(names) {
82 82
 		if (from < (to - 1)) && tooLong(names[from:to]) {
83 83
 			target.NumericReply(code, format, argsAndNames(names[from:to-1])...)
84
-			from, to = to-1, to
84
+			from = to - 1
85 85
 		} else {
86 86
 			to += 1
87 87
 		}

+ 7
- 4
irc/server.go Visa fil

@@ -121,7 +121,7 @@ func (server *Server) loadChannels() {
121 121
 
122 122
 func (server *Server) processCommand(cmd Command) {
123 123
 	client := cmd.Client()
124
-	Log.debug.Printf("%s → %s %s", client, server, cmd)
124
+	Log.debug.Printf("%s → %+v", client, cmd)
125 125
 
126 126
 	if !client.registered {
127 127
 		regCmd, ok := cmd.(RegServerCommand)
@@ -654,9 +654,11 @@ func (msg *DebugCommand) HandleServer(server *Server) {
654 654
 		server.Reply(client, "OK")
655 655
 
656 656
 	case "GCSTATS":
657
-		stats := &debug.GCStats{
657
+		stats := debug.GCStats{
658
+			Pause:          make([]time.Duration, 10),
658 659
 			PauseQuantiles: make([]time.Duration, 5),
659 660
 		}
661
+		debug.ReadGCStats(&stats)
660 662
 		server.Reply(client, "last GC:     %s", stats.LastGC.Format(time.RFC1123))
661 663
 		server.Reply(client, "num GC:      %d", stats.NumGC)
662 664
 		server.Reply(client, "pause total: %s", stats.PauseTotal)
@@ -671,14 +673,15 @@ func (msg *DebugCommand) HandleServer(server *Server) {
671 673
 		server.Reply(client, "num goroutines: %d", count)
672 674
 
673 675
 	case "PROFILEHEAP":
674
-		file, err := os.Create("ergonomadic.heap.prof")
676
+		profFile := "ergonomadic-heap.prof"
677
+		file, err := os.Create(profFile)
675 678
 		if err != nil {
676 679
 			log.Printf("error: %s", err)
677 680
 			break
678 681
 		}
679 682
 		defer file.Close()
680 683
 		pprof.Lookup("heap").WriteTo(file, 0)
681
-		server.Reply(client, "written to ergonomadic-heap.prof")
684
+		server.Reply(client, "written to %s", profFile)
682 685
 	}
683 686
 }
684 687
 

+ 10
- 14
irc/socket.go Visa fil

@@ -4,7 +4,6 @@ import (
4 4
 	"bufio"
5 5
 	"io"
6 6
 	"net"
7
-	"strings"
8 7
 )
9 8
 
10 9
 const (
@@ -15,14 +14,12 @@ const (
15 14
 
16 15
 type Socket struct {
17 16
 	conn   net.Conn
18
-	reader *bufio.Reader
19 17
 	writer *bufio.Writer
20 18
 }
21 19
 
22 20
 func NewSocket(conn net.Conn, commands chan<- Command) *Socket {
23 21
 	socket := &Socket{
24 22
 		conn:   conn,
25
-		reader: bufio.NewReader(conn),
26 23
 		writer: bufio.NewWriter(conn),
27 24
 	}
28 25
 
@@ -41,16 +38,11 @@ func (socket *Socket) Close() {
41 38
 }
42 39
 
43 40
 func (socket *Socket) readLines(commands chan<- Command) {
44
-	commands <- &ProxyCommand{
45
-		hostname: AddrLookupHostname(socket.conn.RemoteAddr()),
46
-	}
41
+	commands <- NewProxyCommand(AddrLookupHostname(socket.conn.RemoteAddr()))
47 42
 
48
-	for {
49
-		line, err := socket.reader.ReadString('\n')
50
-		if socket.isError(err, R) {
51
-			break
52
-		}
53
-		line = strings.TrimRight(line, CRLF)
43
+	scanner := bufio.NewScanner(socket.conn)
44
+	for scanner.Scan() {
45
+		line := scanner.Text()
54 46
 		if len(line) == 0 {
55 47
 			continue
56 48
 		}
@@ -64,9 +56,13 @@ func (socket *Socket) readLines(commands chan<- Command) {
64 56
 		commands <- msg
65 57
 	}
66 58
 
67
-	commands <- &QuitCommand{
68
-		message: "connection closed",
59
+	if err := scanner.Err(); err != nil {
60
+		Log.debug.Printf("%s error: %s", socket, err)
69 61
 	}
62
+
63
+	commands <- NewQuitCommand("connection closed")
64
+
65
+	close(commands)
70 66
 }
71 67
 
72 68
 func (socket *Socket) Write(line string) (err error) {

+ 4
- 18
irc/theater.go Visa fil

@@ -1,9 +1,5 @@
1 1
 package irc
2 2
 
3
-import (
4
-	"fmt"
5
-)
6
-
7 3
 type TheaterClient Name
8 4
 
9 5
 func (c TheaterClient) Id() Name {
@@ -29,10 +25,6 @@ func (m *TheaterIdentifyCommand) LoadPassword(s *Server) {
29 25
 	m.hash = s.theaters[m.channel]
30 26
 }
31 27
 
32
-func (cmd *TheaterIdentifyCommand) String() string {
33
-	return fmt.Sprintf("THEATER_IDENTIFY(channel=%s)", cmd.channel)
34
-}
35
-
36 28
 func (m *TheaterIdentifyCommand) HandleServer(s *Server) {
37 29
 	client := m.Client()
38 30
 	if !m.channel.IsChannel() {
@@ -66,10 +58,6 @@ type TheaterPrivMsgCommand struct {
66 58
 	message Text
67 59
 }
68 60
 
69
-func (cmd *TheaterPrivMsgCommand) String() string {
70
-	return fmt.Sprintf("THEATER_PRIVMSG(channel=%s, asNick=%s, message=%s)", cmd.channel, cmd.asNick, cmd.message)
71
-
72
-}
73 61
 func (m *TheaterPrivMsgCommand) HandleServer(s *Server) {
74 62
 	client := m.Client()
75 63
 
@@ -89,8 +77,9 @@ func (m *TheaterPrivMsgCommand) HandleServer(s *Server) {
89 77
 		return
90 78
 	}
91 79
 
80
+	reply := RplPrivMsg(TheaterClient(m.asNick), channel, m.message)
92 81
 	for member := range channel.members {
93
-		member.Reply(RplPrivMsg(TheaterClient(m.asNick), channel, m.message))
82
+		member.Reply(reply)
94 83
 	}
95 84
 }
96 85
 
@@ -101,10 +90,6 @@ type TheaterActionCommand struct {
101 90
 	action  CTCPText
102 91
 }
103 92
 
104
-func (cmd *TheaterActionCommand) String() string {
105
-	return fmt.Sprintf("THEATER_ACTION(channel=%s, asNick=%s, action=%s)", cmd.channel, cmd.asNick, cmd.action)
106
-}
107
-
108 93
 func (m *TheaterActionCommand) HandleServer(s *Server) {
109 94
 	client := m.Client()
110 95
 
@@ -124,7 +109,8 @@ func (m *TheaterActionCommand) HandleServer(s *Server) {
124 109
 		return
125 110
 	}
126 111
 
112
+	reply := RplCTCPAction(TheaterClient(m.asNick), channel, m.action)
127 113
 	for member := range channel.members {
128
-		member.Reply(RplCTCPAction(TheaterClient(m.asNick), channel, m.action))
114
+		member.Reply(reply)
129 115
 	}
130 116
 }

Laddar…
Avbryt
Spara