quartz 0.1.0 → 0.2.0
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.
- checksums.yaml +4 -4
- data/README.md +11 -4
- data/VERSION +1 -1
- data/go/quartz/quartz.go +7 -2
- data/lib/quartz/client.rb +1 -1
- data/lib/quartz/go_process.rb +45 -5
- data/lib/quartz/go_struct.rb +7 -1
- data/quartz.gemspec +3 -3
- data/spec/go_process_spec.rb +34 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 38e17e14fd92fe48bde386619caf1a6c290b382f
|
4
|
+
data.tar.gz: 67579895994930814c09d929af14a4df14e38a42
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1be3464bd2d6dd945f2f7abc0d4da0551c362fa1d69011a35699daa515b325533f43b3acad5e1a91bd83bb30b8a141fe4daad5d626190fa3bfe13395d694cba9
|
7
|
+
data.tar.gz: dea73da76d59574c5b984e612b5ff1b97c8025db45c42edeb05b4560500521e54943704532c8a3abd187a63f27dab9d3a35d58d9b5a9bfe1da08eed0a6f3fe6b
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# quartz
|
2
2
|
|
3
|
-
[](https://travis-ci.org/DavidHuie/quartz)
|
4
4
|
|
5
5
|
Quartz enables you to call Go code from within your
|
6
6
|
Ruby code. This is accomplished by running a Go program
|
@@ -43,7 +43,7 @@ func (t *Adder) Add(args Args, response *Response) error {
|
|
43
43
|
## Preparing a Quartz RPC server in Go
|
44
44
|
|
45
45
|
Instead of integrating Quartz into an existing Go application,
|
46
|
-
it is recommended to create a new
|
46
|
+
it is recommended to create a new program
|
47
47
|
that explicitly defines the structs that should be available
|
48
48
|
to Ruby.
|
49
49
|
|
@@ -77,11 +77,18 @@ Naturally:
|
|
77
77
|
$ gem install quartz
|
78
78
|
```
|
79
79
|
|
80
|
-
|
80
|
+
If you have a `go run`-able file, you can create a Go client that
|
81
81
|
points to that file:
|
82
82
|
|
83
83
|
```ruby
|
84
|
-
client = Quartz::Client.new(file_path: '
|
84
|
+
client = Quartz::Client.new(file_path: 'my_adder.go')
|
85
|
+
```
|
86
|
+
|
87
|
+
If you compiled the Go program yourself, you can create a client
|
88
|
+
that points to the binary like this:
|
89
|
+
|
90
|
+
```ruby
|
91
|
+
client = Quartz::Client.new(bin_path: 'my_adder_binary')
|
85
92
|
```
|
86
93
|
|
87
94
|
To list exported structs:
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.2.0
|
data/go/quartz/quartz.go
CHANGED
@@ -118,8 +118,13 @@ func (q *Quartz) GetMetadata(_ interface{}, value *map[string]*StructMetadata) e
|
|
118
118
|
}
|
119
119
|
|
120
120
|
func init() {
|
121
|
+
socket_path := os.Getenv("QUARTZ_SOCKET")
|
122
|
+
if socket_path == "" {
|
123
|
+
socket_path = "/tmp/quartz.socket"
|
124
|
+
}
|
125
|
+
|
121
126
|
var err error
|
122
|
-
listener, err = net.Listen("unix",
|
127
|
+
listener, err = net.Listen("unix", socket_path)
|
123
128
|
if err != nil {
|
124
129
|
panic(err)
|
125
130
|
}
|
@@ -131,7 +136,7 @@ func init() {
|
|
131
136
|
|
132
137
|
// Cleanup the socket file when the server is killed
|
133
138
|
sigc := make(chan os.Signal)
|
134
|
-
signal.Notify(sigc,
|
139
|
+
signal.Notify(sigc, syscall.SIGTERM)
|
135
140
|
go func() {
|
136
141
|
<-sigc
|
137
142
|
err := listener.Close()
|
data/lib/quartz/client.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
class Quartz::Client
|
2
2
|
|
3
3
|
def initialize(opts)
|
4
|
-
@process = Quartz::GoProcess.new(
|
4
|
+
@process = Quartz::GoProcess.new(opts)
|
5
5
|
@structs = {}
|
6
6
|
@process.get_metadata.each do |struct_name, metadata|
|
7
7
|
@structs[struct_name.to_sym] = Quartz::GoStruct.new(struct_name, metadata, @process)
|
data/lib/quartz/go_process.rb
CHANGED
@@ -1,18 +1,39 @@
|
|
1
1
|
class Quartz::GoProcess
|
2
2
|
|
3
|
+
attr_reader :temp_file_path
|
4
|
+
|
5
|
+
def self.processes
|
6
|
+
@processes ||= []
|
7
|
+
end
|
8
|
+
|
3
9
|
def initialize(opts)
|
4
|
-
@socket_path = "/tmp/
|
10
|
+
@socket_path = "/tmp/quartz_#{rand(10000)}.sock"
|
5
11
|
ENV['QUARTZ_SOCKET'] = @socket_path
|
6
12
|
|
7
13
|
if opts[:file_path]
|
8
|
-
|
14
|
+
compile_and_run(opts[:file_path])
|
9
15
|
elsif opts[:bin_path]
|
10
|
-
@go_process =
|
16
|
+
@go_process = IO.popen(opts[:bin_path])
|
11
17
|
else
|
12
18
|
raise 'Missing go binary'
|
13
19
|
end
|
14
20
|
|
15
21
|
block_until_server_starts
|
22
|
+
self.class.processes << self
|
23
|
+
end
|
24
|
+
|
25
|
+
def compile_and_run(path)
|
26
|
+
@temp_file_path = "/tmp/quartz_runner_#{rand(10000)}"
|
27
|
+
|
28
|
+
unless system('go', 'build', '-o', @temp_file_path, path)
|
29
|
+
raise 'Go compilation failed'
|
30
|
+
end
|
31
|
+
|
32
|
+
@go_process = IO.popen(@temp_file_path)
|
33
|
+
end
|
34
|
+
|
35
|
+
def pid
|
36
|
+
@go_process.pid
|
16
37
|
end
|
17
38
|
|
18
39
|
def socket
|
@@ -40,7 +61,13 @@ class Quartz::GoProcess
|
|
40
61
|
}
|
41
62
|
|
42
63
|
socket.send(payload.to_json, 0)
|
43
|
-
read
|
64
|
+
response = read
|
65
|
+
|
66
|
+
if response['error']
|
67
|
+
raise "Metadata error: #{read['error']}"
|
68
|
+
end
|
69
|
+
|
70
|
+
response['result']
|
44
71
|
end
|
45
72
|
|
46
73
|
def call(struct_name, method, args)
|
@@ -61,7 +88,20 @@ class Quartz::GoProcess
|
|
61
88
|
MAX_MESSAGE_SIZE = 1_000_000_000 # Bytes
|
62
89
|
|
63
90
|
def read
|
64
|
-
JSON(socket.recv(MAX_MESSAGE_SIZE))
|
91
|
+
JSON(socket.recv(MAX_MESSAGE_SIZE))
|
92
|
+
end
|
93
|
+
|
94
|
+
def cleanup
|
95
|
+
Process.kill('SIGTERM', pid)
|
96
|
+
Process.wait(pid)
|
97
|
+
File.delete(@temp_file_path) if @temp_file_path
|
98
|
+
self.class.processes.delete(self)
|
99
|
+
end
|
100
|
+
|
101
|
+
def self.cleanup
|
102
|
+
processes.each { |p| p.cleanup }
|
65
103
|
end
|
66
104
|
|
67
105
|
end
|
106
|
+
|
107
|
+
at_exit { Quartz::GoProcess.cleanup }
|
data/lib/quartz/go_struct.rb
CHANGED
@@ -30,7 +30,13 @@ class Quartz::GoStruct
|
|
30
30
|
# TODO: validate type
|
31
31
|
end
|
32
32
|
|
33
|
-
@process.call(@struct_name, method_name, args)
|
33
|
+
response = @process.call(@struct_name, method_name, args)
|
34
|
+
|
35
|
+
if response['error']
|
36
|
+
raise "Error calling #{method_name}: #{response['error']}"
|
37
|
+
end
|
38
|
+
|
39
|
+
response['result']
|
34
40
|
end
|
35
41
|
|
36
42
|
end
|
data/quartz.gemspec
CHANGED
@@ -2,15 +2,15 @@
|
|
2
2
|
# DO NOT EDIT THIS FILE DIRECTLY
|
3
3
|
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
|
-
# stub: quartz 0.
|
5
|
+
# stub: quartz 0.2.0 ruby lib
|
6
6
|
|
7
7
|
Gem::Specification.new do |s|
|
8
8
|
s.name = "quartz"
|
9
|
-
s.version = "0.
|
9
|
+
s.version = "0.2.0"
|
10
10
|
|
11
11
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
12
12
|
s.authors = ["David Huie"]
|
13
|
-
s.date = "2014-06-
|
13
|
+
s.date = "2014-06-17"
|
14
14
|
s.description = "A gem for calling #golang code from ruby"
|
15
15
|
s.email = "dahuie@gmail.com"
|
16
16
|
s.extra_rdoc_files = [
|
data/spec/go_process_spec.rb
CHANGED
@@ -20,7 +20,40 @@ describe Quartz::GoProcess do
|
|
20
20
|
|
21
21
|
it 'is able to call a method on a struct' do
|
22
22
|
result = process.call('adder', 'Add', { 'A' => 5, 'B' => 6 })
|
23
|
-
result.should eq({"X"=>11})
|
23
|
+
result.should eq({"id"=>1, "result"=>{"X"=>11}, "error"=>nil})
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'works with an existing binary file' do
|
29
|
+
temp_file = "/tmp/quartz_test_#{rand(10000)}"
|
30
|
+
system('go', 'build', '-o', temp_file, 'spec/test.go')
|
31
|
+
process = Quartz::GoProcess.new(bin_path: temp_file)
|
32
|
+
result = process.call('adder', 'Add', { 'A' => 5, 'B' => 6 })
|
33
|
+
result.should eq({"id"=>1, "result"=>{"X"=>11}, "error"=>nil})
|
34
|
+
File.delete(temp_file)
|
35
|
+
end
|
36
|
+
|
37
|
+
describe '.cleanup' do
|
38
|
+
|
39
|
+
context 'files' do
|
40
|
+
|
41
|
+
it "it deletes temporary files" do
|
42
|
+
File.exists?(process.temp_file_path).should be_true
|
43
|
+
process.cleanup
|
44
|
+
File.exists?(process.temp_file_path).should be_false
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
context 'processes' do
|
50
|
+
|
51
|
+
it "it kills child processes" do
|
52
|
+
File.exists?(process.temp_file_path).should be_true
|
53
|
+
process.cleanup
|
54
|
+
File.exists?(process.temp_file_path).should be_false
|
55
|
+
end
|
56
|
+
|
24
57
|
end
|
25
58
|
|
26
59
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: quartz
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Huie
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-06-
|
11
|
+
date: 2014-06-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|