rfid 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. data/INSTALL.rdoc +55 -0
  2. data/README.rdoc +60 -0
  3. data/bin/rfid +18 -0
  4. data/bin/rfid_checkout +22 -0
  5. data/config.ru +9 -0
  6. data/config/boot.rb +6 -0
  7. data/config/environment.rb +8 -0
  8. data/config/rfid.yml +6 -0
  9. data/config/rfid.yml.sample +6 -0
  10. data/config/thin.yml +14 -0
  11. data/config/thin.yml.sample +14 -0
  12. data/lib/rfid.rb +75 -0
  13. data/lib/rfid/application.rb +115 -0
  14. data/lib/rfid/application/public/favicon.ico +0 -0
  15. data/lib/rfid/application/public/javascripts/application.js +12 -0
  16. data/lib/rfid/application/public/javascripts/debug.js +59 -0
  17. data/lib/rfid/application/public/stylesheets/application.css +49 -0
  18. data/lib/rfid/application/public/stylesheets/bootstrap.css +2467 -0
  19. data/lib/rfid/application/views/events.erb +34 -0
  20. data/lib/rfid/application/views/index.erb +21 -0
  21. data/lib/rfid/application/views/key_sets.erb +13 -0
  22. data/lib/rfid/application/views/key_string.erb +11 -0
  23. data/lib/rfid/application/views/keys.erb +20 -0
  24. data/lib/rfid/application/views/layout.erb +56 -0
  25. data/lib/rfid/application/views/redis.erb +16 -0
  26. data/lib/rfid/application/views/usage.erb +47 -0
  27. data/lib/rfid/cli.rb +78 -0
  28. data/lib/rfid/config.rb +23 -0
  29. data/lib/rfid/core_ext.rb +3 -0
  30. data/lib/rfid/core_ext/json_engine.rb +2 -0
  31. data/lib/rfid/event.rb +101 -0
  32. data/lib/rfid/translator.rb +68 -0
  33. data/lib/rfid/version.rb +3 -0
  34. data/lib/rfid/websocket.rb +35 -0
  35. data/lib/runner.rb +18 -0
  36. data/lib/server.rb +19 -0
  37. data/lib/templates/init +109 -0
  38. data/spec/models/application_spec.rb +54 -0
  39. data/spec/models/config_spec.rb +33 -0
  40. data/spec/models/event_spec.rb +22 -0
  41. data/spec/rfid_spec.rb +58 -0
  42. data/spec/spec_helper.rb +25 -0
  43. metadata +228 -0
@@ -0,0 +1,55 @@
1
+ == RFID install instructions
2
+
3
+ == Ruby 1.9.3
4
+
5
+ http://www.andyhawthorne.co.uk/2011/11/installing-ruby-1-9-3-and-rails-on-ubuntu-11-10/
6
+
7
+ sudo apt-get install build-essential git-core curl
8
+
9
+ sudo apt-get install build-essential openssl libreadline6 libreadline6-dev curl git-core zlib1g zlib1g-dev libssl-dev libyaml-dev libxml2-dev libxslt-dev autoconf libc6-dev ncurses-dev automake libtool bison subversion
10
+
11
+ Install yaml:
12
+
13
+ #get the source
14
+ wget http://pyyaml.org/download/libyaml/yaml-0.1.4.tar.gz
15
+
16
+ #untar the file
17
+ tar xzvf yaml-0.1.4.tar.gz
18
+
19
+ #move into the directory
20
+ cd yaml-0.1.4
21
+
22
+ #compile
23
+ ./configure --prefix=/usr/local
24
+ make
25
+ sudo make install
26
+
27
+
28
+ Make and install ruby:
29
+
30
+ #download the Ruby source
31
+ wget http://ftp.ruby-lang.org/pub/ruby/1.9/ruby-1.9.3-p0.tar.gz
32
+
33
+ #untar the file
34
+ tar xzvf ruby-1.9.3-p0.tar.gz
35
+
36
+ #move into the source directory
37
+ cd ruby-1.9.3-p0
38
+
39
+ #configure with options to avoid errors
40
+ ./configure --prefix=/usr/local --enable-shared --disable-install-doc --with-opt-dir=/usr/local/lib
41
+
42
+ #compile
43
+ make
44
+ sudo make install
45
+
46
+
47
+ == Redis 2.4.2
48
+
49
+ TODO:
50
+
51
+ == Curl
52
+
53
+ sudo apt-get install libcurl3 libcurl3-gnutls libcurl4-openssl-dev
54
+
55
+ Copyright (c) 2011 Aimbulance, released under the MIT license
@@ -0,0 +1,60 @@
1
+ = RFID WebSocket
2
+
3
+ == Setup
4
+
5
+ Install gem:
6
+
7
+ gem install rfid
8
+
9
+ Create logs and pids folders
10
+
11
+ rfid setup
12
+
13
+ sudo /usr/sbin/update-rc.d -f rfid defaults
14
+
15
+ == Start
16
+
17
+ Run websocket:
18
+
19
+ rfid websocket start
20
+
21
+ Run webui (optional):
22
+
23
+ rfid app start
24
+
25
+ == Usage
26
+
27
+ Create event
28
+
29
+ rfid checkout DEVICE_ID CARD1 CARD2 ...
30
+
31
+ rfid checkout 4ea92ba9c546617ab8000001 715=9370462=000195
32
+
33
+ == Usage (development)
34
+
35
+ === WebSocket
36
+
37
+ ruby runner.rb start
38
+ ruby runner.rb restart
39
+ ruby runner.rb stop
40
+
41
+ For testing
42
+
43
+ ruby runner.rb run
44
+
45
+ === Sinatra
46
+
47
+ Start thin server
48
+
49
+ bundle exec thin --rackup config.ru start
50
+
51
+ bundle exec thin start -R config.ru -C config/thin.yml
52
+
53
+ == Platform
54
+
55
+ Ruby 1.9.3-p0
56
+ Redis 2.4.2
57
+ Libcurl (Ubuntu: sudo apt-get install libcurl3 libcurl3-gnutls libcurl4-openssl-dev)
58
+ Browser with websockets enabled
59
+
60
+ Copyright (c) 2011 Aimbulance, released under the MIT license
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rfid'
3
+
4
+ begin
5
+ require 'rfid/cli'
6
+ Rfid::CLI.start
7
+ rescue Interrupt => e
8
+ puts "\nQuitting..."
9
+ puts e.backtrace.join("\n")
10
+ exit 1
11
+ rescue SystemExit => e
12
+ exit e.status
13
+ rescue Exception => e
14
+ puts "Unfortunately, a fatal error has occurred. " +
15
+ "Please report this error to the Rfid issue tracker at " +
16
+ "https://aimbulance.lighthouseapp.com so that we can fix it. Thanks!"
17
+ raise e
18
+ end
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rfid'
3
+
4
+ begin
5
+ require 'rfid/cli'
6
+
7
+ script = Rfid::CLI.new(ARGV)
8
+ script.invoke(:checkout)
9
+ rescue Thor::Error => e
10
+ puts e.message
11
+ rescue Interrupt => e
12
+ puts "\nQuitting..."
13
+ puts e.backtrace.join("\n")
14
+ exit 1
15
+ rescue SystemExit => e
16
+ exit e.status
17
+ rescue Exception => e
18
+ puts "Unfortunately, a fatal error has occurred. " +
19
+ "Please report this error to the Rfid issue tracker at " +
20
+ "https://aimbulance.lighthouseapp.com so that we can fix it. Thanks!"
21
+ raise e
22
+ end
@@ -0,0 +1,9 @@
1
+ require ::File.expand_path('../config/environment', __FILE__)
2
+ require "rack/contrib"
3
+ require "rfid"
4
+
5
+ use Rack::CommonLogger
6
+ use Rack::ShowExceptions
7
+ use Rack::Access, '/' => [ '127.0.0.1' ]
8
+
9
+ run Rfid::Application
@@ -0,0 +1,6 @@
1
+ require 'rubygems'
2
+
3
+ # Set up gems listed in the Gemfile.
4
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
5
+
6
+ require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE'])
@@ -0,0 +1,8 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../../lib", __FILE__)
3
+
4
+ require 'rubygems'
5
+
6
+ # If you have a Gemfile, require the gems listed there, including any gems
7
+ # you've limited to :test, :development, or :production.
8
+ Bundler.require(:default, :development) if defined?(Bundler)
@@ -0,0 +1,6 @@
1
+ redis_url: "redis://127.0.0.1:6379/10"
2
+ redis_key: "rfid_events"
3
+ log_path: "/var/log/rfid.log"
4
+ api_url: "https://rfidapi.aimbulance.com/api/v1"
5
+ device_id: "test"
6
+ device_token: "test"
@@ -0,0 +1,6 @@
1
+ redis_url: "redis://127.0.0.1:6379/10"
2
+ redis_key: "rfid_events"
3
+ log_path: "/var/log/rfid.log"
4
+ api_url: "https://rfidapi.aimbulance.com/api/v1"
5
+ device_id: "test"
6
+ device_token: "test"
@@ -0,0 +1,14 @@
1
+ ---
2
+ address: 127.0.0.1
3
+ pid: /var/run/rfid_thin.pid
4
+ port: 5000
5
+ wait: 10
6
+ timeout: 60
7
+ log: /var/log/rfid_thin.log
8
+ max_conns: 1024
9
+ require: []
10
+
11
+ environment: production
12
+ max_persistent_conns: 512
13
+ daemonize: true
14
+ servers: 1
@@ -0,0 +1,14 @@
1
+ ---
2
+ address: 127.0.0.1
3
+ pid: /var/run/rfid_thin.pid
4
+ port: 5000
5
+ wait: 10
6
+ timeout: 60
7
+ log: /var/log/rfid_thin.log
8
+ max_conns: 1024
9
+ require: []
10
+
11
+ environment: production
12
+ max_persistent_conns: 512
13
+ daemonize: true
14
+ servers: 1
@@ -0,0 +1,75 @@
1
+ require 'active_support/core_ext'
2
+ require 'redis/connection/hiredis'
3
+ require 'redis'
4
+ require 'logger'
5
+ require 'uri'
6
+ require 'rfid/core_ext'
7
+
8
+ module Rfid
9
+ autoload :Application, 'rfid/application'
10
+ autoload :Translator, 'rfid/translator'
11
+ autoload :WebSocket, 'rfid/websocket'
12
+ autoload :Config, 'rfid/config'
13
+ autoload :Event, 'rfid/event'
14
+
15
+ extend self
16
+
17
+ def config
18
+ @config ||= Config.new(config_path)
19
+ end
20
+
21
+ def config_path
22
+ @config_path ||= File.expand_path("../../config/rfid.yml", __FILE__)
23
+ end
24
+
25
+ def redis
26
+ @redis ||= Redis.new(self.redis_options)
27
+ end
28
+
29
+ def redis_options
30
+ url = URI(self.config.redis_url)
31
+ db = (url.path[1..-1] || 10).to_i
32
+ { :host => url.host, :port => url.port, :db => db, :password => url.password }
33
+ end
34
+
35
+ def redis_id
36
+ # support 1.x versions of redis-rb
37
+ if redis.respond_to?(:server)
38
+ redis.server
39
+ elsif redis.respond_to?(:nodes) # distributed
40
+ redis.nodes.map { |n| n.id }.join(', ')
41
+ else
42
+ redis.client.id
43
+ end
44
+ end
45
+
46
+ def push_event(event)
47
+ log("Redis push event", event.inspect)
48
+ redis.rpush(self.config.redis_key, event.to_json)
49
+ end
50
+
51
+ # Returns an array of all known Resque keys in Redis. Redis' KEYS operation
52
+ # is O(N) for the keyspace, so be careful - this can be slow for big databases.
53
+ def keys
54
+ redis.keys("*")
55
+ end
56
+
57
+ def logger
58
+ @logger ||= create_logger(self.config.log_path)
59
+ end
60
+
61
+ def log(*args)
62
+ timestamp = "[#{Time.now.strftime('%d.%m.%Y %H:%M')}]"
63
+ logger.info([timestamp, args.compact].flatten.join(' '))
64
+ end
65
+
66
+ protected
67
+
68
+ def create_logger(filepath)
69
+ logfile = File.open(filepath, 'a')
70
+ logfile.sync = true
71
+ Logger.new(logfile)
72
+ end
73
+ end
74
+
75
+ require 'rfid/version'
@@ -0,0 +1,115 @@
1
+ require 'pathname'
2
+ require 'sinatra'
3
+
4
+ module Rfid
5
+ class Application < Sinatra::Base
6
+ configure do
7
+ root_path = File.join(File.dirname(__FILE__), 'application')
8
+
9
+ enable :logging
10
+
11
+ set :environment, (ENV['RACK_ENV'] || :production)
12
+ set :root_path, Pathname.new(root_path)
13
+ set :public_folder, File.join(root_path, 'public')
14
+ set :views, File.join(root_path, 'views')
15
+ set :static, true
16
+ set :run, false
17
+ end
18
+
19
+ helpers do
20
+ def json_data(data)
21
+ status 200
22
+ content_type "application/json"
23
+ {:response => data}.to_json
24
+ end
25
+
26
+ def current_page
27
+ url_path request.path_info.sub('/','')
28
+ end
29
+
30
+ def url_path(*path_parts)
31
+ [ path_prefix, path_parts ].join("/").squeeze('/')
32
+ end
33
+ alias_method :u, :url_path
34
+
35
+ def path_prefix
36
+ request.env['SCRIPT_NAME']
37
+ end
38
+
39
+ def class_if_current(path = '')
40
+ 'class="active"' if current_page[0, path.size] == path
41
+ end
42
+
43
+ def tab(name)
44
+ dname = name.to_s.downcase
45
+ path = url_path(dname)
46
+ "<li #{class_if_current(path)}><a href='#{path}'>#{name}</a></li>"
47
+ end
48
+
49
+ def redis_get_size(key)
50
+ case Rfid.redis.type(key)
51
+ when 'none'
52
+ []
53
+ when 'list'
54
+ Rfid.redis.llen(key)
55
+ when 'set'
56
+ Rfid.redis.scard(key)
57
+ when 'string'
58
+ Rfid.redis.get(key).length
59
+ when 'zset'
60
+ Rfid.redis.zcard(key)
61
+ end
62
+ end
63
+
64
+ def redis_get_value_as_array(key, start = 0)
65
+ case Rfid.redis.type(key)
66
+ when 'none'
67
+ []
68
+ when 'list'
69
+ Rfid.redis.lrange(key, start, start + 200)
70
+ when 'set'
71
+ Rfid.redis.smembers(key)[start..(start + 200)]
72
+ when 'string'
73
+ [Rfid.redis.get(key)]
74
+ when 'zset'
75
+ Rfid.redis.zrange(key, start, start + 200)
76
+ end
77
+ end
78
+ end
79
+
80
+ get '/' do
81
+ erb :index
82
+ end
83
+
84
+ get '/redis' do
85
+ erb :redis, {:layout => true}, :rfid => Rfid
86
+ end
87
+
88
+ get '/keys' do
89
+ erb :keys, {:layout => true}, :rfid => Rfid
90
+ end
91
+
92
+ get '/keys/:key' do
93
+ @key = params[:key].to_s
94
+ partial = Rfid.redis.type(@key).eql?("string") ? :key_string : :key_sets
95
+ erb partial, {:layout => true}, :rfid => Rfid
96
+ end
97
+
98
+ get '/usage' do
99
+ erb :usage
100
+ end
101
+
102
+ get '/events' do
103
+ erb :events
104
+ end
105
+
106
+ post '/events.?:format?' do
107
+ Rfid.push_event(params[:event])
108
+
109
+ case params[:format]
110
+ when 'json' then json_data(params[:event])
111
+ else redirect "/events?state=success"
112
+ end
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,12 @@
1
+ function jsload(id, source){
2
+ var d = document;
3
+ var s = 'script';
4
+ var js, fjs = d.getElementsByTagName(s)[0];
5
+
6
+ if (d.getElementById(id)) {return;}
7
+ js = d.createElement(s);
8
+ js.id = id;
9
+ js.src = source;
10
+
11
+ fjs.parentNode.insertBefore(js, fjs);
12
+ }
@@ -0,0 +1,59 @@
1
+ function escapeHTML(value) {
2
+ return value.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
3
+ }
4
+
5
+ $(document).ready(function(){
6
+ var debug_console = $('#debug_console');
7
+ var debug_console_tbody = $('tbody', debug_console);
8
+ var channel = new FancyWebSocket("ws://127.0.0.1:8080", { debug: true });
9
+
10
+ function debug(log){
11
+ var logCss = {
12
+ 'socket_opened': 'notice',
13
+ 'socket_closed': 'default',
14
+ 'channel_occupied': 'Occupied',
15
+ 'channel_vacated': 'Vacated',
16
+ 'channel_subscribed': 'notice',
17
+ 'channel_unsubscribed': 'default',
18
+ 'api_message': 'success',
19
+ 'client_message': 'success',
20
+ 'presence_message': 'success',
21
+ 'error': 'important',
22
+ 'api_error': 'important',
23
+ 'client_error': 'important',
24
+ 'pipe_incoming_message': 'warning',
25
+ 'wsapi_message': 'warning'
26
+ };
27
+
28
+ var row = $('<tr>');
29
+ var logType = '<span class="label ' + logCss[log.type] + '">' + log.type + '</span>';
30
+ var message = log.message;
31
+
32
+ row.append('<td class="debug_type">' + logType + '</td>')
33
+ .append('<td class="debug_socket_id">' + (log.socket_id || '') + '</td>')
34
+ .append('<td class="debug_message">' + escapeHTML(message) + '</td>')
35
+ .append('<td class="debug_time">' + log.date + '</td>');
36
+
37
+ if (log.data) {
38
+ var string_data = log.data;
39
+
40
+ try {
41
+ string_data = JSON.stringify(JSON.parse(log.data), null, ' ');
42
+ } catch(e) {}
43
+
44
+ row.find('td.debug_message').append( $('<pre>').text(string_data) );
45
+ }
46
+
47
+ debug_console_tbody.append(row);
48
+ }
49
+
50
+ channel.bind('log_message', function(log){
51
+ debug(log);
52
+ });
53
+
54
+ channel.bind('error', function(data){
55
+ var date = new Date();
56
+ var time = date.getHours() + ":" + date.getMinutes() + ":" + date.getSeconds();
57
+ debug({type: 'error', socket_id: null, message: 'Error', date: time.format("d.m.Y H:i:s"), data: JSON.stringify(data) });
58
+ });
59
+ });