Show last IRC connection error in status tab, log IRC connection errors
This commit is contained in:
parent
786d8013b9
commit
18aff3ded6
19 changed files with 294 additions and 189 deletions
|
@ -20,7 +20,7 @@ type connectDefaults struct {
|
|||
|
||||
type indexData struct {
|
||||
Defaults connectDefaults `json:"defaults"`
|
||||
Servers []storage.Server `json:"servers,omitempty"`
|
||||
Servers []Server `json:"servers,omitempty"`
|
||||
Channels []storage.Channel `json:"channels,omitempty"`
|
||||
|
||||
// Users in the selected channel
|
||||
|
@ -57,32 +57,32 @@ func (d *indexData) addUsersAndMessages(server, channel string, session *Session
|
|||
}
|
||||
|
||||
func getIndexData(r *http.Request, session *Session) *indexData {
|
||||
data := indexData{}
|
||||
servers := session.user.GetServers()
|
||||
connections := session.getConnectionStates()
|
||||
for i, server := range servers {
|
||||
servers[i].Connected = connections[server.Host]
|
||||
servers[i].Port = ""
|
||||
servers[i].TLS = false
|
||||
servers[i].Password = ""
|
||||
servers[i].Username = ""
|
||||
servers[i].Realname = ""
|
||||
for _, server := range servers {
|
||||
server.Password = ""
|
||||
server.Username = ""
|
||||
server.Realname = ""
|
||||
|
||||
data.Servers = append(data.Servers, Server{
|
||||
Server: server,
|
||||
Status: newConnectionUpdate(server.Host, connections[server.Host]),
|
||||
})
|
||||
}
|
||||
|
||||
channels := session.user.GetChannels()
|
||||
for i, channel := range channels {
|
||||
channels[i].Topic = channelStore.GetTopic(channel.Server, channel.Name)
|
||||
}
|
||||
data.Channels = channels
|
||||
|
||||
data := indexData{
|
||||
Defaults: connectDefaults{
|
||||
Name: viper.GetString("defaults.name"),
|
||||
Address: viper.GetString("defaults.address"),
|
||||
Channels: viper.GetStringSlice("defaults.channels"),
|
||||
Password: viper.GetString("defaults.password") != "",
|
||||
SSL: viper.GetBool("defaults.ssl"),
|
||||
},
|
||||
Servers: servers,
|
||||
Channels: channels,
|
||||
data.Defaults = connectDefaults{
|
||||
Name: viper.GetString("defaults.name"),
|
||||
Address: viper.GetString("defaults.address"),
|
||||
Channels: viper.GetStringSlice("defaults.channels"),
|
||||
Password: viper.GetString("defaults.password") != "",
|
||||
SSL: viper.GetBool("defaults.ssl"),
|
||||
}
|
||||
|
||||
server, channel := getTabFromPath(r.URL.EscapedPath())
|
||||
|
|
|
@ -27,31 +27,7 @@ func reconnectIRC() {
|
|||
channels := user.GetChannels()
|
||||
|
||||
for _, server := range user.GetServers() {
|
||||
i := irc.NewClient(server.Nick, server.Username)
|
||||
i.TLS = server.TLS
|
||||
i.Password = server.Password
|
||||
i.Realname = server.Realname
|
||||
i.HandleNickInUse = createNickInUseHandler(i, session)
|
||||
|
||||
if i.TLS {
|
||||
i.TLSConfig = &tls.Config{
|
||||
InsecureSkipVerify: !viper.GetBool("verify_certificates"),
|
||||
}
|
||||
|
||||
if cert := user.GetCertificate(); cert != nil {
|
||||
i.TLSConfig.Certificates = []tls.Certificate{*cert}
|
||||
}
|
||||
}
|
||||
|
||||
session.setIRC(server.Host, i)
|
||||
|
||||
if server.Port != "" {
|
||||
i.Connect(net.JoinHostPort(server.Host, server.Port))
|
||||
} else {
|
||||
i.Connect(server.Host)
|
||||
}
|
||||
|
||||
go newIRCHandler(i, session).run()
|
||||
i := connectIRC(server, session)
|
||||
|
||||
var joining []string
|
||||
for _, channel := range channels {
|
||||
|
@ -63,3 +39,39 @@ func reconnectIRC() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func connectIRC(server storage.Server, session *Session) *irc.Client {
|
||||
i := irc.NewClient(server.Nick, server.Username)
|
||||
i.TLS = server.TLS
|
||||
i.Realname = server.Realname
|
||||
i.HandleNickInUse = createNickInUseHandler(i, session)
|
||||
|
||||
address := server.Host
|
||||
if server.Port != "" {
|
||||
address = net.JoinHostPort(server.Host, server.Port)
|
||||
}
|
||||
|
||||
if server.Password == "" &&
|
||||
viper.GetString("defaults.password") != "" &&
|
||||
address == viper.GetString("defaults.address") {
|
||||
i.Password = viper.GetString("defaults.password")
|
||||
} else {
|
||||
i.Password = server.Password
|
||||
}
|
||||
|
||||
if i.TLS {
|
||||
i.TLSConfig = &tls.Config{
|
||||
InsecureSkipVerify: !viper.GetBool("verify_certificates"),
|
||||
}
|
||||
|
||||
if cert := session.user.GetCertificate(); cert != nil {
|
||||
i.TLSConfig.Certificates = []tls.Certificate{*cert}
|
||||
}
|
||||
}
|
||||
|
||||
session.setIRC(server.Host, i)
|
||||
i.Connect(address)
|
||||
go newIRCHandler(i, session).run()
|
||||
|
||||
return i
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
"unicode"
|
||||
|
@ -37,6 +38,7 @@ func newIRCHandler(client *irc.Client, session *Session) *ircHandler {
|
|||
}
|
||||
|
||||
func (i *ircHandler) run() {
|
||||
var lastConnErr error
|
||||
for {
|
||||
select {
|
||||
case msg, ok := <-i.client.Messages:
|
||||
|
@ -47,11 +49,17 @@ func (i *ircHandler) run() {
|
|||
|
||||
i.dispatchMessage(msg)
|
||||
|
||||
case connected := <-i.client.ConnectionChanged:
|
||||
i.session.sendJSON("connection_update", map[string]bool{
|
||||
i.client.Host: connected,
|
||||
})
|
||||
i.session.setConnectionState(i.client.Host, connected)
|
||||
case state := <-i.client.ConnectionChanged:
|
||||
i.session.sendJSON("connection_update", newConnectionUpdate(i.client.Host, state))
|
||||
i.session.setConnectionState(i.client.Host, state)
|
||||
|
||||
if state.Error != nil && (lastConnErr == nil ||
|
||||
state.Error.Error() != lastConnErr.Error()) {
|
||||
lastConnErr = state.Error
|
||||
i.log("Connection error:", state.Error)
|
||||
} else if state.Connected {
|
||||
i.log("Connected")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -312,6 +320,11 @@ func (i *ircHandler) initHandlers() {
|
|||
}
|
||||
}
|
||||
|
||||
func (i *ircHandler) log(v ...interface{}) {
|
||||
s := fmt.Sprintln(v...)
|
||||
log.Println("[IRC]", i.session.user.ID, i.client.Host, s[:len(s)-1])
|
||||
}
|
||||
|
||||
func parseMode(mode string) *Mode {
|
||||
m := Mode{}
|
||||
add := false
|
||||
|
|
|
@ -3,6 +3,7 @@ package server
|
|||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/khlieng/dispatch/irc"
|
||||
"github.com/khlieng/dispatch/storage"
|
||||
)
|
||||
|
||||
|
@ -16,14 +17,31 @@ type WSResponse struct {
|
|||
Data interface{} `json:"data"`
|
||||
}
|
||||
|
||||
type Connect struct {
|
||||
Name string `json:"name"`
|
||||
Server string `json:"server"`
|
||||
TLS bool `json:"tls"`
|
||||
Password string `json:"password"`
|
||||
Nick string `json:"nick"`
|
||||
Username string `json:"username"`
|
||||
Realname string `json:"realname"`
|
||||
type Server struct {
|
||||
storage.Server
|
||||
Status ConnectionUpdate `json:"status"`
|
||||
}
|
||||
|
||||
type ServerName struct {
|
||||
Server string `json:"server"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
type ConnectionUpdate struct {
|
||||
Server string `json:"server"`
|
||||
Connected bool `json:"connected"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
func newConnectionUpdate(server string, state irc.ConnectionState) ConnectionUpdate {
|
||||
status := ConnectionUpdate{
|
||||
Server: server,
|
||||
Connected: state.Connected,
|
||||
}
|
||||
if state.Error != nil {
|
||||
status.Error = state.Error.Error()
|
||||
}
|
||||
return status
|
||||
}
|
||||
|
||||
type Nick struct {
|
||||
|
|
|
@ -16,7 +16,7 @@ const (
|
|||
|
||||
type Session struct {
|
||||
irc map[string]*irc.Client
|
||||
connectionState map[string]bool
|
||||
connectionState map[string]irc.ConnectionState
|
||||
ircLock sync.Mutex
|
||||
|
||||
ws map[string]*wsConn
|
||||
|
@ -31,7 +31,7 @@ type Session struct {
|
|||
func NewSession(user *storage.User) *Session {
|
||||
return &Session{
|
||||
irc: make(map[string]*irc.Client),
|
||||
connectionState: make(map[string]bool),
|
||||
connectionState: make(map[string]irc.ConnectionState),
|
||||
ws: make(map[string]*wsConn),
|
||||
broadcast: make(chan WSResponse, 32),
|
||||
user: user,
|
||||
|
@ -51,7 +51,9 @@ func (s *Session) getIRC(server string) (*irc.Client, bool) {
|
|||
func (s *Session) setIRC(server string, i *irc.Client) {
|
||||
s.ircLock.Lock()
|
||||
s.irc[server] = i
|
||||
s.connectionState[server] = false
|
||||
s.connectionState[server] = irc.ConnectionState{
|
||||
Connected: false,
|
||||
}
|
||||
s.ircLock.Unlock()
|
||||
|
||||
s.reset <- 0
|
||||
|
@ -74,9 +76,9 @@ func (s *Session) numIRC() int {
|
|||
return n
|
||||
}
|
||||
|
||||
func (s *Session) getConnectionStates() map[string]bool {
|
||||
func (s *Session) getConnectionStates() map[string]irc.ConnectionState {
|
||||
s.ircLock.Lock()
|
||||
state := make(map[string]bool, len(s.connectionState))
|
||||
state := make(map[string]irc.ConnectionState, len(s.connectionState))
|
||||
|
||||
for k, v := range s.connectionState {
|
||||
state[k] = v
|
||||
|
@ -86,9 +88,9 @@ func (s *Session) getConnectionStates() map[string]bool {
|
|||
return state
|
||||
}
|
||||
|
||||
func (s *Session) setConnectionState(server string, connected bool) {
|
||||
func (s *Session) setConnectionState(server string, state irc.ConnectionState) {
|
||||
s.ircLock.Lock()
|
||||
s.connectionState[server] = connected
|
||||
s.connectionState[server] = state
|
||||
s.ircLock.Unlock()
|
||||
}
|
||||
|
||||
|
|
|
@ -1,19 +1,13 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"encoding/json"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/kjk/betterguid"
|
||||
"github.com/spf13/viper"
|
||||
|
||||
"github.com/khlieng/dispatch/irc"
|
||||
"github.com/khlieng/dispatch/storage"
|
||||
)
|
||||
|
||||
type wsHandler struct {
|
||||
|
@ -87,56 +81,17 @@ func (h *wsHandler) init(r *http.Request) {
|
|||
}
|
||||
|
||||
func (h *wsHandler) connect(b []byte) {
|
||||
var data Connect
|
||||
var data Server
|
||||
json.Unmarshal(b, &data)
|
||||
|
||||
host, port, err := net.SplitHostPort(data.Server)
|
||||
if err != nil {
|
||||
host = data.Server
|
||||
}
|
||||
|
||||
if _, ok := h.session.getIRC(host); !ok {
|
||||
if _, ok := h.session.getIRC(data.Host); !ok {
|
||||
log.Println(h.addr, "[IRC] Add server", data.Server)
|
||||
|
||||
i := irc.NewClient(data.Nick, data.Username)
|
||||
i.TLS = data.TLS
|
||||
i.Realname = data.Realname
|
||||
i.HandleNickInUse = createNickInUseHandler(i, h.session)
|
||||
connectIRC(data.Server, h.session)
|
||||
|
||||
if data.Password == "" &&
|
||||
viper.GetString("defaults.password") != "" &&
|
||||
data.Server == viper.GetString("defaults.address") {
|
||||
i.Password = viper.GetString("defaults.password")
|
||||
} else {
|
||||
i.Password = data.Password
|
||||
}
|
||||
|
||||
if i.TLS {
|
||||
i.TLSConfig = &tls.Config{
|
||||
InsecureSkipVerify: !viper.GetBool("verify_certificates"),
|
||||
}
|
||||
|
||||
if cert := h.session.user.GetCertificate(); cert != nil {
|
||||
i.TLSConfig.Certificates = []tls.Certificate{*cert}
|
||||
}
|
||||
}
|
||||
|
||||
h.session.setIRC(host, i)
|
||||
i.Connect(data.Server)
|
||||
go newIRCHandler(i, h.session).run()
|
||||
|
||||
go h.session.user.AddServer(storage.Server{
|
||||
Name: data.Name,
|
||||
Host: host,
|
||||
Port: port,
|
||||
TLS: data.TLS,
|
||||
Password: data.Password,
|
||||
Nick: data.Nick,
|
||||
Username: data.Username,
|
||||
Realname: data.Realname,
|
||||
})
|
||||
go h.session.user.AddServer(data.Server)
|
||||
} else {
|
||||
log.Println(h.addr, "[IRC]", data.Server, "already added")
|
||||
log.Println(h.addr, "[IRC]", data.Host, "already added")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -287,7 +242,7 @@ func (h *wsHandler) fetchMessages(b []byte) {
|
|||
}
|
||||
|
||||
func (h *wsHandler) setServerName(b []byte) {
|
||||
var data Connect
|
||||
var data ServerName
|
||||
json.Unmarshal(b, &data)
|
||||
|
||||
if isValidServerName(data.Name) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue