Skip to content

Commit

Permalink
feat: scan device, connect.
Browse files Browse the repository at this point in the history
  • Loading branch information
dengzii committed Dec 8, 2020
1 parent 4a98b58 commit 6e9ec92
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 55 deletions.
4 changes: 0 additions & 4 deletions src/com/dengzii/plugin/adb/ui/AboutDialog.kt
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,4 @@ class AboutDialog : XDialog("About") {
private fun browser(url: String) {
BrowserUtil.browse(url)
}
}

fun main() {
AboutDialog().show()
}
14 changes: 11 additions & 3 deletions src/com/dengzii/plugin/adb/ui/MainDialog.kt
Original file line number Diff line number Diff line change
Expand Up @@ -196,9 +196,17 @@ class MainDialog : MainDialogDesign() {
item("Connect Manual") {
ConnectDialog().show { updateDevice() }
}
item("Scan Device") {
ScanDeviceDialog.show {

item("Scan Device [beta]") {
ScanDeviceDialog.show { address ->
setHintLabel("Connecting to ${address.address.hostAddress}:${address.port}")
DeviceManager.connectDevice(address.address.hostAddress, address.port) { success, msg ->
invokeLater {
if (success) {
updateDevice()
}
setHintLabel(msg)
}
}
}
}
item("Exit") {
Expand Down
91 changes: 59 additions & 32 deletions src/com/dengzii/plugin/adb/ui/ScanDeviceDialog.kt
Original file line number Diff line number Diff line change
@@ -1,40 +1,46 @@
package com.dengzii.plugin.adb.ui

import com.dengzii.plugin.adb.tools.invokeLater
import com.dengzii.plugin.adb.tools.ui.ColumnInfo
import com.dengzii.plugin.adb.tools.ui.TableAdapter
import com.dengzii.plugin.adb.tools.ui.XDialog
import com.dengzii.plugin.adb.tools.ui.onClick
import com.dengzii.plugin.adb.utils.DeviceManager
import com.intellij.ide.ui.fullRow
import com.intellij.ui.components.JBScrollPane
import com.intellij.ui.layout.panel
import java.awt.BorderLayout
import java.awt.Component
import java.net.InetSocketAddress
import java.util.concurrent.ExecutorService
import java.util.concurrent.atomic.AtomicBoolean
import javax.swing.*

class ScanDeviceDialog(private var callback: (Map<String, Int>) -> Unit) : XDialog("Scan Device") {
class ScanDeviceDialog(private var callback: (InetSocketAddress) -> Unit) : XDialog("Scan Device [beta]") {

private val table: JTable = JTable()
private val tableData = mutableListOf<MutableList<Any?>>()
private val columnInfo = mutableListOf<ColumnInfo<Any>>()
private val model = TableAdapter(tableData, columnInfo)
private val tableAdapter = TableAdapter(tableData, columnInfo)

private lateinit var buttonScan: JButton
private lateinit var labelProgress: JLabel
private lateinit var fieldTimeout: JTextField
private lateinit var fieldThreadSize: JTextField
private lateinit var fieldTimeoutPing: JTextField
private lateinit var fieldTimeoutAdb: JTextField
private lateinit var fieldThreadNum: JTextField
private lateinit var fieldPortStart: JTextField
private lateinit var fieldPortEnd: JTextField

companion object {
fun show(callback: (Map<String, Int>) -> Unit) {
fun show(callback: (InetSocketAddress) -> Unit) {
ScanDeviceDialog(callback).packAndShow()
}
}

init {
persistDialogState = false
val c = object : ColumnInfo<Any>("Operate", true) {
override val columnClass = Int::class.java
override val columnClass = InetSocketAddress::class.java

override fun getEditComponent(item: Any?, row: Int, col: Int) = getButton(item)

Expand All @@ -45,52 +51,64 @@ class ScanDeviceDialog(private var callback: (Map<String, Int>) -> Unit) : XDial
layout = BorderLayout(4, 4)
add(OperateButtonColumn.Button("Connect").apply {
onClick {
println(value)
if (value is InetSocketAddress) {
hideAndDispose()
callback.invoke(value)
}
}
}, BorderLayout.CENTER)
}
}
}
columnInfo.add(ColumnInfo("IP/PORT"))
columnInfo.add(c)
table.rowHeight = 45
table.rowHeight = 35
table.columnSelectionAllowed = false
table.rowSelectionAllowed = false
model.setup(table)
tableAdapter.setup(table)

contentPane = panel {
row { label("") }
row {
label("Timeout").withLargeLeftGap()
cell {
intTextField({ 2000 }, {}).apply {
fieldTimeout = component
label("Ping:")
intTextField({ 1000 }, {}).apply {
fieldTimeoutPing = component
}
label("")

label("ADB:").withLargeLeftGap()
intTextField({ 1000 }, {}).apply {
fieldTimeoutAdb = component
}
label("")
}
}
row {
label("Thread Num").withLargeLeftGap()
cell {
intTextField({ Runtime.getRuntime().availableProcessors() }, {}).apply {
fieldThreadSize = component
intTextField({ Runtime.getRuntime().availableProcessors() * 2 }, {}).apply {
fieldThreadNum = component
}
label("")

label("Available Processors: ")
label("${Runtime.getRuntime().availableProcessors()}")
label("")
}
}
row {
label("ADB Port").withLargeLeftGap()
cell {
intTextField({ 5555 }, { println(it) }, range = 5555..5561).apply {
intTextField({ 5555 }, { println(it) }).apply {
fieldPortStart = component
// isEnabled = false
}
label("-")
intTextField({ 5561 }, { }, range = 5555..5561).apply {
intTextField({ 5559 }, { }).apply {
fieldPortEnd = component
// isEnabled = false
}
label("4 ports. ")
label("odd, gte 5555, lte 5585 ")
}
}
row {
Expand All @@ -108,8 +126,8 @@ class ScanDeviceDialog(private var callback: (Map<String, Int>) -> Unit) : XDial
}
}
}
row {
panel("", JScrollPane().apply {
fullRow {
panel("", JBScrollPane().apply {
table.fillsViewportHeight = true
setViewportView(table)
})
Expand All @@ -119,23 +137,32 @@ class ScanDeviceDialog(private var callback: (Map<String, Int>) -> Unit) : XDial
}

private var scanExecutor: ExecutorService? = null
private var tableInUpdate = AtomicBoolean(false)

private fun scan() {
when (buttonScan.text) {
"Scan" -> {
tableData.clear()
tableAdapter.fireTableDataChanged()
scanExecutor = DeviceManager.scanAvailableDevicesLan(
timeout = fieldTimeout.text.toInt(),
threadPoolSize = fieldThreadSize.text.toInt()
timeout = fieldTimeoutPing.text.toInt(),
adbTimeout = fieldTimeoutAdb.text.toInt(),
threadPoolSize = fieldThreadNum.text.toInt(),
ports = (fieldPortStart.text.toInt()..fieldPortEnd.text.toInt() step 1).toList()
) { progress, message, ip ->
labelProgress.text = "$progress% $message"
if (ip.isNotEmpty()){
tableData.clear()
ip.forEach {
tableData.add(mutableListOf("${it.address.hostAddress}:${it.port}", it.port))
invokeLater {
labelProgress.text = "$progress% $message"
if (ip.isNotEmpty() && !tableInUpdate.getAndSet(true)) {
tableData.clear()
ip.forEach {
tableData.add(mutableListOf("${it.address.hostAddress}:${it.port}", it))
}
tableAdapter.fireTableDataChanged()
tableInUpdate.set(false)
}
if (progress == 100) {
buttonScan.text = "Scan"
}
model.fireTableDataChanged()
}
if (progress == 100) {
buttonScan.text = "Scan"
}
}
buttonScan.text = "Stop"
Expand All @@ -151,7 +178,7 @@ class ScanDeviceDialog(private var callback: (Map<String, Int>) -> Unit) : XDial
override fun onOpened() {
super.onOpened()
location = getLocationCenterOfScreen()
model.fireTableStructureChanged()
tableAdapter.fireTableStructureChanged()
}

}
39 changes: 23 additions & 16 deletions src/com/dengzii/plugin/adb/utils/DeviceManager.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,8 @@ package com.dengzii.plugin.adb.utils
import com.dengzii.plugin.adb.Config
import com.dengzii.plugin.adb.Device
import com.dengzii.plugin.adb.XLog
import io.netty.util.internal.SocketUtils
import org.apache.commons.net.telnet.TelnetClient
import java.net.*
import java.nio.channels.SocketChannel
import java.util.*
import java.util.concurrent.*
import java.util.concurrent.atomic.AtomicInteger
Expand Down Expand Up @@ -121,13 +119,20 @@ object DeviceManager {
}
}

fun connectDevice(ip: String, port: Int, listener: (success: Boolean, message: String) -> Unit) {
AdbUtils.connect(ip, port).execute { res ->
listener.invoke(res.success, res.output)
}
}

private val scanned = AtomicInteger(0)
private val scanDeviceIpList = Vector<InetSocketAddress>()

fun scanAvailableDevicesLan(
timeout: Int = 1000,
timeout: Int = 2000,
adbTimeout: Int = 1000,
ports: List<Int> = listOf(5555, 5557, 5559),
threadPoolSize: Int = Runtime.getRuntime().availableProcessors() * 10,
threadPoolSize: Int = Runtime.getRuntime().availableProcessors() * 2,
callback: (progress: Int, message: String, ip: List<InetSocketAddress>) -> Unit
): ExecutorService {
val executor = Executors.newFixedThreadPool(threadPoolSize)
Expand All @@ -136,41 +141,43 @@ object DeviceManager {
scanned.set(0)
scanDeviceIpList.clear()
val telnetClient = TelnetClient()
(executor as ThreadPoolExecutor).setKeepAliveTime(5, TimeUnit.SECONDS)
telnetClient.connectTimeout = adbTimeout
val logBuilder = StringBuffer()
callback.invoke(0, "scanning...", emptyList())
subnetIp.forEach { inetAddress ->
executor.submit {
if (Thread.interrupted()) {
return@submit
}
val reachable = inetAddress.isReachable(timeout)
if (Thread.interrupted()) {
return@submit
}
var msg = ""
SocketChannel.open()
if (reachable) {
val socket = Socket()
var s = "${inetAddress.hostAddress} "
for (i in ports) {
try {
msg = "${inetAddress.hostAddress}:${i}"
s = s.plus("$i ")
val socketAddress = InetSocketAddress(inetAddress.hostAddress, i)
socket.connect(socketAddress, 500)
telnetClient.connect(inetAddress, i)
scanDeviceIpList.add(socketAddress)
telnetClient.disconnect()
break
} catch (e: Exception) {
}
}
logBuilder.append("${s}\n")
} else {
msg = "${inetAddress.hostAddress} is unreachable."
}

if (scanned.incrementAndGet() >= availableIpSize) {
val progress = (scanned.incrementAndGet().toFloat() / availableIpSize.toFloat()) * 100
if (scanned.get() >= availableIpSize) {
msg = "scan finish, ${scanDeviceIpList.size} device may available."
XLog.d(logBuilder.toString())
callback.invoke(progress.toInt(), msg, scanDeviceIpList)
executor.shutdownNow()
}
val progress = (scanned.get().toFloat() / availableIpSize.toFloat()) * 100
callback.invoke(progress.toInt(), msg, scanDeviceIpList)
if (!Thread.interrupted()) {
callback.invoke(progress.toInt(), msg, scanDeviceIpList)
}
}
}
return executor
Expand Down

0 comments on commit 6e9ec92

Please sign in to comment.