source: code/trunk/server.go@ 75

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

Remove unused user.getChannel, move getUpstream to user

File size: 4.1 KB
RevLine 
[1]1package jounce
2
3import (
4 "fmt"
[37]5 "log"
[1]6 "net"
[24]7 "sync"
[67]8 "time"
[1]9
10 "gopkg.in/irc.v3"
11)
12
[67]13// TODO: make configurable
14var keepAlivePeriod = time.Minute
[71]15var retryConnectMinDelay = time.Minute
[67]16
17func setKeepAlive(c net.Conn) error {
18 tcpConn, ok := c.(*net.TCPConn)
19 if !ok {
20 return fmt.Errorf("cannot enable keep-alive on a non-TCP connection")
21 }
22 if err := tcpConn.SetKeepAlive(true); err != nil {
23 return err
24 }
25 return tcpConn.SetKeepAlivePeriod(keepAlivePeriod)
26}
27
[9]28type Logger interface {
29 Print(v ...interface{})
30 Printf(format string, v ...interface{})
31}
32
[21]33type prefixLogger struct {
34 logger Logger
35 prefix string
36}
37
38var _ Logger = (*prefixLogger)(nil)
39
40func (l *prefixLogger) Print(v ...interface{}) {
41 v = append([]interface{}{l.prefix}, v...)
42 l.logger.Print(v...)
43}
44
45func (l *prefixLogger) Printf(format string, v ...interface{}) {
46 v = append([]interface{}{l.prefix}, v...)
47 l.logger.Printf("%v"+format, v...)
48}
49
[37]50type user struct {
51 username string
52 srv *Server
53
[40]54 lock sync.Mutex
55 upstreamConns []*upstreamConn
56 downstreamConns []*downstreamConn
[37]57}
58
[57]59func newUser(srv *Server, username string) *user {
60 return &user{
61 username: username,
62 srv: srv,
63 }
64}
65
[39]66func (u *user) forEachUpstream(f func(uc *upstreamConn)) {
67 u.lock.Lock()
68 for _, uc := range u.upstreamConns {
[41]69 if !uc.registered || uc.closed {
[39]70 continue
71 }
72 f(uc)
73 }
74 u.lock.Unlock()
75}
76
[40]77func (u *user) forEachDownstream(f func(dc *downstreamConn)) {
78 u.lock.Lock()
79 for _, dc := range u.downstreamConns {
80 f(dc)
81 }
82 u.lock.Unlock()
83}
84
[75]85func (u *user) getUpstream(name string) *Upstream {
86 for i, upstream := range u.srv.Upstreams {
87 if upstream.Addr == name {
88 return &u.srv.Upstreams[i]
[46]89 }
90 }
[75]91 return nil
[46]92}
93
[10]94type Upstream struct {
95 Addr string
96 Nick string
97 Username string
98 Realname string
[19]99 Channels []string
[10]100}
101
102type Server struct {
103 Hostname string
104 Logger Logger
[50]105 RingCap int
[64]106 Debug bool
[10]107 Upstreams []Upstream // TODO: per-user
[22]108
[24]109 lock sync.Mutex
[37]110 users map[string]*user
[22]111 downstreamConns []*downstreamConn
[10]112}
113
[37]114func NewServer() *Server {
115 return &Server{
[50]116 Logger: log.New(log.Writer(), "", log.LstdFlags),
117 RingCap: 4096,
118 users: make(map[string]*user),
[37]119 }
120}
121
[5]122func (s *Server) prefix() *irc.Prefix {
123 return &irc.Prefix{Name: s.Hostname}
124}
125
[71]126func (s *Server) runUpstream(u *user, upstream *Upstream) {
127 var lastTry time.Time
128 for {
129 if dur := time.Now().Sub(lastTry); dur < retryConnectMinDelay {
130 delay := retryConnectMinDelay - dur
131 s.Logger.Printf("waiting %v before trying to reconnect to %q", delay.Truncate(time.Second), upstream.Addr)
132 time.Sleep(delay)
133 }
134 lastTry = time.Now()
135
136 uc, err := connectToUpstream(u, upstream)
137 if err != nil {
138 s.Logger.Printf("failed to connect to upstream server %q: %v", upstream.Addr, err)
139 continue
140 }
141
142 uc.register()
143
144 u.lock.Lock()
145 u.upstreamConns = append(u.upstreamConns, uc)
146 u.lock.Unlock()
147
148 if err := uc.readMessages(); err != nil {
149 uc.logger.Printf("failed to handle messages: %v", err)
150 }
151 uc.Close()
152
153 u.lock.Lock()
154 for i := range u.upstreamConns {
155 if u.upstreamConns[i] == uc {
156 u.upstreamConns = append(u.upstreamConns[:i], u.upstreamConns[i+1:]...)
157 break
158 }
159 }
160 u.lock.Unlock()
161 }
162}
163
[10]164func (s *Server) Run() {
[37]165 // TODO: multi-user
[57]166 u := newUser(s, "jounce")
[37]167
168 s.lock.Lock()
169 s.users[u.username] = u
170 s.lock.Unlock()
171
[10]172 for i := range s.Upstreams {
[71]173 go s.runUpstream(u, &s.Upstreams[i])
[10]174 }
175}
176
[38]177func (s *Server) getUser(name string) *user {
178 s.lock.Lock()
179 u := s.users[name]
180 s.lock.Unlock()
181 return u
182}
183
[3]184func (s *Server) Serve(ln net.Listener) error {
[1]185 for {
[22]186 netConn, err := ln.Accept()
[1]187 if err != nil {
188 return fmt.Errorf("failed to accept connection: %v", err)
189 }
190
[67]191 setKeepAlive(netConn)
192
[65]193 dc := newDownstreamConn(s, netConn)
[1]194 go func() {
[24]195 s.lock.Lock()
[65]196 s.downstreamConns = append(s.downstreamConns, dc)
[24]197 s.lock.Unlock()
[29]198
[65]199 if err := dc.readMessages(); err != nil {
200 dc.logger.Printf("failed to handle messages: %v", err)
[1]201 }
[65]202 dc.Close()
[29]203
[24]204 s.lock.Lock()
[65]205 for i := range s.downstreamConns {
206 if s.downstreamConns[i] == dc {
[24]207 s.downstreamConns = append(s.downstreamConns[:i], s.downstreamConns[i+1:]...)
208 break
209 }
210 }
211 s.lock.Unlock()
[1]212 }()
213 }
214}
Note: See TracBrowser for help on using the repository browser.