blob: a239ebe7b35918c4d2bdb445cf1de01ae2377d97 [file] [log] [blame]
var events = require('events')
var Promise = require('bluebird')
var syrup = require('stf-syrup')
var logger = require('../../../util/logger')
var wire = require('../../../wire')
var wireutil = require('../../../wire/util')
var grouputil = require('../../../util/grouputil')
var lifecycle = require('../../../util/lifecycle')
module.exports = syrup.serial()
.dependency(require('./solo'))
.dependency(require('./util/identity'))
.dependency(require('./service'))
.dependency(require('../support/router'))
.dependency(require('../support/push'))
.dependency(require('../support/sub'))
.dependency(require('../support/channels'))
.define(function(options, solo, ident, service, router, push, sub, channels) {
var log = logger.createLogger('device:plugins:group')
var currentGroup = null
var plugin = new events.EventEmitter()
plugin.get = Promise.method(function() {
if (!currentGroup) {
throw new grouputil.NoGroupError()
}
return currentGroup
})
plugin.join = function(newGroup, timeout, identifier) {
var joinNewGroup = function() {
currentGroup = newGroup;
log.important('Now owned by "%s".', currentGroup.email);
log.info('Subscribing to group channel "%s".', currentGroup.group);
channels.register(currentGroup.group, {
timeout: timeout || options.groupTimeout,
alias: solo.channel
});
sub.subscribe(currentGroup.group);
push.send([
wireutil.global,
wireutil.envelope(new wire.JoinGroupMessage(
options.serial,
currentGroup))
]);
plugin.emit('join', currentGroup, identifier);
return currentGroup;
};
return plugin.get().then(function() {
if (currentGroup.group !== newGroup.group) {
return plugin.leave('kick').then(function() {
return joinNewGroup();
});
}
return currentGroup;
}).catch(grouputil.NoGroupError, joinNewGroup);
};
plugin.keepalive = function() {
if (currentGroup) {
channels.keepalive(currentGroup.group)
}
}
plugin.leave = function(reason) {
return plugin.get()
.then(function(group) {
log.important('No longer owned by "%s"', group.email)
log.info('Unsubscribing from group channel "%s"', group.group)
channels.unregister(group.group)
sub.unsubscribe(group.group)
push.send([
wireutil.global
, wireutil.envelope(new wire.LeaveGroupMessage(
options.serial
, group
, reason
))
])
currentGroup = null
plugin.emit('leave', group)
return group
})
}
plugin.on('join', function() {
service.wake()
service.acquireWakeLock()
})
plugin.on('leave', function() {
service.pressKey('home')
service.thawRotation()
service.releaseWakeLock()
})
router
.on(wire.GroupMessage, function(channel, message) {
var reply = wireutil.reply(options.serial)
grouputil.match(ident, message.requirements)
.then(function() {
return plugin.join(message.owner, message.timeout)
})
.then(function() {
push.send([
channel
, reply.okay()
])
})
.catch(grouputil.RequirementMismatchError, function(err) {
push.send([
channel
, reply.fail(err.message)
])
})
.catch(grouputil.AlreadyGroupedError, function(err) {
push.send([
channel
, reply.fail(err.message)
])
})
})
.on(wire.AutoGroupMessage, function(channel, message) {
return plugin.join(message.owner, message.timeout, message.identifier)
.then(function() {
plugin.emit('autojoin', message.identifier, true)
})
.catch(grouputil.AlreadyGroupedError, function() {
plugin.emit('autojoin', message.identifier, false)
})
})
.on(wire.UngroupMessage, function(channel, message) {
var reply = wireutil.reply(options.serial)
grouputil.match(ident, message.requirements)
.then(function() {
return plugin.leave('ungroup_request')
})
.then(function() {
push.send([
channel
, reply.okay()
])
})
.catch(grouputil.NoGroupError, function(err) {
push.send([
channel
, reply.fail(err.message)
])
})
})
channels.on('timeout', function(channel) {
if (currentGroup && channel === currentGroup.group) {
plugin.leave('automatic_timeout')
}
})
lifecycle.observe(function() {
return plugin.leave('device_absent')
.catch(grouputil.NoGroupError, function() {
return true
})
})
return plugin
})