Module: DashFu

Defined in:
lib/dash_fu.rb

Overview

Use me to push data to Dash-fu in real time.

The only configuration you need is setting the API key in config/environments/production.rb:

DashFu.api_key = "<your API key>"

You only want to push data in production, so make sure the API key is only set in production environment. Calls to created/active with no API key are simply ignored.

You can send events by calling DashFu.push with UID and event, or using the specialized created and active methods.

For example, to assign a user to a cohort, we’re going to notify Dash-fu whenever an acount gets created:

class User < ActiveRecord::Model
  after_create do
    DashFu.created id
  end
end

In this example, we consider a user active whenever they post a status update, and notify Dash-fu accordingly:

class StatusUpdate < ActiveRecord::Model
  after_create do
    DashFu.active id
  end
end

Class Attribute Summary collapse

Class Method Summary collapse

Class Attribute Details

.api_keyObject

Set the API key with:

DashFu.api_key = "<your API key>"


47
48
49
# File 'lib/dash_fu.rb', line 47

def api_key
  @api_key
end

.hostObject

DashFu.host is set by default, this is only useful for testing.



43
44
45
# File 'lib/dash_fu.rb', line 43

def host
  @host
end

.portObject

DashFu.host is set by default, this is only useful for testing.



43
44
45
# File 'lib/dash_fu.rb', line 43

def port
  @port
end

Class Method Details

.active(uid) ⇒ Object

Records that a user has been active in the app.



142
143
144
# File 'lib/dash_fu.rb', line 142

def active(uid)
  push uid, "active"
end

.closeObject

Close connection. If you like crossing your t’s you can call this when the app shutsdown.



154
155
156
157
158
159
160
# File 'lib/dash_fu.rb', line 154

def close
  @mutex.synchronize do
    socket, @socket = @socket, nil
    socket.close if socket
  end
rescue Exception
end

.created(uid) ⇒ Object

Records that a new user account has been created (associate them with cohort).



148
149
150
# File 'lib/dash_fu.rb', line 148

def created(uid)
  push uid, "created"
end

.log(*args) ⇒ Object

Logs an activity. An activity has an actor (the user who performed the activity), the action performed (e.g. posted, commented) and the object of the action (e.g. the post).

You can call this method with actor, action and optional object (two or three arguments), or with a Hash with the keys actor, action, object and timestamp.

For example:

DashFu.log user, 'posted', post.title
DashFu.log actor: user, action: 'posted', object: { content: post.title }

The actor argument is either the ID of a user, an object that responds to to_dashboard, or Hash with the following keys:

  • uid – User identifier (must be unique in application, required)

  • created – Date/time instance when user account was created

  • name – Display name

  • email – Email address

  • image – URL for profile photo

  • url – URL for profile

UID is required, all other properties are optional.

When using an object that responds to to_dashboard, the to_dashboard method must return a Hash with these keys.

The action argument is any string, e.g. ‘posted’, ‘commented’.

The object argument is either a string containing HTML markup, an object that respobds to to_dashboard, or Hash with the following keys:

  • content – HTML markup describing the object

HTML markup may use semantic styling elements such as b, em, p, blockquote. Styles and scripts are stripped, and only links to HTTP/S URLs are preserved.

When using an object that responds to to_dashboard, the to_dashboard method must return a Hash with these keys.

The timestamp argument is the date/time instance the activity occurred.



93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# File 'lib/dash_fu.rb', line 93

def log(*args)
  return unless @api_key # in test/dev mode, return quickly

  if args.length == 1 && args[0].respond_to?(:values_at)
    actor, action, object, timestamp = args[0].values_at(:actor, :action, :object, :timestamp)
  elsif args.length == 2 || args.length == 3
    actor, action, object = *args
  else
    raise ArgumentError.new("Expected Hash or actor, action, (object)")
  end

  if actor.respond_to?(:to_dashboard)
    actor = actor.to_dashboard
  elsif String === actor
    actor = { uid: actor }
  end

  action = action.to_s

  if object.respond_to?(:to_dashboard)
    object = object.to_dashboard
  elsif String === object
    object = { content: object }
  end

  
  params = { actor: actor, action: action, object: object, timestamp: timestamp }
  json = MultiJson.encode(params)
  puts json
  if socket = @socket
    socket.sendmsg_nonblock "POST /v1/activity?api_key=#{@api_key} HTTP/1.1\r\nHost: #{@host}\r\nConnection: keep-alive\r\nContent-Type: application/json\r\nContent-Length: #{json.length}\r\n\r\n#{json}", 0
    socket.recv_nonblock 512 rescue nil
  else
    Thread.new do
      @mutex.synchronize do
        @socket ||= TCPSocket.open(@host, @port || 80)
      end
      log params
    end
  end
rescue Errno::EPIPE, Errno::ECONNRESET, Errno::ETIMEDOUT
  close
  retry
rescue Errno::ECONNREFUSED, Errno::ENETUNREACH
  # No @socket so we'll try to connect next time
end

.push(uid, event) ⇒ Object

Push update for the specified user ID and event. Or you can use active/created.



164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
# File 'lib/dash_fu.rb', line 164

def push(uid, event)
  return unless @api_key
  if socket = @socket
    socket.sendmsg_nonblock "POST /v1/push?api_key=#{@api_key}&uid=#{uid}&event=#{event} HTTP/1.1\r\nHost: #{@host}\r\nConnection: keep-alive\r\nContent-Length: 0\r\n\r\n", 0
    socket.recv_nonblock 512 rescue nil
  else
    Thread.new do
      @mutex.synchronize do
        @socket ||= TCPSocket.open(@host, @port || 80)
      end
      push uid, event
    end
  end
rescue Errno::EPIPE, Errno::ECONNRESET, Errno::ETIMEDOUT
  close
  retry
rescue Errno::ECONNREFUSED, Errno::ENETUNREACH
  # No @socket so we'll try to connect next time
end