source: code/trunk/downstream.go@ 23

Last change on this file since 23 was 23, checked in by contact, 5 years ago

Allow Server to have access to upstreamConn

File size: 4.1 KB
RevLine 
[13]1package jounce
2
3import (
4 "fmt"
5 "io"
6 "net"
7
8 "gopkg.in/irc.v3"
9)
10
11type ircError struct {
12 Message *irc.Message
13}
14
15func newUnknownCommandError(cmd string) ircError {
16 return ircError{&irc.Message{
17 Command: irc.ERR_UNKNOWNCOMMAND,
18 Params: []string{
19 "*",
20 cmd,
21 "Unknown command",
22 },
23 }}
24}
25
26func newNeedMoreParamsError(cmd string) ircError {
27 return ircError{&irc.Message{
28 Command: irc.ERR_NEEDMOREPARAMS,
29 Params: []string{
30 "*",
31 cmd,
32 "Not enough parameters",
33 },
34 }}
35}
36
37func (err ircError) Error() string {
38 return err.Message.String()
39}
40
41type downstreamConn struct {
[23]42 net net.Conn
43 irc *irc.Conn
44 srv *Server
45 logger Logger
[22]46
[13]47 registered bool
48 closed bool
49 nick string
50 username string
51 realname string
52}
53
[22]54func newDownstreamConn(srv *Server, netConn net.Conn) *downstreamConn {
55 return &downstreamConn{
[23]56 net: netConn,
57 irc: irc.NewConn(netConn),
58 srv: srv,
[22]59 logger: &prefixLogger{srv.Logger, fmt.Sprintf("downstream %q: ", netConn.RemoteAddr())},
60 }
61}
62
63func (c *downstreamConn) readMessages() error {
64 c.logger.Printf("new connection")
65 defer c.Close()
66
67 for {
68 msg, err := c.irc.ReadMessage()
69 if err == io.EOF {
70 break
71 } else if err != nil {
72 return fmt.Errorf("failed to read IRC command: %v", err)
73 }
74
75 err = c.handleMessage(msg)
76 if ircErr, ok := err.(ircError); ok {
77 ircErr.Message.Prefix = c.srv.prefix()
78 if err := c.WriteMessage(ircErr.Message); err != nil {
79 return fmt.Errorf("failed to write IRC reply: %v", err)
80 }
81 } else if err != nil {
82 return fmt.Errorf("failed to handle IRC command %q: %v", msg.Command, err)
83 }
84
85 if c.closed {
86 return nil
87 }
88 }
89
90 return c.Close()
91}
92
[13]93func (c *downstreamConn) Close() error {
94 if err := c.net.Close(); err != nil {
95 return err
96 }
97 c.closed = true
98 return nil
99}
100
101func (c *downstreamConn) WriteMessage(msg *irc.Message) error {
102 msg.Prefix = c.srv.prefix()
103 return c.irc.WriteMessage(msg)
104}
105
106func (c *downstreamConn) handleMessage(msg *irc.Message) error {
107 switch msg.Command {
108 case "PING":
109 // TODO: handle params
110 return c.WriteMessage(&irc.Message{
111 Command: "PONG",
112 Params: []string{c.srv.Hostname},
113 })
114 default:
115 if c.registered {
116 return c.handleMessageRegistered(msg)
117 } else {
118 return c.handleMessageUnregistered(msg)
119 }
120 }
121}
122
123func (c *downstreamConn) handleMessageUnregistered(msg *irc.Message) error {
124 switch msg.Command {
125 case "NICK":
126 if len(msg.Params) != 1 {
127 return newNeedMoreParamsError(msg.Command)
128 }
129 c.nick = msg.Params[0]
130 case "USER":
131 if len(msg.Params) != 4 {
132 return newNeedMoreParamsError(msg.Command)
133 }
134 c.username = "~" + msg.Params[0]
135 c.realname = msg.Params[3]
136 case "QUIT":
137 return c.Close()
138 default:
[22]139 c.logger.Printf("unhandled message: %v", msg)
[13]140 return newUnknownCommandError(msg.Command)
141 }
142 if c.username != "" && c.nick != "" {
143 return c.register()
144 }
145 return nil
146}
147
148func (c *downstreamConn) register() error {
149 c.registered = true
150
151 err := c.WriteMessage(&irc.Message{
152 Command: irc.RPL_WELCOME,
153 Params: []string{c.nick, "Welcome to jounce, " + c.nick},
154 })
155 if err != nil {
156 return err
157 }
158
159 err = c.WriteMessage(&irc.Message{
160 Command: irc.RPL_YOURHOST,
161 Params: []string{c.nick, "Your host is " + c.srv.Hostname},
162 })
163 if err != nil {
164 return err
165 }
166
167 err = c.WriteMessage(&irc.Message{
168 Command: irc.RPL_CREATED,
169 Params: []string{c.nick, "This server was created <datetime>"}, // TODO
170 })
171 if err != nil {
172 return err
173 }
174
175 err = c.WriteMessage(&irc.Message{
176 Command: irc.RPL_MYINFO,
[15]177 Params: []string{c.nick, c.srv.Hostname, "unknown", "aiwroO", "OovaimnqpsrtklbeI"},
[13]178 })
179 if err != nil {
180 return err
181 }
182
183 err = c.WriteMessage(&irc.Message{
184 Command: irc.ERR_NOMOTD,
185 Params: []string{c.nick, "No MOTD"},
186 })
187 if err != nil {
188 return err
189 }
190
191 return nil
192}
193
194func (c *downstreamConn) handleMessageRegistered(msg *irc.Message) error {
195 switch msg.Command {
196 case "NICK", "USER":
197 return ircError{&irc.Message{
198 Command: irc.ERR_ALREADYREGISTERED,
199 Params: []string{
200 c.nick,
201 "You may not reregister",
202 },
203 }}
204 case "QUIT":
205 return c.Close()
206 default:
[22]207 c.logger.Printf("unhandled message: %v", msg)
[13]208 return newUnknownCommandError(msg.Command)
209 }
210}
Note: See TracBrowser for help on using the repository browser.