* @param {function(string, string): void} output
* @param {function(string[], function(string): void): void} attachCloseHandler
* @param {boolean=} needsFiltering
- * @param {boolean=} notificationOnly
+ * @param {boolean=} allowLocalOnly
* @return {function(string): void}
*/
- const streamFrom = (ids, req, output, attachCloseHandler, needsFiltering = false, notificationOnly = false, allowLocalOnly = false) => {
- const streamFrom = (ids, req, output, attachCloseHandler, needsFiltering = false) => {
++ const streamFrom = (ids, req, output, attachCloseHandler, needsFiltering = false, allowLocalOnly = false) => {
const accountId = req.accountId || req.remoteAddress;
- const streamType = notificationOnly ? ' (notification)' : '';
- log.verbose(req.requestId, `Starting stream from ${ids.join(', ')} for ${accountId}${streamType}`);
+ log.verbose(req.requestId, `Starting stream from ${ids.join(', ')} for ${accountId}`);
const listener = message => {
const json = parseJSON(message);
output(event, encodedPayload);
};
- if (notificationOnly && event !== 'notification') {
- return;
- }
-
- if (event === 'notification' && !req.allowNotifications) {
- return;
- }
-
+ // Only send local-only statuses to logged-in users
+ if (event === 'update' && payload.local_only && !(req.accountId && allowLocalOnly)) {
+ log.silly(req.requestId, `Message ${payload.id} filtered because it was local-only`);
+ return;
+ }
+
// Only messages that may require filtering are statuses, since notifications
// are already personalized and deletes do not matter
if (!needsFiltering || event !== 'update') {
const onSend = streamToHttp(req, res);
const onEnd = streamHttpEnd(req, subscriptionHeartbeat(channelIds));
- streamFrom(channelIds, req, onSend, onEnd, options.needsFiltering, options.notificationOnly, options.allowLocalOnly);
- streamFrom(channelIds, req, onSend, onEnd, options.needsFiltering);
++ streamFrom(channelIds, req, onSend, onEnd, options.needsFiltering, options.allowLocalOnly);
}).catch(err => {
log.verbose(req.requestId, 'Subscription error:', err.toString());
httpNotFound(res);
switch(name) {
case 'user':
resolve({
- channelIds: req.deviceId ? [`timeline:${req.accountId}`, `timeline:${req.accountId}:${req.deviceId}`] : [`timeline:${req.accountId}`],
- options: { needsFiltering: false, notificationOnly: false, allowLocalOnly: true },
+ channelIds: channelsForUserStream(req),
- options: { needsFiltering: false },
++ options: { needsFiltering: false, allowLocalOnly: true },
});
break;
case 'user:notification':
resolve({
- channelIds: [`timeline:${req.accountId}`],
- options: { needsFiltering: false, notificationOnly: true, allowLocalOnly: true },
+ channelIds: [`timeline:${req.accountId}:notifications`],
- options: { needsFiltering: false },
++ options: { needsFiltering: false, allowLocalOnly: true },
});
break;
case 'public':
resolve({
channelIds: ['timeline:public'],
- options: { needsFiltering: true, notificationOnly: false, allowLocalOnly: isTruthy(params.allow_local_only) },
- options: { needsFiltering: true },
++ options: { needsFiltering: true, allowLocalOnly: isTruthy(params.allow_local_only) },
+ });
+
+ break;
+ case 'public:allow_local_only':
+ resolve({
+ channelIds: ['timeline:public'],
- options: { needsFiltering: true, notificationOnly: false, allowLocalOnly: true },
++ options: { needsFiltering: true, allowLocalOnly: true },
});
break;
case 'public:local':
resolve({
channelIds: ['timeline:public:local'],
- options: { needsFiltering: true, notificationOnly: false, allowLocalOnly: true },
- options: { needsFiltering: true },
++ options: { needsFiltering: true, allowLocalOnly: true },
});
break;
case 'public:remote':
resolve({
channelIds: ['timeline:public:remote'],
- options: { needsFiltering: true, notificationOnly: false, allowLocalOnly: false },
- options: { needsFiltering: true },
++ options: { needsFiltering: true, allowLocalOnly: false },
});
break;
case 'public:media':
resolve({
channelIds: ['timeline:public:media'],
- options: { needsFiltering: true, notificationOnly: false, allowLocalOnly: isTruthy(query.allow_local_only) },
- options: { needsFiltering: true },
++ options: { needsFiltering: true, allowLocalOnly: isTruthy(query.allow_local_only) },
+ });
+
+ break;
+ case 'public:allow_local_only:media':
+ resolve({
+ channelIds: ['timeline:public:media'],
- options: { needsFiltering: true, notificationsOnly: false, allowLocalOnly: true },
++ options: { needsFiltering: true, allowLocalOnly: true },
});
break;
case 'public:local:media':
resolve({
channelIds: ['timeline:public:local:media'],
- options: { needsFiltering: true, notificationOnly: false, allowLocalOnly: true },
- options: { needsFiltering: true },
++ options: { needsFiltering: true, allowLocalOnly: true },
});
break;
case 'public:remote:media':
resolve({
channelIds: ['timeline:public:remote:media'],
- options: { needsFiltering: true, notificationOnly: false, allowLocalOnly: false },
- options: { needsFiltering: true },
++ options: { needsFiltering: true, allowLocalOnly: false },
});
break;
case 'direct':
resolve({
channelIds: [`timeline:direct:${req.accountId}`],
- options: { needsFiltering: false, notificationOnly: false, allowLocalOnly: true },
- options: { needsFiltering: false },
++ options: { needsFiltering: false, allowLocalOnly: true },
});
break;
} else {
resolve({
channelIds: [`timeline:hashtag:${params.tag.toLowerCase()}`],
- options: { needsFiltering: true, notificationOnly: false, allowLocalOnly: true },
- options: { needsFiltering: true },
++ options: { needsFiltering: true, allowLocalOnly: true },
});
}
} else {
resolve({
channelIds: [`timeline:hashtag:${params.tag.toLowerCase()}:local`],
- options: { needsFiltering: true, notificationOnly: false, allowLocalOnly: true },
- options: { needsFiltering: true },
++ options: { needsFiltering: true, allowLocalOnly: true },
});
}
authorizeListAccess(params.list, req).then(() => {
resolve({
channelIds: [`timeline:list:${params.list}`],
- options: { needsFiltering: false, notificationOnly: false, allowLocalOnly: true },
- options: { needsFiltering: false },
++ options: { needsFiltering: false, allowLocalOnly: true },
});
}).catch(() => {
reject('Not authorized to stream this list');
const onSend = streamToWs(request, socket, streamNameFromChannelName(channelName, params));
const stopHeartbeat = subscriptionHeartbeat(channelIds);
- const listener = streamFrom(channelIds, request, onSend, undefined, options.needsFiltering, options.notificationOnly, options.allowLocalOnly);
- const listener = streamFrom(channelIds, request, onSend, undefined, options.needsFiltering);
++
++ const listener = streamFrom(channelIds, request, onSend, undefined, options.needsFiltering, options.allowLocalOnly);
subscriptions[channelIds.join(';')] = {
listener,