1
0

dropbox_watch_agent.rb 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. module Agents
  2. class DropboxWatchAgent < Agent
  3. include DropboxConcern
  4. cannot_receive_events!
  5. default_schedule "every_1m"
  6. description <<-MD
  7. #{'## Include the `dropbox-api` and `omniauth-dropbox` gems in your `Gemfile` and set `DROPBOX_OAUTH_KEY` and `DROPBOX_OAUTH_SECRET` in your environment to use Dropbox Agents.' if dependencies_missing?}
  8. The _DropboxWatchAgent_ watches the given `dir_to_watch` and emits events with the detected changes.
  9. MD
  10. event_description <<-MD
  11. The event payload will contain the following fields:
  12. {
  13. "added": [ {
  14. "path": "/path/to/added/file",
  15. "rev": "1526952fd5",
  16. "modified": "Fri, 10 Oct 2014 19:00:43 +0000"
  17. } ],
  18. "removed": [ ... ],
  19. "updated": [ ... ]
  20. }
  21. MD
  22. def default_options
  23. {
  24. 'dir_to_watch' => '/',
  25. 'expected_update_period_in_days' => 1
  26. }
  27. end
  28. def validate_options
  29. errors.add(:base, 'The `dir_to_watch` property is required.') unless options['dir_to_watch'].present?
  30. errors.add(:base, 'Invalid `expected_update_period_in_days` format.') unless options['expected_update_period_in_days'].present? && is_positive_integer?(options['expected_update_period_in_days'])
  31. end
  32. def working?
  33. event_created_within?(interpolated['expected_update_period_in_days']) && !received_event_without_error?
  34. end
  35. def check
  36. current_contents = ls(interpolated['dir_to_watch'])
  37. diff = DropboxDirDiff.new(previous_contents, current_contents)
  38. create_event(payload: diff.to_hash) unless previous_contents.nil? || diff.empty?
  39. remember(current_contents)
  40. end
  41. private
  42. def is_positive_integer?(value)
  43. Integer(value) >= 0
  44. rescue
  45. false
  46. end
  47. def ls(dir_to_watch)
  48. dropbox.ls(dir_to_watch).map { |entry| slice_json(entry, 'path', 'rev', 'modified') }
  49. end
  50. def slice_json(json, *keys)
  51. keys.each_with_object({}){|key, hash| hash[key.to_s] = json[key.to_s]}
  52. end
  53. def previous_contents
  54. self.memory['contents']
  55. end
  56. def remember(contents)
  57. self.memory['contents'] = contents
  58. end
  59. # == Auxiliary classes ==
  60. class DropboxDirDiff
  61. def initialize(previous, current)
  62. @previous, @current = [previous || [], current || []]
  63. end
  64. def empty?
  65. (@previous == @current)
  66. end
  67. def to_hash
  68. calculate_diff
  69. { added: @added, removed: @removed, updated: @updated }
  70. end
  71. private
  72. def calculate_diff
  73. @updated = @current.select do |current_entry|
  74. previous_entry = find_by_path(@previous, current_entry['path'])
  75. (current_entry != previous_entry) && !previous_entry.nil?
  76. end
  77. updated_entries = @updated + @previous.select do |previous_entry|
  78. find_by_path(@updated, previous_entry['path'])
  79. end
  80. @added = @current - @previous - updated_entries
  81. @removed = @previous - @current - updated_entries
  82. end
  83. def find_by_path(array, path)
  84. array.find { |entry| entry['path'] == path }
  85. end
  86. end
  87. end
  88. end