123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107 |
- module Agents
- class DropboxWatchAgent < Agent
- include DropboxConcern
- cannot_receive_events!
- default_schedule "every_1m"
- description <<~MD
- The Dropbox Watch Agent watches the given `dir_to_watch` and emits events with the detected changes.
- #{'## 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?}
- MD
- event_description <<~MD
- The event payload will contain the following fields:
- {
- "added": [ {
- "path": "/path/to/added/file",
- "rev": "1526952fd5",
- "modified": "2017-10-14T18:39:41Z"
- } ],
- "removed": [ ... ],
- "updated": [ ... ]
- }
- MD
- def default_options
- {
- 'dir_to_watch' => '/',
- 'expected_update_period_in_days' => 1
- }
- end
- def validate_options
- errors.add(:base, 'The `dir_to_watch` property is required.') unless options['dir_to_watch'].present?
- 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'])
- end
- def working?
- event_created_within?(interpolated['expected_update_period_in_days']) && !received_event_without_error?
- end
- def check
- current_contents = ls(interpolated['dir_to_watch'])
- diff = DropboxDirDiff.new(previous_contents, current_contents)
- create_event(payload: diff.to_hash) unless previous_contents.nil? || diff.empty?
- remember(current_contents)
- end
- private
- def ls(dir_to_watch)
- dropbox.ls(dir_to_watch)
- .select { |entry| entry.respond_to?(:rev) }
- .map { |file| { 'path' => file.path, 'rev' => file.rev, 'modified' => file.server_modified } }
- end
- def previous_contents
- self.memory['contents']
- end
- def remember(contents)
- self.memory['contents'] = contents
- end
- # == Auxiliary classes ==
- class DropboxDirDiff
- def initialize(previous, current)
- @previous = previous || []
- @current = current || []
- end
- def empty?
- (@previous == @current)
- end
- def to_hash
- calculate_diff
- { added: @added, removed: @removed, updated: @updated }
- end
- private
- def calculate_diff
- @updated = @current.select do |current_entry|
- previous_entry = find_by_path(@previous, current_entry['path'])
- (current_entry != previous_entry) && !previous_entry.nil?
- end
- updated_entries = @updated + @previous.select do |previous_entry|
- find_by_path(@updated, previous_entry['path'])
- end
- @added = @current - @previous - updated_entries
- @removed = @previous - @current - updated_entries
- end
- def find_by_path(array, path)
- array.find { |entry| entry['path'] == path }
- end
- end
- end
- end
|