Show last IRC connection error in status tab, log IRC connection errors
This commit is contained in:
parent
786d8013b9
commit
18aff3ded6
File diff suppressed because one or more lines are too long
@ -39,6 +39,14 @@ i[class^="icon-"]:before, i[class*=" icon-"]:before {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.success {
|
||||
color: #6BB758 !important;
|
||||
}
|
||||
|
||||
.error {
|
||||
color: #F6546A !important;
|
||||
}
|
||||
|
||||
.wrap {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
|
@ -12,13 +12,14 @@ export default class TabList extends PureComponent {
|
||||
const tabs = [];
|
||||
|
||||
channels.forEach((server, address) => {
|
||||
const srv = servers.get(address);
|
||||
tabs.push(
|
||||
<TabListItem
|
||||
key={address}
|
||||
server={address}
|
||||
content={servers.getIn([address, 'name'])}
|
||||
content={srv.name}
|
||||
selected={tab.server === address && tab.name === null}
|
||||
connected={servers.getIn([address, 'connected'])}
|
||||
connected={srv.status.connected}
|
||||
onClick={this.handleTabClick}
|
||||
/>
|
||||
);
|
||||
|
@ -15,9 +15,9 @@ export default class TabListItem extends PureComponent {
|
||||
classes.push('tab-server');
|
||||
|
||||
if (connected) {
|
||||
style.color = '#6BB758';
|
||||
classes.push('success');
|
||||
} else {
|
||||
style.color = '#F6546A';
|
||||
classes.push('error');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -55,6 +55,7 @@ export default class Chat extends Component {
|
||||
nick,
|
||||
search,
|
||||
showUserList,
|
||||
status,
|
||||
tab,
|
||||
title,
|
||||
users,
|
||||
@ -81,6 +82,7 @@ export default class Chat extends Component {
|
||||
<div className={chatClass}>
|
||||
<ChatTitle
|
||||
channel={channel}
|
||||
status={status}
|
||||
tab={tab}
|
||||
title={title}
|
||||
onCloseClick={this.handleCloseClick}
|
||||
|
@ -7,7 +7,7 @@ import { linkify } from 'util';
|
||||
|
||||
export default class ChatTitle extends PureComponent {
|
||||
render() {
|
||||
const { title, tab, channel, onTitleChange,
|
||||
const { status, title, tab, channel, onTitleChange,
|
||||
onToggleSearch, onToggleUserList, onCloseClick } = this.props;
|
||||
|
||||
let closeTitle;
|
||||
@ -19,6 +19,11 @@ export default class ChatTitle extends PureComponent {
|
||||
closeTitle = 'Disconnect';
|
||||
}
|
||||
|
||||
let serverError = null;
|
||||
if (!tab.name && status.error) {
|
||||
serverError = <span className="error">Error! {status.error}</span>;
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="chat-title-bar">
|
||||
@ -34,6 +39,7 @@ export default class ChatTitle extends PureComponent {
|
||||
</Editable>
|
||||
<div className="chat-topic-wrap">
|
||||
<span className="chat-topic">{linkify(channel.get('topic')) || null}</span>
|
||||
{serverError}
|
||||
</div>
|
||||
<i className="icon-search" title="Search" onClick={onToggleSearch} />
|
||||
<i
|
||||
|
@ -10,7 +10,7 @@ import { getSelectedMessages, getHasMoreMessages,
|
||||
runCommand, sendMessage, fetchMessages, addFetchedMessages } from 'state/messages';
|
||||
import { openPrivateChat, closePrivateChat } from 'state/privateChats';
|
||||
import { getSearch, searchMessages, toggleSearch } from 'state/search';
|
||||
import { getCurrentNick, disconnect, setNick, setServerName } from 'state/servers';
|
||||
import { getCurrentNick, getCurrentServerStatus, disconnect, setNick, setServerName } from 'state/servers';
|
||||
import { getSelectedTab, select } from 'state/tab';
|
||||
import { getShowUserList, toggleUserList } from 'state/ui';
|
||||
|
||||
@ -22,6 +22,7 @@ const mapState = createStructuredSelector({
|
||||
nick: getCurrentNick,
|
||||
search: getSearch,
|
||||
showUserList: getShowUserList,
|
||||
status: getCurrentServerStatus,
|
||||
tab: getSelectedTab,
|
||||
title: getSelectedTabTitle,
|
||||
users: getSelectedChannelUsers
|
||||
|
@ -1,4 +1,26 @@
|
||||
import { setServerName } from '../servers';
|
||||
import { connect, setServerName } from '../servers';
|
||||
|
||||
describe('connect()', () => {
|
||||
it('sets host and port correctly', () => {
|
||||
expect(connect('cake.com:1881', '', {})).toMatchObject({
|
||||
socket: {
|
||||
data: {
|
||||
host: 'cake.com',
|
||||
port: '1881'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
expect(connect('cake.com', '', {})).toMatchObject({
|
||||
socket: {
|
||||
data: {
|
||||
host: 'cake.com',
|
||||
port: undefined
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('setServerName()', () => {
|
||||
it('passes valid names to the server', () => {
|
||||
|
@ -8,10 +8,13 @@ describe('server reducer', () => {
|
||||
|
||||
expect(state.toJS()).toEqual({
|
||||
'127.0.0.1': {
|
||||
connected: false,
|
||||
name: '127.0.0.1',
|
||||
nick: 'nick',
|
||||
editedNick: null
|
||||
editedNick: null,
|
||||
status: {
|
||||
connected: false,
|
||||
error: null
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@ -19,10 +22,13 @@ describe('server reducer', () => {
|
||||
|
||||
expect(state.toJS()).toEqual({
|
||||
'127.0.0.1': {
|
||||
connected: false,
|
||||
name: '127.0.0.1',
|
||||
nick: 'nick',
|
||||
editedNick: null
|
||||
editedNick: null,
|
||||
status: {
|
||||
connected: false,
|
||||
error: null
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@ -32,16 +38,22 @@ describe('server reducer', () => {
|
||||
|
||||
expect(state.toJS()).toEqual({
|
||||
'127.0.0.1': {
|
||||
connected: false,
|
||||
name: '127.0.0.1',
|
||||
nick: 'nick',
|
||||
editedNick: null
|
||||
editedNick: null,
|
||||
status: {
|
||||
connected: false,
|
||||
error: null
|
||||
}
|
||||
},
|
||||
'127.0.0.2': {
|
||||
connected: false,
|
||||
name: 'srv',
|
||||
nick: 'nick',
|
||||
editedNick: null
|
||||
editedNick: null,
|
||||
status: {
|
||||
connected: false,
|
||||
error: null
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
@ -87,9 +99,8 @@ describe('server reducer', () => {
|
||||
editing: true
|
||||
});
|
||||
|
||||
expect(state.toJS()).toEqual({
|
||||
expect(state.toJS()).toMatchObject({
|
||||
'127.0.0.1': {
|
||||
connected: false,
|
||||
name: '127.0.0.1',
|
||||
nick: 'nick',
|
||||
editedNick: 'nick2'
|
||||
@ -111,9 +122,8 @@ describe('server reducer', () => {
|
||||
nick: ''
|
||||
});
|
||||
|
||||
expect(state.toJS()).toEqual({
|
||||
expect(state.toJS()).toMatchObject({
|
||||
'127.0.0.1': {
|
||||
connected: false,
|
||||
name: '127.0.0.1',
|
||||
nick: 'nick',
|
||||
editedNick: null
|
||||
@ -130,9 +140,8 @@ describe('server reducer', () => {
|
||||
newNick: 'nick2'
|
||||
});
|
||||
|
||||
expect(state.toJS()).toEqual({
|
||||
expect(state.toJS()).toMatchObject({
|
||||
'127.0.0.1': {
|
||||
connected: false,
|
||||
name: '127.0.0.1',
|
||||
nick: 'nick2',
|
||||
editedNick: null
|
||||
@ -153,9 +162,8 @@ describe('server reducer', () => {
|
||||
server: '127.0.0.1'
|
||||
});
|
||||
|
||||
expect(state.toJS()).toEqual({
|
||||
expect(state.toJS()).toMatchObject({
|
||||
'127.0.0.1': {
|
||||
connected: false,
|
||||
name: '127.0.0.1',
|
||||
nick: 'nick',
|
||||
editedNick: null
|
||||
@ -171,13 +179,17 @@ describe('server reducer', () => {
|
||||
host: '127.0.0.1',
|
||||
name: 'stuff',
|
||||
nick: 'nick',
|
||||
connected: true
|
||||
status: {
|
||||
connected: true
|
||||
}
|
||||
},
|
||||
{
|
||||
host: '127.0.0.2',
|
||||
name: 'stuffz',
|
||||
nick: 'nick2',
|
||||
connected: false
|
||||
status: {
|
||||
connected: false
|
||||
}
|
||||
},
|
||||
]
|
||||
});
|
||||
@ -187,13 +199,19 @@ describe('server reducer', () => {
|
||||
name: 'stuff',
|
||||
nick: 'nick',
|
||||
editedNick: null,
|
||||
connected: true
|
||||
status: {
|
||||
connected: true,
|
||||
error: null
|
||||
}
|
||||
},
|
||||
'127.0.0.2': {
|
||||
name: 'stuffz',
|
||||
nick: 'nick2',
|
||||
editedNick: null,
|
||||
connected: false
|
||||
status: {
|
||||
connected: false,
|
||||
error: null
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
@ -202,7 +220,8 @@ describe('server reducer', () => {
|
||||
let state = reducer(undefined, connect('127.0.0.1:1337', 'nick', {}));
|
||||
state = reducer(state, {
|
||||
type: actions.socket.CONNECTION_UPDATE,
|
||||
'127.0.0.1': true
|
||||
server: '127.0.0.1',
|
||||
connected: true
|
||||
});
|
||||
|
||||
expect(state.toJS()).toEqual({
|
||||
@ -210,7 +229,29 @@ describe('server reducer', () => {
|
||||
name: '127.0.0.1',
|
||||
nick: 'nick',
|
||||
editedNick: null,
|
||||
connected: true
|
||||
status: {
|
||||
connected: true,
|
||||
error: null
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
state = reducer(state, {
|
||||
type: actions.socket.CONNECTION_UPDATE,
|
||||
server: '127.0.0.1',
|
||||
connected: false,
|
||||
error: 'Bad stuff happened'
|
||||
});
|
||||
|
||||
expect(state.toJS()).toEqual({
|
||||
'127.0.0.1': {
|
||||
name: '127.0.0.1',
|
||||
nick: 'nick',
|
||||
editedNick: null,
|
||||
status: {
|
||||
connected: false,
|
||||
error: 'Bad stuff happened'
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -4,11 +4,16 @@ import createReducer from 'util/createReducer';
|
||||
import { getSelectedTab, updateSelection } from './tab';
|
||||
import * as actions from './actions';
|
||||
|
||||
const Status = Record({
|
||||
connected: false,
|
||||
error: null
|
||||
});
|
||||
|
||||
const Server = Record({
|
||||
nick: '',
|
||||
editedNick: null,
|
||||
name: '',
|
||||
connected: false
|
||||
status: new Status()
|
||||
});
|
||||
|
||||
export const getServers = state => state.servers;
|
||||
@ -31,6 +36,12 @@ export const getCurrentServerName = createSelector(
|
||||
(servers, tab) => servers.getIn([tab.server, 'name'])
|
||||
);
|
||||
|
||||
export const getCurrentServerStatus = createSelector(
|
||||
getServers,
|
||||
getSelectedTab,
|
||||
(servers, tab) => servers.getIn([tab.server, 'status'])
|
||||
);
|
||||
|
||||
export default createReducer(Map(), {
|
||||
[actions.CONNECT](state, { host, nick, options }) {
|
||||
if (!state.has(host)) {
|
||||
@ -81,27 +92,27 @@ export default createReducer(Map(), {
|
||||
|
||||
return state.withMutations(s => {
|
||||
data.forEach(server => {
|
||||
server.status = new Status(server.status);
|
||||
s.set(server.host, new Server(server));
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
[actions.socket.CONNECTION_UPDATE](state, action) {
|
||||
return state.withMutations(s =>
|
||||
Object.keys(action).forEach(server => {
|
||||
if (s.has(server)) {
|
||||
s.setIn([server, 'connected'], action[server]);
|
||||
}
|
||||
})
|
||||
);
|
||||
if (state.has(action.server)) {
|
||||
return state.setIn([action.server, 'status'], new Status(action));
|
||||
}
|
||||
return state;
|
||||
}
|
||||
});
|
||||
|
||||
export function connect(server, nick, options) {
|
||||
let host = server;
|
||||
let port;
|
||||
const i = server.indexOf(':');
|
||||
if (i > 0) {
|
||||
host = server.slice(0, i);
|
||||
port = server.slice(i + 1);
|
||||
}
|
||||
|
||||
return {
|
||||
@ -112,7 +123,8 @@ export function connect(server, nick, options) {
|
||||
socket: {
|
||||
type: 'connect',
|
||||
data: {
|
||||
server,
|
||||
host,
|
||||
port,
|
||||
nick,
|
||||
username: options.username || nick,
|
||||
password: options.password,
|
||||
|
@ -20,7 +20,7 @@ type Client struct {
|
||||
Username string
|
||||
Realname string
|
||||
Messages chan *Message
|
||||
ConnectionChanged chan bool
|
||||
ConnectionChanged chan ConnectionState
|
||||
HandleNickInUse func(string) string
|
||||
|
||||
nick string
|
||||
@ -47,7 +47,7 @@ func NewClient(nick, username string) *Client {
|
||||
Username: username,
|
||||
Realname: nick,
|
||||
Messages: make(chan *Message, 32),
|
||||
ConnectionChanged: make(chan bool, 16),
|
||||
ConnectionChanged: make(chan ConnectionState, 16),
|
||||
out: make(chan string, 32),
|
||||
quit: make(chan struct{}),
|
||||
reconnect: make(chan struct{}),
|
||||
|
23
irc/conn.go
23
irc/conn.go
@ -10,8 +10,6 @@ import (
|
||||
)
|
||||
|
||||
func (c *Client) Connect(address string) {
|
||||
c.ConnectionChanged <- false
|
||||
|
||||
if idx := strings.Index(address, ":"); idx < 0 {
|
||||
c.Host = address
|
||||
|
||||
@ -26,6 +24,7 @@ func (c *Client) Connect(address string) {
|
||||
c.Server = address
|
||||
c.dialer = &net.Dialer{Timeout: 10 * time.Second}
|
||||
|
||||
c.connChange(false, nil)
|
||||
go c.run()
|
||||
}
|
||||
|
||||
@ -71,8 +70,20 @@ func (c *Client) run() {
|
||||
}
|
||||
}
|
||||
|
||||
type ConnectionState struct {
|
||||
Connected bool
|
||||
Error error
|
||||
}
|
||||
|
||||
func (c *Client) connChange(connected bool, err error) {
|
||||
c.ConnectionChanged <- ConnectionState{
|
||||
Connected: connected,
|
||||
Error: err,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Client) disconnect() {
|
||||
c.ConnectionChanged <- false
|
||||
c.connChange(false, nil)
|
||||
c.lock.Lock()
|
||||
c.connected = false
|
||||
c.lock.Unlock()
|
||||
@ -91,7 +102,9 @@ func (c *Client) tryConnect() {
|
||||
}
|
||||
|
||||
err := c.connect()
|
||||
if err == nil {
|
||||
if err != nil {
|
||||
c.connChange(false, err)
|
||||
} else {
|
||||
c.backoff.Reset()
|
||||
|
||||
c.flushChannels()
|
||||
@ -123,7 +136,7 @@ func (c *Client) connect() error {
|
||||
}
|
||||
|
||||
c.connected = true
|
||||
c.ConnectionChanged <- true
|
||||
c.connChange(true, nil)
|
||||
c.reader = bufio.NewReader(c.conn)
|
||||
|
||||
c.register()
|
||||
|
@ -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) {
|
||||
|
@ -23,15 +23,14 @@ type User struct {
|
||||
}
|
||||
|
||||
type Server struct {
|
||||
Name string `json:"name"`
|
||||
Host string `json:"host"`
|
||||
Port string `json:"port,omitempty"`
|
||||
TLS bool `json:"tls,omitempty"`
|
||||
Password string `json:"password,omitempty"`
|
||||
Nick string `json:"nick"`
|
||||
Username string `json:"username,omitempty"`
|
||||
Realname string `json:"realname,omitempty"`
|
||||
Connected bool `json:"connected"`
|
||||
Name string `json:"name"`
|
||||
Host string `json:"host"`
|
||||
Port string `json:"port"`
|
||||
TLS bool `json:"tls,omitempty"`
|
||||
Password string `json:"password,omitempty"`
|
||||
Nick string `json:"nick"`
|
||||
Username string `json:"username,omitempty"`
|
||||
Realname string `json:"realname,omitempty"`
|
||||
}
|
||||
|
||||
type Channel struct {
|
||||
|
Loading…
Reference in New Issue
Block a user