Added title bar and basic message and command input
This commit is contained in:
parent
508a04cf4c
commit
f42d6011c6
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,3 +1,4 @@
|
||||
bin/
|
||||
client/dist/
|
||||
client/node_modules/
|
||||
client/node_modules/
|
||||
data.db
|
@ -24,4 +24,4 @@
|
||||
"react-router": "~0.11.6",
|
||||
"react": "~0.12.2"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
var Reflux = require('reflux');
|
||||
|
||||
var sock = require('../socket.js')('/ws');
|
||||
|
||||
var channelActions = Reflux.createActions([
|
||||
@ -6,7 +7,9 @@ var channelActions = Reflux.createActions([
|
||||
'joined',
|
||||
'part',
|
||||
'parted',
|
||||
'quit',
|
||||
'setUsers',
|
||||
'setTopic',
|
||||
'load'
|
||||
]);
|
||||
|
||||
@ -26,10 +29,18 @@ sock.on('part', function(data) {
|
||||
channelActions.parted(data.user, data.server, data.channels[0]);
|
||||
});
|
||||
|
||||
sock.on('quit', function(data) {
|
||||
channelActions.quit(data.user, data.server);
|
||||
});
|
||||
|
||||
sock.on('users', function(data) {
|
||||
channelActions.setUsers(data.users, data.server, data.channel);
|
||||
});
|
||||
|
||||
sock.on('topic', function(data) {
|
||||
channelActions.setTopic(data.topic, data.server, data.channel);
|
||||
});
|
||||
|
||||
sock.on('channels', function(data) {
|
||||
channelActions.load(data);
|
||||
});
|
||||
|
@ -1,13 +1,19 @@
|
||||
var Reflux = require('reflux');
|
||||
|
||||
var sock = require('../socket.js')('/ws');
|
||||
|
||||
var messageActions = Reflux.createActions([
|
||||
'send',
|
||||
'add',
|
||||
'selectTab'
|
||||
]);
|
||||
|
||||
messageActions.send.preEmit = function() {
|
||||
|
||||
messageActions.send.preEmit = function(message, to, server) {
|
||||
sock.send('chat', {
|
||||
server: server,
|
||||
to: to,
|
||||
message: message
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = messageActions;
|
@ -1,4 +1,5 @@
|
||||
var Reflux = require('reflux');
|
||||
|
||||
var sock = require('../socket.js')('/ws');
|
||||
|
||||
var serverActions = Reflux.createActions([
|
||||
|
@ -26,7 +26,7 @@ sock.on('connect', function() {
|
||||
|
||||
channelActions.join({
|
||||
server: 'irc.freenode.net',
|
||||
channels: [ '#stuff', '#go-nuts' ]
|
||||
channels: [ '#stuff' ]
|
||||
});
|
||||
});
|
||||
|
||||
@ -35,7 +35,8 @@ channelActions.joined.listen(function(user, server, channel) {
|
||||
server: server,
|
||||
from: '',
|
||||
to: channel,
|
||||
message: user + ' joined the channel'
|
||||
message: user + ' joined the channel',
|
||||
type: 'info'
|
||||
});
|
||||
});
|
||||
|
||||
@ -44,7 +45,8 @@ channelActions.parted.listen(function(user, server, channel) {
|
||||
server: server,
|
||||
from: '',
|
||||
to: channel,
|
||||
message: user + ' left the channel'
|
||||
message: user + ' left the channel',
|
||||
type: 'info'
|
||||
});
|
||||
});
|
||||
|
||||
@ -56,15 +58,6 @@ sock.on('pm', function(data) {
|
||||
messageActions.add(data);
|
||||
});
|
||||
|
||||
sock.on('topic', function(data) {
|
||||
messageActions.add({
|
||||
server: data.server,
|
||||
from: '',
|
||||
to: data.channel,
|
||||
message: data.topic
|
||||
});
|
||||
});
|
||||
|
||||
sock.on('motd', function(data) {
|
||||
_.each(data.content.split('\n'), function(line) {
|
||||
messageActions.add({
|
||||
|
@ -1,15 +1,14 @@
|
||||
var React = require('react');
|
||||
|
||||
var TabList = require('./TabList.jsx');
|
||||
var MessageBox = require('./MessageBox.jsx');
|
||||
var UserList = require('./UserList.jsx');
|
||||
var Chat = require('./Chat.jsx');
|
||||
|
||||
var App = React.createClass({
|
||||
render: function() {
|
||||
return (
|
||||
<div>
|
||||
<TabList />
|
||||
<MessageBox />
|
||||
<UserList />
|
||||
<Chat />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
21
client/src/js/components/Chat.jsx
Normal file
21
client/src/js/components/Chat.jsx
Normal file
@ -0,0 +1,21 @@
|
||||
var React = require('react');
|
||||
|
||||
var ChatTitle = require('./ChatTitle.jsx');
|
||||
var MessageBox = require('./MessageBox.jsx');
|
||||
var MessageInput = require('./MessageInput.jsx');
|
||||
var UserList = require('./UserList.jsx');
|
||||
|
||||
var Chat = React.createClass({
|
||||
render: function() {
|
||||
return (
|
||||
<div>
|
||||
<ChatTitle />
|
||||
<MessageBox />
|
||||
<MessageInput />
|
||||
<UserList />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = Chat;
|
48
client/src/js/components/ChatTitle.jsx
Normal file
48
client/src/js/components/ChatTitle.jsx
Normal file
@ -0,0 +1,48 @@
|
||||
var React = require('react');
|
||||
var Reflux = require('reflux');
|
||||
|
||||
var channelStore = require('../stores/channel.js');
|
||||
var selectedTabStore = require('../stores/selectedTab.js');
|
||||
|
||||
var ChatTitle = React.createClass({
|
||||
mixins: [
|
||||
Reflux.connect(channelStore, 'channels'),
|
||||
Reflux.connect(selectedTabStore, 'selectedTab')
|
||||
],
|
||||
|
||||
getInitialState: function() {
|
||||
return {
|
||||
channels: channelStore.getState(),
|
||||
selectedTab: selectedTabStore.getState()
|
||||
};
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var tab = this.state.selectedTab;
|
||||
var title;
|
||||
|
||||
if (tab.channel) {
|
||||
var channel = this.state.channels[tab.server][tab.channel];
|
||||
if (channel) {
|
||||
title = tab.channel
|
||||
title += ' [';
|
||||
title += channel.users.length;
|
||||
title += ']';
|
||||
|
||||
if (channel.topic) {
|
||||
title += ': ' + channel.topic;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
title = tab.server;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="chat-title-bar">
|
||||
<span className="chat-title" title={title}>{title}</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = ChatTitle;
|
@ -1,6 +1,7 @@
|
||||
var React = require('react');
|
||||
var Reflux = require('reflux');
|
||||
var _ = require('lodash');
|
||||
|
||||
var messageStore = require('../stores/message.js');
|
||||
var selectedTabStore = require('../stores/selectedTab.js');
|
||||
|
||||
@ -32,7 +33,13 @@ var MessageBox = React.createClass({
|
||||
render: function() {
|
||||
var tab = this.state.selectedTab.channel || this.state.selectedTab.server;
|
||||
var messages = _.map(this.state.messages[tab], function(message) {
|
||||
return <p>{message.from ? message.from + ': ' : null}{message.message}</p>;
|
||||
var messageClass = 'message';
|
||||
switch (message.type) {
|
||||
case 'info':
|
||||
messageClass += ' message-info';
|
||||
break;
|
||||
}
|
||||
return <p className={messageClass}>{message.from ? message.from + ': ' : null}{message.message}</p>;
|
||||
});
|
||||
|
||||
return (
|
||||
|
65
client/src/js/components/MessageInput.jsx
Normal file
65
client/src/js/components/MessageInput.jsx
Normal file
@ -0,0 +1,65 @@
|
||||
var React = require('react');
|
||||
var Reflux = require('reflux');
|
||||
|
||||
var selectedTabStore = require('../stores/selectedTab.js');
|
||||
var messageActions = require('../actions/message.js');
|
||||
var channelActions = require('../actions/channel.js');
|
||||
|
||||
function dispatchCommand(cmd, channel, server) {
|
||||
var params = cmd.slice(1).split(' ');
|
||||
|
||||
switch (params[0].toLowerCase()) {
|
||||
case 'join':
|
||||
if (params[1]) {
|
||||
channelActions.join({
|
||||
server: server,
|
||||
channels: [params[1]]
|
||||
});
|
||||
}
|
||||
break;
|
||||
|
||||
case 'part':
|
||||
if (channel) {
|
||||
channelActions.part({
|
||||
server: server,
|
||||
channels: [channel]
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var MessageInput = React.createClass({
|
||||
mixins: [
|
||||
Reflux.connect(selectedTabStore, 'selectedTab')
|
||||
],
|
||||
|
||||
getInitialState: function() {
|
||||
return {
|
||||
selectedTab: selectedTabStore.getState()
|
||||
};
|
||||
},
|
||||
|
||||
handleKey: function(e) {
|
||||
if (e.which === 13 && e.target.value) {
|
||||
var tab = this.state.selectedTab;
|
||||
|
||||
if (e.target.value.charAt(0) === '/') {
|
||||
dispatchCommand(e.target.value, tab.channel, tab.server);
|
||||
} else {
|
||||
messageActions.send(e.target.value, tab.channel, tab.server);
|
||||
}
|
||||
e.target.value = '';
|
||||
}
|
||||
},
|
||||
|
||||
render: function() {
|
||||
return (
|
||||
<div className="message-input-wrap">
|
||||
<input className="message-input" type="text" onKeyDown={this.handleKey} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = MessageInput;
|
@ -1,6 +1,7 @@
|
||||
var React = require('react');
|
||||
var Reflux = require('reflux');
|
||||
var _ = require('lodash');
|
||||
|
||||
var channelStore = require('../stores/channel.js');
|
||||
var selectedTabStore = require('../stores/selectedTab.js');
|
||||
|
||||
@ -20,11 +21,14 @@ var UserList = React.createClass({
|
||||
render: function() {
|
||||
var users = null;
|
||||
var tab = this.state.selectedTab;
|
||||
|
||||
|
||||
if (tab.channel) {
|
||||
users = _.map(this.state.channels[tab.server][tab.channel].users, function(user) {
|
||||
return <p>{user}</p>;
|
||||
});
|
||||
var channel = this.state.channels[tab.server][tab.channel];
|
||||
if (channel) {
|
||||
users = _.map(channel.users, function(user) {
|
||||
return <p>{user}</p>;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
|
@ -1,4 +1,5 @@
|
||||
var EventEmitter = require('events').EventEmitter;
|
||||
|
||||
var _ = require('lodash');
|
||||
|
||||
var sockets = {};
|
||||
@ -8,7 +9,7 @@ function createSocket(path) {
|
||||
return sockets[path];
|
||||
} else {
|
||||
var ws = new WebSocket('ws://' + window.location.host + path);
|
||||
|
||||
|
||||
var sock = {
|
||||
send: function(type, data) {
|
||||
ws.send(JSON.stringify({ type: type, request: data }));
|
||||
|
@ -1,5 +1,6 @@
|
||||
var Reflux = require('reflux');
|
||||
var _ = require('lodash');
|
||||
|
||||
var actions = require('../actions/channel.js');
|
||||
|
||||
var channels = {};
|
||||
@ -36,16 +37,29 @@ var channelStore = Reflux.createStore({
|
||||
this.trigger(channels);
|
||||
},
|
||||
|
||||
quit: function(user, server) {
|
||||
_.each(channels[server], function(channel) {
|
||||
_.pull(channel.users, user);
|
||||
});
|
||||
this.trigger(channels);
|
||||
},
|
||||
|
||||
setUsers: function(users, server, channel) {
|
||||
initChannel(server, channel);
|
||||
channels[server][channel].users = users;
|
||||
this.trigger(channels);
|
||||
},
|
||||
|
||||
setTopic: function(topic, server, channel) {
|
||||
channels[server][channel].topic = topic;
|
||||
this.trigger(channels);
|
||||
},
|
||||
|
||||
load: function(storedChannels) {
|
||||
_.each(storedChannels, function(channel) {
|
||||
initChannel(channel.server, channel.name);
|
||||
channels[channel.server][channel.name].users = channel.users;
|
||||
channels[channel.server][channel.name].topic = channel.topic;
|
||||
});
|
||||
this.trigger(channels);
|
||||
},
|
||||
|
@ -1,25 +1,40 @@
|
||||
var Reflux = require('reflux');
|
||||
|
||||
var actions = require('../actions/message.js');
|
||||
|
||||
var messages = {};
|
||||
|
||||
function addMessage(message, dest) {
|
||||
if (!(dest in messages)) {
|
||||
messages[dest] = [message];
|
||||
} else {
|
||||
messages[dest].push(message);
|
||||
}
|
||||
}
|
||||
|
||||
var messageStore = Reflux.createStore({
|
||||
init: function() {
|
||||
this.listenToMany(actions);
|
||||
},
|
||||
|
||||
send: function(message, to, server) {
|
||||
addMessage({
|
||||
server: server,
|
||||
from: 'self',
|
||||
to: to,
|
||||
message: message
|
||||
}, to);
|
||||
|
||||
this.trigger(messages);
|
||||
},
|
||||
|
||||
add: function(message) {
|
||||
var dest = message.to || message.from;
|
||||
if (message.from.indexOf('.') !== -1) {
|
||||
dest = message.server;
|
||||
}
|
||||
|
||||
if (!(dest in messages)) {
|
||||
messages[dest] = [message];
|
||||
} else {
|
||||
messages[dest].push(message);
|
||||
}
|
||||
|
||||
addMessage(message, dest);
|
||||
this.trigger(messages);
|
||||
},
|
||||
|
||||
|
@ -1,11 +1,15 @@
|
||||
var Reflux = require('reflux');
|
||||
var _ = require('lodash');
|
||||
|
||||
var actions = require('../actions/tab.js');
|
||||
var channelActions = require('../actions/channel.js');
|
||||
|
||||
var selectedTab = {};
|
||||
|
||||
var selectedTabStore = Reflux.createStore({
|
||||
init: function() {
|
||||
this.listenToMany(actions);
|
||||
this.listenTo(channelActions.part, 'part');
|
||||
},
|
||||
|
||||
select: function(server, channel) {
|
||||
@ -14,6 +18,19 @@ var selectedTabStore = Reflux.createStore({
|
||||
this.trigger(selectedTab);
|
||||
},
|
||||
|
||||
part: function(data) {
|
||||
var self = this;
|
||||
if (data.server === selectedTab.server) {
|
||||
_.each(data.channels, function(channel) {
|
||||
if (channel === selectedTab.channel) {
|
||||
delete selectedTab.channel;
|
||||
self.trigger(selectedTab);
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
getState: function() {
|
||||
return selectedTab;
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
var Reflux = require('reflux');
|
||||
|
||||
var actions = require('../actions/server.js');
|
||||
|
||||
var servers = {};
|
||||
|
@ -1,6 +1,7 @@
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
@ -9,6 +10,14 @@ body {
|
||||
color: #FFF;
|
||||
}
|
||||
|
||||
input {
|
||||
font: 16px Inconsolata, sans-serif;
|
||||
background: rgba(0,0,0,0.25);
|
||||
color: #FFF;
|
||||
outline: none;
|
||||
border: none;
|
||||
}
|
||||
|
||||
p {
|
||||
line-height: 1.5;
|
||||
}
|
||||
@ -19,7 +28,7 @@ p {
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
right: 200px;
|
||||
padding: 20px;
|
||||
padding: 15px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
@ -31,23 +40,64 @@ p {
|
||||
color: #AAA;
|
||||
}
|
||||
|
||||
.messagebox {
|
||||
.chat-title-bar {
|
||||
position: fixed;
|
||||
left: 200px;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
right: 200px;
|
||||
padding: 20px;
|
||||
height: 50px;
|
||||
padding: 0 15px;
|
||||
line-height: 50px;
|
||||
background: rgba(0,0,0,0.25);
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.chat-title {
|
||||
|
||||
}
|
||||
|
||||
.messagebox {
|
||||
position: fixed;
|
||||
left: 200px;
|
||||
top: 50px;
|
||||
bottom: 50px;
|
||||
right: 200px;
|
||||
padding: 15px;
|
||||
overflow: auto;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.message {
|
||||
|
||||
}
|
||||
|
||||
.message-info {
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.message-input-wrap {
|
||||
position: fixed;
|
||||
left: 200px;
|
||||
bottom: 0px;
|
||||
right: 0;
|
||||
height: 50px;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.message-input {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
.userlist {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
bottom: 50px;
|
||||
right: 0;
|
||||
width: 200px;
|
||||
padding: 20px;
|
||||
padding: 15px;
|
||||
overflow: auto;
|
||||
}
|
@ -26,6 +26,11 @@ type Join struct {
|
||||
Channels []string `json:"channels"`
|
||||
}
|
||||
|
||||
type Quit struct {
|
||||
Server string `json:"server"`
|
||||
User string `json:"user"`
|
||||
}
|
||||
|
||||
type Chat struct {
|
||||
Server string `json:"server"`
|
||||
From string `json:"from"`
|
||||
|
@ -2,7 +2,7 @@ package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
"github.com/khlieng/irc/storage"
|
||||
@ -16,7 +16,7 @@ func handleMessages(irc *IRC, session *Session) {
|
||||
for msg := range irc.Messages {
|
||||
switch msg.Command {
|
||||
case JOIN:
|
||||
user := parseUser(msg.Prefix)
|
||||
user := msg.Prefix
|
||||
|
||||
session.sendJSON("join", Join{
|
||||
Server: irc.Host,
|
||||
@ -34,7 +34,7 @@ func handleMessages(irc *IRC, session *Session) {
|
||||
}
|
||||
|
||||
case PART:
|
||||
user := parseUser(msg.Prefix)
|
||||
user := msg.Prefix
|
||||
|
||||
session.sendJSON("part", Join{
|
||||
Server: irc.Host,
|
||||
@ -65,15 +65,18 @@ func handleMessages(irc *IRC, session *Session) {
|
||||
}
|
||||
|
||||
case QUIT:
|
||||
/*
|
||||
session.sendJSON("quit", Quit{
|
||||
Server: irc.Host,
|
||||
User: user,
|
||||
})
|
||||
*/
|
||||
user := msg.Prefix
|
||||
|
||||
session.sendJSON("quit", Quit{
|
||||
Server: irc.Host,
|
||||
User: user,
|
||||
})
|
||||
|
||||
channelStore.RemoveUserAll(user, irc.Host)
|
||||
|
||||
case RPL_WELCOME,
|
||||
RPL_YOURHOST,
|
||||
RPL_CREATED,
|
||||
RPL_LUSERCLIENT,
|
||||
RPL_LUSEROP,
|
||||
RPL_LUSERUNKNOWN,
|
||||
@ -92,6 +95,8 @@ func handleMessages(irc *IRC, session *Session) {
|
||||
Topic: msg.Trailing,
|
||||
})
|
||||
|
||||
channelStore.SetTopic(msg.Trailing, irc.Host, msg.Params[1])
|
||||
|
||||
case RPL_NAMREPLY:
|
||||
users := strings.Split(msg.Trailing, " ")
|
||||
|
||||
@ -138,10 +143,5 @@ func handleMessages(irc *IRC, session *Session) {
|
||||
}
|
||||
|
||||
func printMessage(msg *Message, irc *IRC) {
|
||||
fmt.Printf("%s: %s %s %s\n", irc.nick, msg.Prefix, msg.Command, msg.Params)
|
||||
|
||||
if msg.Trailing != "" {
|
||||
fmt.Println(msg.Trailing)
|
||||
}
|
||||
fmt.Println()
|
||||
log.Println(irc.nick+":", msg.Prefix, msg.Command, msg.Params, msg.Trailing)
|
||||
}
|
||||
|
@ -5,63 +5,98 @@ import (
|
||||
)
|
||||
|
||||
type ChannelStore struct {
|
||||
data map[string]map[string][]string
|
||||
lock sync.Mutex
|
||||
users map[string]map[string][]string
|
||||
userLock sync.Mutex
|
||||
|
||||
topic map[string]map[string]string
|
||||
topicLock sync.Mutex
|
||||
}
|
||||
|
||||
func NewChannelStore() *ChannelStore {
|
||||
return &ChannelStore{
|
||||
data: make(map[string]map[string][]string),
|
||||
users: make(map[string]map[string][]string),
|
||||
topic: make(map[string]map[string]string),
|
||||
}
|
||||
}
|
||||
|
||||
func (c *ChannelStore) GetUsers(server, channel string) []string {
|
||||
c.lock.Lock()
|
||||
c.userLock.Lock()
|
||||
|
||||
users := make([]string, len(c.data[server][channel]))
|
||||
copy(users, c.data[server][channel])
|
||||
users := make([]string, len(c.users[server][channel]))
|
||||
copy(users, c.users[server][channel])
|
||||
|
||||
c.lock.Unlock()
|
||||
c.userLock.Unlock()
|
||||
|
||||
return users
|
||||
}
|
||||
|
||||
func (c *ChannelStore) SetUsers(users []string, server, channel string) {
|
||||
c.lock.Lock()
|
||||
c.userLock.Lock()
|
||||
|
||||
if _, ok := c.data[server]; !ok {
|
||||
c.data[server] = make(map[string][]string)
|
||||
if _, ok := c.users[server]; !ok {
|
||||
c.users[server] = make(map[string][]string)
|
||||
}
|
||||
|
||||
c.data[server][channel] = users
|
||||
c.users[server][channel] = users
|
||||
|
||||
c.lock.Unlock()
|
||||
c.userLock.Unlock()
|
||||
}
|
||||
|
||||
func (c *ChannelStore) AddUser(user, server, channel string) {
|
||||
c.lock.Lock()
|
||||
c.userLock.Lock()
|
||||
|
||||
if _, ok := c.data[server]; !ok {
|
||||
c.data[server] = make(map[string][]string)
|
||||
if _, ok := c.users[server]; !ok {
|
||||
c.users[server] = make(map[string][]string)
|
||||
}
|
||||
|
||||
if users, ok := c.data[server][channel]; ok {
|
||||
c.data[server][channel] = append(users, user)
|
||||
if users, ok := c.users[server][channel]; ok {
|
||||
c.users[server][channel] = append(users, user)
|
||||
} else {
|
||||
c.data[server][channel] = []string{user}
|
||||
c.users[server][channel] = []string{user}
|
||||
}
|
||||
|
||||
c.lock.Unlock()
|
||||
c.userLock.Unlock()
|
||||
}
|
||||
|
||||
func (c *ChannelStore) RemoveUser(user, server, channel string) {
|
||||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
c.userLock.Lock()
|
||||
c.removeUser(user, server, channel)
|
||||
c.userLock.Unlock()
|
||||
}
|
||||
|
||||
for i, u := range c.data[server][channel] {
|
||||
func (c *ChannelStore) RemoveUserAll(user, server string) {
|
||||
c.userLock.Lock()
|
||||
|
||||
for channel, _ := range c.users[server] {
|
||||
c.removeUser(user, server, channel)
|
||||
}
|
||||
|
||||
c.userLock.Unlock()
|
||||
}
|
||||
|
||||
func (c *ChannelStore) GetTopic(server, channel string) string {
|
||||
c.topicLock.Lock()
|
||||
defer c.topicLock.Unlock()
|
||||
|
||||
return c.topic[server][channel]
|
||||
}
|
||||
|
||||
func (c *ChannelStore) SetTopic(topic, server, channel string) {
|
||||
c.topicLock.Lock()
|
||||
|
||||
if _, ok := c.topic[server]; !ok {
|
||||
c.topic[server] = make(map[string]string)
|
||||
}
|
||||
|
||||
c.topic[server][channel] = topic
|
||||
c.topicLock.Unlock()
|
||||
}
|
||||
|
||||
func (c *ChannelStore) removeUser(user, server, channel string) {
|
||||
for i, u := range c.users[server][channel] {
|
||||
if u == user {
|
||||
users := c.data[server][channel]
|
||||
c.data[server][channel] = append(users[:i], users[i+1:]...)
|
||||
users := c.users[server][channel]
|
||||
c.users[server][channel] = append(users[:i], users[i+1:]...)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ type Channel struct {
|
||||
Server string `json:"server"`
|
||||
Name string `json:"name"`
|
||||
Users []string `json:"users"`
|
||||
Topic string `json:"topic,omitempty"`
|
||||
}
|
||||
|
||||
type User struct {
|
||||
@ -99,7 +100,7 @@ func (u User) GetChannels() []Channel {
|
||||
}
|
||||
|
||||
func (u User) AddServer(server Server) {
|
||||
db.Update(func(tx *bolt.Tx) error {
|
||||
go db.Update(func(tx *bolt.Tx) error {
|
||||
b := tx.Bucket([]byte("Servers"))
|
||||
data, _ := json.Marshal(server)
|
||||
|
||||
@ -110,7 +111,7 @@ func (u User) AddServer(server Server) {
|
||||
}
|
||||
|
||||
func (u User) AddChannel(channel Channel) {
|
||||
db.Update(func(tx *bolt.Tx) error {
|
||||
go db.Update(func(tx *bolt.Tx) error {
|
||||
b := tx.Bucket([]byte("Channels"))
|
||||
data, _ := json.Marshal(channel)
|
||||
|
||||
@ -121,16 +122,25 @@ func (u User) AddChannel(channel Channel) {
|
||||
}
|
||||
|
||||
func (u User) RemoveServer(address string) {
|
||||
db.Update(func(tx *bolt.Tx) error {
|
||||
tx.Bucket([]byte("Channels")).Delete([]byte(u.UUID + ":" + address))
|
||||
go db.Update(func(tx *bolt.Tx) error {
|
||||
serverID := []byte(u.UUID + ":" + address)
|
||||
|
||||
tx.Bucket([]byte("Servers")).Delete(serverID)
|
||||
|
||||
b := tx.Bucket([]byte("Channels"))
|
||||
c := b.Cursor()
|
||||
|
||||
for k, _ := c.Seek(serverID); bytes.HasPrefix(k, serverID); k, _ = c.Next() {
|
||||
b.Delete(k)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func (u User) RemoveChannel(server, channel string) {
|
||||
db.Update(func(tx *bolt.Tx) error {
|
||||
tx.Bucket([]byte("Servers")).Delete([]byte(u.UUID + ":" + server + ":" + channel))
|
||||
go db.Update(func(tx *bolt.Tx) error {
|
||||
tx.Bucket([]byte("Channels")).Delete([]byte(u.UUID + ":" + server + ":" + channel))
|
||||
|
||||
return nil
|
||||
})
|
||||
|
@ -48,6 +48,7 @@ func handleWS(ws *websocket.Conn) {
|
||||
channels := session.user.GetChannels()
|
||||
for i, channel := range channels {
|
||||
channels[i].Users = channelStore.GetUsers(channel.Server, channel.Name)
|
||||
channels[i].Topic = channelStore.GetTopic(channel.Server, channel.Name)
|
||||
}
|
||||
|
||||
session.sendJSON("channels", channels)
|
||||
@ -106,6 +107,17 @@ func handleWS(ws *websocket.Conn) {
|
||||
irc.Part(data.Channels...)
|
||||
}
|
||||
|
||||
case "quit":
|
||||
var data Quit
|
||||
|
||||
json.Unmarshal(req.Request, &data)
|
||||
|
||||
if irc, ok := session.getIRC(data.Server); ok {
|
||||
channelStore.RemoveUserAll(irc.nick, data.Server)
|
||||
session.user.RemoveServer(data.Server)
|
||||
irc.Quit()
|
||||
}
|
||||
|
||||
case "chat":
|
||||
var data Chat
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user