我正在使用Node.js编写消息传递应用程序,我需要检测同一用户何时在一个组中发送N个连续消息(以避免垃圾邮件发送者)。我使用bacon.js Bus
我push
来自所有用户的传入消息。
消息如下所示:
{
"text": "My message",
"user": { "id": 1, name: "Pep" }
}
到目前为止,这是我的工作代码:
const Bacon = require('baconjs')
const bus = new Bacon.Bus();
const CONSECUTIVE_MESSAGES = 5;
bus.slidingWindow(CONSECUTIVE_MESSAGES)
.filter((messages) => {
return messages.length === MAX_CONSECUTIVE_MESSAGES &&
_.uniqBy(messages, 'user.id').length === 1;
})
.onValue((messages) => {
console.log(`User ${__.last(messages).user.id}`);
});
// ... on every message
bus.push(message);
它创建一个滑动窗口,仅保留我想要检测的连续消息的数字。在每个事件上,只有当窗口中的所有消息属于同一用户时,它才会过滤数组以使数据流向下一步。最后,在onValue
中,最后一条消息需要获取用户ID。
代码看起来很脏/很复杂:
filter
对于溪流来说看起来并不自然。当N 连续事件符合某些条件时,是否有更好的方法来发出事件? onValue
函数中是否有更好的方法只接收一个事件与用户(而不是一组消息)。有什么改进的想法吗?如果有帮助的话,我可以将它迁移到rxjs。
答案 0 :(得分:0)
可能以
开头latestMsgsP = bus.slidingWindow(CONSECUTIVE_MESSAGES)
.map(msgs => msgs.filter(msg => msgAge(msg) < AGE_LIMIT))
看看我们是否应该封锁某人
let blockedUserIdP = latestMsgsP.map(getUserToBlock)
你可以在哪里使用无耻的命令,例如
function getUserToBlock(msgs) {
if (msgs.length < CONSECUTIVE_MESSAGES) return
let prevUserId;
for (var i = 0; i < msgs.length; i++) {
let userId = msgs[i].user.id
if (prevUserId && prevUserId != userId) return
prevUserId = userId
}
return prevUserId
}
答案 1 :(得分:0)
请考虑尽早映射感兴趣的媒体资源,然后简化流中的其余部分。此外,随着阈值的增加,对滑动窗口中每个项目的相等性检查将无法很好地扩展。考虑改用scan
,这样您只需保留一个计数,当当前值和先前值不匹配时,该计数将重置。
bus
.map('.user.id')
.scan([0], ([n, a], b) => [a === b ? n + 1 : 1, b])
.filter(([n]) => n >= MAX_CONSECUTIVE_MESSAGES)
.onValue(([count, userId]) => void console.log(`User ${userId}`));