baconjs:使用条件限制连续事件

时间:2018-04-14 08:36:38

标签: node.js reactive-programming bacon.js

我正在使用Node.js编写消息传递应用程序,我需要检测同一用户何时在一个组中发送N个连续消息(以避免垃圾邮件发送者)。我使用bacon.js Buspush来自所有用户的传入消息。

消息如下所示:

{
  "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。

代码看起来很脏/很复杂:

  1. filter对于溪流来说看起来并不自然。当N 连续事件符合某些条件时,是否有更好的方法来发出事件?
  2. onValue函数中是否有更好的方法只接收一个事件与用户(而不是一组消息)。
  3. 它并非真正节流。如果用户在一年内发送N条消息,则不应该检测到他或她。流应该以某种方式忘记旧事件。
  4. 有什么改进的想法吗?如果有帮助的话,我可以将它迁移到rxjs。

2 个答案:

答案 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}`));