dropbox_watch_agent.rb 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. module Agents
  2. class DropboxWatchAgent < Agent
  3. include DropboxConcern
  4. cannot_receive_events!
  5. default_schedule "every_1m"
  6. description <<~MD
  7. The Dropbox Watch Agent watches the given `dir_to_watch` and emits events with the detected changes.
  8. #{'## 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?}
  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": "2017-10-14T18:39:41Z"
  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,
  31. 'Invalid `expected_update_period_in_days` format.') unless options['expected_update_period_in_days'].present? && is_positive_integer?(options['expected_update_period_in_days'])
  32. end
  33. def working?
  34. event_created_within?(interpolated['expected_update_period_in_days']) && !received_event_without_error?
  35. end
  36. def check
  37. current_contents = ls(interpolated['dir_to_watch'])
  38. diff = DropboxDirDiff.new(previous_contents, current_contents)
  39. create_event(payload: diff.to_hash) unless previous_contents.nil? || diff.empty?
  40. remember(current_contents)
  41. end
  42. private
  43. def ls(dir_to_watch)
  44. dropbox.ls(dir_to_watch)
  45. .select { |entry| entry.respond_to?(:rev) }
  46. .map { |file| { 'path' => file.path, 'rev' => file.rev, 'modified' => file.server_modified } }
  47. end
  48. def previous_contents
  49. self.memory['contents']
  50. end
  51. def remember(contents)
  52. self.memory['contents'] = contents
  53. end
  54. # == Auxiliary classes ==
  55. class DropboxDirDiff
  56. def initialize(previous, current)
  57. @previous = previous || []
  58. @current = current || []
  59. end
  60. def empty?
  61. (@previous == @current)
  62. end
  63. def to_hash
  64. calculate_diff
  65. { added: @added, removed: @removed, updated: @updated }
  66. end
  67. private
  68. def calculate_diff
  69. @updated = @current.select do |current_entry|
  70. previous_entry = find_by_path(@previous, current_entry['path'])
  71. (current_entry != previous_entry) && !previous_entry.nil?
  72. end
  73. updated_entries = @updated + @previous.select do |previous_entry|
  74. find_by_path(@updated, previous_entry['path'])
  75. end
  76. @added = @current - @previous - updated_entries
  77. @removed = @previous - @current - updated_entries
  78. end
  79. def find_by_path(array, path)
  80. array.find { |entry| entry['path'] == path }
  81. end
  82. end
  83. end
  84. end