Add IRC connection status indicator
This commit is contained in:
parent
83aef5df7b
commit
f429a528ba
File diff suppressed because one or more lines are too long
@ -61,6 +61,7 @@ i[class^="icon-"]:before, i[class*=" icon-"]:before {
|
|||||||
|
|
||||||
.tablist p {
|
.tablist p {
|
||||||
padding: 3px 15px;
|
padding: 3px 15px;
|
||||||
|
padding-right: 10px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,11 +78,30 @@ i[class^="icon-"]:before, i[class*=" icon-"]:before {
|
|||||||
border-left: 5px solid #6BB758;
|
border-left: 5px solid #6BB758;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tab-content {
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
.tab-server {
|
.tab-server {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
color: #999;
|
color: #999;
|
||||||
margin-top: 10px !important;
|
margin-top: 10px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tab-server .tab-content {
|
||||||
|
flex: 1;
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-indicator {
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
.button-connect {
|
.button-connect {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 50px;
|
height: 50px;
|
||||||
|
@ -26,6 +26,7 @@ export const SET_NICK = 'SET_NICK';
|
|||||||
export const SOCKET_CERT_FAIL = 'SOCKET_CERT_FAIL';
|
export const SOCKET_CERT_FAIL = 'SOCKET_CERT_FAIL';
|
||||||
export const SOCKET_CERT_SUCCESS = 'SOCKET_CERT_SUCCESS';
|
export const SOCKET_CERT_SUCCESS = 'SOCKET_CERT_SUCCESS';
|
||||||
export const SOCKET_CHANNELS = 'SOCKET_CHANNELS';
|
export const SOCKET_CHANNELS = 'SOCKET_CHANNELS';
|
||||||
|
export const SOCKET_CONNECTION_UPDATE = 'SOCKET_CONNECTION_UPDATE';
|
||||||
export const SOCKET_JOIN = 'SOCKET_JOIN';
|
export const SOCKET_JOIN = 'SOCKET_JOIN';
|
||||||
export const SOCKET_MESSAGE = 'SOCKET_MESSAGE';
|
export const SOCKET_MESSAGE = 'SOCKET_MESSAGE';
|
||||||
export const SOCKET_MODE = 'SOCKET_MODE';
|
export const SOCKET_MODE = 'SOCKET_MODE';
|
||||||
|
@ -35,6 +35,7 @@ export default class TabList extends Component {
|
|||||||
selected.channel === null &&
|
selected.channel === null &&
|
||||||
selected.user === null
|
selected.user === null
|
||||||
}
|
}
|
||||||
|
connected={servers.getIn([address, 'connected'])}
|
||||||
onClick={this.handleTabClick}
|
onClick={this.handleTabClick}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
@ -20,8 +20,24 @@ export default class TabListItem extends Component {
|
|||||||
classes.push('selected');
|
classes.push('selected');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let indicator = null;
|
||||||
|
if (this.props.connected !== undefined) {
|
||||||
|
const style = {};
|
||||||
|
|
||||||
|
if (this.props.connected) {
|
||||||
|
style.background = '#6BB758';
|
||||||
|
} else {
|
||||||
|
style.background = '#F6546A';
|
||||||
|
}
|
||||||
|
|
||||||
|
indicator = <i className="tab-indicator" style={style}></i>;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<p className={classes.join(' ')} onClick={this.handleClick}>{content}</p>
|
<p className={classes.join(' ')} onClick={this.handleClick}>
|
||||||
|
<span className="tab-content">{content}</span>
|
||||||
|
{indicator}
|
||||||
|
</p>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
import { Map, Record } from 'immutable';
|
import { Map, Record } from 'immutable';
|
||||||
import createReducer from '../util/createReducer';
|
import createReducer from '../util/createReducer';
|
||||||
import * as actions from '../actions';
|
import * as actions from '../actions';
|
||||||
|
import forEach from 'lodash/collection/forEach';
|
||||||
|
|
||||||
const Server = Record({
|
const Server = Record({
|
||||||
nick: null,
|
nick: null,
|
||||||
name: null
|
name: null,
|
||||||
|
connected: false
|
||||||
});
|
});
|
||||||
|
|
||||||
export default createReducer(Map(), {
|
export default createReducer(Map(), {
|
||||||
@ -42,5 +44,13 @@ export default createReducer(Map(), {
|
|||||||
s.set(server.address, new Server(server));
|
s.set(server.address, new Server(server));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
[actions.SOCKET_CONNECTION_UPDATE](state, action) {
|
||||||
|
return state.withMutations(s => forEach(action, (connected, server) => {
|
||||||
|
if (s.has(server)) {
|
||||||
|
s.setIn([server, 'connected'], connected);
|
||||||
|
}
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -12,14 +12,15 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Client struct {
|
type Client struct {
|
||||||
Server string
|
Server string
|
||||||
Host string
|
Host string
|
||||||
TLS bool
|
TLS bool
|
||||||
TLSConfig *tls.Config
|
TLSConfig *tls.Config
|
||||||
Password string
|
Password string
|
||||||
Username string
|
Username string
|
||||||
Realname string
|
Realname string
|
||||||
Messages chan *Message
|
Messages chan *Message
|
||||||
|
ConnectionChanged chan bool
|
||||||
|
|
||||||
nick string
|
nick string
|
||||||
|
|
||||||
@ -40,13 +41,14 @@ type Client struct {
|
|||||||
|
|
||||||
func NewClient(nick, username string) *Client {
|
func NewClient(nick, username string) *Client {
|
||||||
return &Client{
|
return &Client{
|
||||||
nick: nick,
|
nick: nick,
|
||||||
Username: username,
|
Username: username,
|
||||||
Realname: nick,
|
Realname: nick,
|
||||||
Messages: make(chan *Message, 32),
|
Messages: make(chan *Message, 32),
|
||||||
out: make(chan string, 32),
|
ConnectionChanged: make(chan bool, 16),
|
||||||
quit: make(chan struct{}),
|
out: make(chan string, 32),
|
||||||
reconnect: make(chan struct{}),
|
quit: make(chan struct{}),
|
||||||
|
reconnect: make(chan struct{}),
|
||||||
backoff: &backoff.Backoff{
|
backoff: &backoff.Backoff{
|
||||||
Jitter: true,
|
Jitter: true,
|
||||||
},
|
},
|
||||||
|
@ -10,6 +10,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (c *Client) Connect(address string) {
|
func (c *Client) Connect(address string) {
|
||||||
|
c.ConnectionChanged <- false
|
||||||
|
|
||||||
if idx := strings.Index(address, ":"); idx < 0 {
|
if idx := strings.Index(address, ":"); idx < 0 {
|
||||||
c.Host = address
|
c.Host = address
|
||||||
|
|
||||||
@ -70,6 +72,7 @@ func (c *Client) connect() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
c.connected = true
|
c.connected = true
|
||||||
|
c.ConnectionChanged <- true
|
||||||
c.reader = bufio.NewReader(c.conn)
|
c.reader = bufio.NewReader(c.conn)
|
||||||
|
|
||||||
c.register()
|
c.register()
|
||||||
@ -154,6 +157,7 @@ func (c *Client) recv() {
|
|||||||
return
|
return
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
c.ConnectionChanged <- false
|
||||||
c.lock.Lock()
|
c.lock.Lock()
|
||||||
c.connected = false
|
c.connected = false
|
||||||
c.lock.Unlock()
|
c.lock.Unlock()
|
||||||
@ -181,6 +185,7 @@ func (c *Client) recv() {
|
|||||||
|
|
||||||
func (c *Client) close() {
|
func (c *Client) close() {
|
||||||
if c.Connected() {
|
if c.Connected() {
|
||||||
|
c.ConnectionChanged <- false
|
||||||
c.lock.Lock()
|
c.lock.Lock()
|
||||||
c.connected = false
|
c.connected = false
|
||||||
c.lock.Unlock()
|
c.lock.Unlock()
|
||||||
|
@ -31,13 +31,21 @@ func newIRCHandler(client *irc.Client, session *Session) *ircHandler {
|
|||||||
|
|
||||||
func (i *ircHandler) run() {
|
func (i *ircHandler) run() {
|
||||||
for {
|
for {
|
||||||
msg, ok := <-i.client.Messages
|
select {
|
||||||
if !ok {
|
case msg, ok := <-i.client.Messages:
|
||||||
i.session.deleteIRC(i.client.Host)
|
if !ok {
|
||||||
return
|
i.session.deleteIRC(i.client.Host)
|
||||||
}
|
return
|
||||||
|
}
|
||||||
|
|
||||||
i.dispatchMessage(msg)
|
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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,8 +8,9 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Session struct {
|
type Session struct {
|
||||||
irc map[string]*irc.Client
|
irc map[string]*irc.Client
|
||||||
ircLock sync.Mutex
|
connectionState map[string]bool
|
||||||
|
ircLock sync.Mutex
|
||||||
|
|
||||||
ws map[string]*wsConn
|
ws map[string]*wsConn
|
||||||
wsLock sync.Mutex
|
wsLock sync.Mutex
|
||||||
@ -20,9 +21,10 @@ type Session struct {
|
|||||||
|
|
||||||
func NewSession() *Session {
|
func NewSession() *Session {
|
||||||
return &Session{
|
return &Session{
|
||||||
irc: make(map[string]*irc.Client),
|
irc: make(map[string]*irc.Client),
|
||||||
ws: make(map[string]*wsConn),
|
connectionState: make(map[string]bool),
|
||||||
out: make(chan WSResponse, 32),
|
ws: make(map[string]*wsConn),
|
||||||
|
out: make(chan WSResponse, 32),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -37,12 +39,14 @@ func (s *Session) getIRC(server string) (*irc.Client, bool) {
|
|||||||
func (s *Session) setIRC(server string, i *irc.Client) {
|
func (s *Session) setIRC(server string, i *irc.Client) {
|
||||||
s.ircLock.Lock()
|
s.ircLock.Lock()
|
||||||
s.irc[server] = i
|
s.irc[server] = i
|
||||||
|
s.connectionState[server] = false
|
||||||
s.ircLock.Unlock()
|
s.ircLock.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Session) deleteIRC(server string) {
|
func (s *Session) deleteIRC(server string) {
|
||||||
s.ircLock.Lock()
|
s.ircLock.Lock()
|
||||||
delete(s.irc, server)
|
delete(s.irc, server)
|
||||||
|
delete(s.connectionState, server)
|
||||||
s.ircLock.Unlock()
|
s.ircLock.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,6 +58,24 @@ func (s *Session) numIRC() int {
|
|||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Session) getConnectionStates() map[string]bool {
|
||||||
|
s.ircLock.Lock()
|
||||||
|
state := make(map[string]bool, len(s.connectionState))
|
||||||
|
|
||||||
|
for k, v := range s.connectionState {
|
||||||
|
state[k] = v
|
||||||
|
}
|
||||||
|
s.ircLock.Unlock()
|
||||||
|
|
||||||
|
return state
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Session) setConnectionState(server string, connected bool) {
|
||||||
|
s.ircLock.Lock()
|
||||||
|
s.connectionState[server] = connected
|
||||||
|
s.ircLock.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Session) setWS(addr string, w *wsConn) {
|
func (s *Session) setWS(addr string, w *wsConn) {
|
||||||
s.wsLock.Lock()
|
s.wsLock.Lock()
|
||||||
s.ws[addr] = w
|
s.ws[addr] = w
|
||||||
|
@ -71,6 +71,7 @@ func (h *wsHandler) init(uuid string) {
|
|||||||
|
|
||||||
h.session.sendJSON("channels", channels)
|
h.session.sendJSON("channels", channels)
|
||||||
h.session.sendJSON("servers", h.session.user.GetServers())
|
h.session.sendJSON("servers", h.session.user.GetServers())
|
||||||
|
h.session.sendJSON("connection_update", h.session.getConnectionStates())
|
||||||
|
|
||||||
for _, channel := range channels {
|
for _, channel := range channels {
|
||||||
h.session.sendJSON("users", Userlist{
|
h.session.sendJSON("users", Userlist{
|
||||||
|
Loading…
Reference in New Issue
Block a user