smartdust-client 1.2.0 → 1.3.1
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/Gemfile.lock +8 -4
- data/README.md +33 -18
- data/lib/di.rb +6 -7
- data/lib/stf/client.rb +1 -1
- data/lib/stf/interactor/android_util.rb +45 -0
- data/lib/stf/interactor/connect_ios_interactor.rb +57 -33
- data/lib/stf/interactor/start_debug_session_interactor.rb +10 -39
- data/lib/stf/interactor/start_one_debug_session_interactor.rb +2 -2
- data/lib/stf/interactor/stop_all_debug_sessions_interactor.rb +43 -3
- data/lib/stf/interactor/stop_debug_session_interactor.rb +29 -35
- data/lib/stf/model/device_list.rb +0 -5
- data/lib/stf/version.rb +1 -1
- data/lib/stf/view/cli.rb +4 -4
- data/smartdust-client.gemspec +1 -1
- metadata +4 -4
- data/lib/stf/model/device_enhancer.rb +0 -17
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 816ea829cc813bc39511bf89151d1b059ba7acbe79ce3067f8a94fde987d363b
|
4
|
+
data.tar.gz: c564c0444b14986ca503408eea5d7b2686618ef3ddef7f3d509db0873f09d475
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c5b2abe3b36c04ec06a32eedc3fdb14b7952851e4e2b9ee693a312c2c78e2881c1bc588b9b51ed8554738d2ce0b27cbdb03db3274d34cd682d0a4ea8b0c9ab38
|
7
|
+
data.tar.gz: e8801265e92c781f29b7c50f0083dbdec4543e2063e9db7f279b0a612fe5572a7c653e6bd602f3a161ef725429cd53693089101e73b1ce2ecab602fcb1cc5c24
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
smartdust-client (1.
|
4
|
+
smartdust-client (1.3.0)
|
5
5
|
ADB (~> 0.5)
|
6
6
|
dante (~> 0.2.0)
|
7
7
|
dry-configurable (~> 0.1.4)
|
@@ -16,8 +16,9 @@ GEM
|
|
16
16
|
childprocess (>= 0.3.5)
|
17
17
|
addressable (2.8.1)
|
18
18
|
public_suffix (>= 2.0.2, < 6.0)
|
19
|
-
childprocess (
|
20
|
-
|
19
|
+
childprocess (5.1.0)
|
20
|
+
logger (~> 1.5)
|
21
|
+
concurrent-ruby (1.3.5)
|
21
22
|
crack (0.4.5)
|
22
23
|
rexml
|
23
24
|
dante (0.2.0)
|
@@ -29,9 +30,12 @@ GEM
|
|
29
30
|
concurrent-ruby (~> 1.0)
|
30
31
|
dry-configurable (~> 0.1, >= 0.1.3)
|
31
32
|
facets (3.1.0)
|
32
|
-
gli (2.
|
33
|
+
gli (2.22.2)
|
34
|
+
ostruct
|
33
35
|
hashdiff (1.0.1)
|
34
36
|
json (2.6.3)
|
37
|
+
logger (1.6.6)
|
38
|
+
ostruct (0.6.1)
|
35
39
|
public_suffix (5.0.1)
|
36
40
|
rack (1.6.13)
|
37
41
|
rack-protection (1.5.5)
|
data/README.md
CHANGED
@@ -4,6 +4,8 @@
|
|
4
4
|
|
5
5
|
# Smartdust CLI client
|
6
6
|

|
7
|
+
Documentation: https://docs.smartdust.me/docs/cli-client.
|
8
|
+
|
7
9
|
Automation client for connecting to Smartdust Lab devices via adb from a terminal.
|
8
10
|
Designed with the following scenario in mind:
|
9
11
|
|
@@ -11,7 +13,7 @@ Designed with the following scenario in mind:
|
|
11
13
|
2. Do something with the device via adb (Instrumentation Test, adb install, etc)
|
12
14
|
3. Disconnect from device
|
13
15
|
|
14
|
-
Due to it being a console tool, it's very easy to use
|
16
|
+
Due to it being a console tool, it's very easy to use it for test automation in a CI\CD pipeline, for example in Jenkins.
|
15
17
|
|
16
18
|
Allows for filtering by any device description parameter
|
17
19
|
as well as listing all available values of a given parameter
|
@@ -21,48 +23,61 @@ e.g. all unique names of devices in the lab instance.
|
|
21
23
|
## Prequisities
|
22
24
|
|
23
25
|
- Ruby along with RubyGems installed - versions higher than 3.0.2 are not guaranteed to work
|
24
|
-
-
|
26
|
+
- Android dependencies:
|
27
|
+
- adb (Android Debug Bridge)
|
28
|
+
- iOS dependencies:
|
29
|
+
- idevice_id (libimobiledevice)
|
30
|
+
- usbfluxd (https://github.com/corellium/usbfluxd/tree/master) (this needs to be patched to connect to multiple devices from the same Lab instance)
|
25
31
|
|
26
32
|
## Installation
|
27
|
-
|
28
|
-
-
|
29
|
-
|
30
|
-
- ```gem install smartdust-client-1.0.0.gem``` (or different version, see output of the previous command)
|
33
|
+
### From RubyGems
|
34
|
+
- Install as a Ruby Gem:
|
35
|
+
```gem install smartdust-client```
|
31
36
|
|
32
|
-
|
37
|
+
### From sources
|
38
|
+
- Open your terminal
|
39
|
+
- "cd" into the directory where the repository is cloned
|
40
|
+
- Run the following commands: (adding "sudo" might be needed)
|
41
|
+
- ```gem build smartdust-client.gemspec```
|
42
|
+
- ```gem install smartdust-client-1.2.0.gem``` (or different version, see output of the previous command)
|
33
43
|
|
34
44
|
## Usage
|
35
45
|
|
36
46
|
```
|
37
47
|
NAME
|
38
|
-
|
48
|
+
smartdust-client - Smartdust Lab client (version 1.2.0)
|
39
49
|
|
40
50
|
SYNOPSIS
|
41
|
-
|
51
|
+
smartdust-client [global options] command [command options] [arguments...]
|
42
52
|
|
43
53
|
GLOBAL OPTIONS
|
44
54
|
--help - Show this message
|
45
|
-
|
46
|
-
|
55
|
+
--log=arg - Log file (default: none)
|
56
|
+
--pid=arg - PID file (default: none)
|
57
|
+
-t, --token=arg - Authorization token, can also be set by environment variable SD_TOKEN (default: none)
|
58
|
+
-u, --url=arg - URL to Smartdust Lab, can also be set by environment variable SD_URL (default: none)
|
47
59
|
-v, --[no-]verbose - Be verbose
|
48
60
|
|
49
61
|
COMMANDS
|
50
|
-
clean - Frees all devices that are assigned to current user in
|
51
|
-
connect - Search for a device available in
|
52
|
-
disconnect - Disconnect device(s) from local adb server and remove device(s) from user devices in
|
62
|
+
clean - Frees all devices that are assigned to current user in Smartdust Lab. Doesn't modify local adb
|
63
|
+
connect - Search for a device available in Smartdust Lab and attach it to local adb server
|
64
|
+
disconnect - Disconnect device(s) from local adb server and remove device(s) from user devices in Smartdust Lab
|
53
65
|
help - Shows a list of commands or help for one command
|
54
66
|
keys - Show available keys for filtering
|
67
|
+
trustme - Add adb public key into Smartdust Lab
|
55
68
|
values - Show known values for the filtering key
|
56
|
-
|
57
|
-
ENVIRONMENT VARIABLES
|
58
|
-
STF_TOKEN - Authorization token
|
59
|
-
STF_URL - URL to STF
|
60
69
|
```
|
61
70
|
- Authorization token can be obtained from the Smartdust Lab web interface in Settings -> Keys
|
62
71
|
- When connecting with this tool for the first time, have the Smartdust Lab web interface open
|
63
72
|
to accept adding a new ADB key. This is necessary for every new machine that hasn't connected
|
64
73
|
yet to Remote Debug on a given Lab instance.
|
65
74
|
|
75
|
+
## Development
|
76
|
+
- Install Ruby 3.0.2
|
77
|
+
- Install Ruby Bundler: ```gem install bundler -v 1.17.3```
|
78
|
+
- Run ```bundle install``` in the project directory (might require adjusting directory permissions or sudo)
|
79
|
+
- Run the program with ```bundle exec ruby lib/stf.rb```
|
80
|
+
|
66
81
|
## License
|
67
82
|
|
68
83
|
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
data/lib/di.rb
CHANGED
@@ -12,7 +12,6 @@ require 'stf/interactor/get_values_interactor'
|
|
12
12
|
require 'stf/interactor/add_adb_public_key'
|
13
13
|
require 'stf/interactor/connect_ios_interactor'
|
14
14
|
require 'stf/validate/uri_validator'
|
15
|
-
require 'stf/model/device_enhancer'
|
16
15
|
|
17
16
|
class DI
|
18
17
|
class << self
|
@@ -23,7 +22,7 @@ class DI
|
|
23
22
|
|
24
23
|
# one time object
|
25
24
|
c.register(:dante_runner,
|
26
|
-
-> {Dante::Runner.new('
|
25
|
+
-> {Dante::Runner.new('smartdust-client')})
|
27
26
|
|
28
27
|
# one time object because dante is one time
|
29
28
|
c.register(:demonizer,
|
@@ -72,13 +71,13 @@ class DI
|
|
72
71
|
-> {Stf::AddAdbPublicKeyInteractor.new},
|
73
72
|
memoize: true)
|
74
73
|
|
75
|
-
c.register(:device_enhancer,
|
76
|
-
-> {Stf::DeviceEnhancer.new},
|
77
|
-
memoize: true)
|
78
|
-
|
79
74
|
c.register(:connect_ios,
|
80
|
-
-> {Stf::ConnectIosInteractor.new
|
75
|
+
-> {Stf::ConnectIosInteractor.new},
|
81
76
|
memoize: true)
|
77
|
+
|
78
|
+
c.register(:android_util,
|
79
|
+
-> {Stf::AndroidUtil.new},
|
80
|
+
memoize: true)
|
82
81
|
end
|
83
82
|
|
84
83
|
def [](what)
|
data/lib/stf/client.rb
CHANGED
@@ -55,7 +55,7 @@ module Stf
|
|
55
55
|
end
|
56
56
|
|
57
57
|
def destroy_tunnel(ip, port)
|
58
|
-
response = execute "/api/v1/tunnel", Net::HTTP::Delete, {ipAddress: ip, port: port}.to_json
|
58
|
+
response = execute "/api/v1/tunnel/{ip}/{port}", Net::HTTP::Delete, {ipAddress: ip, port: port}.to_json
|
59
59
|
return response.success
|
60
60
|
end
|
61
61
|
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'ADB'
|
2
|
+
module Stf
|
3
|
+
class AndroidUtil
|
4
|
+
include ADB
|
5
|
+
|
6
|
+
def get_present_adb_devices_ids
|
7
|
+
adb_out = `adb devices`
|
8
|
+
adb_out = adb_out.split("\n")
|
9
|
+
adb_out.shift
|
10
|
+
adb_out = adb_out.select { |line| line.include? 'device' }
|
11
|
+
adb_out.map! { |line| line.split("\t").first }
|
12
|
+
end
|
13
|
+
|
14
|
+
def map_adb_urls_to_serial
|
15
|
+
adb_urls = get_present_adb_devices_ids
|
16
|
+
urls_to_serials = Hash.new
|
17
|
+
adb_urls.each do |adb_url|
|
18
|
+
serial = `adb -s #{adb_url} shell getprop ro.serialno`
|
19
|
+
serial = serial.strip
|
20
|
+
urls_to_serials[adb_url] = serial
|
21
|
+
end
|
22
|
+
urls_to_serials
|
23
|
+
end
|
24
|
+
|
25
|
+
def map_serials_to_adb_urls
|
26
|
+
adb_urls = get_present_adb_devices_ids
|
27
|
+
serials_to_urls = Hash.new
|
28
|
+
adb_urls.each do |adb_url|
|
29
|
+
serial = `adb -s #{adb_url} shell getprop ro.serialno`
|
30
|
+
serial = serial.strip
|
31
|
+
serials_to_urls[serial] = adb_url
|
32
|
+
end
|
33
|
+
serials_to_urls
|
34
|
+
end
|
35
|
+
|
36
|
+
def cleanup_adb_devices
|
37
|
+
to_disconnect = devices - get_present_adb_devices_ids
|
38
|
+
to_disconnect.each do |id|
|
39
|
+
execute_adb_with 30, "disconnect #{id}"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
@@ -1,49 +1,73 @@
|
|
1
|
+
require 'rexml/document'
|
2
|
+
require 'open3'
|
3
|
+
require 'mkmf'
|
4
|
+
|
5
|
+
require 'stf/log/log'
|
6
|
+
|
1
7
|
module Stf
|
2
8
|
class ConnectIosInteractor
|
9
|
+
include Log
|
3
10
|
|
4
|
-
|
5
|
-
|
6
|
-
def initialize(sd_remote_ios_path, ideviceid_path)
|
7
|
-
@sd_remote_ios = sd_remote_ios_path
|
8
|
-
@ideviceid = ideviceid_path
|
9
|
-
end
|
11
|
+
@active = false
|
10
12
|
|
11
|
-
def
|
12
|
-
if
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
`sudo systemctl restart usbmuxd`
|
17
|
-
disconnect()
|
18
|
-
connected_before = connected_ios_devices().count
|
19
|
-
fork do
|
20
|
-
`sudo #{@sd_remote_ios} -c #{url} &`
|
21
|
-
end
|
22
|
-
sleep 2
|
23
|
-
if connected_ios_devices().count > connected_before
|
24
|
-
@@connected_ios_urls.append(url)
|
25
|
-
else
|
26
|
-
raise "Cannot connect to iOS device"
|
13
|
+
def initialize
|
14
|
+
if find_executable('usbfluxctl') != nil
|
15
|
+
stdout, stderr, status = Open3.capture3("usbfluxctl list xml")
|
16
|
+
unless stderr.include? "Failed"
|
17
|
+
@active = true
|
27
18
|
end
|
28
19
|
end
|
20
|
+
unless @active
|
21
|
+
logger.info "iOS dependencies not available. Install 'usbfluxd' distributed by SmartDust. Make sure to start 'usbfluxd -n' with root permissions before connecting to iOS devices. Also ensure that 'usbfluxctl' is in your $PATH."
|
22
|
+
end
|
29
23
|
end
|
30
24
|
|
31
|
-
|
32
|
-
|
33
|
-
|
25
|
+
|
26
|
+
def connect(url)
|
27
|
+
raise "iOS connecting is not active" unless @active
|
28
|
+
Open3.capture3("usbfluxctl add #{url}")
|
29
|
+
sleep(1)
|
30
|
+
logger.info ios_serials_to_urls.to_s
|
31
|
+
unless ios_serials_to_urls.values.include? url
|
32
|
+
raise "Cannot connect to iOS device"
|
33
|
+
end
|
34
34
|
end
|
35
35
|
|
36
|
-
def
|
37
|
-
|
36
|
+
def disconnect(url)
|
37
|
+
raise "iOS connecting is not active" unless @active
|
38
|
+
Open3.capture3("usbfluxctl del #{url}")
|
38
39
|
end
|
39
40
|
|
40
|
-
def
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
41
|
+
def ios_serials_to_urls
|
42
|
+
return {} unless @active
|
43
|
+
stdout, stderr, status = Open3.capture3("usbfluxctl list xml")
|
44
|
+
result = {}
|
45
|
+
|
46
|
+
doc = REXML::Document.new(stdout)
|
47
|
+
instances = doc.elements['plist/dict/dict']
|
48
|
+
|
49
|
+
if instances.nil?
|
50
|
+
return {}
|
51
|
+
end
|
52
|
+
|
53
|
+
instances.elements.each('dict') do |instance|
|
54
|
+
host = instance.elements["string[preceding-sibling::key[text()='Host']]"]
|
55
|
+
port = instance.elements["integer[preceding-sibling::key[text()='Port']]"]
|
56
|
+
if host.nil? || port.nil?
|
57
|
+
next
|
58
|
+
end
|
59
|
+
url = "#{host.text}:#{port.text}"
|
60
|
+
|
61
|
+
devices = instance.elements['array']
|
62
|
+
if devices
|
63
|
+
devices.elements.each do |device|
|
64
|
+
serial = device.text
|
65
|
+
result[serial] = url
|
66
|
+
end
|
67
|
+
end
|
46
68
|
end
|
69
|
+
|
70
|
+
result
|
47
71
|
end
|
48
72
|
|
49
73
|
end
|
@@ -5,6 +5,7 @@ require 'stf/client'
|
|
5
5
|
require 'stf/log/log'
|
6
6
|
require 'stf/model/device_list'
|
7
7
|
require 'stf/interactor/connect_ios_interactor'
|
8
|
+
require 'stf/interactor/android_util'
|
8
9
|
|
9
10
|
module Stf
|
10
11
|
class StartDebugSessionInteractor
|
@@ -46,8 +47,8 @@ module Stf
|
|
46
47
|
return false
|
47
48
|
end
|
48
49
|
|
49
|
-
connected_count = count_connected_devices(filter)
|
50
|
-
logger.info "
|
50
|
+
connected_count = count_connected_devices(filter, force_filter)
|
51
|
+
logger.info "Number of connected devices: #{connected_count}"
|
51
52
|
|
52
53
|
return true if nodaemon_flag
|
53
54
|
|
@@ -82,7 +83,7 @@ module Stf
|
|
82
83
|
one_time_mode = !daemon_mode
|
83
84
|
|
84
85
|
while true do
|
85
|
-
|
86
|
+
DI[:stop_all_debug_sessions_interactor].disconnect_unwanted_devices(filter, force_filter, healthcheck)
|
86
87
|
|
87
88
|
if one_time_mode && Time.now > finish_time
|
88
89
|
raise "Connect loop timeout reached"
|
@@ -96,7 +97,7 @@ module Stf
|
|
96
97
|
if all_flag
|
97
98
|
to_connect = stf_devices.size
|
98
99
|
else
|
99
|
-
connected = (
|
100
|
+
connected = (DI[:android_util].get_present_adb_devices_ids + DI[:connect_ios].ios_serials_to_urls.keys)
|
100
101
|
to_connect = wanted - connected.size
|
101
102
|
end
|
102
103
|
|
@@ -116,43 +117,13 @@ module Stf
|
|
116
117
|
end
|
117
118
|
end
|
118
119
|
|
119
|
-
def count_connected_devices(filter)
|
120
|
+
def count_connected_devices(filter, force_filter)
|
120
121
|
stf_devices = DeviceList.new(DI[:stf].get_user_devices)
|
121
|
-
stf_devices = stf_devices.by_filter(filter) if filter
|
122
|
-
connected = (
|
123
|
-
connected
|
122
|
+
stf_devices = stf_devices.by_filter(filter) if filter && force_filter
|
123
|
+
connected = (DI[:android_util].map_serials_to_adb_urls.keys + DI[:connect_ios].ios_serials_to_urls.keys)
|
124
|
+
connected_filtered = stf_devices.asArray.map {|d| d.serial} & connected
|
125
|
+
connected_filtered.size
|
124
126
|
end
|
125
127
|
|
126
|
-
def cleanup_disconnected_devices(filter, force_filter, healthcheck)
|
127
|
-
to_disconnect = []
|
128
|
-
stf_devices = DeviceList.new(DI[:stf].get_user_devices)
|
129
|
-
|
130
|
-
if filter && force_filter
|
131
|
-
disconnect_because_filter = stf_devices.except_filter(filter).as_connect_url_list
|
132
|
-
unless disconnect_because_filter.empty?
|
133
|
-
logger.info 'will be disconnected by filter: ' + disconnect_because_filter.join(',')
|
134
|
-
to_disconnect += disconnect_because_filter
|
135
|
-
end
|
136
|
-
end
|
137
|
-
|
138
|
-
if healthcheck
|
139
|
-
disconnect_by_health = stf_devices.select_not_healthy(healthcheck).as_connect_url_list
|
140
|
-
unless disconnect_by_health.empty?
|
141
|
-
logger.info 'will be disconnected by health check: ' + disconnect_by_health.join(',')
|
142
|
-
to_disconnect += disconnect_by_health
|
143
|
-
end
|
144
|
-
end
|
145
|
-
|
146
|
-
dead_persons = stf_devices.as_connect_url_list - (devices + DI[:connect_ios].connected_ios_urls())
|
147
|
-
unless dead_persons.empty?
|
148
|
-
logger.info 'will be disconnected because not present locally: ' + dead_persons.join(',')
|
149
|
-
to_disconnect += dead_persons
|
150
|
-
end
|
151
|
-
|
152
|
-
to_disconnect.reject {|url| url.to_s.empty?}.uniq.each do |url|
|
153
|
-
logger.info 'Cleanup the device ' + url.to_s
|
154
|
-
DI[:stop_debug_session_interactor].execute(url)
|
155
|
-
end
|
156
|
-
end
|
157
128
|
end
|
158
129
|
end
|
@@ -42,7 +42,7 @@ module Stf
|
|
42
42
|
logger.error "Can't open tunnel to provider with IP #{provider_ip}"
|
43
43
|
raise
|
44
44
|
end
|
45
|
-
remote_connect_tunneled_url =
|
45
|
+
remote_connect_tunneled_url = remote_connect_url_split[0] + ":" + result.port.to_s
|
46
46
|
logger.info remote_connect_tunneled_url
|
47
47
|
|
48
48
|
case device.getValue "platform"
|
@@ -51,7 +51,7 @@ module Stf
|
|
51
51
|
shell('echo adbtest', {serial: "#{remote_connect_tunneled_url}"}, 30)
|
52
52
|
raise ADBError, "Could not execute shell test" unless stdout_contains "adbtest"
|
53
53
|
when "iOS"
|
54
|
-
DI[:connect_ios].connect(remote_connect_tunneled_url
|
54
|
+
DI[:connect_ios].connect(remote_connect_tunneled_url)
|
55
55
|
else
|
56
56
|
logger.error "Unrecognized device platform"
|
57
57
|
end
|
@@ -5,6 +5,7 @@ require 'stf/client'
|
|
5
5
|
require 'stf/log/log'
|
6
6
|
require 'stf/interactor/stop_debug_session_interactor'
|
7
7
|
require 'stf/model/device_list'
|
8
|
+
require 'stf/interactor/android_util'
|
8
9
|
|
9
10
|
module Stf
|
10
11
|
class StopAllDebugSessionsInteractor
|
@@ -16,12 +17,51 @@ module Stf
|
|
16
17
|
DI[:demonizer].kill unless options[:nokill]
|
17
18
|
|
18
19
|
stf_devices = DeviceList.new(DI[:stf].get_user_devices)
|
19
|
-
|
20
20
|
stf_devices = stf_devices.by_filter options[:byFilter] if options[:byFilter]
|
21
|
+
stf_devices.asArray.each {|d| DI[:stop_debug_session_interactor].execute d}
|
22
|
+
end
|
23
|
+
|
24
|
+
def disconnect_unwanted_devices(filter, force_filter, healthcheck)
|
25
|
+
DI[:android_util].cleanup_adb_devices
|
26
|
+
to_disconnect = [] # array of device serials
|
27
|
+
active_user_devices = DeviceList.new(DI[:stf].get_user_devices)
|
28
|
+
adb_serials_to_urls = DI[:android_util].map_serials_to_adb_urls
|
29
|
+
|
30
|
+
if filter && force_filter
|
31
|
+
disconnect_because_filter = active_user_devices.except_filter(filter).asArray.map { |d| d.serial }
|
32
|
+
unless disconnect_because_filter.empty?
|
33
|
+
logger.info 'will be disconnected by filter: ' + disconnect_because_filter.join(',')
|
34
|
+
to_disconnect += disconnect_because_filter
|
35
|
+
end
|
36
|
+
end
|
21
37
|
|
22
|
-
|
38
|
+
if healthcheck
|
39
|
+
disconnect_by_health = active_user_devices.select_not_healthy(healthcheck).asArray.map { |d| d.serial }
|
40
|
+
unless disconnect_by_health.empty?
|
41
|
+
logger.info 'will be disconnected by health check: ' + disconnect_by_health.join(',')
|
42
|
+
to_disconnect += disconnect_by_health
|
43
|
+
end
|
44
|
+
end
|
23
45
|
|
24
|
-
|
46
|
+
dead_persons = active_user_devices.asArray.map { |d| d.serial } - (adb_serials_to_urls.keys + DI[:connect_ios].ios_serials_to_urls.keys)
|
47
|
+
unless dead_persons.empty?
|
48
|
+
logger.info 'will be disconnected because not present locally: ' + dead_persons.join(',')
|
49
|
+
to_disconnect += dead_persons
|
50
|
+
end
|
51
|
+
|
52
|
+
without_active_session = (adb_serials_to_urls.keys + DI[:connect_ios].ios_serials_to_urls.keys) - active_user_devices.asArray.map{ |d| d.serial }
|
53
|
+
unless without_active_session.empty?
|
54
|
+
logger.info 'will be disconnected because session is not active in SmartDust Lab: ' + without_active_session.join(',')
|
55
|
+
to_disconnect += without_active_session
|
56
|
+
end
|
57
|
+
|
58
|
+
DeviceList.new(DI[:stf].get_devices).asArray.filter {|device|
|
59
|
+
to_disconnect.include? device.serial
|
60
|
+
}.each do |device|
|
61
|
+
logger.info 'Cleanup the device ' + device.serial
|
62
|
+
DI[:stop_debug_session_interactor].execute(device)
|
63
|
+
end
|
25
64
|
end
|
65
|
+
|
26
66
|
end
|
27
67
|
end
|
@@ -9,50 +9,44 @@ module Stf
|
|
9
9
|
include Log
|
10
10
|
include ADB
|
11
11
|
|
12
|
-
def execute(
|
13
|
-
remote_devices = DI[:stf].get_user_devices
|
14
|
-
device = remote_devices.find {|d| d.remoteConnect == true && DI[:device_enhancer].get_tunneled_remote_connect_url(d).eql?(remote_connect_url)}
|
15
|
-
|
16
|
-
# try to disconnect anyway
|
17
|
-
if DI[:connect_ios].connected_ios_devices.include? remote_connect_url
|
18
|
-
DI[:connect_ios].disconnect()
|
19
|
-
else
|
20
|
-
execute_adb_with 30, "disconnect #{remote_connect_url}"
|
21
|
-
end
|
12
|
+
def execute(device)
|
22
13
|
|
23
|
-
if device.
|
24
|
-
|
25
|
-
|
14
|
+
if DI[:connect_ios].ios_serials_to_urls.keys.include? device.serial
|
15
|
+
DI[:connect_ios].disconnect(DI[:connect_ios].ios_serials_to_urls[device.serial])
|
16
|
+
elsif devices.include? device.serial
|
17
|
+
execute_adb_with 30, "disconnect #{remote_connect_url}"
|
26
18
|
end
|
27
19
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
20
|
+
if DeviceList.new(DI[:stf].get_user_devices).asArray.map {|d| d.serial}.include? device.serial
|
21
|
+
success = false
|
22
|
+
1..10.times do
|
23
|
+
begin
|
24
|
+
success = DI[:stf].stop_debug(device.serial)
|
25
|
+
break if success
|
26
|
+
rescue
|
27
|
+
end
|
28
|
+
|
29
|
+
logger.error 'Can\'t stop debug session. Retrying'
|
30
|
+
end
|
31
|
+
|
32
|
+
1..10.times do
|
33
|
+
begin
|
34
|
+
success = DI[:stf].remove_device(device.serial)
|
35
|
+
break if success
|
36
|
+
rescue
|
37
|
+
end
|
38
|
+
logger.error 'Can\'t remove device from user devices. Retrying'
|
35
39
|
end
|
36
40
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
begin
|
42
|
-
success = DI[:stf].remove_device(device.serial)
|
43
|
-
break if success
|
44
|
-
rescue
|
41
|
+
if success
|
42
|
+
logger.info "Successfully removed #{device.serial}"
|
43
|
+
else
|
44
|
+
logger.error "Error removing #{device.serial}"
|
45
45
|
end
|
46
|
-
logger.error 'Can\'t remove device from user devices. Retrying'
|
47
|
-
end
|
48
|
-
|
49
|
-
if success
|
50
|
-
logger.info "Successfully removed #{remote_connect_url}"
|
51
|
-
else
|
52
|
-
logger.error "Error removing #{remote_connect_url}"
|
53
46
|
end
|
54
47
|
|
55
48
|
success
|
56
49
|
end
|
57
50
|
end
|
51
|
+
|
58
52
|
end
|
@@ -52,11 +52,6 @@ module Stf
|
|
52
52
|
}
|
53
53
|
end
|
54
54
|
|
55
|
-
def as_connect_url_list
|
56
|
-
@devices.reject { |d| d.remoteConnectUrl.nil? || d.remoteConnectUrl.empty? }
|
57
|
-
.map{|d| DI[:device_enhancer].get_tunneled_remote_connect_url(d)}
|
58
|
-
end
|
59
|
-
|
60
55
|
def select
|
61
56
|
DeviceList.new(@devices.select {|d| yield(d)})
|
62
57
|
end
|
data/lib/stf/version.rb
CHANGED
data/lib/stf/view/cli.rb
CHANGED
@@ -2,8 +2,10 @@ module Stf
|
|
2
2
|
module CLI
|
3
3
|
require 'di'
|
4
4
|
require 'gli'
|
5
|
+
require 'stf/log/log'
|
5
6
|
|
6
7
|
include GLI::App
|
8
|
+
include Log
|
7
9
|
|
8
10
|
extend self
|
9
11
|
|
@@ -105,8 +107,7 @@ module Stf
|
|
105
107
|
desc 'Add adb public key into Smartdust Lab'
|
106
108
|
command :trustme do |c|
|
107
109
|
c.desc 'Location of adb public key'
|
108
|
-
c.flag [:k, :adb_public_key_location]
|
109
|
-
c.default_value '~/.android/adbkey.pub'
|
110
|
+
c.flag [:k, :adb_public_key_location], :default_value => '~/.android/adbkey.pub'
|
110
111
|
|
111
112
|
c.action do |_, options, _|
|
112
113
|
filename = File.expand_path(options[:adb_public_key_location])
|
@@ -117,5 +118,4 @@ module Stf
|
|
117
118
|
|
118
119
|
exit run(ARGV)
|
119
120
|
end
|
120
|
-
end
|
121
|
-
|
121
|
+
end
|
data/smartdust-client.gemspec
CHANGED
@@ -9,7 +9,7 @@ Gem::Specification.new do |spec|
|
|
9
9
|
spec.authors = ['Smartdust']
|
10
10
|
spec.email = ['jordan@smartdust.me']
|
11
11
|
spec.summary = %q{Connect to devices from Smartdust Lab via adb from cli}
|
12
|
-
spec.homepage = 'https://
|
12
|
+
spec.homepage = 'https://docs.smartdust.me/docs/cli-client'
|
13
13
|
spec.license = 'MIT'
|
14
14
|
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
15
15
|
spec.require_paths = ['lib']
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: smartdust-client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.3.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Smartdust
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2025-05-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: gli
|
@@ -229,6 +229,7 @@ files:
|
|
229
229
|
- lib/stf.rb
|
230
230
|
- lib/stf/client.rb
|
231
231
|
- lib/stf/interactor/add_adb_public_key.rb
|
232
|
+
- lib/stf/interactor/android_util.rb
|
232
233
|
- lib/stf/interactor/connect_ios_interactor.rb
|
233
234
|
- lib/stf/interactor/get_keys_interactor.rb
|
234
235
|
- lib/stf/interactor/get_values_interactor.rb
|
@@ -239,7 +240,6 @@ files:
|
|
239
240
|
- lib/stf/interactor/stop_debug_session_interactor.rb
|
240
241
|
- lib/stf/log/log.rb
|
241
242
|
- lib/stf/model/device.rb
|
242
|
-
- lib/stf/model/device_enhancer.rb
|
243
243
|
- lib/stf/model/device_list.rb
|
244
244
|
- lib/stf/system/demonizer.rb
|
245
245
|
- lib/stf/validate/uri_validator.rb
|
@@ -247,7 +247,7 @@ files:
|
|
247
247
|
- lib/stf/view/cli.rb
|
248
248
|
- smartdust-client.gemspec
|
249
249
|
- smartdust-logo-text-2021.png
|
250
|
-
homepage: https://
|
250
|
+
homepage: https://docs.smartdust.me/docs/cli-client
|
251
251
|
licenses:
|
252
252
|
- MIT
|
253
253
|
metadata: {}
|
@@ -1,17 +0,0 @@
|
|
1
|
-
module Stf
|
2
|
-
class DeviceEnhancer
|
3
|
-
def get_tunneled_remote_connect_url(device)
|
4
|
-
provider = device.provider
|
5
|
-
provider_ip = provider["ip"]
|
6
|
-
result = DI[:stf].start_debug device.serial
|
7
|
-
remote_connect_url_split = result.remoteConnectUrl.split ":"
|
8
|
-
remote_connect_port = remote_connect_url_split[1]
|
9
|
-
result = DI[:stf].check_tunnel provider_ip, remote_connect_port
|
10
|
-
if result.success
|
11
|
-
remote_connect_hostname = remote_connect_url_split[0]
|
12
|
-
remote_connect_hostname + ":" + result.port.to_s
|
13
|
-
else nil
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|