diff --git a/Gemfile b/Gemfile
index b4c5129..f56b1cf 100644
--- a/Gemfile
+++ b/Gemfile
@@ -31,7 +31,8 @@ gem 'newrelic_rpm'
gem 'actionpack-xml_parser'
gem 'activeadmin', github: 'gregbell/active_admin'
gem 'chronic'
-gem "non-stupid-digest-assets"
+gem 'non-stupid-digest-assets'
+gem 'em-http-request'
# to use debugger
# gem 'ruby-debug'
diff --git a/Gemfile.lock b/Gemfile.lock
index 37a9bbf..aee9758 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -355,6 +355,7 @@ DEPENDENCIES
database_cleaner (~> 1.2.0)
devise
dynamic_form
+ em-http-request
exception_notification
factory_girl_rails
faker
diff --git a/app/controllers/channels_controller.rb b/app/controllers/channels_controller.rb
index be69ca0..f46134f 100644
--- a/app/controllers/channels_controller.rb
+++ b/app/controllers/channels_controller.rb
@@ -1,11 +1,19 @@
class ChannelsController < ApplicationController
include ChannelsHelper, ApiKeys
- before_filter :require_user, :except => [ :show, :post_data, :social_show, :social_feed, :public]
+ before_filter :require_user, :except => [:realtime, :realtime_update, :show, :post_data, :social_show, :social_feed, :public]
before_filter :set_channels_menu
layout 'application', :except => [:social_show, :social_feed]
- protect_from_forgery :except => [:post_data, :create, :destroy, :clear]
+ protect_from_forgery :except => [:realtime, :realtime_update, :post_data, :create, :destroy, :clear]
require 'csv'
+ # get list of all realtime channels
+ def realtime
+ # error if no key
+ respond_with_error(:error_auth_required) and return if params[:realtime_key] != REALTIME_DAEMON_KEY
+ channels = Channel.where("realtime_io_serial_number IS NOT NULL")
+ render :json => channels.to_json(:root => false, :only => [:id, :realtime_io_serial_number])
+ end
+
# view list of watched channels
def watched
@channels = current_user.watched_channels
@@ -235,6 +243,33 @@ class ChannelsController < ApplicationController
end
end
+ # post from realtime.io daemon
+ def realtime_update
+ # exit if not authenticated
+ respond_with_error(:error_auth_required) and return if params[:realtime_key] != REALTIME_DAEMON_KEY
+
+ # set feed and channel
+ feed = Feed.new
+ channel = Channel.find(params[:id])
+
+ # update entry_id for channel and feed
+ entry_id = channel.next_entry_id
+ channel.last_entry_id = entry_id
+ feed.entry_id = entry_id
+ # set user agent
+ channel.user_agent = 'realtime.io'
+
+ # set feed details
+ feed.channel_id = channel.id
+ feed.status = params[:status]
+
+ # save channel and feed
+ channel.save
+ feed.save
+
+ render :nothing => true
+ end
+
# response is '0' if failure, 'entry_id' if success
def post_data
diff --git a/app/controllers/stream_controller.rb b/app/controllers/stream_controller.rb
index f5ddbf5..1982d82 100644
--- a/app/controllers/stream_controller.rb
+++ b/app/controllers/stream_controller.rb
@@ -54,11 +54,11 @@ class StreamController < ApplicationController
def stream_example
# get the channel
- channel = Channel.find(params[:channel_id])
+ #channel = Channel.find(params[:channel_id])
# stream the response
- response.headers['Content-Type'] = 'text/csv'
- response.headers['Content-Disposition'] = 'attachment; filename=feeds.csv'
+ #response.headers['Content-Type'] = 'text/csv'
+ #response.headers['Content-Disposition'] = 'attachment; filename=feeds.csv'
20.times {
response.stream.write "hello world\n"
sleep 1
diff --git a/app/models/channel.rb b/app/models/channel.rb
index ef568bb..3814a87 100644
--- a/app/models/channel.rb
+++ b/app/models/channel.rb
@@ -2,50 +2,51 @@
#
# Table name: channels
#
-# id :integer not null, primary key
-# user_id :integer
-# name :string(255)
-# description :string(255)
-# latitude :decimal(15, 10)
-# longitude :decimal(15, 10)
-# field1 :string(255)
-# field2 :string(255)
-# field3 :string(255)
-# field4 :string(255)
-# field5 :string(255)
-# field6 :string(255)
-# field7 :string(255)
-# field8 :string(255)
-# scale1 :integer
-# scale2 :integer
-# scale3 :integer
-# scale4 :integer
-# scale5 :integer
-# scale6 :integer
-# scale7 :integer
-# scale8 :integer
-# created_at :datetime
-# updated_at :datetime
-# elevation :string(255)
-# last_entry_id :integer
-# public_flag :boolean default(FALSE)
-# options1 :string(255)
-# options2 :string(255)
-# options3 :string(255)
-# options4 :string(255)
-# options5 :string(255)
-# options6 :string(255)
-# options7 :string(255)
-# options8 :string(255)
-# social :boolean default(FALSE)
-# slug :string(255)
-# status :string(255)
-# url :string(255)
-# video_id :string(255)
-# video_type :string(255)
-# clearing :boolean default(FALSE), not null
-# ranking :integer
-# user_agent :string(255)
+# id :integer not null, primary key
+# user_id :integer
+# name :string(255)
+# description :string(255)
+# latitude :decimal(15, 10)
+# longitude :decimal(15, 10)
+# field1 :string(255)
+# field2 :string(255)
+# field3 :string(255)
+# field4 :string(255)
+# field5 :string(255)
+# field6 :string(255)
+# field7 :string(255)
+# field8 :string(255)
+# scale1 :integer
+# scale2 :integer
+# scale3 :integer
+# scale4 :integer
+# scale5 :integer
+# scale6 :integer
+# scale7 :integer
+# scale8 :integer
+# created_at :datetime
+# updated_at :datetime
+# elevation :string(255)
+# last_entry_id :integer
+# public_flag :boolean default(FALSE)
+# options1 :string(255)
+# options2 :string(255)
+# options3 :string(255)
+# options4 :string(255)
+# options5 :string(255)
+# options6 :string(255)
+# options7 :string(255)
+# options8 :string(255)
+# social :boolean default(FALSE)
+# slug :string(255)
+# status :string(255)
+# url :string(255)
+# video_id :string(255)
+# video_type :string(255)
+# clearing :boolean default(FALSE), not null
+# ranking :integer
+# user_agent :string(255)
+# realtime_io_serial_number :string(36)
#
class Channel < ActiveRecord::Base
diff --git a/app/views/docs/charts.html.erb b/app/views/docs/charts.html.erb
index cf1142c..9eea54f 100644
--- a/app/views/docs/charts.html.erb
+++ b/app/views/docs/charts.html.erb
@@ -27,7 +27,7 @@
yaxis (string) Chart's y-axis label, default: field name (optional)
color (string) Line color, default: red (optional)
bgcolor (string) Background color, default: white (optional)
- type (line/bar/column) Type of chart, default: line (optional)
+ type (line/bar/column/spline) Type of chart, default: line (optional)
width (integer) Chart width in pixels, iframe width will be 20px larger, default chart width: 400. Set to auto to automatically adjust chart size based on its parent container. (optional)
height (integer) Chart height in pixels, iframe height will be 20px larger, default chart height: 200. Set to auto to automatically adjust chart size based on its parent container. (optional)
dynamic (true/false) Make chart update automatically every 15 seconds, default: false (optional)
diff --git a/config/routes.rb b/config/routes.rb
index d42872c..0485594 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -80,12 +80,14 @@ Thingspeak::Application.routes.draw do
collection do
get :public
get :watched
+ get :realtime
end
member do
get :import
post :upload
post :clear
put :watch
+ post :realtime_update
end
resources :feed
diff --git a/db/migrate/20140515161337_add_realtime_io_serial_number_to_channels.rb b/db/migrate/20140515161337_add_realtime_io_serial_number_to_channels.rb
new file mode 100644
index 0000000..33a6e81
--- /dev/null
+++ b/db/migrate/20140515161337_add_realtime_io_serial_number_to_channels.rb
@@ -0,0 +1,7 @@
+class AddRealtimeIoSerialNumberToChannels < ActiveRecord::Migration
+ def change
+ add_column :channels, :realtime_io_serial_number, :string, :limit => 36
+ add_index :channels, :realtime_io_serial_number
+ end
+end
+
diff --git a/db/schema.rb b/db/schema.rb
index d679075..a5de4ea 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema.define(version: 20140410174033) do
+ActiveRecord::Schema.define(version: 20140515161337) do
create_table "active_admin_comments", force: true do |t|
t.string "namespace"
@@ -63,8 +63,8 @@ ActiveRecord::Schema.define(version: 20140410174033) do
t.integer "user_id"
t.string "name"
t.string "description"
- t.decimal "latitude", precision: 15, scale: 10
- t.decimal "longitude", precision: 15, scale: 10
+ t.decimal "latitude", precision: 15, scale: 10
+ t.decimal "longitude", precision: 15, scale: 10
t.string "field1"
t.string "field2"
t.string "field3"
@@ -85,7 +85,7 @@ ActiveRecord::Schema.define(version: 20140410174033) do
t.datetime "updated_at"
t.string "elevation"
t.integer "last_entry_id"
- t.boolean "public_flag", default: false
+ t.boolean "public_flag", default: false
t.string "options1"
t.string "options2"
t.string "options3"
@@ -94,19 +94,21 @@ ActiveRecord::Schema.define(version: 20140410174033) do
t.string "options6"
t.string "options7"
t.string "options8"
- t.boolean "social", default: false
+ t.boolean "social", default: false
t.string "slug"
t.string "status"
t.string "url"
t.string "video_id"
t.string "video_type"
- t.boolean "clearing", default: false, null: false
+ t.boolean "clearing", default: false, null: false
t.integer "ranking"
t.string "user_agent"
+ t.string "realtime_io_serial_number", limit: 36
end
add_index "channels", ["public_flag", "last_entry_id", "updated_at"], name: "channels_public_viewable", using: :btree
add_index "channels", ["ranking"], name: "index_channels_on_ranking", using: :btree
+ add_index "channels", ["realtime_io_serial_number"], name: "index_channels_on_realtime_io_serial_number", using: :btree
add_index "channels", ["slug"], name: "index_channels_on_slug", using: :btree
add_index "channels", ["user_id"], name: "index_channels_on_user_id", using: :btree
diff --git a/spec/models/channel_spec.rb b/spec/models/channel_spec.rb
index a8eae89..58c4c32 100644
--- a/spec/models/channel_spec.rb
+++ b/spec/models/channel_spec.rb
@@ -3,50 +3,51 @@
#
# Table name: channels
#
-# id :integer not null, primary key
-# user_id :integer
-# name :string(255)
-# description :string(255)
-# latitude :decimal(15, 10)
-# longitude :decimal(15, 10)
-# field1 :string(255)
-# field2 :string(255)
-# field3 :string(255)
-# field4 :string(255)
-# field5 :string(255)
-# field6 :string(255)
-# field7 :string(255)
-# field8 :string(255)
-# scale1 :integer
-# scale2 :integer
-# scale3 :integer
-# scale4 :integer
-# scale5 :integer
-# scale6 :integer
-# scale7 :integer
-# scale8 :integer
-# created_at :datetime
-# updated_at :datetime
-# elevation :string(255)
-# last_entry_id :integer
-# public_flag :boolean default(FALSE)
-# options1 :string(255)
-# options2 :string(255)
-# options3 :string(255)
-# options4 :string(255)
-# options5 :string(255)
-# options6 :string(255)
-# options7 :string(255)
-# options8 :string(255)
-# social :boolean default(FALSE)
-# slug :string(255)
-# status :string(255)
-# url :string(255)
-# video_id :string(255)
-# video_type :string(255)
-# clearing :boolean default(FALSE), not null
-# ranking :integer
-# user_agent :string(255)
+# id :integer not null, primary key
+# user_id :integer
+# name :string(255)
+# description :string(255)
+# latitude :decimal(15, 10)
+# longitude :decimal(15, 10)
+# field1 :string(255)
+# field2 :string(255)
+# field3 :string(255)
+# field4 :string(255)
+# field5 :string(255)
+# field6 :string(255)
+# field7 :string(255)
+# field8 :string(255)
+# scale1 :integer
+# scale2 :integer
+# scale3 :integer
+# scale4 :integer
+# scale5 :integer
+# scale6 :integer
+# scale7 :integer
+# scale8 :integer
+# created_at :datetime
+# updated_at :datetime
+# elevation :string(255)
+# last_entry_id :integer
+# public_flag :boolean default(FALSE)
+# options1 :string(255)
+# options2 :string(255)
+# options3 :string(255)
+# options4 :string(255)
+# options5 :string(255)
+# options6 :string(255)
+# options7 :string(255)
+# options8 :string(255)
+# social :boolean default(FALSE)
+# slug :string(255)
+# status :string(255)
+# url :string(255)
+# video_id :string(255)
+# video_type :string(255)
+# clearing :boolean default(FALSE), not null
+# ranking :integer
+# user_agent :string(255)
+# realtime_io_serial_number :string(36)
#
require 'spec_helper'