c3d 0.3.5 → 0.4.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 201a408f2b1225395095cf724407ff44421d53fc
4
- data.tar.gz: 678e8aebd10af7dfbe8a16335247202f40dcc1c9
3
+ metadata.gz: 3e3c857c8641103af8966a052019e2cb72cb51ab
4
+ data.tar.gz: 422e5af13e5fbd73aa8fff740c9e388cbb60d328
5
5
  SHA512:
6
- metadata.gz: da221566c106410d2a1d6c7dd1e0902cc096f3fee448354bcc3f79bcd9364b0322e9bb2c71572052e1d4b512d51bfc6c35ee3c63dc9fcdc5ca138bde967b7caa
7
- data.tar.gz: 578d967c0d82ee1e8f41fce0b9a71523bb0598ee7b1146316889341df882e122368f903486a8865a012d0baf727a4d4fb083ba1c528e0186bb0f24babbbef206
6
+ metadata.gz: f21645b41a5e8160cd35e88c79c3da567526678366e6295b2e084073132999aabfbbad5fabee87a8152b1d32e3d8a3879180909b54c6a88f23434a1d58fe17cb
7
+ data.tar.gz: cc8540abcf257322d7e7ac4015b471f455ead3d9452f0ef400340e261a155ec8dcbbee7ba46c437a5c562f273fc713f86c83e3b444a32cd3e6aa8864d3c8ac99
data/Gemfile CHANGED
@@ -1,9 +1,3 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
- gemspec
4
-
5
- gem 'httparty', '~> 0.13'
6
- gem 'bencode', '~> 0.8'
7
- gem 'celluloid', '~> 0.15'
8
- gem 'celluloid-zmq', '~> 0.15'
9
- gem 'foreman'
3
+ gemspec
data/Gemfile.lock CHANGED
@@ -1,10 +1,10 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- c3d (0.3.0)
4
+ c3d (0.3.5)
5
5
  bencode (~> 0.8)
6
6
  celluloid (~> 0.15)
7
- celluloid-zmq (~> 0.15)
7
+ commander (~> 4.1)
8
8
  httparty (~> 0.13)
9
9
 
10
10
  GEM
@@ -13,34 +13,35 @@ GEM
13
13
  bencode (0.8.1)
14
14
  celluloid (0.15.2)
15
15
  timers (~> 1.1.0)
16
- celluloid-zmq (0.15.0)
17
- celluloid (>= 0.13.0)
18
- ffi
19
- ffi-rzmq
20
- dotenv (0.7.0)
21
- ffi (1.9.3)
22
- ffi-rzmq (2.0.1)
23
- ffi-rzmq-core (>= 1.0.1)
24
- ffi-rzmq-core (1.0.3)
25
- ffi (~> 1.9)
26
- foreman (0.67.0)
27
- dotenv (~> 0.7.0)
28
- thor (~> 0.17.0)
16
+ commander (4.1.6)
17
+ highline (~> 1.6.11)
18
+ diff-lcs (1.2.5)
19
+ epm (0.3.7)
20
+ commander (~> 4.1.6)
21
+ highline (1.6.21)
29
22
  httparty (0.13.1)
30
23
  json (~> 1.8)
31
24
  multi_xml (>= 0.5.2)
32
25
  json (1.8.1)
33
26
  multi_xml (0.5.5)
34
- thor (0.17.0)
27
+ rspec (3.0.0)
28
+ rspec-core (~> 3.0.0)
29
+ rspec-expectations (~> 3.0.0)
30
+ rspec-mocks (~> 3.0.0)
31
+ rspec-core (3.0.1)
32
+ rspec-support (~> 3.0.0)
33
+ rspec-expectations (3.0.1)
34
+ diff-lcs (>= 1.2.0, < 2.0)
35
+ rspec-support (~> 3.0.0)
36
+ rspec-mocks (3.0.1)
37
+ rspec-support (~> 3.0.0)
38
+ rspec-support (3.0.0)
35
39
  timers (1.1.0)
36
40
 
37
41
  PLATFORMS
38
42
  ruby
39
43
 
40
44
  DEPENDENCIES
41
- bencode (~> 0.8)
42
45
  c3d!
43
- celluloid (~> 0.15)
44
- celluloid-zmq (~> 0.15)
45
- foreman
46
- httparty (~> 0.13)
46
+ epm
47
+ rspec (~> 3.0)
data/Rakefile CHANGED
@@ -1,2 +1,14 @@
1
1
  require 'bundler'
2
2
  Bundler::GemHelper.install_tasks
3
+
4
+ desc "Run all RSpec test examples"
5
+ task :spec do
6
+ require 'rspec'
7
+ require 'rspec/core/rake_task'
8
+ RSpec::Core::RakeTask.new do |spec|
9
+ spec.rspec_opts = ["-c", "-f progress"]
10
+ spec.pattern = 'spec/**/*_spec.rb'
11
+ end
12
+ end
13
+
14
+ task :default => :spec
data/bin/c3d ADDED
@@ -0,0 +1,40 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require File.join(File.dirname(__FILE__), '..', 'lib', 'c3d.rb')
4
+ require 'commander/import'
5
+
6
+ program :version, C3D.version
7
+ program :description, 'Contract Controlled Content Dissemination Server.'
8
+
9
+ ##
10
+ ## Package Workflow Commands
11
+ ##
12
+ command :start do |c|
13
+ c.syntax = 'c3d start'
14
+ c.description = 'Start your default c3d server.'
15
+ c.action do
16
+ print "Please be patient, this will take a few seconds.\n"
17
+ C3D.start
18
+ print "Server has started.\n"
19
+ end
20
+ end
21
+
22
+ command :stop do |c|
23
+ c.syntax = 'c3d stop'
24
+ c.description = 'Stop your default c3d server.'
25
+ c.action do
26
+ C3D.stop
27
+ print "Server has stopped.\n"
28
+ end
29
+ end
30
+
31
+ command :restart do |c|
32
+ c.syntax = 'c3d restart'
33
+ c.summary = ''
34
+ c.description = 'Restart your default c3d server.'
35
+ c.action do
36
+ print "Please be patient, this will take a few seconds.\n"
37
+ C3D.restart
38
+ print "Server has been restarted.\n"
39
+ end
40
+ end
data/c3d.gemspec CHANGED
@@ -20,10 +20,12 @@ Gem::Specification.new do |s|
20
20
  s.test_files = s.files.grep(%r{^(test|spec|features)/})
21
21
  s.require_paths = ["lib"]
22
22
 
23
- s.add_runtime_dependency 'httparty', '~> 0.13'
24
- s.add_runtime_dependency 'bencode', '~> 0.8'
25
- s.add_runtime_dependency 'celluloid', '~> 0.15'
26
- s.add_runtime_dependency 'celluloid-zmq', '~> 0.15'
23
+ s.add_dependency 'httparty', '~> 0.13'
24
+ s.add_dependency 'celluloid', '~> 0.15'
25
+ s.add_dependency 'commander', '~> 4.1'
26
+ s.add_dependency 'bencode', '~> 0.8'
27
+ s.add_development_dependency 'rspec', '~> 3.0'
28
+ s.add_development_dependency 'epm'
27
29
 
28
30
  s.description = <<desc
29
31
  This gem is designed to assist in distribution mangement of content which is controlled by an Ethereum contract.
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ module C3D
4
+ class Blacklist
5
+ include Celluloid
6
+
7
+ def initialize contract
8
+ contract = Array(contract)
9
+ puts "[C3D::#{Time.now.strftime( "%F %T" )}] Running Blacklist."
10
+ C3D::TreeBuilder.new [], contract
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ module C3D
4
+ class Crawler
5
+ include Celluloid
6
+
7
+ def initialize contract
8
+ puts "[C3D::#{Time.now.strftime( "%F %T" )}] Finding Peak of >>\t" + contract
9
+ @parse = find_the_peak contract
10
+ @purge = []
11
+ puts "[C3D::#{Time.now.strftime( "%F %T" )}] Parsing Tree >>\t\t" + @parse
12
+ C3D::TreeBuilder.new @parse, @purge
13
+ end
14
+
15
+ private
16
+ def find_the_peak contract
17
+ parent = send_query contract, '0x14'
18
+ until parent == '0x'
19
+ child = parent
20
+ parent = send_query parent, '0x14'
21
+ break if child == parent
22
+ end
23
+ return [child]
24
+ end
25
+
26
+ def send_query contract, storage
27
+ $eth.get_storage_at contract, storage
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ module C3D
4
+ module Getter
5
+ extend self
6
+
7
+ def get blob_id
8
+ if blob_id[0..1] == '0x'
9
+ blob_id = blob_id[2..-1]
10
+ end
11
+ btih = blob_id[0..39]
12
+ dn = blob_id[40..-1]
13
+ mag_link = "magnet:?xt=urn:btih:" + btih + "&dn=" + dn
14
+ $puller.create mag_link
15
+ puts "[C3D::#{Time.now.strftime( "%F %T" )}] Getting >>\t\t" + mag_link
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ module C3D
4
+ class Subscribe
5
+ include Celluloid
6
+
7
+ def initialize
8
+ @parse = JSON.load File.read ENV['WATCH_FILE']
9
+ @purge = JSON.load File.read ENV['IGNORE_FILE']
10
+ puts "[C3D::#{Time.now.strftime( "%F %T" )}] Parsing Watchlist"
11
+ C3D::TreeBuilder.new @parse, @purge
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,146 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ module C3D
4
+ class ConnectEth
5
+ include Celluloid
6
+
7
+ def initialize client
8
+ @client = client
9
+ @uri = URI.parse "http://#{ENV['ETH_HOST']}:#{ENV['ETH_PORT']}"
10
+ @question_socket = Net::HTTP.new @uri.host, @uri.port
11
+ @request = Net::HTTP::Post.new @uri.request_uri
12
+ @request.content_type = 'application/json'
13
+ @last_push = Time.now
14
+ puts "[C3D-EPM::#{Time.now.strftime( "%F %T" )}] c3D->eth via RPC on port >>\t#{ENV['ETH_PORT']}"
15
+ end
16
+
17
+ def get_storage_at address, storage_location
18
+ address = guard_addresses address
19
+ storage_location = guard_addresses storage_location
20
+
21
+ case @client
22
+ when :go
23
+ request = {
24
+ id: 'c3d-client',
25
+ method: "EthereumApi.GetStorageAt",
26
+ params: [{
27
+ address: address,
28
+ key: storage_location
29
+ }]
30
+ }
31
+ when :cpp
32
+ request = {
33
+ method: "storageAt",
34
+ params: {
35
+ a: address,
36
+ x: storage_location
37
+ },
38
+ id: 'c3d-client',
39
+ jsonrpc: '2.0'
40
+ }
41
+ end
42
+
43
+ send_command request
44
+ end
45
+
46
+ def transact recipient, data='', value='', gas='100000', gas_price='100000000000000'
47
+ sleep 0.5 if ( Time.now - @last_push < 0.5 )
48
+ recipient = guard_addresses recipient
49
+ data = build_data data
50
+ case @client
51
+ when :go
52
+ request = {
53
+ id: 'c3d-client',
54
+ method: "EthereumApi.Transact",
55
+ params: [{
56
+ recipient: recipient,
57
+ value: value,
58
+ gas: gas,
59
+ gasprice: gas_price
60
+ }]
61
+ }
62
+ when :cpp
63
+ request = {
64
+ method: 'transact',
65
+ params: {
66
+ sec: ENV['ETH_KEY'],
67
+ xValue: value.to_s,
68
+ aDest: recipient,
69
+ bData: data,
70
+ xGas: gas.to_s,
71
+ xGasPrice: gas_price.to_s
72
+ },
73
+ id: 'c3d-client',
74
+ jsonrpc: '2.0'
75
+ }
76
+ end
77
+ @last_push = Time.now
78
+ send_command request
79
+ end
80
+
81
+
82
+ def get_key
83
+ case @client
84
+ when :go
85
+ request = {
86
+ id: 'c3d-client',
87
+ method: "EthereumApi.GetKey",
88
+ params: [{}]
89
+ }
90
+ when :cpp
91
+ request = {
92
+ id: 'c3d-client',
93
+ method: "key",
94
+ params: {},
95
+ jsonrpc: '2.0'
96
+ }
97
+ end
98
+
99
+ send_command request
100
+ end
101
+
102
+ private
103
+
104
+ def guard_addresses address
105
+ unless address[0..1] == "0x"
106
+ address = "0x" + address
107
+ end
108
+ address
109
+ end
110
+
111
+ def build_data data
112
+ if data.class == Array
113
+ builded = "0x"
114
+ data.each do |piece|
115
+ if piece[0..1] == "0x"
116
+ piece = piece[2..-1]
117
+ piece = piece.rjust(64,'0')
118
+ else
119
+ piece = piece.unpack('c*').map{|s| s.to_s(16)}.join('')
120
+ piece = piece.ljust(64,'0')
121
+ end
122
+ builded << piece
123
+ end
124
+ return builded
125
+ else
126
+ return data
127
+ end
128
+ end
129
+
130
+ def send_command request
131
+ @request.body = request.to_json
132
+ puts "[C3D-EPM::#{Time.now.strftime( "%F %T" )}] Sending Question >>\t#{@request.body}"
133
+ handle_response JSON.parse(@question_socket.request(@request).body)
134
+ end
135
+
136
+ def handle_response response
137
+ unless response["error"]
138
+ puts "[C3D-EPM::#{Time.now.strftime( "%F %T" )}] Received Answer >>\tanswer:#{response['result']}"
139
+ return response["result"]
140
+ else
141
+ puts "[C3D-EPM::#{Time.now.strftime( "%F %T" )}] Received Answer >>\tERROR!"
142
+ return nil
143
+ end
144
+ end
145
+ end
146
+ end
@@ -0,0 +1,148 @@
1
+ #!/usr/bin/env ruby
2
+ # This is based off of work by fguillen for the transmission_api gem here: https://github.com/fguillen/TransmissionApi
3
+
4
+ module C3D
5
+ class ConnectTorrent
6
+ include Celluloid
7
+ attr_accessor :session_id, :url, :basic_auth, :fields, :debug_mode
8
+
9
+ TORRENT_FIELDS = [
10
+ "id",
11
+ "name",
12
+ "totalSize",
13
+ "isFinished",
14
+ "percentDone",
15
+ ]
16
+
17
+ def initialize opts
18
+ @url = opts[:url]
19
+ @fields = opts[:fields] || TORRENT_FIELDS
20
+ @basic_auth = { :username => opts[:username], :password => opts[:password] } if opts[:username]
21
+ @debug_mode = opts[:debug_mode] || false
22
+ @session_id = "c3d-torrent"
23
+ end
24
+
25
+ def all
26
+ log ("[C3D-EPM::#{Time.now.strftime( "%F %T" )}] Getting All Torrents"), true
27
+
28
+ response =
29
+ post(
30
+ :method => "torrent-get",
31
+ :arguments => {
32
+ :fields => fields
33
+ }
34
+ )
35
+
36
+ response["arguments"]["torrents"]
37
+ end
38
+
39
+ def find id
40
+ log ("[C3D-EPM::#{Time.now.strftime( "%F %T" )}] Getting Torrent ID >> "+ "#{id}"), true
41
+
42
+ response =
43
+ post(
44
+ :method => "torrent-get",
45
+ :arguments => {
46
+ :fields => fields,
47
+ :ids => [id]
48
+ }
49
+ )
50
+
51
+ response["arguments"]["torrents"].first
52
+ end
53
+
54
+ def create filename
55
+ log ("[C3D-EPM::#{Time.now.strftime( "%F %T" )}] Adding Blob >>\t\t"+ "#{filename}"), true
56
+
57
+ response =
58
+ post(
59
+ :method => "torrent-add",
60
+ :arguments => {
61
+ :filename => filename,
62
+ :'download-dir' => ENV['BLOBS_DIR'],
63
+ :'peer-limit' => 99
64
+ }
65
+ )
66
+
67
+ response["arguments"]
68
+ end
69
+
70
+ def destroy id
71
+ log ("[C3D-EPM::#{Time.now.strftime( "%F %T" )}] Remove Torrent ID >> "+ "#{id}"), true
72
+
73
+ response =
74
+ post(
75
+ :method => "torrent-remove",
76
+ :arguments => {
77
+ :ids => [id],
78
+ :"delete-local-data" => true
79
+ }
80
+ )
81
+
82
+ response
83
+ end
84
+
85
+ private
86
+ def post(opts)
87
+ JSON::parse( http_post(opts).body )
88
+ end
89
+
90
+ def http_post(opts)
91
+ post_options = {
92
+ :body => opts.to_json,
93
+ :headers => { "x-transmission-session-id" => session_id }
94
+ }
95
+ post_options.merge!( :basic_auth => basic_auth ) if basic_auth
96
+
97
+ log "url: #{url}"
98
+ log "post_body:"
99
+ log JSON.parse(post_options[:body]).to_yaml
100
+ log "------------------"
101
+
102
+ response = HTTParty.post( url, post_options )
103
+
104
+ log_response response
105
+
106
+ # retry connection if session_id incorrect
107
+ if( response.code == 409 )
108
+ log "changing session_id"
109
+ @session_id = response.headers["x-transmission-session-id"]
110
+ response = http_post(opts)
111
+ end
112
+
113
+ response
114
+ end
115
+
116
+ def log(message, override = false)
117
+ if debug_mode || override
118
+ puts "#{message}"
119
+ end
120
+ end
121
+
122
+ def log_response(response)
123
+ body = nil
124
+ begin
125
+ body = JSON.parse(response.body).to_yaml
126
+ rescue
127
+ body = response.body
128
+ end
129
+
130
+ headers = response.headers.to_yaml
131
+
132
+ log "response.code: #{response.code}"
133
+ log "response.message: #{response.message}"
134
+
135
+ log "response.body_raw:"
136
+ log response.body
137
+ log "-----------------"
138
+
139
+ log "response.body:"
140
+ log body
141
+ log "-----------------"
142
+
143
+ log "response.headers:"
144
+ log headers
145
+ log "------------------"
146
+ end
147
+ end
148
+ end
@@ -0,0 +1,84 @@
1
+ #!/usr/bin/env ruby
2
+ # based off of work by mukaibot here: https://github.com/mukaibot/mktorrent/blob/master/lib/mktorrent.rb
3
+ # and work by @Burgestrand here: https://gist.github.com/Burgestrand/1733611
4
+
5
+ module C3D
6
+ class Blobber
7
+ include Celluloid
8
+ attr_accessor :tor_file, :blob_file, :sha1_trun, :btih
9
+
10
+ def initialize blob
11
+ @piecelength = 32 * 1024
12
+ if blob
13
+ prepare blob
14
+ build
15
+ write_torrent
16
+ publish_torrent
17
+ end
18
+ end
19
+
20
+ private
21
+
22
+ def prepare blob
23
+ sha1_full = Digest::SHA1.hexdigest blob
24
+ @sha1_trun = sha1_full[0..23]
25
+ @tor_file = File.join(ENV['TORRENTS_DIR'], "#{sha1_trun}.torrent")
26
+ @blob_file = File.join(ENV['BLOBS_DIR'], sha1_trun)
27
+ File.open(@blob_file, 'w'){|f| f.write(blob)}
28
+ @files = [{ path: @blob_file.split('/'), length: File::open(@blob_file).size }]
29
+ end
30
+
31
+ def build
32
+ @info = { :'created by' => "OWIG3",
33
+ :'creation date' => DateTime.now.strftime("%s").to_i,
34
+ encoding: "UTF-8",
35
+ info: { name: @files.first[:path].last,
36
+ :'piece length' => @piecelength,
37
+ length: @files.first[:length],
38
+ :private => 0, #1 is private
39
+ }
40
+ }
41
+ @info[:info][:pieces] = ""
42
+ i = 0
43
+ read_pieces(@files.first[:path], @piecelength) do |piece|
44
+ @info[:info][:pieces] += Digest::SHA1.digest(piece)
45
+ i += 1
46
+ end
47
+ end
48
+
49
+ def read_pieces file, length
50
+ buffer = ""
51
+ puts "[C3D-EPM::#{Time.now.strftime( "%F %T" )}] Hashing Blob >>\t\t" + "#{file.join("/")}"
52
+ File.open(file.join("/")) do |fh|
53
+ begin
54
+ read = fh.read(length - buffer.length)
55
+ if (buffer.length + read.length) == length
56
+ yield(buffer + read)
57
+ buffer = ""
58
+ else
59
+ buffer += read
60
+ end
61
+ end until fh.eof?
62
+ end
63
+ yield buffer
64
+ end
65
+
66
+ def write_torrent
67
+ File.open(@tor_file, 'w') do |torrentfile|
68
+ torrentfile.write @info.bencode
69
+ end
70
+ puts "[C3D-EPM::#{Time.now.strftime( "%F %T" )}] Torrent Link >>\t\t" + "#{@tor_file}"
71
+ end
72
+
73
+ def publish_torrent
74
+ torrent = $puller.create @tor_file
75
+ begin
76
+ @btih = torrent["torrent-added"]['hashString']
77
+ rescue
78
+ @btih = torrent["torrent-duplicate"]['hashString']
79
+ end
80
+ mag_link = "magnet:?xt=urn:btih:" + @btih + "&dn=" + @sha1_trun
81
+ puts "[C3D-EPM::#{Time.now.strftime( "%F %T" )}] Magnet Link >>\t\t" + mag_link
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,64 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ module C3D
4
+ module TransmissionRunner
5
+ extend self
6
+ def start_transmission
7
+ unless is_trans_running?
8
+ pid = spawn "transmission-daemon -f --no-incomplete-dir -o -C -p #{ENV['TORRENT_RPC'].split(':').last[0..3]} -w #{ENV['BLOBS_DIR']} -g #{File.join(ENV['HOME'], '.epm')}"
9
+ sleep 3
10
+ at_exit { Process.kill("INT", pid) }
11
+ end
12
+ end
13
+
14
+ def is_trans_running?
15
+ a = `ps ux`.split("\n").select{|e| e[/transmission-daemon/]}
16
+ b = `ps ux`.split("\n").select{|e| e[/transmission-daemon -f --no-incomplete-dir -o -C -p /]}
17
+ if ! a.empty? and b.empty?
18
+ p "Please stop your default Transmission Server with `sudo service transmission-daemon stop` and then restart."
19
+ exit 0
20
+ end
21
+ return (! b.empty?)
22
+ end
23
+ end
24
+
25
+ module EthRunner
26
+ extend self
27
+
28
+ def start_ethereum settings
29
+ unless is_eth_running?
30
+ path = settings["path-to-eth"] || "/opt/cpp-ethereum/build/eth/eth"
31
+ port = settings["eth_rpc_port"] || "9090"
32
+ peer_port = settings["eth_peer_port"] || "30303"
33
+ client_name = settings["eth_client_name"] || "c3d-headless"
34
+ remote = settings["eth_remote"] || ""
35
+ if remote != ""
36
+ remote = "-r #{remote}"
37
+ end
38
+ dir = settings["blockchain_dir"] || ""
39
+ if dir != ""
40
+ dir = "-d #{dir}"
41
+ end
42
+ mine = settings["eth_mine"] || "off"
43
+ if mine == ("off" || "false")
44
+ mine = "-m off"
45
+ elsif mine == ("on" || "true")
46
+ mine = "-m on"
47
+ end
48
+ key = settings["primary_account_key"] || ""
49
+ if key != ""
50
+ key = "-s #{key}"
51
+ end
52
+ pid = spawn "#{path} --json-rpc-port #{port} -l #{peer_port} -c #{client_name} #{remote} #{dir} #{mine} #{key}"
53
+ sleep 7
54
+ at_exit { Process.kill("INT", pid) }
55
+ end
56
+ end
57
+
58
+
59
+ def is_eth_running?
60
+ a = `ps ux`.split("\n").select{|e| e[/eth --json-rpc-port/]}
61
+ return (! a.empty?)
62
+ end
63
+ end
64
+ end