weibo_publish_agent.rb 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. module Agents
  2. class WeiboPublishAgent < Agent
  3. include WeiboConcern
  4. cannot_be_scheduled!
  5. description <<~MD
  6. The Weibo Publish Agent publishes tweets from the events it receives.
  7. #{'## Include `weibo_2` in your Gemfile to use this Agent!' if dependencies_missing?}
  8. You must first set up a Weibo app and generate an `access_token` for the user that will be used for posting status updates.
  9. You'll use that `access_token`, along with the `app_key` and `app_secret` for your Weibo app. You must also include the Weibo User ID (as `uid`) of the person to publish as.
  10. You must also specify a `message_path` parameter: a [JSONPaths](http://goessner.net/articles/JsonPath/) to the value to tweet.
  11. You can also specify a `pic_path` parameter: a [JSONPaths](http://goessner.net/articles/JsonPath/) to the picture url to tweet along.
  12. Set `expected_update_period_in_days` to the maximum amount of time that you'd expect to pass between Events being created by this Agent.
  13. MD
  14. def validate_options
  15. unless options['uid'].present? &&
  16. options['expected_update_period_in_days'].present?
  17. errors.add(:base, "expected_update_period_in_days and uid are required")
  18. end
  19. end
  20. def working?
  21. event_created_within?(interpolated['expected_update_period_in_days']) && most_recent_event && most_recent_event.payload['success'] == true && !recent_error_logs?
  22. end
  23. def default_options
  24. {
  25. 'uid' => "",
  26. 'access_token' => "---",
  27. 'app_key' => "---",
  28. 'app_secret' => "---",
  29. 'expected_update_period_in_days' => "10",
  30. 'message_path' => "text",
  31. 'pic_path' => "pic"
  32. }
  33. end
  34. def receive(incoming_events)
  35. # if there are too many, dump a bunch to avoid getting rate limited
  36. if incoming_events.count > 20
  37. incoming_events = incoming_events.first(20)
  38. end
  39. incoming_events.each do |event|
  40. tweet_text = Utils.value_at(event.payload, interpolated(event)['message_path'])
  41. pic_url = Utils.value_at(event.payload, interpolated(event)['pic_path'])
  42. if event.agent.type == "Agents::TwitterUserAgent"
  43. tweet_text = unwrap_tco_urls(tweet_text, event.payload)
  44. end
  45. begin
  46. if valid_image?(pic_url)
  47. publish_tweet_with_pic tweet_text, pic_url
  48. else
  49. publish_tweet tweet_text
  50. end
  51. create_event payload: {
  52. 'success' => true,
  53. 'published_tweet' => tweet_text,
  54. 'published_pic' => pic_url,
  55. 'agent_id' => event.agent_id,
  56. 'event_id' => event.id
  57. }
  58. rescue OAuth2::Error => e
  59. create_event payload: {
  60. 'success' => false,
  61. 'error' => e.message,
  62. 'failed_tweet' => tweet_text,
  63. 'failed_pic' => pic_url,
  64. 'agent_id' => event.agent_id,
  65. 'event_id' => event.id
  66. }
  67. end
  68. # you can't tweet too fast, give it a minute, i mean... 10 seconds
  69. sleep 10 if incoming_events.length > 1
  70. end
  71. end
  72. def publish_tweet(text)
  73. weibo_client.statuses.update text
  74. end
  75. def publish_tweet_with_pic(text, pic)
  76. weibo_client.statuses.upload text, open(pic)
  77. end
  78. def valid_image?(url)
  79. url = URI.parse(url)
  80. http = Net::HTTP.new(url.host, url.port)
  81. http.use_ssl = (url.scheme == "https")
  82. http.start do |http|
  83. # images supported #http://open.weibo.com/wiki/2/statuses/upload
  84. return ['image/gif', 'image/jpeg', 'image/png'].include? http.head(url.request_uri)['Content-Type']
  85. end
  86. rescue StandardError => e
  87. false
  88. end
  89. def unwrap_tco_urls(text, tweet_json)
  90. tweet_json[:entities][:urls].each do |url|
  91. text.gsub! url[:url], url[:expanded_url]
  92. end
  93. text
  94. end
  95. end
  96. end