c-lightningrb 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|