Skip to content

Commit

Permalink
Merge pull request #573 from MortezaBashsiz/android-dev
Browse files Browse the repository at this point in the history
update latest version (1.0.7)
  • Loading branch information
0ut0fCode authored May 23, 2023
2 parents afb08d0 + 6b07e43 commit 159bf84
Show file tree
Hide file tree
Showing 27 changed files with 561 additions and 79 deletions.
21 changes: 21 additions & 0 deletions android/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
*.iml
.gradle
/local.properties
/.idea/caches
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
.DS_Store
/build
/captures
.externalNativeBuild
.cxx
local.properties

app/debug/

.idea/

app/google-services.json
6 changes: 4 additions & 2 deletions android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ android {
applicationId "ir.filternet.cfscanner"
minSdk 24
targetSdk 33
versionCode 6
versionName "1.0.6"
versionCode 7
versionName "1.0.7"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables {
useSupportLibrary true
Expand Down Expand Up @@ -223,6 +223,8 @@ dependencies {
implementation "dev.chrisbanes.snapper:snapper:0.2.1"
implementation "com.github.skydoves:whatif:1.1.2"
implementation 'com.coolerfall:android-http-download-manager:2.0.0'

implementation "com.airbnb.android:lottie-compose:6.0.0"
}

appmetrica {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@ sealed class ScanButtonState {
object Ready : ScanButtonState()
data class Scanning(val scan:Scan ,val progress: ScanProgress) : ScanButtonState()
data class Disabled(val message:String = "") : ScanButtonState()
object WaitingForNetwork : ScanButtonState()
data class Paused(val message:String = "") : ScanButtonState()
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ data class ScanSettings(
val worker: Float = 4.99f,
val speedTestSize: Float = 300f,
val fronting: String = BuildConfig.FrontingAddress,
val pingFilter: Float = 2900f,
val autoSkipPortion:Float = 0f,
val autoFetch: Boolean = true,
val shuffle: Boolean = false,
val customRange: Boolean = false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import java.util.concurrent.Semaphore
import java.util.concurrent.TimeUnit
import javax.inject.Inject
import javax.inject.Singleton
import kotlin.random.Random

@Singleton
class CFScanner @Inject constructor(
Expand All @@ -48,6 +49,8 @@ class CFScanner @Inject constructor(
private val cidrs: ArrayList<CIDR> = arrayListOf()
private var scan: Scan? = null

private var skipCurrentRange: Boolean = false

fun startScan(scan: Scan, options: ScanOptions = ScanOptions()) {
discoveryJob?.cancel()
discoveryJob = launch(Dispatchers.IO) {
Expand Down Expand Up @@ -88,20 +91,28 @@ class CFScanner @Inject constructor(
return discoveryJob?.isActive ?: false
}


fun skipCurrentRange() {
if (!skipCurrentRange) {
skipCurrentRange = true
}
}

private suspend fun CoroutineScope.startScan(scan: Scan, options: ScanOptions) {
val scope = this
val config = scan.config
val isp = scan.isp


val allCIDR = getScanCidrs(scan,options)
this@CFScanner.scan = scan.copy(scanCidrOrder = allCIDR.joinToString(" "){ it.uid.toString() })
val allCIDR = getScanCidrs(scan, options)
this@CFScanner.scan = scan.copy(scanCidrOrder = allCIDR.joinToString(" ") { it.uid.toString() })

delay(1000)

/* set options */
val parallel = options.parallel
frontDomain = options.frontingDomain
val autoSkip = options.autoSkipPortion

/* load previous scan history*/
val (lastCidr, lastConnection) = getLastDetails(scan)
Expand All @@ -111,7 +122,7 @@ class CFScanner @Inject constructor(
/* ================= */

/* Start Process Log */
logger.add(Log("worker", context.getString(R.string.worker_initialized,parallel), STATUS.SUCCESS))
logger.add(Log("worker", context.getString(R.string.worker_initialized, parallel), STATUS.SUCCESS))
Timber.d("CFScanner: Start Scan by $parallel worker")
/* ================= */

Expand All @@ -123,14 +134,14 @@ class CFScanner @Inject constructor(
yield()
}
val ipCount = allCIDR.map { calculateUsableHostCountBySubnetMask(it.subnetMask) }.reduce { a, i -> a + i }
logger.add(Log("ips", context.getString(R.string.ip_found_to_check,ipCount), STATUS.SUCCESS))
logger.add(Log("ips", context.getString(R.string.ip_found_to_check, ipCount), STATUS.SUCCESS))

delay(1000)

runBlocking {
// worker controller
val semaphore = Semaphore(parallel)

var skipped = 0
allCIDR.let {

// delete scanned cidr
Expand All @@ -153,10 +164,12 @@ class CFScanner @Inject constructor(
} ?: -1

/* Start Scan Log */
logger.add(Log(cidr.address, context.getString(R.string.start_scan_for,cidr.address,cidr.subnetMask), STATUS.INPROGRESS))
logger.add(Log(cidr.address, context.getString(R.string.start_scan_for, cidr.address, cidr.subnetMask), STATUS.INPROGRESS))
Timber.d("CFScanner: Start Scan for ${cidr.address}/${cidr.subnetMask} by $count ips")
/* ============== */

var failed = 0
skipped = 0
repeat(count) { index ->

val ip = getIpAddressByIndex(cidr.address, cidr.subnetMask, index)
Expand All @@ -166,6 +179,22 @@ class CFScanner @Inject constructor(
return@repeat
}

// auto skip
if (autoSkip >= 1 && !skipCurrentRange) {
val shouldSkip = (((failed*1f) / count)*100f) >= autoSkip
if (shouldSkip){
logger.add(Log(ip+ Random(100).toString(), context.getString(R.string.auto_skip_triggered_for,cidr.address), STATUS.SUCCESS))
skipCurrentRange()
}
}

// skip range check
if (skipCurrentRange) {
skipped++
return@repeat
}


semaphore.acquire()
scope.launch {
ip?.let {
Expand All @@ -174,13 +203,26 @@ class CFScanner @Inject constructor(
logger.add(Log(it, it, STATUS.INPROGRESS))
Timber.d("CFScanner: check status for $it")
yield()
val delay = checkIpDelay(config, it)
var delay = checkIpDelay(config, it)
yield()
if (delay > 0) {
founded++
logger.add(Log(it, "$it ($delay ms)", STATUS.SUCCESS))
Timber.d("CFScanner: result status for $it ==> Success (${delay}ms)")

// apply ping limit filter on result
if (delay > options.pingFilter) {
logger.add(Log(it, context.getString(R.string.ping_error, it), STATUS.FAILED))
failed++
delay = -1
} else {
// reset failed count to avoid auto skip
failed = 0

founded++
logger.add(Log(it, "$it ($delay ms)", STATUS.SUCCESS))
Timber.d("CFScanner: result status for $it ==> Success (${delay}ms)")
}

} else {
failed++
Timber.d("CFScanner: result status for $it ==> Failed!")
}

Expand All @@ -199,7 +241,14 @@ class CFScanner @Inject constructor(
semaphore.release()
}
}
logger.add(Log(cidr.address, context.getString(R.string.end_scan_for,cidr.address,cidr.subnetMask), STATUS.SUCCESS))

skipCurrentRange = false

if (skipped > 0) {
logger.add(Log(cidr.address + Random(100).toString(), context.getString(R.string.skipped_range, skipped, cidr.address), STATUS.SUCCESS))
} else {
logger.add(Log(cidr.address, context.getString(R.string.end_scan_for, cidr.address, cidr.subnetMask), STATUS.SUCCESS))
}
}

semaphore.tryAcquire(parallel, 10, TimeUnit.SECONDS)
Expand All @@ -218,8 +267,8 @@ class CFScanner @Inject constructor(

// 2. convert cidrs order to cidr list
val cidrList = cidrRepository.getAllCIDR(options.autoFetch)
// filter custom range
.let { if(options.customRange) it.filter { it.custom } else it }
// filter custom range
.let { if (options.customRange) it.filter { it.custom } else it }

return if (!cidrIdList.isNullOrEmpty()) {
cidrList.sortedBy { cidrIdList.indexOf(it.uid) }
Expand All @@ -238,14 +287,14 @@ class CFScanner @Inject constructor(
private suspend fun checkIpDelay(config: Config, address: String, port: Int = 443): Long {
// 1. check port opening
if (!isPortOpen(address, port, 2000)) {
logger.add(Log(address, context.getString(R.string.port_close,address), STATUS.FAILED))
logger.add(Log(address, context.getString(R.string.port_close, address), STATUS.FAILED))
Timber.d("CFScanner: check status for $address ==> Port $port is not Open!")
return -1
}

// 2. check domain fronting
if (!checkDomainFronting(address)) {
logger.add(Log(address, context.getString(R.string.fronting_error,address), STATUS.FAILED))
logger.add(Log(address, context.getString(R.string.fronting_error, address), STATUS.FAILED))
Timber.d("CFScanner: check status for $address ==> Fronting not Ok!")
return -1
}
Expand Down Expand Up @@ -317,7 +366,7 @@ class CFScanner @Inject constructor(
val conf = v2rarUtils.createServerConfig(config)?.fullConfig?.getByCustomVnextOutbound(port, ip)?.getByCustomInbound(ports)?.toPrettyPrinting()!!
val client = V2RayClient(context, conf)
client.connect("$ip:$port")
logger.add(Log(ip, context.getString(R.string.v2ray_cooldown,ip), STATUS.INPROGRESS))
logger.add(Log(ip, context.getString(R.string.v2ray_cooldown, ip), STATUS.INPROGRESS))
delay(2000)
val delay = client.measureDelay()

Expand All @@ -328,14 +377,14 @@ class CFScanner @Inject constructor(
client.disconnect()
}

}catch (e:Exception){
} catch (e: Exception) {
e.printStackTrace()
logger.add(Log(ip, context.getString(R.string.v2ray_failed,ip), STATUS.FAILED))
logger.add(Log(ip, context.getString(R.string.v2ray_failed, ip), STATUS.FAILED))
}


if (delay < 0) {
logger.add(Log(ip, context.getString(R.string.v2ray_failed,ip), STATUS.FAILED))
logger.add(Log(ip, context.getString(R.string.v2ray_failed, ip), STATUS.FAILED))
}
return delay
}
Expand Down Expand Up @@ -382,6 +431,8 @@ class CFScanner @Inject constructor(
data class ScanOptions(
val parallel: Int = 4,
val frontingDomain: String = "",
val pingFilter: Float = 2900f,
val autoSkipPortion: Float = 0f,
val autoFetch: Boolean = true,
val shuffle: Boolean = false,
val customRange: Boolean = false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ class CloudScannerService : Service(),

private var isp: ISP? = null
private var scan: Scan? = null
private var serviceStatus: ServiceStatus = ServiceStatus.Idle()
private var serviceStatus: ServiceStatus = ServiceStatus.WaitingForNetwork(scan)


/* connection flow */
Expand Down Expand Up @@ -184,6 +184,10 @@ class CloudScannerService : Service(),
stopScan()
}

fun skipCurrentRange() {
_skipCurrentRange()
}

fun getLastScan(): Scan? = scan

fun getServiceStatus(): ServiceStatus = serviceStatus
Expand Down Expand Up @@ -220,19 +224,29 @@ class CloudScannerService : Service(),
frontingDomain = scanSettings.fronting,
autoFetch = scanSettings.autoFetch,
shuffle = scanSettings.shuffle,
customRange = scanSettings.customRange
customRange = scanSettings.customRange,
pingFilter = scanSettings.pingFilter,
autoSkipPortion = scanSettings.autoSkipPortion,
)
)
}
}

private fun stopScan() {
Timber.d("CloudScannerService stopScan")
cfScanner?.apply {
cfScanner.apply {
stopScan(true)
}
}


private fun _skipCurrentRange() {
Timber.d("CloudScannerService skipCurrentRange")
cfScanner.apply {
skipCurrentRange()
}
}

/**
* save success connection besides of last connection for each scan
* @param connections List<Connection>
Expand All @@ -242,6 +256,7 @@ class CloudScannerService : Service(),
Timber.d("CloudScannerService: add connections to db: ${connections.size}")
val healthyConnections = connections.filter { it.delay > 0 }
val lastConnection = connections.lastOrNull()

if (healthyConnections.isNotEmpty()) {
connectionRepository.insertAll(healthyConnections)
}
Expand Down Expand Up @@ -303,7 +318,7 @@ class CloudScannerService : Service(),
this.scan = scan

if (networkManager.getNetworkState() == NetworkManager.NetworkState.DISCONNECTED) {
setServiceStatus(ServiceStatus.Disabled(reason))
setServiceStatus(ServiceStatus.WaitingForNetwork(scan))
} else {
setServiceStatus(ServiceStatus.Paused(scan, ScanProgress(), reason))
}
Expand Down Expand Up @@ -334,7 +349,7 @@ class CloudScannerService : Service(),
if (cfScanner.isRunning()) {
cfScanner.stopScan(byUser = false, reason = "No internet connection")
}
setServiceStatus(ServiceStatus.Disabled("No internet connection"))
setServiceStatus(ServiceStatus.WaitingForNetwork(scan))
}

NetworkManager.NetworkState.DISCONNECTED -> {
Expand Down Expand Up @@ -368,6 +383,7 @@ class CloudScannerService : Service(),
data class Idle(val isp: ISP? = null) : ServiceStatus()
data class Scanning(val scan: Scan) : ServiceStatus()
data class Paused(val scan: Scan, val progress: ScanProgress, val message: String) : ServiceStatus()
data class WaitingForNetwork(val scan: Scan? = null) : ServiceStatus()
data class Disabled(val message: String) : ServiceStatus()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,11 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import ir.filternet.cfscanner.R
import ir.filternet.cfscanner.utils.mirror

@Composable
Expand All @@ -36,7 +38,7 @@ fun HeaderPage(title: String,modifier:Modifier = Modifier, onBackPress: () -> Un
Icons.Rounded.ArrowBackIos, contentDescription = null,
Modifier
.clip(RoundedCornerShape(50))
.clickable {
.clickable(onClickLabel = stringResource(id = R.string.back)) {
onBackPress()
}
.background(MaterialTheme.colors.primary.copy(alpha = 0.05f))
Expand Down
Loading

0 comments on commit 159bf84

Please sign in to comment.