From d7d2bfe7d2aa73ef271b54771dc611da16d0e605 Mon Sep 17 00:00:00 2001 From: Andrew Cantino Date: Thu, 9 Jan 2014 14:26:46 -0800 Subject: [PATCH] add documentation --- app/models/agent.rb | 22 ++++++++++++++++------ app/models/agent_log.rb | 3 +++ app/models/contact.rb | 2 ++ app/models/event.rb | 6 ++++++ app/models/link.rb | 1 + app/models/user.rb | 1 + bin/decrypt_backup.rb | 3 +++ bin/schedule.rb | 3 +++ bin/twitter_stream.rb | 4 ++++ 9 files changed, 39 insertions(+), 6 deletions(-) diff --git a/app/models/agent.rb b/app/models/agent.rb index 32d2600d..79dfff31 100644 --- a/app/models/agent.rb +++ b/app/models/agent.rb @@ -3,6 +3,9 @@ require 'assignable_types' require 'markdown_class_attributes' require 'utils' +# Agent is the core class in Huginn, representing a configurable, schedulable, reactive system with memory that can +# be sub-classed for many different purposes. Agents can emit Events, as well as receive them and react in many different ways. +# The basic Agent API is detailed on the Huginn wiki: https://github.com/cantino/huginn/wiki/Creating-a-new-agent class Agent < ActiveRecord::Base include AssignableTypes include MarkdownClassAttributes @@ -226,6 +229,9 @@ class Agent < ActiveRecord::Base !!@cannot_receive_events end + # Find all Agents that have received Events since the last execution of this method. Update those Agents with + # their new `last_checked_event_id` and queue each of the Agents to be called with #receive using `async_receive`. + # This is called by bin/schedule.rb periodically. def receive! Agent.transaction do sql = Agent. @@ -256,9 +262,9 @@ class Agent < ActiveRecord::Base end # Given an Agent id and an array of Event ids, load the Agent, call #receive on it with the Event objects, and then - # save it with an updated _last_receive_at_ timestamp. + # save it with an updated `last_receive_at` timestamp. # - # This method is tagged with _handle_asynchronously_ and will be delayed and run with delayed_job. It accepts Agent + # This method is tagged with `handle_asynchronously` and will be delayed and run with delayed_job. It accepts Agent # and Event ids instead of a literal ActiveRecord models because it is preferable to serialize delayed_jobs with ids. def async_receive(agent_id, event_ids) agent = Agent.find(agent_id) @@ -273,6 +279,8 @@ class Agent < ActiveRecord::Base end handle_asynchronously :async_receive + # Given a schedule name, run `check` via `bulk_check` on all Agents with that schedule. + # This is called by bin/schedule.rb for each schedule in `SCHEDULES`. def run_schedule(schedule) types = where(:schedule => schedule).group(:type).pluck(:type) types.each do |type| @@ -280,7 +288,8 @@ class Agent < ActiveRecord::Base end end - # You can override this to define a custom bulk_check for your type of Agent. + # Schedule `async_check`s for every Agent on the given schedule. This is normally called by `run_schedule` once + # per type of agent, so you can override this to define custom bulk check behavior for your custom Agent type. def bulk_check(schedule) raise "Call #bulk_check on the appropriate subclass of Agent" if self == Agent where(:schedule => schedule).pluck("agents.id").each do |agent_id| @@ -288,10 +297,11 @@ class Agent < ActiveRecord::Base end end - # Given an Agent id, load the Agent, call #check on it, and then save it with an updated _last_check_at_ timestamp. + # Given an Agent id, load the Agent, call #check on it, and then save it with an updated `last_check_at` timestamp. # - # This method is tagged with _handle_asynchronously_ and will be delayed and run with delayed_job. It accepts an Agent - # id instead of a literal Agent because it is preferable to serialize delayed_jobs with ids. + # This method is tagged with `handle_asynchronously` and will be delayed and run with delayed_job. It accepts an Agent + # id instead of a literal Agent because it is preferable to serialize delayed_jobs with ids, instead of with the full + # Agents. def async_check(agent_id) agent = Agent.find(agent_id) begin diff --git a/app/models/agent_log.rb b/app/models/agent_log.rb index ce9c000c..7fca4482 100644 --- a/app/models/agent_log.rb +++ b/app/models/agent_log.rb @@ -1,3 +1,6 @@ +# AgentLogs are temporary records of Agent activity, intended for debugging and error tracking. They can be viewed +# in Agents' detail pages. AgentLogs with a `level` of 4 or greater are considered "errors" and automatically update +# Agents' `last_error_log_at` column. These are often used to determine if an Agent is `working?`. class AgentLog < ActiveRecord::Base attr_accessible :agent, :inbound_event, :level, :message, :outbound_event diff --git a/app/models/contact.rb b/app/models/contact.rb index b812fd22..6adeafb6 100644 --- a/app/models/contact.rb +++ b/app/models/contact.rb @@ -1,3 +1,5 @@ +# Contacts are used only for the contact form on the Huginn website. If you host a public Huginn instance, you can use +# these to receive messages from visitors. class Contact < ActiveRecord::Base attr_accessible :email, :message, :name diff --git a/app/models/event.rb b/app/models/event.rb index 43033e51..efa56cc4 100644 --- a/app/models/event.rb +++ b/app/models/event.rb @@ -1,5 +1,8 @@ require 'json_serialized_field' +# Events are how Huginn Agents communicate and log information about the world. Events can be emitted and received by +# Agents. They contain a serialized `payload` of arbitrary JSON data, as well as optional `lat`, `lng`, and `expires_at` +# fields. class Event < ActiveRecord::Base include JSONSerializedField @@ -16,10 +19,13 @@ class Event < ActiveRecord::Base where("events.created_at > ?", timespan) } + # Emit this event again, as a new Event. def reemit! agent.create_event :payload => payload, :lat => lat, :lng => lng end + # Look for Events whose `expires_at` is present and in the past. Remove those events and then update affected Agents' + # `events_counts` cache columns. This method is called by bin/schedule.rb periodically. def self.cleanup_expired! affected_agents = Event.where("expires_at IS NOT NULL AND expires_at < ?", Time.now).group("agent_id").pluck(:agent_id) Event.where("expires_at IS NOT NULL AND expires_at < ?", Time.now).delete_all diff --git a/app/models/link.rb b/app/models/link.rb index 498dc0d4..5ae935a8 100644 --- a/app/models/link.rb +++ b/app/models/link.rb @@ -1,3 +1,4 @@ +# A Link connects Agents in a directed Event flow from the `source` to the `receiver`. class Link < ActiveRecord::Base attr_accessible :source_id, :receiver_id diff --git a/app/models/user.rb b/app/models/user.rb index 2aa8eb08..969bc681 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -1,3 +1,4 @@ +# Huginn is designed to be a multi-User system. Users have many Agents (and Events created by those Agents). class User < ActiveRecord::Base # Include default devise modules. Others available are: # :token_authenticatable, :confirmable, diff --git a/bin/decrypt_backup.rb b/bin/decrypt_backup.rb index 7c966381..14fe208e 100755 --- a/bin/decrypt_backup.rb +++ b/bin/decrypt_backup.rb @@ -1,5 +1,8 @@ #!/usr/bin/env ruby +# If you're using the backup gem, described on the Huginn wiki and at doc/deployment/backup, then you can use this +# utility to decrypt backups. + in_file = ARGV.shift out_file = ARGV.shift || "decrypted_backup.tar" diff --git a/bin/schedule.rb b/bin/schedule.rb index a95ca447..1efd5a19 100755 --- a/bin/schedule.rb +++ b/bin/schedule.rb @@ -1,5 +1,8 @@ #!/usr/bin/env ruby +# This process is used to maintain Huginn's upkeep behavior, automatically running scheduled Agents and +# periodically propagating and expiring Events. It's typically run via foreman and the included Procfile. + unless defined?(Rails) puts puts "Please run me with rails runner, for example:" diff --git a/bin/twitter_stream.rb b/bin/twitter_stream.rb index d3de5226..474639c0 100755 --- a/bin/twitter_stream.rb +++ b/bin/twitter_stream.rb @@ -1,5 +1,9 @@ #!/usr/bin/env ruby +# This process is used by TwitterStreamAgents to watch the Twitter stream in real time. It periodically checks for +# new or changed TwitterStreamAgents and starts to follow the stream for them. It is typically run by foreman via +# the included Procfile. + unless defined?(Rails) puts puts "Please run me with rails runner, for example:"