quartz 0.2.2 → 0.2.3
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 +4 -4
- data/VERSION +1 -1
- data/go/quartz/quartz.go +40 -89
- data/lib/quartz/go_process.rb +4 -7
- data/lib/quartz/go_struct.rb +1 -1
- data/quartz.gemspec +2 -2
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 39afea8c7e6257e1015e85a28419bfe839879c2b
|
|
4
|
+
data.tar.gz: dd1345ed700b6e1b343d382436ed14f3032352ef
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: bad1814c347eb1e6727b208bb30b09b288af48f18a5a3e2014cd5e20d1e9108fda38e1c86388c2177913db07b0e14ca7b82d0d4b0d1657645cac2b1570cb29a8
|
|
7
|
+
data.tar.gz: c8913655aea693c38519c7fe4165d31f9f85708f73ac648d4b2fa3a2f26365f1b1c2e068c0ec3ec9e34bb01a72d37c594bea3e091fbec3c695b9038de7931e3d
|
data/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# quartz
|
|
2
2
|
|
|
3
|
-
[](https://travis-ci.org/DavidHuie/quartz)
|
|
3
|
+
[](https://travis-ci.org/DavidHuie/quartz) [](https://codeclimate.com/github/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
|
|
@@ -18,9 +18,9 @@ the `examples/` directory.
|
|
|
18
18
|
Quartz shares Go code by exporting methods on a struct to Ruby.
|
|
19
19
|
|
|
20
20
|
Quartz requires that all arguments to exported struct methods be JSON-serializable
|
|
21
|
-
|
|
22
|
-
`(A, *B)`, where `A` and `B` are
|
|
23
|
-
Here's an example of an exportable struct and method:
|
|
21
|
+
types. Additionally, the arguments to an exported method should be of the form
|
|
22
|
+
`(A, *B)`, where `A` and `B` are JSON-serializable types. The method should also
|
|
23
|
+
return an error. Here's an example of an exportable struct and method:
|
|
24
24
|
|
|
25
25
|
```go
|
|
26
26
|
type Adder struct{}
|
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.2.
|
|
1
|
+
0.2.3
|
data/go/quartz/quartz.go
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
package quartz
|
|
2
2
|
|
|
3
3
|
import (
|
|
4
|
-
"encoding/json"
|
|
5
4
|
"net"
|
|
6
5
|
"net/rpc"
|
|
7
6
|
"net/rpc/jsonrpc"
|
|
@@ -11,20 +10,26 @@ import (
|
|
|
11
10
|
"syscall"
|
|
12
11
|
)
|
|
13
12
|
|
|
14
|
-
|
|
15
|
-
quartz *Quartz
|
|
16
|
-
listener net.Listener
|
|
17
|
-
)
|
|
18
|
-
|
|
13
|
+
// This holds information about exported structs.
|
|
19
14
|
type Quartz struct {
|
|
20
15
|
Registry map[string]*StructMetadata
|
|
21
16
|
}
|
|
22
17
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
18
|
+
// Return's the struct registry. This method is exported via RPC
|
|
19
|
+
// so that the Ruby client can have knowledge about which structs and
|
|
20
|
+
// which methods are exported.
|
|
21
|
+
func (q *Quartz) GetMetadata(_ interface{}, value *map[string]*StructMetadata) error {
|
|
22
|
+
*value = q.Registry
|
|
23
|
+
return nil
|
|
26
24
|
}
|
|
27
25
|
|
|
26
|
+
var (
|
|
27
|
+
quartz = &Quartz{
|
|
28
|
+
Registry: make(map[string]*StructMetadata),
|
|
29
|
+
}
|
|
30
|
+
socketPath = "/tmp/quartz.socket"
|
|
31
|
+
)
|
|
32
|
+
|
|
28
33
|
type StructMetadata struct {
|
|
29
34
|
NameToMethodMetadata map[string]*MethodMetadata
|
|
30
35
|
TargetStruct interface{} `json:"-"`
|
|
@@ -37,106 +42,55 @@ func NewStructMetadata(targetStruct interface{}) *StructMetadata {
|
|
|
37
42
|
}
|
|
38
43
|
}
|
|
39
44
|
|
|
40
|
-
|
|
41
|
-
|
|
45
|
+
type MethodMetadata struct {
|
|
46
|
+
Method reflect.Method `json:"-"`
|
|
47
|
+
ArgumentToType map[string]string
|
|
48
|
+
}
|
|
42
49
|
|
|
50
|
+
// Exports a struct via RPC and generates metadata for each of the struct's methods.
|
|
51
|
+
func RegisterName(name string, s interface{}) error {
|
|
43
52
|
quartz.Registry[name] = NewStructMetadata(s)
|
|
44
|
-
|
|
45
53
|
t := reflect.TypeOf(s)
|
|
46
54
|
for i := 0; i < t.NumMethod(); i++ {
|
|
47
55
|
method := t.Method(i)
|
|
48
|
-
|
|
49
56
|
// TODO: only export methods with JSON serializable arguments
|
|
50
57
|
// and responses.
|
|
51
|
-
|
|
52
58
|
metadata := &MethodMetadata{
|
|
53
59
|
method,
|
|
54
60
|
StructFieldToType(method.Type.In(1)),
|
|
55
61
|
}
|
|
56
|
-
|
|
57
62
|
quartz.Registry[name].NameToMethodMetadata[method.Name] = metadata
|
|
58
63
|
}
|
|
59
|
-
|
|
60
|
-
return nil
|
|
64
|
+
return rpc.RegisterName(name, s)
|
|
61
65
|
}
|
|
62
66
|
|
|
67
|
+
// Given a struct type, creates a mapping of field name
|
|
68
|
+
// to string representation of the field name's type.
|
|
63
69
|
func StructFieldToType(t reflect.Type) map[string]string {
|
|
64
70
|
fieldToType := make(map[string]string)
|
|
65
|
-
|
|
66
71
|
for i := 0; i < t.NumField(); i++ {
|
|
67
72
|
fieldToType[t.Field(i).Name] = t.Field(i).Type.String()
|
|
68
73
|
}
|
|
69
|
-
|
|
70
74
|
return fieldToType
|
|
71
75
|
}
|
|
72
76
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
func (q *Quartz) Call(args *CallArgs, response *interface{}) error {
|
|
80
|
-
|
|
81
|
-
// TODO: validate args
|
|
82
|
-
|
|
83
|
-
metadata := quartz.Registry[args.StructName]
|
|
84
|
-
method := metadata.NameToMethodMetadata[args.Method].Method
|
|
85
|
-
|
|
86
|
-
structValue := reflect.ValueOf(metadata.TargetStruct)
|
|
87
|
-
methodArgsValue := reflect.ValueOf([]byte(args.MethodArgs))
|
|
88
|
-
unmarshallerValue := reflect.ValueOf(json.Unmarshal)
|
|
89
|
-
functionResponse := reflect.Indirect(reflect.ValueOf(response))
|
|
90
|
-
|
|
91
|
-
// Determine what arguments the function requires
|
|
92
|
-
argsType := method.Type.In(1)
|
|
93
|
-
responseType := method.Type.In(2).Elem()
|
|
94
|
-
responseValuePointer := reflect.New(responseType)
|
|
95
|
-
|
|
96
|
-
// Create a value that's a direct reference to the arg argument
|
|
97
|
-
argStructPointer := reflect.New(argsType)
|
|
98
|
-
argStruct := reflect.Indirect(argStructPointer)
|
|
99
|
-
|
|
100
|
-
// Unmarshall the argument json
|
|
101
|
-
// TODO: check for unmarshalling errors
|
|
102
|
-
unmarshallerValue.Call([]reflect.Value{methodArgsValue, argStructPointer})
|
|
103
|
-
|
|
104
|
-
// Call the method
|
|
105
|
-
err := method.Func.Call([]reflect.Value{structValue, argStruct, responseValuePointer})
|
|
106
|
-
if !err[0].IsNil() {
|
|
107
|
-
return err[0].Interface().(error)
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
// Set this method's response value
|
|
111
|
-
rpcResponse := reflect.Indirect(responseValuePointer)
|
|
112
|
-
functionResponse.Set(rpcResponse)
|
|
113
|
-
|
|
114
|
-
return nil
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
func (q *Quartz) GetMetadata(_ interface{}, value *map[string]*StructMetadata) error {
|
|
118
|
-
*value = q.Registry
|
|
119
|
-
return nil
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
func init() {
|
|
123
|
-
socket_path := os.Getenv("QUARTZ_SOCKET")
|
|
124
|
-
if socket_path == "" {
|
|
125
|
-
socket_path = "/tmp/quartz.socket"
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
var err error
|
|
129
|
-
listener, err = net.Listen("unix", socket_path)
|
|
77
|
+
func Start() {
|
|
78
|
+
// Start the server and accept connections on a
|
|
79
|
+
// UNIX domain socket.
|
|
80
|
+
rpc.Register(quartz)
|
|
81
|
+
listener, err := net.Listen("unix", socketPath)
|
|
130
82
|
if err != nil {
|
|
131
83
|
panic(err)
|
|
132
84
|
}
|
|
85
|
+
for {
|
|
86
|
+
conn, err := listener.Accept()
|
|
87
|
+
if err != nil {
|
|
88
|
+
panic(err)
|
|
89
|
+
}
|
|
90
|
+
go jsonrpc.ServeConn(conn)
|
|
91
|
+
}
|
|
133
92
|
|
|
134
|
-
|
|
135
|
-
quartz.Registry = make(map[string]*StructMetadata)
|
|
136
|
-
|
|
137
|
-
rpc.Register(quartz)
|
|
138
|
-
|
|
139
|
-
// Cleanup the socket file when the server is killed
|
|
93
|
+
// Destroy the socket file when the server is killed.
|
|
140
94
|
sigc := make(chan os.Signal)
|
|
141
95
|
signal.Notify(sigc, syscall.SIGTERM)
|
|
142
96
|
go func() {
|
|
@@ -149,12 +103,9 @@ func init() {
|
|
|
149
103
|
}()
|
|
150
104
|
}
|
|
151
105
|
|
|
152
|
-
func
|
|
153
|
-
for
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
panic(err)
|
|
157
|
-
}
|
|
158
|
-
go jsonrpc.ServeConn(conn)
|
|
106
|
+
func init() {
|
|
107
|
+
// The Ruby gem sets this environment variable for us.
|
|
108
|
+
if os.Getenv("QUARTZ_SOCKET") != "" {
|
|
109
|
+
socketPath = os.Getenv("QUARTZ_SOCKET")
|
|
159
110
|
}
|
|
160
111
|
}
|
data/lib/quartz/go_process.rb
CHANGED
|
@@ -57,6 +57,8 @@ class Quartz::GoProcess
|
|
|
57
57
|
payload = {
|
|
58
58
|
'method' => 'Quartz.GetMetadata',
|
|
59
59
|
'params' => [],
|
|
60
|
+
# This parameter isn't needed because we use a different
|
|
61
|
+
# connection for each thread.
|
|
60
62
|
'id' => 1
|
|
61
63
|
}
|
|
62
64
|
|
|
@@ -72,15 +74,10 @@ class Quartz::GoProcess
|
|
|
72
74
|
|
|
73
75
|
def call(struct_name, method, args)
|
|
74
76
|
payload = {
|
|
75
|
-
'method' =>
|
|
76
|
-
'params' => [
|
|
77
|
-
'StructName' => struct_name,
|
|
78
|
-
'Method' => method,
|
|
79
|
-
'MethodArgs' => args.to_json
|
|
80
|
-
}],
|
|
77
|
+
'method' => "#{struct_name}.#{method}",
|
|
78
|
+
'params' => [args],
|
|
81
79
|
'id' => 1
|
|
82
80
|
}
|
|
83
|
-
|
|
84
81
|
socket.send(payload.to_json, 0)
|
|
85
82
|
read
|
|
86
83
|
end
|
data/lib/quartz/go_struct.rb
CHANGED
data/quartz.gemspec
CHANGED
|
@@ -2,11 +2,11 @@
|
|
|
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.2.
|
|
5
|
+
# stub: quartz 0.2.3 ruby lib
|
|
6
6
|
|
|
7
7
|
Gem::Specification.new do |s|
|
|
8
8
|
s.name = "quartz"
|
|
9
|
-
s.version = "0.2.
|
|
9
|
+
s.version = "0.2.3"
|
|
10
10
|
|
|
11
11
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
|
12
12
|
s.require_paths = ["lib"]
|