如何使用参数化过滤创建类似Twitter的流API?

时间:2016-02-18 19:48:22

标签: python ruby node.js api tornado

我正在尝试开发一个与Twitter的流API(https://dev.twitter.com/streaming/reference/post/statuses/filter)具有相同功能的数据流API,即具有过滤功能的数据流。我正在生成大量数据,并希望将其提供给客户。

我了解如何制作一个为所有客户提供相同数据的应用。这相对容易。我遇到的困难来自于允许客户指定数据过滤器并为每个客户端提供唯一数据。

crude diagram

我的想法:

首先我想开一个流式http请求(比如Twitter)。我可以创建一个接受带参数的GET请求的端点(例如https://stream.example.com/v1/filter.json?track=twitter)。根据这个答案Streaming API vs Rest API?,这不容易扩展,需要大量资源。

然后我想使用websockets并让客户端提供过滤器消息(例如locations = -122.75,36.8,-121.75,37.8)。但是,我找不到一个WS服务器向每个客户端发送唯一数据的好例子。如果它继承了tornado.websocket.WebSocketHandler或类似的实现,那么这个类会是什么样子?

我还考虑将数据推送到消息服务(RabbitMQ)或数据库(Redis),并在客户端连接到其唯一通道时订阅它们。 (我想像这个问题Any ideas how to create parameterised streaming api?)。我不知道创建独特渠道的有效方法。这似乎也过于复杂了。

我更喜欢在Python中这样做,但我也会考虑使用Ruby和JS实现。

1 个答案:

答案 0 :(得分:1)

不太熟悉Python,但我认为这应该可以使用Websockets。这是我在Ruby中对它的看法,希望它有任何帮助。这些都是精简版本,删除了大部分websocket功能只是为了演示。

然而,关于使用流媒体API的最佳实践,我恐怕没有多大帮助。

服务器

require 'em-websocket'
require 'json'

def filtered_stream(filter, ws)
  loop do 
    # do something with filter, transform or send different kinds of data
    ws.send "#{filter} - hello"
    sleep 2
  end
end

EM.run {
  EM::WebSocket.run(:host => "127.0.0.1", :port => 9999) do |ws|
    ws.onopen { |handshake|
      # We can access some information in the handshake object such as headers
      # Perhaps even add the client to a list / table
    }

    ws.onmessage { |msg|
      # use ws.close to close the connection if needed
      # for example if the client attempts to send an invalid message or multiple messages?

      filter = JSON.parse(msg)['locations']
      Thread.new { filtered_stream(filter, ws) }
    }
  end
}

<强>客户端

require 'websocket-eventmachine-client'

EM.run do
  ws = WebSocket::EventMachine::Client.connect(
    :uri => 'ws://localhost:9999',
   )

  ws.onopen do
    # Unsure on how to supply the filter, headers is an option too

    ws.send "{\"locations\":\"-122.75,36.8,-121.75,37.8\"}"
  end

  ws.onmessage do |msg|
    p msg
  end
end