Revert "Remove channel reference counter"
This reverts commit d678fa56d1
. The
reference counter, flawed as it is, was masking far more issues than I
realized. It would require a more significant rearchitecture of the
code to remove it. Probably better to keep it and try to improve it for
now.
This commit is contained in:
parent
3262f7822f
commit
00e9acbe4d
|
@ -16,6 +16,10 @@ describe('KickbanModule', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
mockChannel = {
|
mockChannel = {
|
||||||
name: channelName,
|
name: channelName,
|
||||||
|
refCounter: {
|
||||||
|
ref() { },
|
||||||
|
unref() { }
|
||||||
|
},
|
||||||
logger: {
|
logger: {
|
||||||
log() { }
|
log() { }
|
||||||
},
|
},
|
||||||
|
@ -65,22 +69,11 @@ describe('KickbanModule', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
function patch(fn, after) {
|
|
||||||
let existing = kickban[fn];
|
|
||||||
kickban[fn] = async function () {
|
|
||||||
try {
|
|
||||||
await existing.apply(this, arguments)
|
|
||||||
} finally {
|
|
||||||
after();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
describe('#handleCmdBan', () => {
|
describe('#handleCmdBan', () => {
|
||||||
it('inserts a valid ban', done => {
|
it('inserts a valid ban', done => {
|
||||||
let kicked = false;
|
let kicked = false;
|
||||||
|
|
||||||
patch('banName', () => {
|
mockChannel.refCounter.unref = () => {
|
||||||
assert(kicked, 'Expected user to be kicked');
|
assert(kicked, 'Expected user to be kicked');
|
||||||
|
|
||||||
database.getDB().runTransaction(async tx => {
|
database.getDB().runTransaction(async tx => {
|
||||||
|
@ -97,7 +90,7 @@ describe('KickbanModule', () => {
|
||||||
|
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
};
|
||||||
|
|
||||||
mockChannel.users = [{
|
mockChannel.users = [{
|
||||||
getLowerName() {
|
getLowerName() {
|
||||||
|
@ -254,7 +247,7 @@ describe('KickbanModule', () => {
|
||||||
let firstUserKicked = false;
|
let firstUserKicked = false;
|
||||||
let secondUserKicked = false;
|
let secondUserKicked = false;
|
||||||
|
|
||||||
patch('banAll', () => {
|
mockChannel.refCounter.unref = () => {
|
||||||
assert(firstUserKicked, 'Expected banned user to be kicked');
|
assert(firstUserKicked, 'Expected banned user to be kicked');
|
||||||
assert(
|
assert(
|
||||||
secondUserKicked,
|
secondUserKicked,
|
||||||
|
@ -286,7 +279,7 @@ describe('KickbanModule', () => {
|
||||||
|
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
};
|
||||||
|
|
||||||
mockChannel.users = [{
|
mockChannel.users = [{
|
||||||
getLowerName() {
|
getLowerName() {
|
||||||
|
@ -320,7 +313,7 @@ describe('KickbanModule', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('inserts a valid range ban', done => {
|
it('inserts a valid range ban', done => {
|
||||||
patch('banIP', () => {
|
mockChannel.refCounter.unref = () => {
|
||||||
database.getDB().runTransaction(async tx => {
|
database.getDB().runTransaction(async tx => {
|
||||||
const ipBan = await tx.table('channel_bans')
|
const ipBan = await tx.table('channel_bans')
|
||||||
.where({
|
.where({
|
||||||
|
@ -335,7 +328,7 @@ describe('KickbanModule', () => {
|
||||||
|
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
};
|
||||||
|
|
||||||
kickban.handleCmdIPBan(
|
kickban.handleCmdIPBan(
|
||||||
mockUser,
|
mockUser,
|
||||||
|
@ -345,7 +338,7 @@ describe('KickbanModule', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('inserts a valid wide-range ban', done => {
|
it('inserts a valid wide-range ban', done => {
|
||||||
patch('banIP', () => {
|
mockChannel.refCounter.unref = () => {
|
||||||
database.getDB().runTransaction(async tx => {
|
database.getDB().runTransaction(async tx => {
|
||||||
const ipBan = await tx.table('channel_bans')
|
const ipBan = await tx.table('channel_bans')
|
||||||
.where({
|
.where({
|
||||||
|
@ -360,7 +353,7 @@ describe('KickbanModule', () => {
|
||||||
|
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
};
|
||||||
|
|
||||||
kickban.handleCmdIPBan(
|
kickban.handleCmdIPBan(
|
||||||
mockUser,
|
mockUser,
|
||||||
|
@ -372,7 +365,7 @@ describe('KickbanModule', () => {
|
||||||
it('inserts a valid IPv6 ban', done => {
|
it('inserts a valid IPv6 ban', done => {
|
||||||
const longIP = require('../../lib/utilities').expandIPv6('::abcd');
|
const longIP = require('../../lib/utilities').expandIPv6('::abcd');
|
||||||
|
|
||||||
patch('banAll', () => {
|
mockChannel.refCounter.unref = () => {
|
||||||
database.getDB().runTransaction(async tx => {
|
database.getDB().runTransaction(async tx => {
|
||||||
const ipBan = await tx.table('channel_bans')
|
const ipBan = await tx.table('channel_bans')
|
||||||
.where({
|
.where({
|
||||||
|
@ -387,7 +380,7 @@ describe('KickbanModule', () => {
|
||||||
|
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
};
|
||||||
|
|
||||||
database.getDB().runTransaction(async tx => {
|
database.getDB().runTransaction(async tx => {
|
||||||
await tx.table('aliases')
|
await tx.table('aliases')
|
||||||
|
@ -553,7 +546,7 @@ describe('KickbanModule', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('still adds the IP ban even if the name is already banned', done => {
|
it('still adds the IP ban even if the name is already banned', done => {
|
||||||
patch('banIP', () => {
|
mockChannel.refCounter.unref = () => {
|
||||||
database.getDB().runTransaction(async tx => {
|
database.getDB().runTransaction(async tx => {
|
||||||
const ipBan = await tx.table('channel_bans')
|
const ipBan = await tx.table('channel_bans')
|
||||||
.where({
|
.where({
|
||||||
|
@ -568,7 +561,7 @@ describe('KickbanModule', () => {
|
||||||
|
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
};
|
||||||
|
|
||||||
database.getDB().runTransaction(tx => {
|
database.getDB().runTransaction(tx => {
|
||||||
return tx.table('channel_bans')
|
return tx.table('channel_bans')
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
"author": "Calvin Montgomery",
|
"author": "Calvin Montgomery",
|
||||||
"name": "CyTube",
|
"name": "CyTube",
|
||||||
"description": "Online media synchronizer and chat",
|
"description": "Online media synchronizer and chat",
|
||||||
"version": "3.74.1",
|
"version": "3.74.2",
|
||||||
"repository": {
|
"repository": {
|
||||||
"url": "http://github.com/calzoneman/sync"
|
"url": "http://github.com/calzoneman/sync"
|
||||||
},
|
},
|
||||||
|
|
|
@ -14,6 +14,67 @@ const LOGGER = require('@calzoneman/jsli')('channel');
|
||||||
|
|
||||||
const USERCOUNT_THROTTLE = 10000;
|
const USERCOUNT_THROTTLE = 10000;
|
||||||
|
|
||||||
|
class ReferenceCounter {
|
||||||
|
constructor(channel) {
|
||||||
|
this.channel = channel;
|
||||||
|
this.channelName = channel.name;
|
||||||
|
this.refCount = 0;
|
||||||
|
this.references = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
ref(caller) {
|
||||||
|
if (caller) {
|
||||||
|
if (this.references.hasOwnProperty(caller)) {
|
||||||
|
this.references[caller]++;
|
||||||
|
} else {
|
||||||
|
this.references[caller] = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.refCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
unref(caller) {
|
||||||
|
if (caller) {
|
||||||
|
if (this.references.hasOwnProperty(caller)) {
|
||||||
|
this.references[caller]--;
|
||||||
|
if (this.references[caller] === 0) {
|
||||||
|
delete this.references[caller];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LOGGER.error("ReferenceCounter::unref() called by caller [" +
|
||||||
|
caller + "] but this caller had no active references! " +
|
||||||
|
`(channel: ${this.channelName})`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.refCount--;
|
||||||
|
this.checkRefCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
checkRefCount() {
|
||||||
|
if (this.refCount === 0) {
|
||||||
|
if (Object.keys(this.references).length > 0) {
|
||||||
|
LOGGER.error("ReferenceCounter::refCount reached 0 but still had " +
|
||||||
|
"active references: " +
|
||||||
|
JSON.stringify(Object.keys(this.references)) +
|
||||||
|
` (channel: ${this.channelName})`);
|
||||||
|
for (var caller in this.references) {
|
||||||
|
this.refCount += this.references[caller];
|
||||||
|
}
|
||||||
|
} else if (this.channel.users && this.channel.users.length > 0) {
|
||||||
|
LOGGER.error("ReferenceCounter::refCount reached 0 but still had " +
|
||||||
|
this.channel.users.length + " active users" +
|
||||||
|
` (channel: ${this.channelName})`);
|
||||||
|
this.refCount = this.channel.users.length;
|
||||||
|
} else {
|
||||||
|
this.channel.emit("empty");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function Channel(name) {
|
function Channel(name) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.uniqueName = name.toLowerCase();
|
this.uniqueName = name.toLowerCase();
|
||||||
|
@ -24,6 +85,7 @@ function Channel(name) {
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
this.users = [];
|
this.users = [];
|
||||||
|
this.refCounter = new ReferenceCounter(this);
|
||||||
this.flags = 0;
|
this.flags = 0;
|
||||||
this.id = 0;
|
this.id = 0;
|
||||||
this.ownerName = null;
|
this.ownerName = null;
|
||||||
|
@ -220,16 +282,17 @@ Channel.prototype.saveState = async function () {
|
||||||
|
|
||||||
Channel.prototype.checkModules = function (fn, args, cb) {
|
Channel.prototype.checkModules = function (fn, args, cb) {
|
||||||
const self = this;
|
const self = this;
|
||||||
|
const refCaller = `Channel::checkModules/${fn}`;
|
||||||
this.waitFlag(Flags.C_READY, function () {
|
this.waitFlag(Flags.C_READY, function () {
|
||||||
if (self.dead) return;
|
if (self.dead) return;
|
||||||
|
|
||||||
|
self.refCounter.ref(refCaller);
|
||||||
var keys = Object.keys(self.modules);
|
var keys = Object.keys(self.modules);
|
||||||
var next = function (err, result) {
|
var next = function (err, result) {
|
||||||
if (self.dead) return;
|
|
||||||
|
|
||||||
if (result !== ChannelModule.PASSTHROUGH) {
|
if (result !== ChannelModule.PASSTHROUGH) {
|
||||||
/* Either an error occured, or the module denied the user access */
|
/* Either an error occured, or the module denied the user access */
|
||||||
cb(err, result);
|
cb(err, result);
|
||||||
|
self.refCounter.unref(refCaller);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -237,6 +300,7 @@ Channel.prototype.checkModules = function (fn, args, cb) {
|
||||||
if (m === undefined) {
|
if (m === undefined) {
|
||||||
/* No more modules to check */
|
/* No more modules to check */
|
||||||
cb(null, ChannelModule.PASSTHROUGH);
|
cb(null, ChannelModule.PASSTHROUGH);
|
||||||
|
self.refCounter.unref(refCaller);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -275,32 +339,28 @@ Channel.prototype.notifyModules = function (fn, args) {
|
||||||
Channel.prototype.joinUser = function (user, data) {
|
Channel.prototype.joinUser = function (user, data) {
|
||||||
const self = this;
|
const self = this;
|
||||||
|
|
||||||
|
self.refCounter.ref("Channel::user");
|
||||||
self.waitFlag(Flags.C_READY, function () {
|
self.waitFlag(Flags.C_READY, function () {
|
||||||
|
|
||||||
/* User closed the connection before the channel finished loading */
|
/* User closed the connection before the channel finished loading */
|
||||||
if (user.socket.disconnected) {
|
if (user.socket.disconnected) {
|
||||||
return;
|
self.refCounter.unref("Channel::user");
|
||||||
}
|
|
||||||
|
|
||||||
if (self.dead) {
|
|
||||||
user.kick('Channel is not loaded');
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
user.channel = self;
|
user.channel = self;
|
||||||
user.waitFlag(Flags.U_LOGGED_IN, () => {
|
user.waitFlag(Flags.U_LOGGED_IN, () => {
|
||||||
if (self.dead) {
|
if (self.dead) {
|
||||||
user.kick('Channel is not loaded');
|
LOGGER.warn(
|
||||||
|
'Got U_LOGGED_IN for %s after channel already unloaded',
|
||||||
|
user.getName()
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (user.is(Flags.U_REGISTERED)) {
|
if (user.is(Flags.U_REGISTERED)) {
|
||||||
db.channels.getRank(self.name, user.getName(), (error, rank) => {
|
db.channels.getRank(self.name, user.getName(), (error, rank) => {
|
||||||
if (!error) {
|
if (!error) {
|
||||||
if (self.dead) {
|
|
||||||
user.kick('Channel is not loaded');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
user.setChannelRank(rank);
|
user.setChannelRank(rank);
|
||||||
user.setFlag(Flags.U_HAS_CHANNEL_RANK);
|
user.setFlag(Flags.U_HAS_CHANNEL_RANK);
|
||||||
if (user.inChannel()) {
|
if (user.inChannel()) {
|
||||||
|
@ -314,6 +374,13 @@ Channel.prototype.joinUser = function (user, data) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (user.socket.disconnected) {
|
||||||
|
self.refCounter.unref("Channel::user");
|
||||||
|
return;
|
||||||
|
} else if (self.dead) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
self.checkModules("onUserPreJoin", [user, data], function (err, result) {
|
self.checkModules("onUserPreJoin", [user, data], function (err, result) {
|
||||||
if (result === ChannelModule.PASSTHROUGH) {
|
if (result === ChannelModule.PASSTHROUGH) {
|
||||||
user.channel = self;
|
user.channel = self;
|
||||||
|
@ -322,6 +389,7 @@ Channel.prototype.joinUser = function (user, data) {
|
||||||
user.channel = null;
|
user.channel = null;
|
||||||
user.account.channelRank = 0;
|
user.account.channelRank = 0;
|
||||||
user.account.effectiveRank = user.account.globalRank;
|
user.account.effectiveRank = user.account.globalRank;
|
||||||
|
self.refCounter.unref("Channel::user");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -425,8 +493,8 @@ Channel.prototype.partUser = function (user) {
|
||||||
});
|
});
|
||||||
this.broadcastUsercount();
|
this.broadcastUsercount();
|
||||||
|
|
||||||
|
this.refCounter.unref("Channel::user");
|
||||||
user.die();
|
user.die();
|
||||||
if (this.users.length === 0) this.emit('empty');
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Channel.prototype.maybeResendUserlist = function maybeResendUserlist(user, newRank, oldRank) {
|
Channel.prototype.maybeResendUserlist = function maybeResendUserlist(user, newRank, oldRank) {
|
||||||
|
@ -587,14 +655,13 @@ Channel.prototype.sendUserJoin = function (users, user) {
|
||||||
Channel.prototype.readLog = function (cb) {
|
Channel.prototype.readLog = function (cb) {
|
||||||
const maxLen = 102400;
|
const maxLen = 102400;
|
||||||
const file = this.logger.filename;
|
const file = this.logger.filename;
|
||||||
|
this.refCounter.ref("Channel::readLog");
|
||||||
const self = this;
|
const self = this;
|
||||||
fs.stat(file, function (err, data) {
|
fs.stat(file, function (err, data) {
|
||||||
if (err) {
|
if (err) {
|
||||||
|
self.refCounter.unref("Channel::readLog");
|
||||||
return cb(err, null);
|
return cb(err, null);
|
||||||
}
|
}
|
||||||
if (self.dead) {
|
|
||||||
return cb(new Error('Channel unloaded'), null);
|
|
||||||
}
|
|
||||||
|
|
||||||
const start = Math.max(data.size - maxLen, 0);
|
const start = Math.max(data.size - maxLen, 0);
|
||||||
const end = data.size - 1;
|
const end = data.size - 1;
|
||||||
|
@ -610,6 +677,7 @@ Channel.prototype.readLog = function (cb) {
|
||||||
});
|
});
|
||||||
read.on("end", function () {
|
read.on("end", function () {
|
||||||
cb(null, buffer);
|
cb(null, buffer);
|
||||||
|
self.refCounter.unref("Channel::readLog");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -676,6 +744,10 @@ Channel.prototype.packInfo = function (isAdmin) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isAdmin) {
|
||||||
|
data.activeLockCount = this.refCounter.refCount;
|
||||||
|
}
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
var keys = Object.keys(this.modules);
|
var keys = Object.keys(this.modules);
|
||||||
keys.forEach(function (k) {
|
keys.forEach(function (k) {
|
||||||
|
|
|
@ -77,11 +77,10 @@ KickBanModule.prototype.onUserPostJoin = function (user) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const chan = this.channel;
|
const chan = this.channel;
|
||||||
|
const refCaller = "KickBanModule::onUserPostJoin";
|
||||||
user.waitFlag(Flags.U_LOGGED_IN, function () {
|
user.waitFlag(Flags.U_LOGGED_IN, function () {
|
||||||
|
chan.refCounter.ref(refCaller);
|
||||||
db.channels.isNameBanned(chan.name, user.getName(), function (err, banned) {
|
db.channels.isNameBanned(chan.name, user.getName(), function (err, banned) {
|
||||||
if (chan.dead) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!err && banned) {
|
if (!err && banned) {
|
||||||
user.kick("You are banned from this channel.");
|
user.kick("You are banned from this channel.");
|
||||||
if (chan.modules.chat) {
|
if (chan.modules.chat) {
|
||||||
|
@ -89,6 +88,7 @@ KickBanModule.prototype.onUserPostJoin = function (user) {
|
||||||
"name is banned)");
|
"name is banned)");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
chan.refCounter.unref(refCaller);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -226,9 +226,14 @@ KickBanModule.prototype.handleCmdBan = function (user, msg, _meta) {
|
||||||
var name = args.shift().toLowerCase();
|
var name = args.shift().toLowerCase();
|
||||||
var reason = args.join(" ");
|
var reason = args.join(" ");
|
||||||
|
|
||||||
|
const chan = this.channel;
|
||||||
|
chan.refCounter.ref("KickBanModule::handleCmdBan");
|
||||||
|
|
||||||
this.banName(user, name, reason).catch(error => {
|
this.banName(user, name, reason).catch(error => {
|
||||||
const message = error.message || error;
|
const message = error.message || error;
|
||||||
user.socket.emit("errorMsg", { msg: message });
|
user.socket.emit("errorMsg", { msg: message });
|
||||||
|
}).then(() => {
|
||||||
|
chan.refCounter.unref("KickBanModule::handleCmdBan");
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -252,9 +257,15 @@ KickBanModule.prototype.handleCmdIPBan = function (user, msg, _meta) {
|
||||||
}
|
}
|
||||||
var reason = args.join(" ");
|
var reason = args.join(" ");
|
||||||
|
|
||||||
|
const chan = this.channel;
|
||||||
|
chan.refCounter.ref("KickBanModule::handleCmdIPBan");
|
||||||
|
|
||||||
this.banAll(user, name, range, reason).catch(error => {
|
this.banAll(user, name, range, reason).catch(error => {
|
||||||
|
//console.log('!!!', error.stack);
|
||||||
const message = error.message || error;
|
const message = error.message || error;
|
||||||
user.socket.emit("errorMsg", { msg: message });
|
user.socket.emit("errorMsg", { msg: message });
|
||||||
|
}).then(() => {
|
||||||
|
chan.refCounter.unref("KickBanModule::handleCmdIPBan");
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -416,15 +427,14 @@ KickBanModule.prototype.handleUnban = function (user, data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
|
this.channel.refCounter.ref("KickBanModule::handleUnban");
|
||||||
db.channels.unbanId(this.channel.name, data.id, function (err) {
|
db.channels.unbanId(this.channel.name, data.id, function (err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
|
self.channel.refCounter.unref("KickBanModule::handleUnban");
|
||||||
return user.socket.emit("errorMsg", {
|
return user.socket.emit("errorMsg", {
|
||||||
msg: err
|
msg: err
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (self.channel.dead) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.sendUnban(self.channel.users, data);
|
self.sendUnban(self.channel.users, data);
|
||||||
self.channel.logger.log("[mod] " + user.getName() + " unbanned " + data.name);
|
self.channel.logger.log("[mod] " + user.getName() + " unbanned " + data.name);
|
||||||
|
@ -435,6 +445,7 @@ KickBanModule.prototype.handleUnban = function (user, data) {
|
||||||
banperm
|
banperm
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
self.channel.refCounter.unref("KickBanModule::handleUnban");
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -55,15 +55,18 @@ LibraryModule.prototype.handleUncache = function (user, data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const chan = this.channel;
|
const chan = this.channel;
|
||||||
|
chan.refCounter.ref("LibraryModule::handleUncache");
|
||||||
db.channels.deleteFromLibrary(chan.name, data.id, function (err, _res) {
|
db.channels.deleteFromLibrary(chan.name, data.id, function (err, _res) {
|
||||||
if (chan.dead) {
|
if (chan.dead) {
|
||||||
return;
|
return;
|
||||||
} else if (err) {
|
} else if (err) {
|
||||||
|
chan.refCounter.unref("LibraryModule::handleUncache");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
chan.logger.log("[library] " + user.getName() + " deleted " + data.id +
|
chan.logger.log("[library] " + user.getName() + " deleted " + data.id +
|
||||||
"from the library");
|
"from the library");
|
||||||
|
chan.refCounter.unref("LibraryModule::handleUncache");
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -47,8 +47,9 @@ MediaRefresherModule.prototype.initVimeo = function (data, cb) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const self = this;
|
const self = this;
|
||||||
|
self.channel.refCounter.ref("MediaRefresherModule::initVimeo");
|
||||||
Vimeo.extract(data.id).then(function (direct) {
|
Vimeo.extract(data.id).then(function (direct) {
|
||||||
if (self.channel.dead) {
|
if (self.dead || self.channel.dead) {
|
||||||
self.unload();
|
self.unload();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -62,11 +63,9 @@ MediaRefresherModule.prototype.initVimeo = function (data, cb) {
|
||||||
if (cb) cb();
|
if (cb) cb();
|
||||||
}).catch(function (err) {
|
}).catch(function (err) {
|
||||||
LOGGER.error("Unexpected vimeo::extract() fail: " + err.stack);
|
LOGGER.error("Unexpected vimeo::extract() fail: " + err.stack);
|
||||||
if (self.channel.dead) {
|
|
||||||
self.unload();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (cb) cb();
|
if (cb) cb();
|
||||||
|
}).finally(() => {
|
||||||
|
self.channel.refCounter.unref("MediaRefresherModule::initVimeo");
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -511,19 +511,19 @@ PlaylistModule.prototype.queueStandard = function (user, data) {
|
||||||
};
|
};
|
||||||
|
|
||||||
const self = this;
|
const self = this;
|
||||||
|
this.channel.refCounter.ref("PlaylistModule::queueStandard");
|
||||||
counters.add("playlist:queue:count", 1);
|
counters.add("playlist:queue:count", 1);
|
||||||
this.semaphore.queue(function (lock) {
|
this.semaphore.queue(function (lock) {
|
||||||
InfoGetter.getMedia(data.id, data.type, function (err, media) {
|
InfoGetter.getMedia(data.id, data.type, function (err, media) {
|
||||||
if (err) {
|
if (err) {
|
||||||
error(XSS.sanitizeText(String(err)));
|
error(XSS.sanitizeText(String(err)));
|
||||||
return lock.release();
|
self.channel.refCounter.unref("PlaylistModule::queueStandard");
|
||||||
}
|
|
||||||
if (self.channel.dead) {
|
|
||||||
return lock.release();
|
return lock.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
self._addItem(media, data, user, function () {
|
self._addItem(media, data, user, function () {
|
||||||
lock.release();
|
lock.release();
|
||||||
|
self.channel.refCounter.unref("PlaylistModule::queueStandard");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -546,7 +546,7 @@ PlaylistModule.prototype.queueYouTubePlaylist = function (user, data) {
|
||||||
return lock.release();
|
return lock.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (self.channel.dead) {
|
if (self.dead) {
|
||||||
return lock.release();
|
return lock.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -562,6 +562,8 @@ PlaylistModule.prototype.queueYouTubePlaylist = function (user, data) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.channel.refCounter.ref("PlaylistModule::queueYouTubePlaylist");
|
||||||
|
|
||||||
if (self.channel.modules.library && data.shouldAddToLibrary) {
|
if (self.channel.modules.library && data.shouldAddToLibrary) {
|
||||||
self.channel.modules.library.cacheMediaList(vids);
|
self.channel.modules.library.cacheMediaList(vids);
|
||||||
data.shouldAddToLibrary = false;
|
data.shouldAddToLibrary = false;
|
||||||
|
@ -572,6 +574,8 @@ PlaylistModule.prototype.queueYouTubePlaylist = function (user, data) {
|
||||||
self._addItem(media, data, user);
|
self._addItem(media, data, user);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
self.channel.refCounter.unref("PlaylistModule::queueYouTubePlaylist");
|
||||||
|
|
||||||
lock.release();
|
lock.release();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -589,6 +593,7 @@ PlaylistModule.prototype.handleDelete = function (user, data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var plitem = this.items.find(data);
|
var plitem = this.items.find(data);
|
||||||
|
self.channel.refCounter.ref("PlaylistModule::handleDelete");
|
||||||
this.semaphore.queue(function (lock) {
|
this.semaphore.queue(function (lock) {
|
||||||
if (self._delete(data)) {
|
if (self._delete(data)) {
|
||||||
self.channel.logger.log("[playlist] " + user.getName() + " deleted " +
|
self.channel.logger.log("[playlist] " + user.getName() + " deleted " +
|
||||||
|
@ -596,6 +601,7 @@ PlaylistModule.prototype.handleDelete = function (user, data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
lock.release();
|
lock.release();
|
||||||
|
self.channel.refCounter.unref("PlaylistModule::handleDelete");
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -631,24 +637,26 @@ PlaylistModule.prototype.handleMoveMedia = function (user, data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const self = this;
|
const self = this;
|
||||||
|
self.channel.refCounter.ref("PlaylistModule::handleMoveMedia");
|
||||||
self.semaphore.queue(function (lock) {
|
self.semaphore.queue(function (lock) {
|
||||||
if (self.channel.dead) {
|
|
||||||
return lock.release();
|
|
||||||
}
|
|
||||||
if (!self.items.remove(data.from)) {
|
if (!self.items.remove(data.from)) {
|
||||||
|
self.channel.refCounter.unref("PlaylistModule::handleMoveMedia");
|
||||||
return lock.release();
|
return lock.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.after === "prepend") {
|
if (data.after === "prepend") {
|
||||||
if (!self.items.prepend(from)) {
|
if (!self.items.prepend(from)) {
|
||||||
|
self.channel.refCounter.unref("PlaylistModule::handleMoveMedia");
|
||||||
return lock.release();
|
return lock.release();
|
||||||
}
|
}
|
||||||
} else if (data.after === "append") {
|
} else if (data.after === "append") {
|
||||||
if (!self.items.append(from)) {
|
if (!self.items.append(from)) {
|
||||||
|
self.channel.refCounter.unref("PlaylistModule::handleMoveMedia");
|
||||||
return lock.release();
|
return lock.release();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!self.items.insertAfter(from, data.after)) {
|
if (!self.items.insertAfter(from, data.after)) {
|
||||||
|
self.channel.refCounter.unref("PlaylistModule::handleMoveMedia");
|
||||||
return lock.release();
|
return lock.release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -660,6 +668,7 @@ PlaylistModule.prototype.handleMoveMedia = function (user, data) {
|
||||||
(after ? " after " + after.media.title : ""));
|
(after ? " after " + after.media.title : ""));
|
||||||
self._listDirty = true;
|
self._listDirty = true;
|
||||||
lock.release();
|
lock.release();
|
||||||
|
self.channel.refCounter.unref("PlaylistModule::handleMoveMedia");
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1351,15 +1360,14 @@ PlaylistModule.prototype.handleQueuePlaylist = function (user, data) {
|
||||||
};
|
};
|
||||||
|
|
||||||
const self = this;
|
const self = this;
|
||||||
|
self.channel.refCounter.ref("PlaylistModule::handleQueuePlaylist");
|
||||||
db.getUserPlaylist(user.getName(), data.name, function (err, pl) {
|
db.getUserPlaylist(user.getName(), data.name, function (err, pl) {
|
||||||
if (err) {
|
if (err) {
|
||||||
|
self.channel.refCounter.unref("PlaylistModule::handleQueuePlaylist");
|
||||||
return user.socket.emit("errorMsg", {
|
return user.socket.emit("errorMsg", {
|
||||||
msg: "Playlist load failed: " + err
|
msg: "Playlist load failed: " + err
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (self.channel.dead) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (data.pos === "next") {
|
if (data.pos === "next") {
|
||||||
|
@ -1394,6 +1402,8 @@ PlaylistModule.prototype.handleQueuePlaylist = function (user, data) {
|
||||||
msg: "Internal error occurred when loading playlist.",
|
msg: "Internal error occurred when loading playlist.",
|
||||||
link: null
|
link: null
|
||||||
});
|
});
|
||||||
|
} finally {
|
||||||
|
self.channel.refCounter.unref("PlaylistModule::handleQueuePlaylist");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
@ -357,9 +357,11 @@ Server.prototype.unloadChannel = function (chan, options) {
|
||||||
|
|
||||||
LOGGER.info("Unloaded channel " + chan.name);
|
LOGGER.info("Unloaded channel " + chan.name);
|
||||||
chan.broadcastUsercount.cancel();
|
chan.broadcastUsercount.cancel();
|
||||||
// Empty all outward references from the channel | TODO does this actually help?
|
// Empty all outward references from the channel
|
||||||
Object.keys(chan).forEach(key => {
|
Object.keys(chan).forEach(key => {
|
||||||
delete chan[key];
|
if (key !== "refCounter") {
|
||||||
|
delete chan[key];
|
||||||
|
}
|
||||||
});
|
});
|
||||||
chan.dead = true;
|
chan.dead = true;
|
||||||
promActiveChannels.dec();
|
promActiveChannels.dec();
|
||||||
|
|
|
@ -421,6 +421,10 @@ function showChannelDetailModal(c) {
|
||||||
$("<td/>").text("Public").appendTo(tr);
|
$("<td/>").text("Public").appendTo(tr);
|
||||||
$("<td/>").text(c.public).appendTo(tr);
|
$("<td/>").text(c.public).appendTo(tr);
|
||||||
|
|
||||||
|
tr = $("<tr/>").appendTo(table);
|
||||||
|
$("<td/>").text("ActiveLock Count").appendTo(tr);
|
||||||
|
$("<td/>").text(c.activeLockCount).appendTo(tr);
|
||||||
|
|
||||||
tr = $("<tr/>").appendTo(table);
|
tr = $("<tr/>").appendTo(table);
|
||||||
$("<td/>").text("Chat Filter Count").appendTo(tr);
|
$("<td/>").text("Chat Filter Count").appendTo(tr);
|
||||||
$("<td/>").text(c.chatFilterCount).appendTo(tr);
|
$("<td/>").text(c.chatFilterCount).appendTo(tr);
|
||||||
|
|
Loading…
Reference in a new issue