constable 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.
data/README.md ADDED
@@ -0,0 +1,63 @@
1
+ Constable
2
+ =========
3
+
4
+ Seascape Study with Rain Cloud was painted by John Constable around 1824.
5
+
6
+ Constable the Gem is a way of providing ImageMagick as a service. I doubt
7
+ anything quite as powerful will be generated using the service, but if you do
8
+ make something nice please let me know!
9
+
10
+
11
+ Installing
12
+ ----------
13
+
14
+ The server needs ImageMagick installed. Mostly I do this using `apt-get`:
15
+
16
+ apt-get isntall imagemagick
17
+
18
+ You'll need a broker that talks Stomp somewhere on your network. I use Apache
19
+ Apollo, and I'm not totally sure if the code uses anything that's specific to
20
+ that. I'd love it to be broker-agnostic though, so if you have patches that'll
21
+ bring this closer to reality please send them to me!
22
+
23
+
24
+ Usage
25
+ -----
26
+
27
+ ImageMagick provides a huge nubmer of commands and options. Supporting them
28
+ all is a big task, so I'm implementing just the few that I use. If you need
29
+ something else supported, please do fork and patch the project. Let me know
30
+ and I'll pull your changes.
31
+
32
+ Run the server, somewhere that has ImageMagick installed:
33
+
34
+ constabled --broker stomp://mq.yourdomain.com:61613
35
+
36
+ Use the services on the command line. You don't need ot have ImageMagick
37
+ installed on your client machines, just constable.
38
+
39
+ Command names are based on ImageMagick command names, prefixed with
40
+ `constable-`, eg `constable-identify`. All commands will respond to --help
41
+ and will give you a decent explanation of what they do and their options if
42
+ you ask for it.
43
+
44
+ The commands are designed to take their input on standard input and return
45
+ results on standard output. It's up to you what you do with the input and
46
+ output; write it to a file, pipe it to another process, that's not handled by
47
+ Constable (and I have no plans to handle it).
48
+
49
+ A brief example of what interacting with Constable looks like, here
50
+ identifying some image file I had lying around on disk:
51
+
52
+ $ cat input_file | constable-identify --broker stomp://mq.yourdomain.com:61613
53
+ constabled-164829495-102948483-1939485.jpg JPEG 640x480 DirectClass 87kb 0.050u 0:01
54
+
55
+ I explicitly state the broker in the above commands but if you leave out that
56
+ option it'll default to stomp://localhost:61613 ie it expects a broker running
57
+ on your local machine if you don't tell it otherwise.
58
+
59
+
60
+ Authors
61
+ -------
62
+
63
+ Craig R Webster <http://barkingiguana.com/>
@@ -0,0 +1,34 @@
1
+ #! /usr/bin/env ruby
2
+
3
+ image = STDIN.read
4
+ if image.to_s == ''
5
+ puts "Give me some input!"
6
+ exit 1
7
+ end
8
+
9
+ require 'base64'
10
+ encoded_input = Base64.encode64 image
11
+
12
+ require 'stomp'
13
+ require 'json'
14
+
15
+ results = '/queue/constable.results-' + Process.pid.to_s + '-' + Time.now.to_i.to_s
16
+ client = Stomp::Client.new ARGV[0]
17
+ client.subscribe results, 'auto-delete' => true do |message|
18
+ results = JSON.parse message.body
19
+ if results['exit_code'] == 0
20
+ print results['stdout']
21
+ else
22
+ print results['stderr']
23
+ end
24
+ client.close
25
+ end
26
+
27
+ command = {
28
+ command: 'identify',
29
+ input: encoded_input
30
+ }
31
+ command_json = JSON.generate command
32
+
33
+ client.publish '/queue/constable', command_json, 'reply-to' => results
34
+ client.join
data/bin/constabled ADDED
@@ -0,0 +1,107 @@
1
+ #! /usr/bin/env ruby
2
+
3
+ require 'stomp'
4
+ require 'digest/sha1'
5
+ require 'json'
6
+ require 'tempfile'
7
+ require 'open3'
8
+ require 'base64'
9
+
10
+ class Job
11
+ module WorkingEnvironment
12
+ def with_temp_file
13
+ temp_file = Tempfile.new serial
14
+ yield temp_file
15
+ ensure
16
+ temp_file.close!
17
+ end
18
+
19
+ def serial
20
+ @job_id ||= [
21
+ File.basename($0), Time.now.to_i, rand(1_000_000)
22
+ ].join '-'
23
+ end
24
+
25
+ def using_file_with_content encoded_content, &block
26
+ decoded_content = Base64.decode64 encoded_content
27
+ with_temp_file do |file|
28
+ file.print decoded_content
29
+ file.flush
30
+ yield file
31
+ end
32
+ end
33
+
34
+ def run_command command
35
+ puts "Running #{command}"
36
+ stdin, stdout, stderr, command = Open3.popen3 command
37
+ {
38
+ stdout: stdout.readlines.join,
39
+ stderr: stderr.readlines.join,
40
+ exit_code: command.value.exitstatus,
41
+ pid: command.value.pid
42
+ }
43
+ end
44
+ end
45
+
46
+ class IdentifyCommand
47
+ include WorkingEnvironment
48
+
49
+ attr_accessor :options
50
+ private :options, :options=
51
+
52
+ def initialize options
53
+ self.options = options
54
+ end
55
+
56
+ def execute
57
+ using_file_with_content options['input'] do |file|
58
+ run_command "identify #{file.path}"
59
+ end
60
+ end
61
+ end
62
+
63
+ attr_accessor :options
64
+ private :options, :options=
65
+
66
+ def initialize options
67
+ self.options = options
68
+ end
69
+
70
+ def execute
71
+ handler.execute
72
+ end
73
+
74
+ def handler
75
+ handler_class.new options
76
+ end
77
+
78
+ def handler_class
79
+ Job.const_get handler_name
80
+ end
81
+
82
+ def handler_name
83
+ name = command_name
84
+ name.gsub!(/\/(.?)/) { "::#{$1.upcase}" }
85
+ name.gsub!(/(?:^|_)(.)/) { $1.upcase }
86
+ name + 'Command'
87
+ end
88
+
89
+ def command_name
90
+ options["command"]
91
+ end
92
+ end
93
+
94
+ client = Stomp::Client.new ARGV[0]
95
+ client.subscribe '/queue/constable' do |message|
96
+ puts "Received #{message.headers['message-id']}"
97
+
98
+ options = JSON.parse message.body
99
+ results = Job.new(options).execute
100
+
101
+ result_json = JSON.generate results
102
+ destination = message.headers['reply-to']
103
+ client.publish destination, result_json
104
+ end
105
+
106
+ puts "Waiting for clients..."
107
+ client.join
@@ -0,0 +1,3 @@
1
+ module Constable
2
+ VERSION = '0.0.1'
3
+ end
data/lib/constable.rb ADDED
@@ -0,0 +1 @@
1
+ require 'constable/version'
metadata ADDED
@@ -0,0 +1,65 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: constable
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Craig R Webster
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-09-30 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: stomp
16
+ requirement: &70138922339840 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *70138922339840
25
+ description: Installing ImageMagick and RMagick everywhere sucks, right? So install
26
+ it in one place and have everything else use that one install.
27
+ email:
28
+ - craig@barkingiguana.com
29
+ executables:
30
+ - constabled
31
+ - constable-identify
32
+ extensions: []
33
+ extra_rdoc_files: []
34
+ files:
35
+ - lib/constable/version.rb
36
+ - lib/constable.rb
37
+ - bin/constable-identify
38
+ - bin/constabled
39
+ - README.md
40
+ homepage:
41
+ licenses: []
42
+ post_install_message:
43
+ rdoc_options: []
44
+ require_paths:
45
+ - lib
46
+ required_ruby_version: !ruby/object:Gem::Requirement
47
+ none: false
48
+ requirements:
49
+ - - ! '>='
50
+ - !ruby/object:Gem::Version
51
+ version: '0'
52
+ required_rubygems_version: !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ! '>='
56
+ - !ruby/object:Gem::Version
57
+ version: '0'
58
+ requirements:
59
+ - A broker capable of talking Stomp
60
+ rubyforge_project:
61
+ rubygems_version: 1.8.10
62
+ signing_key:
63
+ specification_version: 3
64
+ summary: ImageMagick as a service
65
+ test_files: []