-
Notifications
You must be signed in to change notification settings - Fork 3
/
manager.go
129 lines (103 loc) · 2.91 KB
/
manager.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
// Copyright (c) 2012-2014 Jeremy Latt
// Copyright (c) 2014-2015 Edmund Huber
// Copyright (c) 2016-2017 Daniel Oaks <daniel@danieloaks.net>
// released under the MIT license
package ircbnc
import (
"crypto/tls"
"fmt"
"log"
"net"
"os"
"syscall"
)
var (
// QuitSignals is the list of signals we quit on
//TODO(dan): Rehash on one of these signals instead, same as Oragono.
QuitSignals = []os.Signal{syscall.SIGINT, syscall.SIGHUP, syscall.SIGTERM, syscall.SIGQUIT}
// BNC: The global instance of Manager.
// TODO: NewManager() sets this each time it's run. It's only run once so no issue.. but it's not tidy
BNC *Manager
)
// Manager handles the different components that keep GoshuBNC spinning.
type Manager struct {
Config *Config
Ds DataStoreInterface
Messages MessageDatastore
Users map[string]*User
Listeners []net.Listener
newConns chan net.Conn
quitSignals chan os.Signal
Source string
StatusNick string
StatusSource string
Bus HookEmitter
Salt []byte
}
// NewManager create a new IRC bouncer from the given config and database.
func NewManager(config *Config, ds DataStoreInterface) *Manager {
m := &Manager{}
BNC = m
m.Bus = MakeHookEmitter()
m.Config = config
m.Ds = ds
m.newConns = make(chan net.Conn)
m.quitSignals = make(chan os.Signal, len(QuitSignals))
m.Users = make(map[string]*User)
// source on our outgoing message/status bot/etc
m.StatusNick = "*status"
m.Source = "irc.goshubnc"
m.StatusSource = fmt.Sprintf("%s!bnc@%s", m.StatusNick, m.Source)
return m
}
// Run starts the bouncer, creating the listeners and server connections.
func (m *Manager) Run() error {
// load users
users := m.Ds.GetAllUsers()
for _, user := range users {
m.Users[user.ID] = user
m.Users[user.ID].StartServerConnections()
}
// open listeners
for _, address := range m.Config.Bouncer.Listeners {
config, listenTLS := m.Config.Bouncer.TLSListeners[address]
listener, err := net.Listen("tcp", address)
if err != nil {
log.Fatal(address, "listen error: ", err)
}
tlsString := "plaintext"
if listenTLS {
tlsConfig, err := config.Config()
if err != nil {
log.Fatal(fmt.Sprintf("TLS listen error on `%s`: %s", address, err.Error()))
}
listener = tls.NewListener(listener, tlsConfig)
tlsString = "TLS"
}
fmt.Println(fmt.Sprintf("listening on %s using %s.", address, tlsString))
go func() {
for {
conn, err := listener.Accept()
if err != nil {
fmt.Println(fmt.Sprintf("%s accept error: %s", address, err))
}
fmt.Println(fmt.Sprintf("%s accept: %s", address, conn.RemoteAddr()))
m.newConns <- conn
}
}()
m.Listeners = append(m.Listeners, listener)
}
// and wait
var done bool
for !done {
select {
case <-m.quitSignals:
//TODO(dan): Write real shutdown code
log.Fatal("Shutting down! (TODO: write real shutdown code)")
done = true
case conn := <-m.newConns:
go NewListener(m, conn)
}
}
return nil
}