Added basic mode support with op/voice and userlist sorting
This commit is contained in:
parent
0c2250b268
commit
721971cbb3
@ -11,6 +11,7 @@ var channelActions = Reflux.createActions([
|
|||||||
'removeUserAll',
|
'removeUserAll',
|
||||||
'setUsers',
|
'setUsers',
|
||||||
'setTopic',
|
'setTopic',
|
||||||
|
'setMode',
|
||||||
'load'
|
'load'
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@ -48,6 +49,10 @@ socket.on('topic', function(data) {
|
|||||||
channelActions.setTopic(data.topic, data.server, data.channel);
|
channelActions.setTopic(data.topic, data.server, data.channel);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
socket.on('mode', function(data) {
|
||||||
|
channelActions.setMode(data);
|
||||||
|
});
|
||||||
|
|
||||||
socket.on('channels', function(data) {
|
socket.on('channels', function(data) {
|
||||||
channelActions.load(data);
|
channelActions.load(data);
|
||||||
});
|
});
|
||||||
|
@ -14,7 +14,7 @@ var Chat = React.createClass({
|
|||||||
<MessageInput />
|
<MessageInput />
|
||||||
<UserList />
|
<UserList />
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ function dispatchCommand(cmd, channel, server) {
|
|||||||
switch (params[0].toLowerCase()) {
|
switch (params[0].toLowerCase()) {
|
||||||
case 'join':
|
case 'join':
|
||||||
if (params[1]) {
|
if (params[1]) {
|
||||||
channelActions.join(params[1], server);
|
channelActions.join([params[1]], server);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ var UserList = React.createClass({
|
|||||||
var channel = this.state.channels[tab.server][tab.channel];
|
var channel = this.state.channels[tab.server][tab.channel];
|
||||||
if (channel) {
|
if (channel) {
|
||||||
users = _.map(channel.users, function(user) {
|
users = _.map(channel.users, function(user) {
|
||||||
return <p>{user}</p>;
|
return <p>{user.renderName}</p>;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,54 @@ function initChannel(server, channel) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function createUser(nick, mode) {
|
||||||
|
return updateRenderName({
|
||||||
|
nick: nick,
|
||||||
|
renderName: nick,
|
||||||
|
mode: mode || ''
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadUser(users, nick) {
|
||||||
|
var mode;
|
||||||
|
|
||||||
|
if (nick[0] === '@') {
|
||||||
|
mode = 'o';
|
||||||
|
} else if (nick[0] === '+') {
|
||||||
|
mode = 'v';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mode) {
|
||||||
|
nick = nick.slice(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
users.push(createUser(nick, mode));
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateRenderName(user) {
|
||||||
|
if (user.mode.indexOf('o') !== -1) {
|
||||||
|
user.renderName = '@' + user.nick;
|
||||||
|
} else if (user.mode.indexOf('v') !== -1) {
|
||||||
|
user.renderName = '+' + user.nick;
|
||||||
|
} else {
|
||||||
|
user.renderName = user.nick;
|
||||||
|
}
|
||||||
|
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
function sortUsers(server, channel) {
|
||||||
|
channels[server][channel].users.sort(function(a, b) {
|
||||||
|
if (a.renderName < b.renderName) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (a.renderName > b.renderName) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
var channelStore = Reflux.createStore({
|
var channelStore = Reflux.createStore({
|
||||||
init: function() {
|
init: function() {
|
||||||
this.listenToMany(actions);
|
this.listenToMany(actions);
|
||||||
@ -28,25 +76,34 @@ var channelStore = Reflux.createStore({
|
|||||||
|
|
||||||
addUser: function(user, server, channel) {
|
addUser: function(user, server, channel) {
|
||||||
initChannel(server, channel);
|
initChannel(server, channel);
|
||||||
channels[server][channel].users.push(user);
|
channels[server][channel].users.push(createUser(user));
|
||||||
|
sortUsers(server, channel);
|
||||||
this.trigger(channels);
|
this.trigger(channels);
|
||||||
},
|
},
|
||||||
|
|
||||||
removeUser: function(user, server, channel) {
|
removeUser: function(user, server, channel) {
|
||||||
_.pull(channels[server][channel].users, user);
|
_.remove(channels[server][channel].users, { nick: user });
|
||||||
this.trigger(channels);
|
this.trigger(channels);
|
||||||
},
|
},
|
||||||
|
|
||||||
removeUserAll: function(user, server) {
|
removeUserAll: function(user, server) {
|
||||||
_.each(channels[server], function(channel) {
|
_.each(channels[server], function(channel) {
|
||||||
_.pull(channel.users, user);
|
_.remove(channel.users, { nick: user });
|
||||||
});
|
});
|
||||||
this.trigger(channels);
|
this.trigger(channels);
|
||||||
},
|
},
|
||||||
|
|
||||||
setUsers: function(users, server, channel) {
|
setUsers: function(users, server, channel) {
|
||||||
initChannel(server, channel);
|
initChannel(server, channel);
|
||||||
channels[server][channel].users = users;
|
var chan = channels[server][channel];
|
||||||
|
|
||||||
|
chan.users = [];
|
||||||
|
|
||||||
|
_.each(users, function(user) {
|
||||||
|
loadUser(chan.users, user);
|
||||||
|
});
|
||||||
|
|
||||||
|
sortUsers(server, channel);
|
||||||
this.trigger(channels);
|
this.trigger(channels);
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -55,12 +112,37 @@ var channelStore = Reflux.createStore({
|
|||||||
this.trigger(channels);
|
this.trigger(channels);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
setMode: function(mode) {
|
||||||
|
var user = _.find(channels[mode.server][mode.channel].users, { nick: mode.user });
|
||||||
|
if (user) {
|
||||||
|
_.each(mode.remove, function(mode) {
|
||||||
|
user.mode = user.mode.replace(mode, '');
|
||||||
|
});
|
||||||
|
_.each(mode.add, function(mode) {
|
||||||
|
user.mode += mode;
|
||||||
|
});
|
||||||
|
|
||||||
|
updateRenderName(user);
|
||||||
|
sortUsers(mode.server, mode.channel);
|
||||||
|
this.trigger(channels);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
load: function(storedChannels) {
|
load: function(storedChannels) {
|
||||||
_.each(storedChannels, function(channel) {
|
_.each(storedChannels, function(channel) {
|
||||||
initChannel(channel.server, channel.name);
|
initChannel(channel.server, channel.name);
|
||||||
channels[channel.server][channel.name].users = channel.users;
|
var chan = channels[channel.server][channel.name];
|
||||||
channels[channel.server][channel.name].topic = channel.topic;
|
|
||||||
|
chan.users = [];
|
||||||
|
chan.topic = channel.topic;
|
||||||
|
|
||||||
|
_.each(channel.users, function(user) {
|
||||||
|
loadUser(chan.users, user);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
sortUsers(channel.server, channel.name);
|
||||||
|
});
|
||||||
|
|
||||||
this.trigger(channels);
|
this.trigger(channels);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -26,6 +26,14 @@ type Join struct {
|
|||||||
Channels []string `json:"channels"`
|
Channels []string `json:"channels"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Mode struct {
|
||||||
|
Server string `json:"server"`
|
||||||
|
Channel string `json:"channel"`
|
||||||
|
User string `json:"user"`
|
||||||
|
Add string `json:"add"`
|
||||||
|
Remove string `json:"remove"`
|
||||||
|
}
|
||||||
|
|
||||||
type Quit struct {
|
type Quit struct {
|
||||||
Server string `json:"server"`
|
Server string `json:"server"`
|
||||||
User string `json:"user"`
|
User string `json:"user"`
|
||||||
|
@ -48,6 +48,19 @@ func handleMessages(irc *IRC, session *Session) {
|
|||||||
session.user.RemoveChannel(irc.Host, msg.Params[0])
|
session.user.RemoveChannel(irc.Host, msg.Params[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case MODE:
|
||||||
|
target := msg.Params[0]
|
||||||
|
if len(msg.Params) > 2 && isChannel(target) {
|
||||||
|
mode := parseMode(msg.Params[1])
|
||||||
|
mode.Server = irc.Host
|
||||||
|
mode.Channel = target
|
||||||
|
mode.User = msg.Params[2]
|
||||||
|
|
||||||
|
session.sendJSON("mode", mode)
|
||||||
|
|
||||||
|
channelStore.SetMode(irc.Host, target, msg.Params[2], mode.Add, mode.Remove)
|
||||||
|
}
|
||||||
|
|
||||||
case PRIVMSG, NOTICE:
|
case PRIVMSG, NOTICE:
|
||||||
if msg.Params[0] == irc.nick {
|
if msg.Params[0] == irc.nick {
|
||||||
session.sendJSON("pm", Chat{
|
session.sendJSON("pm", Chat{
|
||||||
@ -100,9 +113,9 @@ func handleMessages(irc *IRC, session *Session) {
|
|||||||
case RPL_NAMREPLY:
|
case RPL_NAMREPLY:
|
||||||
users := strings.Split(msg.Trailing, " ")
|
users := strings.Split(msg.Trailing, " ")
|
||||||
|
|
||||||
for i, user := range users {
|
/*for i, user := range users {
|
||||||
users[i] = strings.TrimLeft(user, "@+")
|
users[i] = strings.TrimLeft(user, "@+")
|
||||||
}
|
}*/
|
||||||
|
|
||||||
userBuffer := userBuffers[msg.Params[2]]
|
userBuffer := userBuffers[msg.Params[2]]
|
||||||
userBuffers[msg.Params[2]] = append(userBuffer, users...)
|
userBuffers[msg.Params[2]] = append(userBuffer, users...)
|
||||||
@ -142,6 +155,29 @@ func handleMessages(irc *IRC, session *Session) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func parseMode(mode string) *Mode {
|
||||||
|
m := Mode{}
|
||||||
|
add := false
|
||||||
|
|
||||||
|
for _, c := range mode {
|
||||||
|
if c == '+' {
|
||||||
|
add = true
|
||||||
|
} else if c == '-' {
|
||||||
|
add = false
|
||||||
|
} else if add {
|
||||||
|
m.Add += string(c)
|
||||||
|
} else {
|
||||||
|
m.Remove += string(c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &m
|
||||||
|
}
|
||||||
|
|
||||||
|
func isChannel(s string) bool {
|
||||||
|
return strings.IndexAny(s, "&#+!") == 0
|
||||||
|
}
|
||||||
|
|
||||||
func printMessage(msg *Message, irc *IRC) {
|
func printMessage(msg *Message, irc *IRC) {
|
||||||
log.Println(irc.nick+":", msg.Prefix, msg.Command, msg.Params, msg.Trailing)
|
log.Println(irc.nick+":", msg.Prefix, msg.Command, msg.Params, msg.Trailing)
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package storage
|
package storage
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -74,6 +75,20 @@ func (c *ChannelStore) RemoveUserAll(user, server string) {
|
|||||||
c.userLock.Unlock()
|
c.userLock.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *ChannelStore) SetMode(server, channel, user, add, remove string) {
|
||||||
|
c.userLock.Lock()
|
||||||
|
|
||||||
|
if strings.Contains(add, "o") {
|
||||||
|
c.rename(server, channel, user, "@"+user)
|
||||||
|
} else if strings.Contains(add, "v") {
|
||||||
|
c.rename(server, channel, user, "+"+user)
|
||||||
|
} else if strings.IndexAny(remove, "ov") > -1 {
|
||||||
|
c.rename(server, channel, user, user)
|
||||||
|
}
|
||||||
|
|
||||||
|
c.userLock.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
func (c *ChannelStore) GetTopic(server, channel string) string {
|
func (c *ChannelStore) GetTopic(server, channel string) string {
|
||||||
c.topicLock.Lock()
|
c.topicLock.Lock()
|
||||||
defer c.topicLock.Unlock()
|
defer c.topicLock.Unlock()
|
||||||
@ -92,8 +107,21 @@ func (c *ChannelStore) SetTopic(topic, server, channel string) {
|
|||||||
c.topicLock.Unlock()
|
c.topicLock.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *ChannelStore) rename(server, channel, oldNick, newNick string) {
|
||||||
|
for i, u := range c.users[server][channel] {
|
||||||
|
u = strings.TrimLeft(u, "@+")
|
||||||
|
|
||||||
|
if u == oldNick {
|
||||||
|
c.users[server][channel][i] = newNick
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (c *ChannelStore) removeUser(user, server, channel string) {
|
func (c *ChannelStore) removeUser(user, server, channel string) {
|
||||||
for i, u := range c.users[server][channel] {
|
for i, u := range c.users[server][channel] {
|
||||||
|
u = strings.TrimLeft(u, "@+")
|
||||||
|
|
||||||
if u == user {
|
if u == user {
|
||||||
users := c.users[server][channel]
|
users := c.users[server][channel]
|
||||||
c.users[server][channel] = append(users[:i], users[i+1:]...)
|
c.users[server][channel] = append(users[:i], users[i+1:]...)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user