pickynode 0.0.3 → 0.1.0

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: a9ed335fbc05dfe5122819dab044c3f087f6855d
4
- data.tar.gz: ae580a59583a6c5b355883ee71e76cf8b30f8665
3
+ metadata.gz: dfe782c9a3c9232314fb733ca5e9a0cc31f8bdd5
4
+ data.tar.gz: 3044d3f752bdca822b5f0e547f9d478febdad2da
5
5
  SHA512:
6
- metadata.gz: 1051e7d02b39ee86c2a2cc031d484c5f00ac9ee21c9634822395a10ff03702560ff9d5c76d24a4e8fad5374594920b8b42969dfca2159b5161a28c22a86be952
7
- data.tar.gz: 7d215790b39f5b36b0f05cb0e4f4e47bdaaa552e4b975d81a6452e558740f0bdf84cf3818879be03fdc44b2366a3e0e8709df101f1a7faf48161e122f1281ec8
6
+ metadata.gz: c509c44a20db271c1735296f946e17562f968ce4d52d15cb3720c323b1cbfa90de08acef6bfbf01fc4c7a4b2bc79a356d489d34e991670ecdbcfbd2edd8f8e47
7
+ data.tar.gz: db50a3333c22a40e18bc7a08f1c2b34d24b92cd5b7d0035a42c6418c794c0cc5e97ffda1d609990a0f304461df8993cc59d2333d93d58de416d0212ee2e49246
data/.gitignore ADDED
@@ -0,0 +1,50 @@
1
+ *.gem
2
+ *.rbc
3
+ /.config
4
+ /coverage/
5
+ /InstalledFiles
6
+ /pkg/
7
+ /spec/reports/
8
+ /spec/examples.txt
9
+ /test/tmp/
10
+ /test/version_tmp/
11
+ /tmp/
12
+
13
+ # Used by dotenv library to load environment variables.
14
+ # .env
15
+
16
+ ## Specific to RubyMotion:
17
+ .dat*
18
+ .repl_history
19
+ build/
20
+ *.bridgesupport
21
+ build-iPhoneOS/
22
+ build-iPhoneSimulator/
23
+
24
+ ## Specific to RubyMotion (use of CocoaPods):
25
+ #
26
+ # We recommend against adding the Pods directory to your .gitignore. However
27
+ # you should judge for yourself, the pros and cons are mentioned at:
28
+ # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
29
+ #
30
+ # vendor/Pods/
31
+
32
+ ## Documentation cache and generated files:
33
+ /.yardoc/
34
+ /_yardoc/
35
+ /doc/
36
+ /rdoc/
37
+
38
+ ## Environment normalization:
39
+ /.bundle/
40
+ /vendor/bundle
41
+ /lib/bundler/man/
42
+
43
+ # for a library or gem, you might want to ignore these files since the code is
44
+ # intended to run in multiple environments; otherwise, check them in:
45
+ # Gemfile.lock
46
+ # .ruby-version
47
+ # .ruby-gemset
48
+
49
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
50
+ .rvmrc
data/.rubocop.yml ADDED
@@ -0,0 +1,4 @@
1
+ Metrics/BlockLength:
2
+ ExcludedMethods: ['describe', 'context']
3
+ Style/IndentHeredoc:
4
+ Enabled: false
data/.ruby-gemset ADDED
@@ -0,0 +1 @@
1
+ pickynode
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.3.4
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - "2.2.7"
4
+ - "2.3.4"
data/Gemfile ADDED
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+ ruby '>= 2.0'
5
+
6
+ gem 'awesome_print', '~> 1.7'
7
+ gem 'rake', '~> 12.0'
8
+ gem 'rspec', '~> 3.6'
9
+ gem 'rubocop', '~> 0.48'
10
+ gem 'trollop', '~> 2.1'
data/Gemfile.lock ADDED
@@ -0,0 +1,50 @@
1
+ GEM
2
+ remote: https://rubygems.org/
3
+ specs:
4
+ ast (2.3.0)
5
+ awesome_print (1.7.0)
6
+ diff-lcs (1.3)
7
+ parser (2.4.0.0)
8
+ ast (~> 2.2)
9
+ powerpack (0.1.1)
10
+ rainbow (2.2.2)
11
+ rake
12
+ rake (12.0.0)
13
+ rspec (3.6.0)
14
+ rspec-core (~> 3.6.0)
15
+ rspec-expectations (~> 3.6.0)
16
+ rspec-mocks (~> 3.6.0)
17
+ rspec-core (3.6.0)
18
+ rspec-support (~> 3.6.0)
19
+ rspec-expectations (3.6.0)
20
+ diff-lcs (>= 1.2.0, < 2.0)
21
+ rspec-support (~> 3.6.0)
22
+ rspec-mocks (3.6.0)
23
+ diff-lcs (>= 1.2.0, < 2.0)
24
+ rspec-support (~> 3.6.0)
25
+ rspec-support (3.6.0)
26
+ rubocop (0.48.1)
27
+ parser (>= 2.3.3.1, < 3.0)
28
+ powerpack (~> 0.1)
29
+ rainbow (>= 1.99.1, < 3.0)
30
+ ruby-progressbar (~> 1.7)
31
+ unicode-display_width (~> 1.0, >= 1.0.1)
32
+ ruby-progressbar (1.8.1)
33
+ trollop (2.1.2)
34
+ unicode-display_width (1.2.1)
35
+
36
+ PLATFORMS
37
+ ruby
38
+
39
+ DEPENDENCIES
40
+ awesome_print (~> 1.7)
41
+ rake (~> 12.0)
42
+ rspec (~> 3.6)
43
+ rubocop (~> 0.48)
44
+ trollop (~> 2.1)
45
+
46
+ RUBY VERSION
47
+ ruby 2.3.4p301
48
+
49
+ BUNDLED WITH
50
+ 1.14.6
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2017 Josh Ellithorpe
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,61 @@
1
+ [![Gem Version](https://badge.fury.io/rb/pickynode.svg)](https://badge.fury.io/rb/pickynode) [![Build Status](https://travis-ci.org/zquestz/pickynode.svg)](https://travis-ci.org/zquestz/pickynode) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
2
+ # pickynode
3
+
4
+ Some people are picky about the bitcoin nodes they connect to.
5
+
6
+ ### Requirements:
7
+
8
+ You need a working full node on your machine. The `bitcoin-cli` command should be functional.
9
+
10
+ ### Installation:
11
+
12
+ ```
13
+ gem install pickynode
14
+ ```
15
+
16
+ ### Usage:
17
+
18
+ Display list of currently connected nodes:
19
+
20
+ ```
21
+ pickynode
22
+ ```
23
+
24
+ Add node type:
25
+ ```
26
+ pickynode --add=USER_AGENT_FILTER
27
+ ```
28
+
29
+ Ban node type:
30
+ ```
31
+ pickynode --ban=USER_AGENT_FILTER
32
+ ```
33
+
34
+ Connect to node type:
35
+ ```
36
+ pickynode --connect=USER_AGENT_FILTER
37
+ ```
38
+
39
+ Disconnect from node type:
40
+
41
+ ```
42
+ pickynode --disconnect=USER_AGENT_FILTER
43
+ ```
44
+
45
+ ### Help:
46
+
47
+ ```
48
+ pickynode v0.1.0
49
+ Options:
50
+ -a, --add=<s> Add node type
51
+ -c, --connect=<s> Connect to node type
52
+ -b, --ban=<s> Ban node type
53
+ -d, --debug Debug mode
54
+ -o, --output Output commands
55
+ -i, --disconnect=<s> Disconnect from node type
56
+ -v, --version Print version and exit
57
+ -h, --help Show this message
58
+
59
+ ```
60
+
61
+ The --add and --connect commands pull data from Bitnodes.
data/Rakefile ADDED
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env rake
2
+ # frozen_string_literal: true
3
+
4
+ require File.join('bundler', 'gem_tasks')
5
+ require File.join('rspec', 'core', 'rake_task')
6
+
7
+ RSpec::Core::RakeTask.new(:spec)
8
+
9
+ task default: :spec
data/bin/pickynode CHANGED
@@ -1,86 +1,16 @@
1
1
  #!/usr/bin/env ruby
2
- require 'awesome_print'
3
- require 'json'
4
- require 'net/http'
5
- require 'pp'
6
- require 'trollop'
7
- require 'uri'
8
-
9
- VERSION = "0.0.3"
10
-
11
- opts = Trollop::options do
12
- version "pickynode v#{VERSION}"
13
- opt :add, "Add node type", :type => :string
14
- opt :connect, "Connect to node type", :type => :string
15
- opt :ban, "Ban node type", :type => :string
16
- opt :debug, "Debug mode"
17
- opt :output, "Output commands"
18
- opt :disconnect, "Disconnect from node type", :type => :string
19
- end
20
-
21
- def run(cmd, opts={})
22
- puts "Running #{cmd}" if opts[:output] || opts[:debug]
23
- `#{cmd}` unless opts[:debug]
24
- end
25
-
26
- def get_addr_types
27
- nodes = `bitcoin-cli getpeerinfo`
28
- parsed_nodes = JSON.parse(nodes)
29
- parsed_nodes.map { |n| [n["addr"], n["subver"]] }.to_h
30
- end
31
-
32
- def get_bitnode_addr_types
33
- u = URI.parse("https://bitnodes.21.co/api/v1/snapshots/latest/")
34
- nodelist = Net::HTTP.get(u)
35
- parsed_nodelist = JSON.parse(nodelist)
36
- parsed_nodelist['nodes'].map { |k,v| [k, v[1]] }.to_h
37
- end
38
-
39
- if opts[:add] || opts[:connect]
40
- bitnode_addr_types = get_bitnode_addr_types
41
-
42
- if filter = opts[:add]
43
- bitnode_addr_types.each do |k,v|
44
- if v.include?(filter)
45
- u = URI.parse("https://#{k}")
46
- run(%^bitcoin-cli addnode "#{u.host}" "add"^, opts)
47
- end
48
- end
49
- end
50
-
51
- if filter = opts[:connect]
52
- bitnode_addr_types.each do |k,v|
53
- if v.include?(filter)
54
- u = URI.parse("https://#{k}")
55
- run(%^bitcoin-cli addnode "#{u.host}" "onetry"^, opts)
56
- end
57
- end
58
- end
59
- end
60
-
61
- if opts[:ban] || opts[:disconnect]
62
- addr_types = get_addr_types
63
-
64
- if filter = opts[:ban]
65
- addr_types.each do |k,v|
66
- if v.include?(filter)
67
- u = URI.parse("https://#{k}")
68
- run(%^bitcoin-cli setban "#{u.host}" "add"^, opts)
69
- end
70
- end
71
- end
72
-
73
- if filter = opts[:disconnect]
74
- addr_types.each do |k,v|
75
- if v.include?(filter)
76
- run(%^bitcoin-cli disconnectnode "#{k}"^, opts)
77
- end
78
- end
79
- end
80
- end
81
-
82
- unless opts.values.select { |v| v }.empty?
83
- exit(0)
2
+ # frozen_string_literal: true
3
+
4
+ require 'pickynode'
5
+
6
+ opts = Trollop.options do
7
+ version "pickynode v#{Pickynode::VERSION}"
8
+ opt :add, 'Add node type', type: :string
9
+ opt :connect, 'Connect to node type', type: :string
10
+ opt :ban, 'Ban node type', type: :string
11
+ opt :debug, 'Debug mode'
12
+ opt :output, 'Output commands'
13
+ opt :disconnect, 'Disconnect from node type', type: :string
84
14
  end
85
15
 
86
- ap get_addr_types
16
+ Pickynode.new(opts).run
data/lib/pickynode.rb ADDED
@@ -0,0 +1,105 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'awesome_print'
4
+ require 'json'
5
+ require 'net/http'
6
+ require 'trollop'
7
+ require 'uri'
8
+
9
+ # Allows you to easily add/ban/connect/disconnect nodes
10
+ # based on User Agent.
11
+ class Pickynode
12
+ VERSION = '0.1.0'
13
+
14
+ def initialize(opts = {})
15
+ @opts = opts
16
+ end
17
+
18
+ def add(filter)
19
+ return unless filter
20
+ bitnode_addr_types.each do |k, v|
21
+ run_cmd(%(bitcoin-cli addnode "#{k}" "add")) if v.include?(filter)
22
+ end
23
+ end
24
+
25
+ def ban(filter)
26
+ return unless filter
27
+ addr_types.each do |k, v|
28
+ if v.include?(filter)
29
+ u = URI.parse("https://#{k}")
30
+ run_cmd(%(bitcoin-cli setban "#{u.host}" "add"))
31
+ end
32
+ end
33
+ end
34
+
35
+ def connect(filter)
36
+ return unless filter
37
+ bitnode_addr_types.each do |k, v|
38
+ run_cmd(%(bitcoin-cli addnode "#{k}" "onetry")) if v.include?(filter)
39
+ end
40
+ end
41
+
42
+ def disconnect(filter)
43
+ return unless filter
44
+ addr_types.each do |k, v|
45
+ run_cmd(%(bitcoin-cli disconnectnode "#{k}")) if v.include?(filter)
46
+ end
47
+ end
48
+
49
+ def display
50
+ ap addr_types
51
+ end
52
+
53
+ def run
54
+ add(@opts[:add])
55
+ connect(@opts[:connect])
56
+
57
+ ban(@opts[:ban])
58
+ disconnect(@opts[:disconnect])
59
+
60
+ return unless @opts.values.select { |v| v }.empty?
61
+
62
+ display
63
+ end
64
+
65
+ def clear_cache
66
+ @addr_types = nil
67
+ @bitnode_addr_types = nil
68
+ end
69
+
70
+ private
71
+
72
+ def run_cmd(cmd)
73
+ puts "Running #{cmd}" if @opts[:output] || @opts[:debug]
74
+ `#{cmd}` unless @opts[:debug]
75
+ end
76
+
77
+ def addr_types
78
+ return @addr_types if @addr_types
79
+ nodes = getpeerinfo
80
+ parsed_nodes = JSON.parse(nodes)
81
+ @addr_types = parsed_nodes.map do |n|
82
+ [n['addr'], n['subver']]
83
+ end.to_h
84
+ rescue JSON::ParserError
85
+ {}
86
+ end
87
+
88
+ def bitnode_addr_types
89
+ return @bitnode_addr_types if @bitnode_addr_types
90
+ parsed_nodelist = JSON.parse(bitnodes_snapshot)
91
+ @bitnode_addr_types = parsed_nodelist['nodes'].map do |k, v|
92
+ [k, v[1]]
93
+ end.to_h
94
+ rescue JSON::ParserError
95
+ {}
96
+ end
97
+
98
+ def bitnodes_snapshot
99
+ Net::HTTP.get(URI.parse('https://bitnodes.21.co/api/v1/snapshots/latest/'))
100
+ end
101
+
102
+ def getpeerinfo
103
+ `bitcoin-cli getpeerinfo`
104
+ end
105
+ end
data/pickynode.gemspec ADDED
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require File.expand_path(File.join('..', 'lib', 'pickynode'), __FILE__)
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = 'pickynode'
7
+ s.version = Pickynode::VERSION
8
+ s.date = '2017-05-19'
9
+ s.summary = 'Manage connections to your bitcoin node'
10
+ s.description = 'Some people are picky about the \
11
+ bitcoin nodes they connect to.'
12
+ s.authors = ['Josh Ellithorpe']
13
+ s.email = 'quest@mac.com'
14
+ s.homepage = 'http://github.com/zquestz/pickynode'
15
+ s.license = 'MIT'
16
+ s.executables << 'pickynode'
17
+ s.files = `git ls-files`.split("\n")
18
+ s.require_paths = ['lib']
19
+ s.required_ruby_version = '>= 2.0'
20
+
21
+ s.add_dependency 'awesome_print', '~> 1.7'
22
+ s.add_dependency 'trollop', '~> 2.1'
23
+
24
+ s.add_development_dependency 'rspec', '~> 3.6'
25
+ s.add_development_dependency 'rake', '~> 12.0'
26
+ s.add_development_dependency 'rubocop', '~> 0.48'
27
+ end
data/spec/mocks.rb ADDED
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ BITNODES_SNAPSHOT = <<-HEREDOC
4
+ {
5
+ "timestamp": 1495414383,
6
+ "total_nodes": 7055,
7
+ "latest_height": 467520,
8
+ "nodes": {
9
+ "88.99.199.87:8333": [80002, "/BitcoinUnlimited:1.0.2(EB16; AD12)/", 1494608364, 5, 467520, "static.87.199.99.88.clients.your-server.de", null, "DE", 51.2993, 9.491, "Europe/Berlin", "AS24940", "Hetzner Online GmbH"],
10
+ "[2a01:e34:ee3a:5730:21f:5bff:fec5:e356]:8333": [70015, "/Satoshi:0.14.0/", 1495378733, 13, 467520, "2a01:e34:ee3a:5730:21f:5bff:fec5:e356", null, "FR", 46.0, 2.0, "Europe/Paris", "AS12322", "Free SAS"]
11
+ }
12
+ }
13
+ HEREDOC
14
+
15
+ PEER_INFO = <<-HEREDOC
16
+ [
17
+ {
18
+ "id": 2,
19
+ "addr": "131.114.88.218:33422",
20
+ "addrlocal": "67.188.11.253:8333",
21
+ "services": "0000000000000000",
22
+ "relaytxes": true,
23
+ "lastsend": 1495412829,
24
+ "lastrecv": 1495412825,
25
+ "bytessent": 5200917,
26
+ "bytesrecv": 2044140,
27
+ "conntime": 1495393261,
28
+ "timeoffset": -24,
29
+ "pingtime": 0.369602,
30
+ "minping": 0.210565,
31
+ "version": 70002,
32
+ "subver": "/FirstClient/",
33
+ "inbound": true,
34
+ "startingheight": 435862,
35
+ "banscore": 0,
36
+ "synced_headers": 467515,
37
+ "synced_blocks": -1,
38
+ "inflight": [
39
+ ],
40
+ "whitelisted": false
41
+ },
42
+ {
43
+ "id": 3,
44
+ "addr": "[2a01:e34:ee3a:5730:21f:5bff:fec5:e356]:8333",
45
+ "addrlocal": "[2a01:e34:ee3a:5730:21f:5bff:fec5:e356]:8333",
46
+ "services": "0000000000000005",
47
+ "relaytxes": true,
48
+ "lastsend": 1495412829,
49
+ "lastrecv": 1495412830,
50
+ "bytessent": 10235040,
51
+ "bytesrecv": 2729345,
52
+ "conntime": 1495393262,
53
+ "timeoffset": -11,
54
+ "pingtime": 0.275245,
55
+ "minping": 0.07081899999999999,
56
+ "version": 80002,
57
+ "subver": "/SecondClient/",
58
+ "inbound": false,
59
+ "startingheight": 467483,
60
+ "banscore": 0,
61
+ "synced_headers": 467515,
62
+ "synced_blocks": 467515,
63
+ "inflight": [
64
+ ],
65
+ "whitelisted": false
66
+ }
67
+ ]
68
+ HEREDOC
@@ -0,0 +1,202 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'spec_helper'
4
+ require_relative 'mocks'
5
+
6
+ describe Pickynode do
7
+ # Debug mode makes sure we don't execute real commands.
8
+ let(:opts) do
9
+ { debug: true }
10
+ end
11
+
12
+ # IPv6 addresses are long, easier to refer by let.
13
+ let(:ipv6_ip) { '[2a01:e34:ee3a:5730:21f:5bff:fec5:e356]:8333' }
14
+ let(:ipv6_ip_no_port) { '[2a01:e34:ee3a:5730:21f:5bff:fec5:e356]' }
15
+
16
+ # The currently connected nodes for the specs.
17
+ let(:node_hash) do
18
+ { '131.114.88.218:33422' => '/FirstClient/',
19
+ ipv6_ip => '/SecondClient/' }
20
+ end
21
+
22
+ subject { Pickynode.new(opts) }
23
+
24
+ describe '.add' do
25
+ it 'should add nodes based on user agent' do
26
+ expect(subject).to receive(:bitnodes_snapshot).once
27
+ .and_return(BITNODES_SNAPSHOT)
28
+ expect(subject).to receive(:run_cmd)
29
+ .with(%(bitcoin-cli addnode "#{ipv6_ip}" "add"))
30
+ subject.add('Satoshi')
31
+ expect(subject).to receive(:run_cmd)
32
+ .with('bitcoin-cli addnode "88.99.199.87:8333" "add"')
33
+ subject.add('Unlimited')
34
+ end
35
+
36
+ it 'should return if the filter is falsy' do
37
+ expect(subject).to_not receive(:bitnodes_snapshot)
38
+ expect(subject).to_not receive(:run_cmd)
39
+ subject.add(false)
40
+ subject.add(nil)
41
+ end
42
+ end
43
+
44
+ describe '.ban' do
45
+ it 'should ban nodes based on user agent' do
46
+ expect(subject).to receive(:getpeerinfo).once
47
+ .and_return(PEER_INFO)
48
+ expect(URI).to receive(:parse).with('https://131.114.88.218:33422')
49
+ .and_call_original
50
+ expect(subject).to receive(:run_cmd)
51
+ .with('bitcoin-cli setban "131.114.88.218" "add"')
52
+ subject.ban('FirstClient')
53
+ expect(URI).to receive(:parse).with("https://#{ipv6_ip}")
54
+ .and_call_original
55
+ expect(subject).to receive(:run_cmd)
56
+ .with(%(bitcoin-cli setban "#{ipv6_ip_no_port}" "add"))
57
+ subject.ban('SecondClient')
58
+ end
59
+
60
+ it 'should return if the filter is falsy' do
61
+ expect(subject).to_not receive(:getpeerinfo)
62
+ expect(URI).to_not receive(:parse)
63
+ expect(subject).to_not receive(:run_cmd)
64
+ subject.ban(false)
65
+ subject.ban(nil)
66
+ end
67
+ end
68
+
69
+ describe '.connect' do
70
+ it 'should connect to nodes based on user agent' do
71
+ expect(subject).to receive(:bitnodes_snapshot).once
72
+ .and_return(BITNODES_SNAPSHOT)
73
+ expect(subject).to receive(:run_cmd)
74
+ .with('bitcoin-cli addnode "88.99.199.87:8333" "onetry"')
75
+ subject.connect('Unlimited')
76
+ expect(subject).to receive(:run_cmd)
77
+ .with(%(bitcoin-cli addnode "#{ipv6_ip}" "onetry"))
78
+ subject.connect('Satoshi')
79
+ end
80
+
81
+ it 'should return if the filter is falsy' do
82
+ expect(subject).to_not receive(:bitnodes_snapshot)
83
+ expect(subject).to_not receive(:run_cmd)
84
+ subject.connect(false)
85
+ subject.connect(nil)
86
+ end
87
+ end
88
+
89
+ describe '.disconnect' do
90
+ it 'should disconnect nodes based on user agent' do
91
+ expect(subject).to receive(:getpeerinfo).once
92
+ .and_return(PEER_INFO)
93
+ expect(subject).to receive(:run_cmd)
94
+ .with(%(bitcoin-cli disconnectnode "#{ipv6_ip}"))
95
+ subject.disconnect('SecondClient')
96
+ expect(subject).to receive(:run_cmd)
97
+ .with('bitcoin-cli disconnectnode "131.114.88.218:33422"')
98
+ subject.disconnect('FirstClient')
99
+ end
100
+
101
+ it 'should return if the filter is falsy' do
102
+ expect(subject).to_not receive(:getpeerinfo)
103
+ expect(subject).to_not receive(:run_cmd)
104
+ subject.disconnect(false)
105
+ subject.disconnect(nil)
106
+ end
107
+ end
108
+
109
+ describe '.display' do
110
+ it 'should display connected nodes' do
111
+ expect(subject).to receive(:getpeerinfo).and_return(PEER_INFO)
112
+ expect(subject).to receive(:ap).with(node_hash).and_return(node_hash)
113
+ expect(subject.display).to eq(node_hash)
114
+ end
115
+ end
116
+
117
+ describe '.run' do
118
+ context 'with opts' do
119
+ let(:opts) do
120
+ {
121
+ debug: true,
122
+ add: 'Wanted',
123
+ connect: 'Now',
124
+ ban: 'Nefarious',
125
+ disconnect: 'Fools'
126
+ }
127
+ end
128
+
129
+ it 'should call add, connect, ban and disconnect' do
130
+ expect(subject).to receive(:bitnodes_snapshot).once
131
+ .and_return(BITNODES_SNAPSHOT)
132
+ expect(subject).to receive(:getpeerinfo).and_return(PEER_INFO)
133
+ expect(subject).to receive(:add).with(opts[:add])
134
+ .and_call_original
135
+ expect(subject).to receive(:connect).with(opts[:connect])
136
+ .and_call_original
137
+ expect(subject).to receive(:ban).with(opts[:ban])
138
+ .and_call_original
139
+ expect(subject).to receive(:disconnect).with(opts[:disconnect])
140
+ .and_call_original
141
+ expect(subject).to_not receive(:display)
142
+ subject.run
143
+ end
144
+ end
145
+
146
+ context 'without opts' do
147
+ let(:opts) do
148
+ {}
149
+ end
150
+
151
+ it 'should call display' do
152
+ expect(subject).to receive(:getpeerinfo).once
153
+ .and_return(PEER_INFO)
154
+ expect(subject).to receive(:ap).with(node_hash).and_return(node_hash)
155
+ expect(subject).to receive(:display).and_call_original
156
+ subject.run
157
+ end
158
+ end
159
+ end
160
+
161
+ describe 'clear_cache' do
162
+ it 'should clear the bitnodes cache' do
163
+ expect(subject).to receive(:bitnodes_snapshot).once
164
+ .and_return(BITNODES_SNAPSHOT)
165
+ expect(subject).to receive(:run_cmd)
166
+ .with(%(bitcoin-cli addnode "#{ipv6_ip}" "add"))
167
+ expect(subject).to receive(:run_cmd)
168
+ .with('bitcoin-cli addnode "88.99.199.87:8333" "add"')
169
+ subject.add('Satoshi')
170
+ subject.add('Unlimited')
171
+ subject.clear_cache
172
+ expect(subject).to receive(:bitnodes_snapshot).once
173
+ .and_return(BITNODES_SNAPSHOT)
174
+ expect(subject).to receive(:run_cmd)
175
+ .with(%(bitcoin-cli addnode "#{ipv6_ip}" "add"))
176
+ subject.add('Satoshi')
177
+ end
178
+
179
+ it 'should clear the getpeerinfo cache' do
180
+ expect(subject).to receive(:getpeerinfo).once
181
+ .and_return(PEER_INFO)
182
+ expect(URI).to receive(:parse).with('https://131.114.88.218:33422')
183
+ .and_call_original
184
+ expect(URI).to receive(:parse).with(%(https://#{ipv6_ip}))
185
+ .and_call_original
186
+ expect(subject).to receive(:run_cmd)
187
+ .with('bitcoin-cli setban "131.114.88.218" "add"')
188
+ expect(subject).to receive(:run_cmd)
189
+ .with(%(bitcoin-cli setban "#{ipv6_ip_no_port}" "add"))
190
+ subject.ban('FirstClient')
191
+ subject.ban('SecondClient')
192
+ subject.clear_cache
193
+ expect(subject).to receive(:getpeerinfo).once
194
+ .and_return(PEER_INFO)
195
+ expect(URI).to receive(:parse).with('https://131.114.88.218:33422')
196
+ .and_call_original
197
+ expect(subject).to receive(:run_cmd)
198
+ .with('bitcoin-cli setban "131.114.88.218" "add"')
199
+ subject.ban('FirstClient')
200
+ end
201
+ end
202
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'spec_helper'
4
+
5
+ describe 'Rubocop' do
6
+ it 'should pass with no offenses detected' do
7
+ expect(`rubocop`).to include('no offenses detected')
8
+ end
9
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ require File.join('bundler', 'setup')
4
+ require 'rspec'
5
+ require 'pickynode'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pickynode
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Josh Ellithorpe
@@ -38,14 +38,74 @@ dependencies:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '2.1'
41
- description: Some people are picky about the bitcoin nodes they connect to.
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.6'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.6'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '12.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '12.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rubocop
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '0.48'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '0.48'
83
+ description: |-
84
+ Some people are picky about the \
85
+ bitcoin nodes they connect to.
42
86
  email: quest@mac.com
43
87
  executables:
44
88
  - pickynode
45
89
  extensions: []
46
90
  extra_rdoc_files: []
47
91
  files:
92
+ - ".gitignore"
93
+ - ".rubocop.yml"
94
+ - ".ruby-gemset"
95
+ - ".ruby-version"
96
+ - ".travis.yml"
97
+ - Gemfile
98
+ - Gemfile.lock
99
+ - LICENSE
100
+ - README.md
101
+ - Rakefile
48
102
  - bin/pickynode
103
+ - lib/pickynode.rb
104
+ - pickynode.gemspec
105
+ - spec/mocks.rb
106
+ - spec/pickynode_spec.rb
107
+ - spec/rubocop_spec.rb
108
+ - spec/spec_helper.rb
49
109
  homepage: http://github.com/zquestz/pickynode
50
110
  licenses:
51
111
  - MIT
@@ -58,7 +118,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
58
118
  requirements:
59
119
  - - ">="
60
120
  - !ruby/object:Gem::Version
61
- version: '0'
121
+ version: '2.0'
62
122
  required_rubygems_version: !ruby/object:Gem::Requirement
63
123
  requirements:
64
124
  - - ">="