millworker 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Binary file
@@ -0,0 +1,23 @@
1
+ # -*- ruby -*-
2
+
3
+ require 'autotest/restart'
4
+
5
+ # Autotest.add_hook :initialize do |at|
6
+ # at.extra_files << "../some/external/dependency.rb"
7
+ #
8
+ # at.libs << ":../some/external"
9
+ #
10
+ # at.add_exception 'vendor'
11
+ #
12
+ # at.add_mapping(/dependency.rb/) do |f, _|
13
+ # at.files_matching(/test_.*rb$/)
14
+ # end
15
+ #
16
+ # %w(TestA TestB).each do |klass|
17
+ # at.extra_class_map[klass] = "test/test_misc.rb"
18
+ # end
19
+ # end
20
+
21
+ # Autotest.add_hook :run_command do |at|
22
+ # system "rake build"
23
+ # end
File without changes
@@ -0,0 +1,6 @@
1
+ === 1.0.0 / 2012-08-22
2
+
3
+ * 1 major enhancement
4
+
5
+ * Birthday!
6
+
data/LICENSE ADDED
@@ -0,0 +1,23 @@
1
+ (The MIT License)
2
+
3
+ Copyright (c) 2012 Tom Kersten
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ 'Software'), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
+
@@ -0,0 +1,12 @@
1
+ .autotest
2
+ History.txt
3
+ LICENSE
4
+ Manifest.txt
5
+ README.md
6
+ Rakefile
7
+ bin/millworker
8
+ example_tasks/log_to_csv.rb
9
+ lib/millworker.rb
10
+ lib/millworker/version.rb
11
+ spec/spec.opts
12
+ spec/spec_helper.rb
@@ -0,0 +1,83 @@
1
+ # millworker
2
+
3
+ * http://github.com/tomkersten/millworker
4
+
5
+ ## DESCRIPTION:
6
+
7
+ A Ruby gem which takes the pain of continuously reading data from a serial port
8
+ away and lets you focus on dealing with the data received.
9
+
10
+ This was written specifically for reading in data from an ID-20
11
+ RFID card reader and running custom scripts to automatically perform
12
+ various tasks when patrons scanned their badge at the
13
+ [MN Mill](http://mnmill.org) (logging attendance, etc).
14
+
15
+
16
+ Custom scripts are loaded from `ENV["HOME"]/millworker/tasks` and are executed
17
+ in alphabetical order. Each script is executed with the ID of the badge passed
18
+ in as an argument. For example, a script called `tweet_id.rb` existed in the
19
+ afformentioned directory, it would be executed as if you had opened up a
20
+ command terminal and typed `tweet_id.rb RFID_TAG_ID_HERE`.
21
+
22
+ ## SYNOPSIS:
23
+
24
+ Install the millworker gem (see below for instructions).
25
+
26
+ In order read from the correct port on your computer, we need to do a bit of
27
+ setup.
28
+
29
+ ```bash
30
+ millworker setup
31
+ #...you will be prompted for the name of the serial port
32
+ ```
33
+
34
+ Provided you keep the device connected to the same port, you should only
35
+ have to run this one time. In the event that things stop working for some
36
+ odd reason, you can re-run this as many times as necessary to overwrite
37
+ and/or verify your settings.
38
+
39
+ Next, start the worker by issuing the following command
40
+
41
+ ```bash
42
+ millworker start
43
+ ```
44
+
45
+ Each time the reader receives a card, an entry in the logfile is written, which
46
+ includes a timestamp and the data which was read over the serial port. After
47
+ logging this information, each script located in the `millworker/scripts`
48
+ directory is executed with the received data passed in as an argument.
49
+
50
+ You can stop the worker any time by issuing the following command:
51
+
52
+ ```bash
53
+ millworker stop
54
+ ```
55
+
56
+ ## REQUIREMENTS:
57
+
58
+ * Ruby 1.9.3+
59
+ * Please refer to the Gemfile for gem dependencies.
60
+
61
+ ## INSTALL:
62
+
63
+ From the command line:
64
+
65
+ ```bash
66
+ gem install millworker
67
+ ```
68
+
69
+ ## UNINSTALL:
70
+
71
+ From the command line:
72
+
73
+ ```bash
74
+ gem uninstall millworker
75
+ ```
76
+
77
+ __Note:__ You may also want to removes the entire `ENV['HOME']/millworker`
78
+ directory. This is not done automatically to prevent accidental data
79
+ loss.
80
+
81
+ ## LICENSE:
82
+
83
+ See the LICENSE file (hint: MIT)
@@ -0,0 +1,24 @@
1
+ # -*- ruby -*-
2
+
3
+ require 'rubygems'
4
+ require 'hoe'
5
+
6
+ Hoe.plugin :bundler
7
+ Hoe.plugin :git
8
+
9
+ Hoe.spec 'millworker' do
10
+ developer 'Tom Kersten', 'tom@whitespur.com'
11
+ dependency 'gli', "~> 2.0"
12
+ dependency 'dante', "~> 0.1"
13
+ dependency 'serialport', "~> 1.1"
14
+
15
+ self.readme_file = 'README.md'
16
+ self.extra_rdoc_files = FileList['README.md', 'LICENSE']
17
+ self.extra_dev_deps = [['rake'],
18
+ ['aruba'],
19
+ ['hoe-bundler'],
20
+ ['hoe-git']
21
+ ]
22
+ end
23
+
24
+ # vim: syntax=ruby
@@ -0,0 +1,121 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'gli'
4
+ require 'dante'
5
+ require 'fileutils'
6
+ require 'logger'
7
+ require 'serialport'
8
+
9
+ require 'millworker'
10
+
11
+ include GLI::App
12
+
13
+ program_desc 'Listen to a serial port and execute custom scripts with data received.'
14
+
15
+ version Millworker::VERSION
16
+
17
+ SERIAL_PORT = ENV['MILLWORKER_SERIAL_PORT']
18
+ BASE_PATH = ENV['MILLWORKER_PATH'] || File.expand_path(ENV['HOME'] + '/millworker')
19
+ CONFIG_PATH = "#{BASE_PATH}/config.yml"
20
+ TASKS_DIR = "#{BASE_PATH}/tasks"
21
+ TMP_DIR = "#{BASE_PATH}/tmp"
22
+ LOG_DIR = "#{BASE_PATH}/log"
23
+ LOG_PATH = "#{LOG_DIR}/millworker.log"
24
+ DAEMON_LOG_PATH = "#{LOG_DIR}/millworkerd.log"
25
+ PID_PATH = "#{TMP_DIR}/willworker.pid"
26
+ EXAMPLE_TASKS_DIR = File.join(File.dirname(File.dirname(__FILE__)), "example_tasks")
27
+
28
+ def execute(executable)
29
+ result = system(executable) ? "success" : "failure"
30
+ yield result
31
+ end
32
+
33
+ def config
34
+ @config ||= File.exists?(CONFIG_PATH) ? YAML.load(File.open(CONFIG_PATH)) : {}
35
+ end
36
+
37
+ def serial_port
38
+ SerialPort.new(SERIAL_PORT || config[:serial_port])
39
+ end
40
+
41
+
42
+ desc "Set up machine to use `millworker` executable"
43
+ command :setup do |c|
44
+ c.action do |g, o, a|
45
+ puts "Setting up millworker directory structure in #{BASE_PATH}"
46
+ [BASE_PATH, TMP_DIR, LOG_DIR, TASKS_DIR].each do |dir|
47
+ FileUtils.mkdir_p(dir) unless File.directory?(dir)
48
+ end
49
+ puts ""
50
+
51
+ port_name = nil
52
+ until !port_name.nil?
53
+ puts "What is the name of the serial port you'd like to read from? (eg: COM1): "
54
+ port_name= gets
55
+ port_name.strip!
56
+ end
57
+
58
+ File.open(CONFIG_PATH, "w") {|f| f.write({serial_port: port_name}.to_yaml)}
59
+
60
+ puts "Copying example tasks to #{TASKS_DIR}"
61
+ Dir["#{EXAMPLE_TASKS_DIR}/*"].map { |file|
62
+ FileUtils.cp file, TASKS_DIR
63
+ FileUtils.chmod 0755, "#{TASKS_DIR}/#{File.basename(file)}"
64
+ }
65
+
66
+ puts "Done. Now run 'millworker start' and you should be set!"
67
+ end
68
+ end
69
+
70
+ desc "Start lisening for data on an attached ID20 card reader."
71
+ command :start do |c|
72
+ c.switch :stdin, desc: 'Read input from STDIN (command line) instead of a serial port.'
73
+
74
+ c.action do |g, options, args|
75
+ Dante::Runner.new('millworker').execute(daemonize: !options[:stdin],
76
+ pid_path: PID_PATH,
77
+ log_path: DAEMON_LOG_PATH) {
78
+
79
+ FileUtils.mkdir_p(LOG_DIR) unless File.directory?(LOG_DIR)
80
+ logger = Logger.new(LOG_PATH)
81
+
82
+ input = options[:stdin] ? ARGF : serial_port
83
+
84
+ loop do
85
+ data = input.gets
86
+
87
+ unless data.nil? || data.empty?
88
+ data.strip! # Take off newline from serial read
89
+
90
+ logger.info "received: '#{data.chomp}'"
91
+
92
+ # Read task list in every time so the daemon does not need to be
93
+ # restarted after changes
94
+ tasks = Dir["#{TASKS_DIR}/*"]
95
+
96
+ if tasks.empty?
97
+ logger.warn "No tasks to execute in '#{TASKS_DIR}'. Skipping."
98
+ next
99
+ else
100
+ tasks.each do |task|
101
+ command = "#{task} #{data}"
102
+
103
+ execute(command) { |result|
104
+ logger.info("executed: '#{command}', result: #{result}")
105
+ }
106
+ end
107
+ end
108
+ end
109
+ end
110
+ }
111
+ end
112
+ end
113
+
114
+ desc "Stops a running application currently lisening for data."
115
+ command :stop do |c|
116
+ c.action do
117
+ Dante::Runner.new('millworker').execute(kill: true, pid_path: PID_PATH)
118
+ end
119
+ end
120
+
121
+ exit run(ARGV)
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ require 'csv'
3
+
4
+ CSV_FILENAME = "millworker_log.csv"
5
+ CSV_DIR = ENV["MILLWORKER_CSV_DIR"] || File.expand_path("#{ENV['HOME']}/Desktop")
6
+ CSV_PATH = "#{CSV_DIR}/#{CSV_FILENAME}"
7
+
8
+ when_new_file = !File.exists?(CSV_PATH)
9
+
10
+ CSV_OPTIONS = {headers: %w(timestamp card_id),
11
+ write_headers: when_new_file,
12
+ force_quotes: true
13
+ }
14
+ CSV.open(CSV_PATH, "a+", CSV_OPTIONS) {|csv| csv << [Time.now, ARGV[0]]}
@@ -0,0 +1,4 @@
1
+ require 'millworker/version'
2
+
3
+ module Millworker
4
+ end
@@ -0,0 +1,3 @@
1
+ module Millworker
2
+ VERSION = '0.1.0'
3
+ end
@@ -0,0 +1,4 @@
1
+ --colour
2
+ --format
3
+ profile
4
+ --diff
@@ -0,0 +1,3 @@
1
+ require 'lib/<lib_name>'
2
+
3
+ Dir.glob('spec/support/**/*.rb').each {|f| require f}
metadata ADDED
@@ -0,0 +1,245 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: millworker
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Tom Kersten
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain:
12
+ - !binary |-
13
+ LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURNRENDQWhpZ0F3SUJB
14
+ Z0lCQURBTkJna3Foa2lHOXcwQkFRVUZBREErTVF3d0NnWURWUVFEREFOMGIy
15
+ MHgKR1RBWEJnb0praWFKay9Jc1pBRVpGZ2wzYUdsMFpYTndkWEl4RXpBUkJn
16
+ b0praWFKay9Jc1pBRVpGZ05qYjIwdwpIaGNOTVRFd05ESXlNRFF6T1RBNVdo
17
+ Y05NVEl3TkRJeE1EUXpPVEE1V2pBK01Rd3dDZ1lEVlFRRERBTjBiMjB4CkdU
18
+ QVhCZ29Ka2lhSmsvSXNaQUVaRmdsM2FHbDBaWE53ZFhJeEV6QVJCZ29Ka2lh
19
+ SmsvSXNaQUVaRmdOamIyMHcKZ2dFaU1BMEdDU3FHU0liM0RRRUJBUVVBQTRJ
20
+ QkR3QXdnZ0VLQW9JQkFRRHB4b3pEUWdWTi9vWmxqR2xJOW9wbQpDcmhOVkEv
21
+ bHNOaVhaQlVtamZRQzVYUlBZSHptbHVvbjJaejQwNTBsak9ES1grYi90a3ov
22
+ V1ZaNng3YStMb3AyCnlDTExXTGNITmdCMTBqM2ozazZiTTBsM2NmQ2RDdnpl
23
+ dkU3WmdwdzNvL2J6YXpTVDV4MHBOenVyYXNTMW91UWsKeC8ybzlFNnFxSlJ1
24
+ QjUxa2h1WktuaCtNYTUyL0kxS1FhTUo0Ylc2Tk9ncXVGQ0VJdW04TUpKQkpX
25
+ RWRHbTRJdAp2aFMvZGFSZS9BRGtZbGdXbDFZMWs3THh1SCsxVkN4N3pNRk1l
26
+ MUUwQ01KemhHZjd6dU1TMHcrZHF3Ykw1bTNOCk1MRTh2Z3h3VEVPc093R3o0
27
+ d0Q2ek1VZEJZNkZHWXdSazhMR2p2bG9rbjBwWjFqeVdIV1NnMmJVdi8xR0My
28
+ aTkKQWdNQkFBR2pPVEEzTUFrR0ExVWRFd1FDTUFBd0N3WURWUjBQQkFRREFn
29
+ U3dNQjBHQTFVZERnUVdCQlRONjFBegp5a0RZaGVSSHR6c2p3RTdmaUxoWW16
30
+ QU5CZ2txaGtpRzl3MEJBUVVGQUFPQ0FRRUFMd29Jbld1YkpYSllWSDJOClhu
31
+ Q01UNFlseE5zUW9ZZERTeEVhZ05PbVpqSzJlS3RqdTBWOUdqWkFueVlCMnEy
32
+ TExpbHZiTXlWdGcvNkFOMEkKWGhDanlZWlJSQ0FEeXZGR1Y0YUJWdjd5aktG
33
+ UXJJeVh5OEpUMWlYeEhDMU4ybzFESmxaVWx0Q1lOb3pKQmhzTwpWTmJuU3Fl
34
+ OFlZY2V6c3VRMi93OWlhdldYQ2Y5MVFQd25yZkhQWlRyRlBPdmVza0pjdG04
35
+ SGluRjQxZkt3RzVCCmlVSHk4cVZXR0JDcERGWXo2S3orSnRpZ2FJQ2NtMkQ0
36
+ L1dHTHNEVk9tZ0orZzR4b09pQ2U5WkVrZGE4SytsL0YKeVhXcUluUmxGSWxU
37
+ dXdGVHhqMjZqYXVCb3NrQlBvejViZmtaRmphVlJoeVVuUm5Ha2E2Nmx2Y0RP
38
+ R2ZrUlpXUQpOVkFESkE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
39
+ date: 2012-09-10 00:00:00.000000000 Z
40
+ dependencies:
41
+ - !ruby/object:Gem::Dependency
42
+ name: gli
43
+ requirement: !ruby/object:Gem::Requirement
44
+ none: false
45
+ requirements:
46
+ - - ~>
47
+ - !ruby/object:Gem::Version
48
+ version: '2.0'
49
+ type: :runtime
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ none: false
53
+ requirements:
54
+ - - ~>
55
+ - !ruby/object:Gem::Version
56
+ version: '2.0'
57
+ - !ruby/object:Gem::Dependency
58
+ name: dante
59
+ requirement: !ruby/object:Gem::Requirement
60
+ none: false
61
+ requirements:
62
+ - - ~>
63
+ - !ruby/object:Gem::Version
64
+ version: '0.1'
65
+ type: :runtime
66
+ prerelease: false
67
+ version_requirements: !ruby/object:Gem::Requirement
68
+ none: false
69
+ requirements:
70
+ - - ~>
71
+ - !ruby/object:Gem::Version
72
+ version: '0.1'
73
+ - !ruby/object:Gem::Dependency
74
+ name: serialport
75
+ requirement: !ruby/object:Gem::Requirement
76
+ none: false
77
+ requirements:
78
+ - - ~>
79
+ - !ruby/object:Gem::Version
80
+ version: '1.1'
81
+ type: :runtime
82
+ prerelease: false
83
+ version_requirements: !ruby/object:Gem::Requirement
84
+ none: false
85
+ requirements:
86
+ - - ~>
87
+ - !ruby/object:Gem::Version
88
+ version: '1.1'
89
+ - !ruby/object:Gem::Dependency
90
+ name: rake
91
+ requirement: !ruby/object:Gem::Requirement
92
+ none: false
93
+ requirements:
94
+ - - ! '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ type: :development
98
+ prerelease: false
99
+ version_requirements: !ruby/object:Gem::Requirement
100
+ none: false
101
+ requirements:
102
+ - - ! '>='
103
+ - !ruby/object:Gem::Version
104
+ version: '0'
105
+ - !ruby/object:Gem::Dependency
106
+ name: aruba
107
+ requirement: !ruby/object:Gem::Requirement
108
+ none: false
109
+ requirements:
110
+ - - ! '>='
111
+ - !ruby/object:Gem::Version
112
+ version: '0'
113
+ type: :development
114
+ prerelease: false
115
+ version_requirements: !ruby/object:Gem::Requirement
116
+ none: false
117
+ requirements:
118
+ - - ! '>='
119
+ - !ruby/object:Gem::Version
120
+ version: '0'
121
+ - !ruby/object:Gem::Dependency
122
+ name: hoe-bundler
123
+ requirement: !ruby/object:Gem::Requirement
124
+ none: false
125
+ requirements:
126
+ - - ! '>='
127
+ - !ruby/object:Gem::Version
128
+ version: '0'
129
+ type: :development
130
+ prerelease: false
131
+ version_requirements: !ruby/object:Gem::Requirement
132
+ none: false
133
+ requirements:
134
+ - - ! '>='
135
+ - !ruby/object:Gem::Version
136
+ version: '0'
137
+ - !ruby/object:Gem::Dependency
138
+ name: hoe-git
139
+ requirement: !ruby/object:Gem::Requirement
140
+ none: false
141
+ requirements:
142
+ - - ! '>='
143
+ - !ruby/object:Gem::Version
144
+ version: '0'
145
+ type: :development
146
+ prerelease: false
147
+ version_requirements: !ruby/object:Gem::Requirement
148
+ none: false
149
+ requirements:
150
+ - - ! '>='
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ - !ruby/object:Gem::Dependency
154
+ name: hoe
155
+ requirement: !ruby/object:Gem::Requirement
156
+ none: false
157
+ requirements:
158
+ - - ~>
159
+ - !ruby/object:Gem::Version
160
+ version: '3.0'
161
+ type: :development
162
+ prerelease: false
163
+ version_requirements: !ruby/object:Gem::Requirement
164
+ none: false
165
+ requirements:
166
+ - - ~>
167
+ - !ruby/object:Gem::Version
168
+ version: '3.0'
169
+ description: ! 'A Ruby gem which takes the pain of continuously reading data from
170
+ a serial port
171
+
172
+ away and lets you focus on dealing with the data received.
173
+
174
+
175
+ This was written specifically for reading in data from an ID-20
176
+
177
+ RFID card reader and running custom scripts to automatically perform
178
+
179
+ various tasks when patrons scanned their badge at the
180
+
181
+ [MN Mill](http://mnmill.org) (logging attendance, etc).
182
+
183
+
184
+
185
+ Custom scripts are loaded from `ENV["HOME"]/millworker/tasks` and are executed
186
+
187
+ in alphabetical order. Each script is executed with the ID of the badge passed
188
+
189
+ in as an argument. For example, a script called `tweet_id.rb` existed in the
190
+
191
+ afformentioned directory, it would be executed as if you had opened up a
192
+
193
+ command terminal and typed `tweet_id.rb RFID_TAG_ID_HERE`.'
194
+ email:
195
+ - tom@whitespur.com
196
+ executables:
197
+ - millworker
198
+ extensions: []
199
+ extra_rdoc_files:
200
+ - History.txt
201
+ - Manifest.txt
202
+ - README.md
203
+ - LICENSE
204
+ files:
205
+ - .autotest
206
+ - History.txt
207
+ - LICENSE
208
+ - Manifest.txt
209
+ - README.md
210
+ - Rakefile
211
+ - bin/millworker
212
+ - example_tasks/log_to_csv.rb
213
+ - lib/millworker.rb
214
+ - lib/millworker/version.rb
215
+ - spec/spec.opts
216
+ - spec/spec_helper.rb
217
+ - .gemtest
218
+ homepage: http://github.com/tomkersten/millworker
219
+ licenses: []
220
+ post_install_message:
221
+ rdoc_options:
222
+ - --main
223
+ - README.md
224
+ require_paths:
225
+ - lib
226
+ required_ruby_version: !ruby/object:Gem::Requirement
227
+ none: false
228
+ requirements:
229
+ - - ! '>='
230
+ - !ruby/object:Gem::Version
231
+ version: '0'
232
+ required_rubygems_version: !ruby/object:Gem::Requirement
233
+ none: false
234
+ requirements:
235
+ - - ! '>='
236
+ - !ruby/object:Gem::Version
237
+ version: '0'
238
+ requirements: []
239
+ rubyforge_project: millworker
240
+ rubygems_version: 1.8.23
241
+ signing_key:
242
+ specification_version: 3
243
+ summary: A Ruby gem which takes the pain of continuously reading data from a serial
244
+ port away and lets you focus on dealing with the data received
245
+ test_files: []
Binary file