c-lightningrb 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 +54 -0
- data/examples/README.md +9 -0
- data/examples/hello.rb +17 -0
- data/lib/lightning/plugin.rb +50 -26
- data/lib/lightning/request.rb +23 -2
- data/lib/lightning/rpc.rb +48 -3
- data/lib/lightning/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2c2fd714b383235136db352d6b4a907a2b418d595de24f900102497887629d4e
|
4
|
+
data.tar.gz: 6046070fc4a9ba437cd4688a423b4acc8ade9f07953d77a36827e92d8ea7d38b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 96e06e96542e9851634321af9be64d09a774a94f8835eb7d7b49b61058397ecbb7b189bcc91a9eb36597b459b23d7e28931875301a118720ae7555ce4fb61a22
|
7
|
+
data.tar.gz: d7d2b4015a2abbb689fbba7832459bc1c8cc045cf1e4f12a3596d3c4a0ec21580206dad730cde2e855797dab95576c640062c5ace3e6e16a6f44ab21d70ee7a9
|
data/README.md
CHANGED
@@ -21,6 +21,56 @@ Or install it yourself as:
|
|
21
21
|
|
22
22
|
## Examples
|
23
23
|
|
24
|
+
### Using the JSON-RPC client
|
25
|
+
|
26
|
+
```ruby
|
27
|
+
require 'lightning'
|
28
|
+
|
29
|
+
# initialize RPC interface using unix socket file.
|
30
|
+
rpc = Lightning::RPC.new('/home/azuchi/.lightning/lightning-rpc')
|
31
|
+
|
32
|
+
puts rpc.getinfo
|
33
|
+
|
34
|
+
=> {
|
35
|
+
"id": "02a7581f5aafd3ed01a6664ad5108ce1601435d9e9e47c57f1c40cff152cd59307",
|
36
|
+
"alias": "GREENPHOTO",
|
37
|
+
"color": "02a758",
|
38
|
+
"num_peers": 0,
|
39
|
+
"num_pending_channels": 0,
|
40
|
+
"num_active_channels": 0,
|
41
|
+
"num_inactive_channels": 0,
|
42
|
+
"address": [
|
43
|
+
|
44
|
+
],
|
45
|
+
"binding": [
|
46
|
+
{
|
47
|
+
"type": "ipv6",
|
48
|
+
"address": "::",
|
49
|
+
"port": 9735
|
50
|
+
},
|
51
|
+
{
|
52
|
+
"type": "ipv4",
|
53
|
+
"address": "0.0.0.0",
|
54
|
+
"port": 9735
|
55
|
+
}
|
56
|
+
],
|
57
|
+
"version": "v0.7.0",
|
58
|
+
"blockheight": 1518441,
|
59
|
+
"network": "testnet",
|
60
|
+
"msatoshi_fees_collected": 0,
|
61
|
+
"fees_collected_msat": "0msat"
|
62
|
+
}
|
63
|
+
|
64
|
+
puts rpc.invoice(1000, 'example', 'test payment')
|
65
|
+
|
66
|
+
=> {
|
67
|
+
"payment_hash": "76b2f5d6791a2e0be44071543c71d27238e2153fd832ac23d8c027b33e024fb8",
|
68
|
+
"expires_at": 1558856940,
|
69
|
+
"bolt11": "lntb10n1pww5dkupp5w6e0t4nerghqhezqw92rcuwjwguwy9flmqe2cg7ccqnmx0szf7uqdq5w3jhxapqwpshjmt9de6qcqp2phn9mgplxj2mxg59zjrlhwh2p66h2r3p4f7kyk8w4s3zcma5htn807r8lgfmg75hwcvhse8sqtgcyakgezdzjc0zyd87uahe3wsz3qcp4nv6f0",
|
70
|
+
"warning_capacity": "No channels have sufficient incoming capacity"
|
71
|
+
}
|
72
|
+
```
|
73
|
+
|
24
74
|
### Writing a plugin
|
25
75
|
|
26
76
|
You can write your own Plugin by inheriting `Lightning::Plugin`.
|
@@ -30,6 +80,9 @@ You can write your own Plugin by inheriting `Lightning::Plugin`.
|
|
30
80
|
require 'lightning'
|
31
81
|
|
32
82
|
class HelloPlugin < Lightning::Plugin
|
83
|
+
|
84
|
+
# Command line option pass-through
|
85
|
+
option 'greeting', 'World', "What name should I call you?"
|
33
86
|
|
34
87
|
# define new rpc. Usage and description are required only for the definition of RPC.
|
35
88
|
desc '[name]', 'Returns a personalized greeting for {greeting} (set via options).'
|
@@ -61,6 +114,7 @@ p.run
|
|
61
114
|
|
62
115
|
Write all RPC, notification, and hook handlers in Lambda.
|
63
116
|
These Lambdas are implemented as methods, so you can access any of the fields and methods of the Plugin.
|
117
|
+
For example, `Lightning::Plugin` instance has `rpc` field which can access `lightningd` via `Lightning::RPC`.
|
64
118
|
|
65
119
|
And it works if you specify Plugin as the parameter when c-lightning launches.
|
66
120
|
|
data/examples/README.md
ADDED
data/examples/hello.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'lightning'
|
3
|
+
|
4
|
+
class HelloPlugin < Lightning::Plugin
|
5
|
+
|
6
|
+
desc '[name]', 'Returns a personalized greeting for {greeting} (set via options).'
|
7
|
+
define_rpc :hello, -> (name) do
|
8
|
+
log.info "log = #{log}"
|
9
|
+
"hello #{name}"
|
10
|
+
end
|
11
|
+
|
12
|
+
option 'greeting', 'World', "What name should I call you?"
|
13
|
+
|
14
|
+
end
|
15
|
+
|
16
|
+
p = HelloPlugin.new
|
17
|
+
p.run
|
data/lib/lightning/plugin.rb
CHANGED
@@ -53,6 +53,20 @@ module Lightning
|
|
53
53
|
@subscriptions ||= []
|
54
54
|
end
|
55
55
|
|
56
|
+
# get options
|
57
|
+
def options
|
58
|
+
@options ||= []
|
59
|
+
end
|
60
|
+
|
61
|
+
# Define option for lightningd command line.
|
62
|
+
# @param [String] name option name.
|
63
|
+
# @param [String] default default value.
|
64
|
+
# @param [String] description description.
|
65
|
+
def option(name, default, description)
|
66
|
+
# currently only string options are supported.
|
67
|
+
options << {name: name, default: default, description: description, type: 'string'}
|
68
|
+
end
|
69
|
+
|
56
70
|
# Define the definition of RPC method
|
57
71
|
# @param [String] usage the usage of RPC method.
|
58
72
|
# @param [String] desc the description of RPC method.
|
@@ -100,7 +114,6 @@ module Lightning
|
|
100
114
|
|
101
115
|
end
|
102
116
|
|
103
|
-
attr_reader :options
|
104
117
|
attr_reader :stdout
|
105
118
|
attr_reader :stdin
|
106
119
|
attr_reader :log
|
@@ -110,20 +123,21 @@ module Lightning
|
|
110
123
|
|
111
124
|
def initialize
|
112
125
|
methods[:init] = Method.new(:init)
|
113
|
-
@options = {}
|
114
126
|
@stdout = STDOUT
|
115
127
|
@stdin = STDIN
|
116
128
|
methods[:getmanifest] = Method.new(:getmanifest)
|
117
129
|
@log = Lightning::Logger.create(:plugin)
|
118
130
|
end
|
119
131
|
|
120
|
-
def init(
|
132
|
+
def init(opts, configuration)
|
121
133
|
log.info("init")
|
122
134
|
@lightning_dir = configuration['lightning-dir']
|
123
135
|
@rpc_filename = configuration['rpc-file']
|
124
136
|
socket_path = (Pathname.new(lightning_dir) + rpc_filename).to_path
|
125
|
-
@rpc = Lightning::RPC.new(socket_path
|
126
|
-
|
137
|
+
@rpc = Lightning::RPC.new(socket_path)
|
138
|
+
opts.each do |key, value|
|
139
|
+
options.find{|o|o[:name] == key}[:value] = value
|
140
|
+
end
|
127
141
|
nil
|
128
142
|
end
|
129
143
|
|
@@ -132,7 +146,7 @@ module Lightning
|
|
132
146
|
def getmanifest
|
133
147
|
log.info("getmanifest")
|
134
148
|
{
|
135
|
-
options: options
|
149
|
+
options: options,
|
136
150
|
rpcmethods: rpc_methods.map(&:to_h),
|
137
151
|
subscriptions: subscriptions,
|
138
152
|
hooks: hook_methods.map(&:name),
|
@@ -148,20 +162,16 @@ module Lightning
|
|
148
162
|
def run
|
149
163
|
log.info("Plugin run.")
|
150
164
|
begin
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
end
|
158
|
-
rescue Exception => e
|
159
|
-
if e.is_a?(Interrupt)
|
160
|
-
shutdown
|
161
|
-
else
|
162
|
-
log.error e
|
163
|
-
throw e
|
165
|
+
partial = ''
|
166
|
+
stdin.each_line do |l|
|
167
|
+
partial << l
|
168
|
+
msgs = partial.split("\n\n", -1)
|
169
|
+
next if msgs.size < 2
|
170
|
+
partial = multi_dispatch(msgs)
|
164
171
|
end
|
172
|
+
rescue Interrupt
|
173
|
+
log.info "Interrupt occur."
|
174
|
+
shutdown
|
165
175
|
end
|
166
176
|
log.info("Plugin end.")
|
167
177
|
end
|
@@ -179,6 +189,11 @@ module Lightning
|
|
179
189
|
self.class.subscriptions # delegate to class instance
|
180
190
|
end
|
181
191
|
|
192
|
+
# get options
|
193
|
+
def options
|
194
|
+
self.class.options # delegate to class instance
|
195
|
+
end
|
196
|
+
|
182
197
|
def multi_dispatch(msgs)
|
183
198
|
msgs[0...-1].each do |payload|
|
184
199
|
json = JSON.parse(payload)
|
@@ -194,16 +209,25 @@ module Lightning
|
|
194
209
|
end
|
195
210
|
|
196
211
|
def dispatch_request(request)
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
212
|
+
begin
|
213
|
+
method = methods[request.method]
|
214
|
+
raise ArgumentError, "No method #{request.method} found." unless method
|
215
|
+
result = request.method_args.empty? ? send(method.name) : send(method.name, *request.method_args)
|
216
|
+
request.apply_result(result) if result
|
217
|
+
rescue Exception => e
|
218
|
+
log.error e
|
219
|
+
request.write_error(e)
|
220
|
+
end
|
201
221
|
end
|
202
222
|
|
203
223
|
def dispatch_notification(request)
|
204
|
-
|
205
|
-
|
206
|
-
|
224
|
+
begin
|
225
|
+
name = request.method
|
226
|
+
raise ArgumentError, "No handler #{request.method} found." unless subscriptions.include?(request.method)
|
227
|
+
request.method_args.empty? ? send(name) : send(name, *request.method_args)
|
228
|
+
rescue Exception => e
|
229
|
+
log.error e
|
230
|
+
end
|
207
231
|
end
|
208
232
|
|
209
233
|
def rpc_methods
|
data/lib/lightning/request.rb
CHANGED
@@ -32,6 +32,8 @@ module Lightning
|
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
35
|
+
# write response
|
36
|
+
# @param [Hash] result the content of response
|
35
37
|
def apply_result(result)
|
36
38
|
@result = result
|
37
39
|
json = {
|
@@ -39,8 +41,27 @@ module Lightning
|
|
39
41
|
id: id,
|
40
42
|
result: result
|
41
43
|
}.to_json
|
42
|
-
|
43
|
-
|
44
|
+
write(json.to_s)
|
45
|
+
end
|
46
|
+
|
47
|
+
# write error
|
48
|
+
# @param [Exception] e an error.
|
49
|
+
def write_error(e)
|
50
|
+
error = {message: e.message}
|
51
|
+
error[:code] = e.code if e.is_a?(Lightning::RPCError)
|
52
|
+
json = {
|
53
|
+
jsonrpc: '2.0',
|
54
|
+
id: id,
|
55
|
+
error: error
|
56
|
+
}.to_json
|
57
|
+
write(json.to_s)
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def write(content)
|
63
|
+
log.info "write response: #{content}"
|
64
|
+
plugin.stdout.write(content + "\n\n")
|
44
65
|
plugin.stdout.flush
|
45
66
|
end
|
46
67
|
|
data/lib/lightning/rpc.rb
CHANGED
@@ -1,14 +1,59 @@
|
|
1
|
+
require 'socket'
|
2
|
+
require 'json'
|
3
|
+
|
1
4
|
module Lightning
|
2
5
|
|
6
|
+
class RPCError < StandardError
|
7
|
+
|
8
|
+
INVALID_REQUEST = -32600
|
9
|
+
METHOD_NOT_FOUND = -32601
|
10
|
+
INVALID_PARAMS = -32602
|
11
|
+
|
12
|
+
attr_reader :code
|
13
|
+
attr_reader :message
|
14
|
+
|
15
|
+
def initialize(code, message)
|
16
|
+
@code = code
|
17
|
+
@message = message
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
3
22
|
# RPC client for the `lightningd` daemon.
|
4
23
|
class RPC
|
5
24
|
|
6
25
|
attr_reader :socket_path
|
7
|
-
|
26
|
+
attr_accessor :next_id
|
8
27
|
|
9
|
-
def initialize(socket_path
|
28
|
+
def initialize(socket_path)
|
10
29
|
@socket_path = socket_path
|
11
|
-
@
|
30
|
+
@next_id = 0
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def call(method, *kargs)
|
36
|
+
UNIXSocket.open(socket_path) do |socket|
|
37
|
+
msg = {
|
38
|
+
method: method.to_s,
|
39
|
+
params: kargs,
|
40
|
+
id: next_id
|
41
|
+
}
|
42
|
+
socket.write(msg.to_json)
|
43
|
+
self.next_id += 1
|
44
|
+
response = ''
|
45
|
+
loop do
|
46
|
+
response << socket.gets
|
47
|
+
break if response.include?("\n\n")
|
48
|
+
end
|
49
|
+
json = JSON.parse(response)
|
50
|
+
raise RPCError.new(json['error']['code'], json['error']['message']) if json['error']
|
51
|
+
json['result']
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def method_missing(method, *args)
|
56
|
+
call(method, *args)
|
12
57
|
end
|
13
58
|
|
14
59
|
end
|
data/lib/lightning/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: c-lightningrb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- azuchi
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-05-
|
11
|
+
date: 2019-05-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -71,6 +71,8 @@ files:
|
|
71
71
|
- Rakefile
|
72
72
|
- bin/console
|
73
73
|
- bin/setup
|
74
|
+
- examples/README.md
|
75
|
+
- examples/hello.rb
|
74
76
|
- lib/lightning.rb
|
75
77
|
- lib/lightning/logger.rb
|
76
78
|
- lib/lightning/plugin.rb
|