无效的频道名称-可能是什么原因造成的?

时间:2019-01-28 16:42:29

标签: node.js debugging npm lodash npm-start

我正在一个将带有聊天框的网站上工作,基本上它具有一堆用于不同语言的频道,一个主持人频道和一个公告频道。

我遇到了一个错误[join] invalid channel name,由于我对编码/开发非常陌生,所以我认为我会分享我的代码,希望这里的人可以告诉我我在哪里搞砸了。

CHAT.JS

var assert   =  require('assert');
var CBuffer  =  require('CBuffer');
var events   =  require('events');
var util     =  require('util');
var _        =  require('lodash');
var debug    =  require('debug')('app:chat');

var db       =  require('./database');
var lib      =  require('./lib');


//Mute users by ip/username and store muted users in the database

var CHAT_HISTORY_SIZE = 100;

var SPECIAL_CHANNELS = {
    all: {
        desc: 'Channel where all messages are broadcasted, read only',
        writable: false,
        modsOnly: false
    },

    moderators: {
        desc: 'Channel for moderators only, they are joinedds',
        writable: true,
        modsOnly: true
    }

    //This is the behaviour for all the other channels:
    //defaultProps: {
    //    desc: '',
    //    writable: true,
    //    modsOnly: false
    //}
};

// There is a mods channel for every channel
// The mods are joined to a channel called mod:channelName

function Chat(io) {
    var self = this;

    self.io = io;

    // Number of connected clients
    self.clientCount = 0;

    /*
     Collection of muted users.
     key:   Username
     value: Object with the following fields
     time:       Date object when the user was muted
     moderator:  The username of the moderator that muted the user
     timespec:   Initial (nominal diff) time the user has been muted
     end:        Until when the user is muted
     shadow:     If the mute is a shadow mute
     */
    self.muted = {};

    io.on('connection', onConnection);

    function onConnection(socket) {  //socket.user is attached on the login middleware
        debug('socket connection event received');

        //Attach disconnect handler
        socket.on('disconnect', function() {
            --self.clientCount;
            console.log('Client disconnect, left: ', self.clientCount);
            debug('client disconnect');
        });

        //Join to a Room
        socket.on('join', function(channelName) {
            debug('join event received from user %s', socket.user ? socket.user.username : '~guest~');
            self.join(socket, channelName);
        });

        //Register the message event
        socket.on('say', function(message, isBot, customChannelName) {
            self.onSay(socket, message, isBot, customChannelName);
        });

        ++self.clientCount;
        console.log('Client joined: ', self.clientCount, ' - ', socket.user ? socket.user.username : '~guest~'); //TODO: Add ip address
    }

    events.EventEmitter.call(self); //Call event emitter 'constructor' function
}

util.inherits(Chat, events.EventEmitter);

Chat.prototype.join = function(socket, channelName) {
    var self = this;

    var moderator = socket.user && socket.user.moderator;

    //Check channelName variable and avoid users to join the mods channel
    **if(isChannelNameInvalid(channelName) || isChannelNameModsOnly(channelName))
        return sendError(socket, '[join] Invalid channel name');**

    //Check if the channel is moderators only
    if(SPECIAL_CHANNELS.hasOwnProperty(channelName))
        if(SPECIAL_CHANNELS[channelName].modsOnly && !moderator)
            return sendError(socket, '[join] This channel is moderators only');

    //Check if the user was joined to another room before, if it was leave that room
    if(socket.currentChannel)
        socket.leave(socket.currentChannel);

    //If mod leave the mods channel for this channel
    if(socket.modCurrentChannel)
        socket.leave(socket.modCurrentChannel);

    //Save the name of the current room in the socket, this can also be used to check if the user is joined into a channel
    socket.currentChannel = channelName;

    //Get user history of a room and send it to the user
    self.getHistory(channelName, function(err, history) {

        //If we couldn't reach the history send an empty history to the user
        if(err) {
            history = [];
        }

        var res = {
            history: history,
            username: socket.user ? socket.user.username : null,
            channel: channelName,
            moderator: moderator
        };

        //Actually join the socket.io room
        socket.join(channelName);

        //If the user is mod and is not on the mods channel join him to the channel mod:channelName
        if(moderator && channelName !== 'moderators') {
            var chan = 'mod:'+channelName;
            socket.join(chan);
            socket.modCurrentChannel = chan;
        }

        //Return join info to the user
        socket.emit('join', res);
    });

};

Chat.prototype.onSay = function(socket, message, isBot, customChannelName) {
    if (!socket.user)
        return sendError(socket, '[say] you must be logged in to chat');

    if (!socket.currentChannel)
        return sendError(socket, '[say] you must be joined before you can chat');

    //Check if the message is for a custom channel
    var channelName;
    if(customChannelName)
        if(isChannelNameInvalid(customChannelName))
            return sendError(socket, '[say] invalid channel name');
        else
            channelName = customChannelName;
    else
        channelName = socket.currentChannel;

    //Check if the message is for a non writable channel ('all')
    if(SPECIAL_CHANNELS.hasOwnProperty(channelName) && !SPECIAL_CHANNELS[channelName].writable)
        return sendErrorChat(socket, 'The all channel is read only');

    //Message validation
    message = message.trim();

    if (typeof message !== 'string')
        return sendError(socket, '[say] no message');

    if (message.length == 0 || message.length > 500)
        return sendError(socket, '[say] invalid message size');

    var cmdReg = /^\/([a-zA-z]*)\s*(.*)$/;
    var cmdMatch = message.match(cmdReg);

    if (cmdMatch) //If the message is a command try to execute it
        this.doChatCommand(socket.user, cmdMatch, channelName, socket);
    else //If not broadcast the message
        this.say(socket, socket.user, message, channelName, isBot);

};

Chat.prototype.doChatCommand = function(user, cmdMatch, channelName, socket) {
    var self = this;

    var cmd  = cmdMatch[1];
    var rest = cmdMatch[2];

    switch (cmd) {
        case 'shutdown':
            return sendErrorChat(socket, '[shutdown] deprecated feature boss');
        case 'mute':
        case 'shadowmute':
            if (user.moderator) {
                var muteReg = /^\s*([a-zA-Z0-9_\-]+)\s*([1-9]\d*[dhms])?\s*$/;
                var muteMatch = rest.match(muteReg);

                if (!muteMatch)
                    return sendErrorChat(socket, 'Usage: /mute <user> [time]');

                var username = muteMatch[1];
                var timespec = muteMatch[2] ? muteMatch[2] : "30m";
                var shadow   = cmd === 'shadowmute';

                self.mute(shadow, user, username, timespec, channelName,
                    function (err) {
                        if (err)
                            return sendErrorChat(socket, err);
                    });
            } else {
                return sendErrorChat(socket, '[mute] Not a moderator.');
            }
            break;
        case 'unmute':
            if (user.moderator) {
                var unmuteReg = /^\s*([a-zA-Z0-9_\-]+)\s*$/;
                var unmuteMatch = rest.match(unmuteReg);

                if (!unmuteMatch)
                    return sendErrorChat(socket, 'Usage: /unmute <user>');

                var username = unmuteMatch[1];
                self.unmute(
                    user, username, channelName,
                    function (err) {
                        if (err) return sendErrorChat(socket, err);
                    });
            }
            break;
        default:
            sendErrorChat(socket, 'Unknown command ' + cmd);
            break;
    }
};

Chat.prototype.getHistory = function (channelName, callback) {
    if(channelName === 'all')
        db.getAllChatTable(CHAT_HISTORY_SIZE, fn);
    else
        db.getChatTable(CHAT_HISTORY_SIZE, channelName, fn);

    function fn (err, history) {
        if(err) {
            console.error('[INTERNAL_ERROR] got error ', err, ' loading chat table');
            return callback(err);
        }

        callback(null, history);
    }
};

Chat.prototype.say = function(socket, user, message, channelName, isBot) {
    var self = this;

    var date = new Date();

    isBot = !!isBot;

    var msg = {
        date:      date,
        type:      'say',
        username:  user.username,
        role:      user.userclass,
        message:   message,
        bot:       isBot,
        channelName: channelName
    };

    //Check if the user is muted
    if (lib.hasOwnProperty(self.muted, user.username)) {
        var muted = self.muted[user.username];
        if (muted.end < date) {
            // User has been muted before, but enough time has passed.
            delete self.muted[user.username];
        } else if (muted.shadow) {
            // User is shadow muted. Echo the message back to the
            // user but don't broadcast.
            self.sendMessageToUser(socket, msg);
            return;
        } else {
            self.sendMessageToUser(socket, {
                date:      date,
                type:      'info',
                username:  user.username,
                role:      user.userclass,
                message:   'You\'re muted. ' + lib.printTimeString(muted.end - date) + ' remaining',
                bot:       false,
                channelName: channelName
            });
            return;
        }
    }

    self.sendMessageToChannel(channelName, msg, user.id);
};

/** Send a message to the user of this socket **/
Chat.prototype.sendMessageToUser = function(socket, msg) {
    socket.emit('msg', msg);
};

/** Send a message to a channel and to the all channel and store it in the database **/
Chat.prototype.sendMessageToChannel = function(channelName, msg, userID) {
    console.assert(msg.hasOwnProperty('bot') && msg.date, msg.hasOwnProperty('message') && msg.type);
    this.io.to(channelName).emit('msg', msg);
    this.io.to('all').emit('msg', msg);
    this.saveChatMessage(userID, msg.message, channelName, msg.bot, msg.date);
};

Chat.prototype.saveChatMessage = function(userId, message, channelName, isBot, date) {
    db.addChatMessage(userId, date, message, channelName, isBot, function(err) {
       if(err)
        console.error('[INTERNAL_ERROR] got error ', err, ' saving chat message of user id ', userId);
    });
};

Chat.prototype.mute = function(shadow, moderatorUser, username, time, channelName, callback) {
    var self = this;
    var now = new Date();
    var ms  = lib.parseTimeString(time);
    var end = new Date(Date.now() + ms);

    // Query the db to make sure that the username exists.
    db.getUserByName(username, function(err, userInfo) {

        if (err) {
            if(typeof err === 'string') //USERNAME_DOES_NOT_EXIST
                callback(err);
            else
                console.error('[INTERNAL_ERROR] got error ', err, ' muting user ', userInfo.username);
            return;
        }
        assert(userInfo);

        // Overriding previous mutes.
        self.muted[userInfo.username] = {
            date:        now,
            moderator:   moderatorUser.username,
            timespec:    time,
            end:         end,
            shadow:      shadow
        };

        var msg = {
            date:        now,
            type:        'mute',
            message: null,
            moderator:   moderatorUser.username,
            username:    userInfo.username,
            timespec:    time,
            shadow:      shadow,
            bot: false
        };

        //If mute shadow inform only mods about it
        if (shadow) {
            self.io.to('moderators').emit('msg', msg);
            self.io.to('mod:'+channelName).emit('msg', msg);
        //If regular mute send mute message to the channel
        } else {
            self.io.to(channelName).emit('msg', msg);
            self.io.to('moderators').emit('msg', msg);
        }

        callback(null);
    });
};

Chat.prototype.unmute = function(moderatorUser, username, channelName, callback) {
    var self = this;
    var now = new Date();

    if (!lib.hasOwnProperty(self.muted, username))
        return callback('USER_NOT_MUTED');

    var shadow = self.muted[username].shadow;
    delete self.muted[username];

    var msg = {
        date:      now,
        type:      'unmute',
        message: null,
        moderator: moderatorUser.username,
        username:  username,
        shadow:    shadow,
        bot: false
    };

    //If mute shadow inform only mods about it
    if (shadow) {
        self.io.to('moderators').emit('msg', msg);
        self.io.to('mod:'+channelName).emit('msg', msg);
        //If regular mute send mute message to the channel
    } else {
        self.io.to(channelName).emit('msg', msg);
        self.io.to('moderators').emit('msg', msg);
    }

    callback(null);
};

//Send an error to the chat to a client's socket
function sendErrorChat(socket, message) {
    socket.emit('msg', {
        date: new Date(),
        type: 'error',
        message: message
    });
}

//Send an error event to a client's socket
function sendError(socket, description) {
    console.warn('Chat client error ', description);
    socket.emit('err', description);
}

function isChannelNameInvalid(channelName) {
    return (typeof channelName !== 'string' || channelName.length < 1 || channelName.length > 100);
}

function isChannelNameModsOnly(channelName) {
    return /^mod:/.test(channelName);
}

module.exports = Chat;

1 个答案:

答案 0 :(得分:0)

好吧,我可能错了,但是我觉得那不是您编写的一段代码,因此您对幕后的情况缺乏深刻的了解。我建议您从头开始做一些事情,而不要从教程中复制内容,以对您使用的技术有更扎实的了解,但是您可以自由地遵循自己喜欢的任何方式。无论如何,错误显然是由方法给出的:

function isChannelNameInvalid(channelName) {
    return (typeof channelName !== 'string' || channelName.length < 1 || channelName.length > 100);
}

所以我想您应该为我们提供有关您使用的频道名称的更多信息。