Skip to content

Commit f3316cc

Browse files
committed
onlineHandler
1 parent afb9090 commit f3316cc

File tree

1 file changed

+80
-32
lines changed
  • src/main/java/com/kenvix/nwafunet

1 file changed

+80
-32
lines changed

src/main/java/com/kenvix/nwafunet/Main.kt

Lines changed: 80 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
@file:JvmName("Main")
2+
23
package com.kenvix.nwafunet
34

45
import com.github.ajalt.clikt.core.CliktCommand
@@ -21,26 +22,42 @@ import java.net.http.HttpRequest
2122
import java.net.http.HttpResponse
2223
import java.time.Duration
2324
import java.util.logging.Level
25+
import kotlin.math.log
2426
import kotlin.system.exitProcess
2527

2628
/**
2729
* -Djava.util.logging.ConsoleHandler.level=INFO
2830
*/
2931
object Entry : CliktCommand() {
30-
val portalAddress: String by option("-z", "--portal").help("Login Portal URL. For example http://172.26.8.11").default("http://172.26.8.11")
31-
private val ip: String? by option("-a", "--ip").help("Outbound IP").help("Your outbound IP address. Leave blank for auto detect.")
32+
val portalAddress: String by option("-z", "--portal").help("Login Portal URL. For example http://172.26.8.11")
33+
.default("http://172.26.8.11")
34+
private val ip: String? by option("-a", "--ip").help("Outbound IP")
35+
.help("Your outbound IP address. Leave blank for auto detect.")
3236

3337
val accountId: String by option("-u", "--username").prompt("Account ID").help("Account ID")
3438
val accountPassword: String by option("-p", "--password").prompt("Password").help("Password")
35-
val networkInterface: String? by option("-i", "--interface").help("Network Interface Name. All traffic will be sent through this interface if specified.").convert { it.trim() }
36-
val waitInterface: Int by option().int().help("Wait Network Interface if it is currently unavailable every N seconds. Default 0 for disabled.").default(0)
39+
val networkInterface: String? by option(
40+
"-i",
41+
"--interface"
42+
).help("Network Interface Name. All traffic will be sent through this interface if specified.")
43+
.convert { it.trim() }
44+
val waitInterface: Int by option().int()
45+
.help("Wait Network Interface if it is currently unavailable every N seconds. Default 0 for disabled.")
46+
.default(0)
3747

3848
val logout: Boolean by option().boolean().default(false)
39-
val checkAlive: Int by option("-c", "--check-alive").int().help("Check whether network is still alive every N seconds. 0 for disabled.").default(0)
40-
val keepAlive: Int by option().int().help("Send heart packet to keep alive every N seconds. 0 for disabled.").default(0)
49+
val checkAlive: Int by option("-c", "--check-alive").int()
50+
.help("Check whether network is still alive every N seconds. 0 for disabled.").default(0)
51+
val keepAlive: Int by option().int().help("Send heart packet to keep alive every N seconds. 0 for disabled.")
52+
.default(0)
4153
val isRetry: Int by option("--retry").int().help("Retry every N seconds if failed. 0 for disabled.").default(10)
4254
val retryWaitTime: Int by option("-r", "--retry-wait-time").int().help("Retry wait time in N seconds").default(2)
43-
val logLevel: Level by option("-l", "--log-level").convert { Level.parse(it) }.help("Log Level. FINEST < FINER < FINE < CONFIG < INFO < WARNING < SEVERE").default(Level.INFO)
55+
val logLevel: Level by option("-l", "--log-level").convert { Level.parse(it) }
56+
.help("Log Level. FINEST < FINER < FINE < CONFIG < INFO < WARNING < SEVERE").default(Level.INFO)
57+
58+
val onlineHandler: String? by option().help("Execute command when network online. For example: /usr/bin/notify-send 'Network is online'")
59+
val waitOnlineHandler: Boolean by option().boolean().default(false)
60+
// val offlineHandler: String? by option().help("Execute command when network offline. For example: /usr/bin/notify-send 'Network is offline'")
4461

4562
val httpClient by lazy {
4663
HttpClient.newBuilder()
@@ -49,7 +66,10 @@ object Entry : CliktCommand() {
4966
if (networkInterface == null) {
5067
it
5168
} else {
52-
it.localAddress(getInterfaceAvailableLocalAddress() ?: throw IllegalArgumentException("Network interface $networkInterface not found"))
69+
it.localAddress(
70+
getInterfaceAvailableLocalAddress()
71+
?: throw IllegalArgumentException("Network interface $networkInterface not found")
72+
)
5373
}
5474
}.build()
5575
}
@@ -73,7 +93,7 @@ object Entry : CliktCommand() {
7393
private val logger by lazy { Logging.getLogger("Entry", logLevel) }
7494
private val mutex = Mutex()
7595

76-
override fun run() { }
96+
override fun run() {}
7797

7898
@OptIn(DelicateCoroutinesApi::class)
7999
suspend fun entry(): Int {
@@ -197,23 +217,47 @@ object Entry : CliktCommand() {
197217
}
198218

199219
suspend fun performNetworkAuth() {
200-
while (!isIntraNetworkReady()) {
201-
// performLogout()
202-
delay(500L)
203-
204-
val loginResult = performLogin()
205-
206-
if (loginResult && logout) {
207-
performLogout()
208-
delay(1000L)
209-
performLogout()
210-
delay(1000L)
211-
performLogout()
220+
coroutineScope {
221+
while (!isIntraNetworkReady()) {
222+
// performLogout()
223+
delay(500L)
224+
225+
val loginResult = performLogin()
226+
227+
if (loginResult && logout) {
228+
performLogout()
229+
delay(1000L)
230+
performLogout()
231+
delay(1000L)
232+
performLogout()
233+
}
234+
235+
if (!loginResult) {
236+
logger.warning("Failed to login, retrying... after $retryWaitTime seconds")
237+
delay(retryWaitTime * 1000L)
238+
}
212239
}
213240

214-
if (!loginResult)
215-
logger.warning("Failed to login, retrying... after $retryWaitTime seconds")
216-
delay(retryWaitTime * 1000L)
241+
if (onlineHandler != null) {
242+
logger.fine("Network is online, executing online handler: $onlineHandler")
243+
launch(Dispatchers.IO) {
244+
try {
245+
@Suppress("DEPRECATION")
246+
val proc = Runtime.getRuntime().exec(onlineHandler)
247+
val ret = proc.onExit().await()
248+
249+
if (ret.exitValue() != 0) {
250+
logger.warning("Online handler exited with non-zero code: $ret")
251+
} else {
252+
logger.fine("Online handler executed successfully")
253+
}
254+
} catch (e: Exception) {
255+
logger.severe("Failed to execute online handler: ${e.message}")
256+
}
257+
}.also { if (waitOnlineHandler) it.join() }
258+
}
259+
260+
logger.info("Login is successful. Network is ready.")
217261
}
218262
}
219263

@@ -265,7 +309,7 @@ object Entry : CliktCommand() {
265309
}
266310

267311
private fun createRequestBuilderWithCommonHeaders(url: String): HttpRequest.Builder {
268-
return com.kenvix.nwafunet.srun.createRequestBuilderWithCommonHeaders(url, portalAddress)
312+
return com.kenvix.nwafunet.srun.createRequestBuilderWithCommonHeaders(url, portalAddress)
269313
}
270314

271315
suspend fun performLogin(): Boolean {
@@ -285,9 +329,10 @@ object Entry : CliktCommand() {
285329
suspend fun performLogout() {
286330
logger.info("Performing logout request")
287331
val time = System.currentTimeMillis()
288-
val request = createRequestBuilderWithCommonHeaders("${portalAddress}/cgi-bin/srun_portal?callback=jQuery112405095399744250795_$time&action=logout&username=$accountId&ip=$outboundIp&ac_id=1&_=$time")
289-
.GET()
290-
.build()
332+
val request =
333+
createRequestBuilderWithCommonHeaders("${portalAddress}/cgi-bin/srun_portal?callback=jQuery112405095399744250795_$time&action=logout&username=$accountId&ip=$outboundIp&ac_id=1&_=$time")
334+
.GET()
335+
.build()
291336
val rsp = httpClient.sendAsync(request, HttpResponse.BodyHandlers.ofString()).await()
292337
logger.debug("Logout request response # ${rsp.statusCode()}: ${rsp.body()}")
293338
val err = checkForError(rsp.body())
@@ -304,7 +349,8 @@ object Entry : CliktCommand() {
304349

305350
try {
306351
// 发送请求并检查响应状态码
307-
val response: HttpResponse<Void> = httpClient.sendAsync(request, HttpResponse.BodyHandlers.discarding()).await()
352+
val response: HttpResponse<Void> =
353+
httpClient.sendAsync(request, HttpResponse.BodyHandlers.discarding()).await()
308354
if (response.statusCode() == 204) {
309355
logger.fine("Public Network is reachable")
310356
return true
@@ -322,12 +368,14 @@ object Entry : CliktCommand() {
322368
logger.fine("Checking Intra network status")
323369

324370
val timestamp = System.currentTimeMillis()
325-
val request = createRequestBuilderWithCommonHeaders("$portalAddress/cgi-bin/rad_user_info?callback=jQuery112406390292035501186_$timestamp&_=$timestamp")
326-
.build()
371+
val request =
372+
createRequestBuilderWithCommonHeaders("$portalAddress/cgi-bin/rad_user_info?callback=jQuery112406390292035501186_$timestamp&_=$timestamp")
373+
.build()
327374

328375
try {
329376
// 发送请求并检查响应状态码
330-
val response: HttpResponse<String> = httpClient.sendAsync(request, HttpResponse.BodyHandlers.ofString()).await()
377+
val response: HttpResponse<String> =
378+
httpClient.sendAsync(request, HttpResponse.BodyHandlers.ofString()).await()
331379
if ("online_device_total" in response.body() || "not_online_error" !in response.body()) {
332380
logger.fine("Intra Network is online")
333381
return true

0 commit comments

Comments
 (0)