import api.CloudflareApiService import com.google.gson.Gson import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.runBlocking import kotlinx.coroutines.withContext import model.Configure import model.zones.UpdateDnsBody import okhttp3.OkHttpClient import okhttp3.Request import retrofit2.Retrofit import retrofit2.converter.gson.GsonConverterFactory import java.io.File import java.io.IOException import kotlin.system.exitProcess private lateinit var config: Configure private lateinit var token: String private lateinit var domain: String fun main() { println("Cloudflare DDNS 更新程式已啟動") val confFile = File("config.json") if (!confFile.exists()) { confFile.createNewFile() println("請先設定 config.json 檔案") return } val configRawText = confFile.readText(Charsets.UTF_8) if (configRawText.isEmpty()) { println("請先設定 config.json 檔案") return } config = loadConfigFile(configRawText) val retrofit = Retrofit.Builder() .baseUrl("https://api.cloudflare.com") .addConverterFactory(GsonConverterFactory.create()) .build() val apiService = retrofit.create(CloudflareApiService::class.java) runBlocking { println("-------- [ 開始更新 DNS ] --------") val client = OkHttpClient() val request: Request = Request.Builder() .url("https://ifconfig.me") .addHeader("User-Agent", "") .method("GET", null) .build() val ipAddress = try { val response = withContext(Dispatchers.IO) { client.newCall(request).execute() } if (response.isSuccessful) { response.body()?.string() ?: run { println("無法取得 WAN IP 位址") return@runBlocking } } else { null } } catch (e: IOException) { null } finally { client.dispatcher().executorService().shutdown() } if (ipAddress != null) { println("您目前的 WAN IP 位址為: $ipAddress") try { println("驗證 CF 權杖是否有效...") val verifyTokenResult = apiService.getVerifyToken("Bearer $token") if (verifyTokenResult.success) { println("CF 權杖有效,載入 Zone 資料中...") val zonesResult = apiService.getZones("Bearer $token") if (zonesResult.success) { println("Zone 資料載入成功,取得域名資料中...") val zoneData = zonesResult.result.firstOrNull { it.name == domain } ?: run { println("無法找到指定的域名 [ $domain ]...") return@runBlocking } val zoneId = zoneData.id val zoneDnsRecords = apiService.getZoneDnsRecords("Bearer $token", zoneId) if (zoneDnsRecords.success) { println("域名資料載入成功,處理中...") val record = zoneDnsRecords.result.firstOrNull { it.name == domain } ?: run { println("無法找到指定的域名 [ $domain ]...") return@runBlocking } val recordId = record.id val updateDnsBody = UpdateDnsBody( type = "A", name = record.name, content = ipAddress, ttl = 120, proxied = false ) val updateDnsResult = apiService.updateZoneDnsRecords("Bearer $token", zoneId, recordId, updateDnsBody) if (updateDnsResult.success) { println("更新 DDNS 成功") exitProcess(0) } else { println("更新 DDNS 失敗") exitProcess(0) } } else { println("無法取得域名資料資料") exitProcess(0) } } else { println("無法取得 Zone 資料") exitProcess(0) } } else { println("CF 權杖無效") exitProcess(0) } } catch (e: Exception) { e.printStackTrace() println("Error: ${e.message}") exitProcess(0) } } else { println("無法取得 WAN IP 位址...") exitProcess(0) } } } private fun loadConfigFile(configRawText: String): Configure { val config = Gson().fromJson(configRawText, Configure::class.java) token = config.token domain = config.domain println("-------- [ 設定檔已載入 ] --------") println("CF 權杖: $token") println("欲更新的域名: $domain") return config }