Refactor and Bump version to 1.1.0
This commit is contained in:
@@ -1,43 +0,0 @@
|
|||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
|
|
||||||
env:
|
|
||||||
INFENDRO__TOKEN: ${{ secrets.TOKEN }}
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
release:
|
|
||||||
runs-on: linux
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- uses: actions/cache/restore@v4
|
|
||||||
with:
|
|
||||||
key: gradle
|
|
||||||
path: |
|
|
||||||
~/.gradle/caches/
|
|
||||||
~/.gradle/wrapper/
|
|
||||||
~/.konan/
|
|
||||||
|
|
||||||
- uses: actions/setup-java@v4
|
|
||||||
with:
|
|
||||||
java-version: '24'
|
|
||||||
distribution: 'temurin'
|
|
||||||
|
|
||||||
- run: |
|
|
||||||
./gradlew assemble
|
|
||||||
mv ./build/bin/linuxX64/releaseExecutable/ddns.kexe ./ddns
|
|
||||||
|
|
||||||
- uses: actions/upload-artifact@v3
|
|
||||||
with:
|
|
||||||
name: ddns
|
|
||||||
path: ./ddns
|
|
||||||
|
|
||||||
- uses: actions/cache/save@v4
|
|
||||||
with:
|
|
||||||
key: gradle
|
|
||||||
path: |
|
|
||||||
~/.gradle/caches/
|
|
||||||
~/.gradle/wrapper/
|
|
||||||
~/.konan/
|
|
||||||
20
README.md
20
README.md
@@ -15,7 +15,7 @@ The resulting binary will be located in `./build/bin/releaseExecutable/`.
|
|||||||
The following command updates all A and AAAA DNS records in Porkbun for `example.com` and `test.example.com`.
|
The following command updates all A and AAAA DNS records in Porkbun for `example.com` and `test.example.com`.
|
||||||
|
|
||||||
```
|
```
|
||||||
ddns porkbun \
|
ddns porkbun update \
|
||||||
--key=<key> \
|
--key=<key> \
|
||||||
--secret-key=<secret key> \
|
--secret-key=<secret key> \
|
||||||
--domain=example.com \
|
--domain=example.com \
|
||||||
@@ -27,12 +27,18 @@ Alternatively, a file can be used to declare one or more configurations.
|
|||||||
The above example can be declared as follows.
|
The above example can be declared as follows.
|
||||||
|
|
||||||
```
|
```
|
||||||
porkbun
|
[
|
||||||
key=<key>
|
{
|
||||||
secret-key=<secret key>
|
"type": "porkbun",
|
||||||
domain=example.com
|
"key": "<key>",
|
||||||
subdomain=
|
"secretKey": "<secret key>"
|
||||||
subdomain=test
|
"domain": "example.com",
|
||||||
|
"subdomains": [
|
||||||
|
"",
|
||||||
|
"test"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
```
|
```
|
||||||
|
|
||||||
To use this config file, execute the command `ddns --config=<config file>`.
|
To use this config file, execute the command `ddns --config=<config file>`.
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import com.infendro.plugin.infendro
|
import com.infendro.plugin.infendro
|
||||||
|
|
||||||
group = "com.infendro"
|
group = "com.infendro"
|
||||||
version = "1.0.0"
|
version = "1.1.0"
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
alias(libs.plugins.infendro)
|
alias(libs.plugins.infendro)
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
[versions]
|
[versions]
|
||||||
infendro = "1.0.0"
|
infendro = "1.1.0"
|
||||||
kotlin = "2.2.21"
|
kotlin = "2.3.0"
|
||||||
io = "0.8.2"
|
io = "0.9.0"
|
||||||
coroutines = "1.10.2"
|
coroutines = "1.10.2"
|
||||||
serialization = "1.9.0"
|
serialization = "1.10.0"
|
||||||
cli = "1.3.0"
|
cli = "1.4.0"
|
||||||
ktor = "3.3.3"
|
ktor = "3.4.0"
|
||||||
|
|
||||||
[plugins]
|
[plugins]
|
||||||
infendro = { id = "com.infendro.plugin", version.ref = "infendro" }
|
infendro = { id = "com.infendro.plugin", version.ref = "infendro" }
|
||||||
|
|||||||
@@ -1,110 +1,5 @@
|
|||||||
package com.infendro.ddns
|
package com.infendro.ddns
|
||||||
|
|
||||||
import com.infendro.cli.argument.string
|
import com.infendro.ddns.command.ddns
|
||||||
import com.infendro.cli.argument.stringOrElse
|
|
||||||
import com.infendro.cli.argument.strings
|
|
||||||
import com.infendro.cli.command.cli
|
|
||||||
import com.infendro.ddns.Argument.CONFIG
|
|
||||||
import com.infendro.ddns.Argument.DOMAIN
|
|
||||||
import com.infendro.ddns.Argument.IP_SERVICE
|
|
||||||
import com.infendro.ddns.Argument.KEY
|
|
||||||
import com.infendro.ddns.Argument.SECRET_KEY
|
|
||||||
import com.infendro.ddns.Argument.SUBDOMAIN
|
|
||||||
import com.infendro.ddns.argument.ipService
|
|
||||||
import com.infendro.ddns.config.Config
|
|
||||||
import com.infendro.ddns.dns.DnsService
|
|
||||||
import com.infendro.ddns.dns.DnsService.Companion.PORKBUN
|
|
||||||
import com.infendro.ddns.dns.model.DnsRecord
|
|
||||||
import com.infendro.ddns.dns.porkbun.Porkbun
|
|
||||||
import com.infendro.ddns.ip.IpService
|
|
||||||
|
|
||||||
private object Argument {
|
fun main(args: Array<String>) = ddns.run(*args)
|
||||||
val CONFIG = stringOrElse("config", "/etc/ddns.conf")
|
|
||||||
|
|
||||||
val DOMAIN = string("domain")
|
|
||||||
val SUBDOMAIN = strings("subdomain", min = 1)
|
|
||||||
val IP_SERVICE = ipService("ip-service")
|
|
||||||
|
|
||||||
// Porkbun
|
|
||||||
val KEY = string("key")
|
|
||||||
val SECRET_KEY = string("secret-key")
|
|
||||||
}
|
|
||||||
|
|
||||||
fun main(
|
|
||||||
args: Array<String>,
|
|
||||||
) {
|
|
||||||
cli {
|
|
||||||
arguments(CONFIG)
|
|
||||||
|
|
||||||
execute {
|
|
||||||
val config by CONFIG
|
|
||||||
|
|
||||||
Config.get(config)
|
|
||||||
.run {
|
|
||||||
val domain by DOMAIN
|
|
||||||
val subdomains by SUBDOMAIN
|
|
||||||
val ipService by IP_SERVICE
|
|
||||||
|
|
||||||
val dnsService = when (name) {
|
|
||||||
PORKBUN -> {
|
|
||||||
val key by KEY
|
|
||||||
val secretkey by SECRET_KEY
|
|
||||||
|
|
||||||
Porkbun(key, secretkey)
|
|
||||||
}
|
|
||||||
|
|
||||||
else -> throw Exception()
|
|
||||||
}
|
|
||||||
|
|
||||||
dnsService.update(ipService, domain, subdomains)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
command(PORKBUN) {
|
|
||||||
arguments(
|
|
||||||
DOMAIN,
|
|
||||||
SUBDOMAIN,
|
|
||||||
IP_SERVICE,
|
|
||||||
KEY,
|
|
||||||
SECRET_KEY,
|
|
||||||
)
|
|
||||||
|
|
||||||
execute {
|
|
||||||
val domain by DOMAIN
|
|
||||||
val subdomains by SUBDOMAIN
|
|
||||||
val ipService by IP_SERVICE
|
|
||||||
|
|
||||||
val key by KEY
|
|
||||||
val secretkey by SECRET_KEY
|
|
||||||
val dnsService = Porkbun(key, secretkey)
|
|
||||||
|
|
||||||
dnsService.update(ipService, domain, subdomains)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}.run(args)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun Config.run(
|
|
||||||
block: Config.Service.() -> Unit,
|
|
||||||
) {
|
|
||||||
for (service in services) {
|
|
||||||
service.block()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun DnsService.update(
|
|
||||||
ipService: IpService,
|
|
||||||
domain: String,
|
|
||||||
subdomains: List<String>,
|
|
||||||
) {
|
|
||||||
val (ipv4, ipv6) = ipService.ip
|
|
||||||
|
|
||||||
val records = getRecords(domain, subdomains)
|
|
||||||
val aRecords = records
|
|
||||||
.filter { it.type == DnsRecord.Type.A }
|
|
||||||
val aaaaRecords = records
|
|
||||||
.filter { it.type == DnsRecord.Type.AAAA }
|
|
||||||
|
|
||||||
updateRecords(aRecords, ipv4)
|
|
||||||
updateRecords(aaaaRecords, ipv6)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,36 +0,0 @@
|
|||||||
package com.infendro.ddns.argument
|
|
||||||
|
|
||||||
import com.infendro.cli.argument.Argument
|
|
||||||
import com.infendro.cli.command.Command
|
|
||||||
import com.infendro.ddns.ip.IpService
|
|
||||||
import com.infendro.ddns.ip.ipify.Ipify
|
|
||||||
|
|
||||||
object IpServiceParser : Argument.Parser<IpService> {
|
|
||||||
override fun parse(
|
|
||||||
text: String?,
|
|
||||||
): IpService {
|
|
||||||
return when (text) {
|
|
||||||
IpService.IPIFY -> Ipify
|
|
||||||
else -> throw Exception()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class IpServiceOrDefaultArgument(
|
|
||||||
override val name: String,
|
|
||||||
) : Argument.SingleOrElse<IpService>() {
|
|
||||||
override val other: IpService
|
|
||||||
get() = IpService.DEFAULT
|
|
||||||
|
|
||||||
override val parser: Parser<IpService>
|
|
||||||
get() = IpServiceParser
|
|
||||||
}
|
|
||||||
|
|
||||||
fun ipService(
|
|
||||||
name: String,
|
|
||||||
) = IpServiceOrDefaultArgument(name)
|
|
||||||
|
|
||||||
fun Command.Builder.ipService(
|
|
||||||
name: String,
|
|
||||||
) = IpServiceOrDefaultArgument(name)
|
|
||||||
.also { argument(it) }
|
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package com.infendro.ddns.command
|
||||||
|
|
||||||
|
import com.infendro.cli.command.argument.argument
|
||||||
|
import com.infendro.cli.command.option.option
|
||||||
|
import com.infendro.ddns.ip.ipify.Ipify
|
||||||
|
import com.infendro.ddns.parameter.ipService
|
||||||
|
|
||||||
|
internal object Parameters {
|
||||||
|
val DOMAIN = argument.string("domain")
|
||||||
|
val SUBDOMAINS = argument.string("subdomains").variable(min = 1)
|
||||||
|
val IP_SERVICE = option.ipService("ip-service").orElse(Ipify)
|
||||||
|
}
|
||||||
9
src/commonMain/kotlin/com/infendro/ddns/command/ddns.kt
Normal file
9
src/commonMain/kotlin/com/infendro/ddns/command/ddns.kt
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
package com.infendro.ddns.command
|
||||||
|
|
||||||
|
import com.infendro.cli.command.command
|
||||||
|
|
||||||
|
val ddns = command("ddns") {
|
||||||
|
execute { help() }
|
||||||
|
+update
|
||||||
|
+porkbun
|
||||||
|
}
|
||||||
29
src/commonMain/kotlin/com/infendro/ddns/command/porkbun.kt
Normal file
29
src/commonMain/kotlin/com/infendro/ddns/command/porkbun.kt
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
package com.infendro.ddns.command
|
||||||
|
|
||||||
|
import com.infendro.cli.command.command
|
||||||
|
import com.infendro.cli.command.option.option
|
||||||
|
import com.infendro.ddns.command.Parameters.DOMAIN
|
||||||
|
import com.infendro.ddns.command.Parameters.IP_SERVICE
|
||||||
|
import com.infendro.ddns.command.Parameters.SUBDOMAINS
|
||||||
|
import com.infendro.ddns.dns.porkbun.Porkbun
|
||||||
|
|
||||||
|
val porkbun = command("porkbun") {
|
||||||
|
execute { help() }
|
||||||
|
|
||||||
|
+command("update") {
|
||||||
|
val key = +option.string("key")
|
||||||
|
val secretKey = +option.string("secret-key")
|
||||||
|
register(DOMAIN, SUBDOMAINS)
|
||||||
|
register(IP_SERVICE)
|
||||||
|
|
||||||
|
execute {
|
||||||
|
val key by key
|
||||||
|
val secretKey by secretKey
|
||||||
|
val domain by DOMAIN
|
||||||
|
val subdomains by SUBDOMAINS
|
||||||
|
val ipService by IP_SERVICE
|
||||||
|
|
||||||
|
Porkbun(key, secretKey).update(domain, subdomains, ipService)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
35
src/commonMain/kotlin/com/infendro/ddns/command/update.kt
Normal file
35
src/commonMain/kotlin/com/infendro/ddns/command/update.kt
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
package com.infendro.ddns.command
|
||||||
|
|
||||||
|
import com.infendro.cli.command.command
|
||||||
|
import com.infendro.cli.command.option.option
|
||||||
|
import com.infendro.ddns.config.Config
|
||||||
|
import com.infendro.ddns.ip.ipify.Ipify
|
||||||
|
import com.infendro.ddns.parameter.path
|
||||||
|
import kotlinx.io.buffered
|
||||||
|
import kotlinx.io.files.Path
|
||||||
|
import kotlinx.io.files.SystemFileSystem
|
||||||
|
import kotlinx.io.readString
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
|
|
||||||
|
val update = command("update") {
|
||||||
|
val config = +option.path("config").orElse(Path("/etc/ddns.conf"))
|
||||||
|
|
||||||
|
execute {
|
||||||
|
val config by config
|
||||||
|
|
||||||
|
val source = SystemFileSystem.source(config).buffered()
|
||||||
|
val text = source.readString()
|
||||||
|
|
||||||
|
val entries: List<Config.Entry> = Json.decodeFromString(text)
|
||||||
|
update(entries)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun update(entries: List<Config.Entry>) {
|
||||||
|
for (entry in entries) {
|
||||||
|
val domain = entry.domain
|
||||||
|
val subdomains = entry.subdomains
|
||||||
|
val ipService = entry.ipService ?: Ipify
|
||||||
|
entry.dnsService.update(domain, subdomains, ipService)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,128 +1,29 @@
|
|||||||
package com.infendro.ddns.config
|
package com.infendro.ddns.config
|
||||||
|
|
||||||
import com.infendro.cli.argument.Argument.*
|
import com.infendro.ddns.dns.DnsService
|
||||||
import com.infendro.ddns.config.Regex.ARGUMENT
|
import com.infendro.ddns.ip.IpService
|
||||||
import com.infendro.ddns.config.Regex.EMPTY_LINES
|
import kotlinx.serialization.SerialName
|
||||||
import kotlin.reflect.KProperty
|
import kotlinx.serialization.Serializable
|
||||||
import kotlinx.io.buffered
|
|
||||||
import kotlinx.io.files.Path
|
|
||||||
import kotlinx.io.files.SystemFileSystem
|
|
||||||
import kotlinx.io.readString
|
|
||||||
|
|
||||||
class Config(
|
interface Config {
|
||||||
val services: List<Service>,
|
@Serializable
|
||||||
) {
|
sealed class Entry {
|
||||||
class Service(
|
abstract val domain: String
|
||||||
val name: String,
|
abstract val subdomains: List<String>
|
||||||
val arguments: List<Argument>,
|
abstract val ipService: IpService?
|
||||||
) {
|
abstract val dnsService: DnsService
|
||||||
class Argument(
|
|
||||||
val name: String,
|
|
||||||
val value: String,
|
|
||||||
)
|
|
||||||
|
|
||||||
operator fun <T> Single<T>.getValue(
|
@Serializable
|
||||||
thisRef: Any?,
|
@SerialName("porkbun")
|
||||||
property: KProperty<*>,
|
class Porkbun(
|
||||||
): T {
|
val key: String,
|
||||||
return parser.parse(
|
val secretKey: String,
|
||||||
arguments
|
override val domain: String,
|
||||||
.find { it.name == name }!!
|
override val subdomains: List<String>,
|
||||||
.value
|
@Serializable(with = IpServiceSerializer::class)
|
||||||
)
|
override val ipService: IpService? = null,
|
||||||
}
|
) : Entry() {
|
||||||
|
override val dnsService: DnsService = com.infendro.ddns.dns.porkbun.Porkbun(key, secretKey)
|
||||||
operator fun <T> SingleOrElse<T>.getValue(
|
|
||||||
thisRef: Any?,
|
|
||||||
property: KProperty<*>,
|
|
||||||
): T {
|
|
||||||
return arguments
|
|
||||||
.find { it.name == name }
|
|
||||||
?.let { parser.parse(it.value) }
|
|
||||||
?: other
|
|
||||||
}
|
|
||||||
|
|
||||||
operator fun <T> SingleOrNull<T>.getValue(
|
|
||||||
thisRef: Any?,
|
|
||||||
property: KProperty<*>,
|
|
||||||
): T? {
|
|
||||||
return arguments
|
|
||||||
.find { it.name == name }
|
|
||||||
?.let { parser.parse(it.value) }
|
|
||||||
}
|
|
||||||
|
|
||||||
operator fun <T> Multiple<T>.getValue(
|
|
||||||
thisRef: Any?,
|
|
||||||
property: KProperty<*>,
|
|
||||||
): List<T> {
|
|
||||||
return arguments
|
|
||||||
.filter { it.name == name }
|
|
||||||
.map { parser.parse(it.value) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
fun get(
|
|
||||||
path: String,
|
|
||||||
): Config {
|
|
||||||
val path = Path(path)
|
|
||||||
val source = SystemFileSystem.source(path).buffered()
|
|
||||||
val text = source
|
|
||||||
.readString()
|
|
||||||
.process()
|
|
||||||
|
|
||||||
return parse(text)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun String.process(): String {
|
|
||||||
val builder = StringBuilder()
|
|
||||||
for (line in lines()) {
|
|
||||||
val comment = line.indexOf("""//""")
|
|
||||||
if (comment != -1) {
|
|
||||||
builder.appendLine(
|
|
||||||
line
|
|
||||||
.slice(0..<comment)
|
|
||||||
.trim()
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
builder.appendLine(
|
|
||||||
line.trim()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return builder.toString().trim()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun parse(
|
|
||||||
text: String,
|
|
||||||
): Config {
|
|
||||||
val services = text
|
|
||||||
.split(EMPTY_LINES)
|
|
||||||
.map { parseService(it) }
|
|
||||||
|
|
||||||
return Config(services)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun parseService(
|
|
||||||
text: String,
|
|
||||||
): Service {
|
|
||||||
val lines = text.lines()
|
|
||||||
val name = lines[0]
|
|
||||||
val arguments = lines
|
|
||||||
.drop(1)
|
|
||||||
.map { parseArgument(it) }
|
|
||||||
|
|
||||||
return Service(name, arguments)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun parseArgument(
|
|
||||||
text: String,
|
|
||||||
): Service.Argument {
|
|
||||||
val match = ARGUMENT.find(text)!!
|
|
||||||
val name = match.groups["name"]!!.value
|
|
||||||
val value = match.groups["value"]!!.value
|
|
||||||
|
|
||||||
return Service.Argument(name, value)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package com.infendro.ddns.config
|
||||||
|
|
||||||
|
import com.infendro.ddns.ip.IpService
|
||||||
|
import com.infendro.ddns.ip.ipify.Ipify
|
||||||
|
import kotlinx.serialization.KSerializer
|
||||||
|
import kotlinx.serialization.descriptors.PrimitiveKind
|
||||||
|
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
|
||||||
|
import kotlinx.serialization.descriptors.SerialDescriptor
|
||||||
|
import kotlinx.serialization.encoding.Decoder
|
||||||
|
import kotlinx.serialization.encoding.Encoder
|
||||||
|
|
||||||
|
object IpServiceSerializer : KSerializer<IpService> {
|
||||||
|
override val descriptor: SerialDescriptor =
|
||||||
|
PrimitiveSerialDescriptor("IpService", PrimitiveKind.STRING)
|
||||||
|
|
||||||
|
override fun serialize(encoder: Encoder, value: IpService) = throw NotImplementedError()
|
||||||
|
|
||||||
|
override fun deserialize(decoder: Decoder): IpService {
|
||||||
|
val value = decoder.decodeString()
|
||||||
|
return when (value) {
|
||||||
|
"ipify" -> Ipify
|
||||||
|
else -> throw Exception()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
package com.infendro.ddns.config
|
|
||||||
|
|
||||||
object Regex {
|
|
||||||
val EMPTY_LINES = Regex("""\n{2,}""")
|
|
||||||
val ARGUMENT = Regex("""(?<name>[a-z]+(?:-[a-z]+)*)(?:=(?<value>.*))?""")
|
|
||||||
}
|
|
||||||
@@ -1,29 +1,30 @@
|
|||||||
package com.infendro.ddns.dns
|
package com.infendro.ddns.dns
|
||||||
|
|
||||||
import com.infendro.ddns.dns.model.DnsRecord
|
import com.infendro.ddns.dns.model.DnsRecord
|
||||||
|
import com.infendro.ddns.ip.IpService
|
||||||
|
|
||||||
interface DnsService {
|
interface DnsService {
|
||||||
fun getRecords(
|
fun getRecords(domain: String, subdomains: List<String>): List<DnsRecord>
|
||||||
domain: String,
|
|
||||||
subdomains: List<String>,
|
|
||||||
): List<DnsRecord>
|
|
||||||
|
|
||||||
fun updateRecord(
|
fun updateRecord(record: DnsRecord, value: String)
|
||||||
record: DnsRecord,
|
|
||||||
value: String,
|
|
||||||
)
|
|
||||||
|
|
||||||
fun updateRecords(
|
fun updateRecords(records: List<DnsRecord>, value: String) {
|
||||||
records: List<DnsRecord>,
|
|
||||||
value: String,
|
|
||||||
) {
|
|
||||||
for (record in records) {
|
for (record in records) {
|
||||||
if (record.value == value) continue
|
if (record.value == value) continue
|
||||||
updateRecord(record, value)
|
updateRecord(record, value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
fun update(domain: String, subdomains: List<String>, ipService: IpService) {
|
||||||
const val PORKBUN = "porkbun"
|
val (ipv4, ipv6) = ipService.ip
|
||||||
|
|
||||||
|
val records = getRecords(domain, subdomains)
|
||||||
|
val aRecords = records
|
||||||
|
.filter { it.type == DnsRecord.Type.A }
|
||||||
|
val aaaaRecords = records
|
||||||
|
.filter { it.type == DnsRecord.Type.AAAA }
|
||||||
|
|
||||||
|
updateRecords(aRecords, ipv4)
|
||||||
|
updateRecords(aaaaRecords, ipv6)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,10 +13,9 @@ data class DnsRecord(
|
|||||||
val domain: String,
|
val domain: String,
|
||||||
) {
|
) {
|
||||||
val full: String
|
val full: String
|
||||||
get() = if (subdomain != null) {
|
get() = when {
|
||||||
"$subdomain.$domain"
|
subdomain != null -> "$subdomain.$domain"
|
||||||
} else {
|
else -> domain
|
||||||
domain
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,10 +15,7 @@ class Porkbun(
|
|||||||
val key: String,
|
val key: String,
|
||||||
val secretkey: String,
|
val secretkey: String,
|
||||||
) : DnsService {
|
) : DnsService {
|
||||||
override fun getRecords(
|
override fun getRecords(domain: String, subdomains: List<String>): List<DnsRecord> = runBlocking {
|
||||||
domain: String,
|
|
||||||
subdomains: List<String>,
|
|
||||||
): List<DnsRecord> = runBlocking {
|
|
||||||
val response = http.post("https://api.porkbun.com/api/json/v3/dns/retrieve/$domain") {
|
val response = http.post("https://api.porkbun.com/api/json/v3/dns/retrieve/$domain") {
|
||||||
val request = GetRecordsRequest(
|
val request = GetRecordsRequest(
|
||||||
apikey = key,
|
apikey = key,
|
||||||
@@ -50,10 +47,7 @@ class Porkbun(
|
|||||||
.filter { it.type in DnsRecord.Type.address && (it.domain.subdomain ?: "") in subdomains }
|
.filter { it.type in DnsRecord.Type.address && (it.domain.subdomain ?: "") in subdomains }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun updateRecord(
|
override fun updateRecord(record: DnsRecord, value: String): Unit = runBlocking {
|
||||||
record: DnsRecord,
|
|
||||||
value: String,
|
|
||||||
): Unit = runBlocking {
|
|
||||||
http.post("https://api.porkbun.com/api/json/v3/dns/edit/${record.domain.domain}/${record.id}") {
|
http.post("https://api.porkbun.com/api/json/v3/dns/edit/${record.domain.domain}/${record.id}") {
|
||||||
val request = UpdateRecordRequest(
|
val request = UpdateRecordRequest(
|
||||||
apikey = key,
|
apikey = key,
|
||||||
|
|||||||
@@ -1,16 +1,9 @@
|
|||||||
package com.infendro.ddns.ip
|
package com.infendro.ddns.ip
|
||||||
|
|
||||||
import com.infendro.ddns.ip.ipify.Ipify
|
|
||||||
|
|
||||||
interface IpService {
|
interface IpService {
|
||||||
val ipv4: String
|
val ipv4: String
|
||||||
val ipv6: String
|
val ipv6: String
|
||||||
|
|
||||||
val ip: Pair<String, String>
|
val ip: Pair<String, String>
|
||||||
get() = Pair(ipv4, ipv6)
|
get() = Pair(ipv4, ipv6)
|
||||||
|
|
||||||
companion object {
|
|
||||||
const val IPIFY = "ipify"
|
|
||||||
val DEFAULT = Ipify
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import kotlinx.coroutines.runBlocking
|
|||||||
object Ipify : IpService {
|
object Ipify : IpService {
|
||||||
override val ipv4: String
|
override val ipv4: String
|
||||||
get() = runBlocking {
|
get() = runBlocking {
|
||||||
val response = http.get("https://api.ipify.org?format=json")
|
val response = http.get("https://api4.ipify.org?format=json")
|
||||||
val body = response.body<GetIpResponse>()
|
val body = response.body<GetIpResponse>()
|
||||||
body.ip
|
body.ip
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package com.infendro.ddns.parameter
|
||||||
|
|
||||||
|
import com.infendro.cli.command.argument.ArgumentFactory
|
||||||
|
import com.infendro.cli.command.argument.argument
|
||||||
|
import com.infendro.cli.command.option.OptionFactory
|
||||||
|
import com.infendro.cli.command.option.option
|
||||||
|
import com.infendro.cli.parser.Parser
|
||||||
|
import com.infendro.ddns.ip.IpService
|
||||||
|
import com.infendro.ddns.ip.ipify.Ipify
|
||||||
|
|
||||||
|
object IpServiceParser : Parser<IpService>(IpService::class) {
|
||||||
|
override fun parse(text: String): Result<IpService> {
|
||||||
|
val service = when (text) {
|
||||||
|
"ipify" -> Ipify
|
||||||
|
else -> return failure(text)
|
||||||
|
}
|
||||||
|
return success(service)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun ArgumentFactory.ipService(name: String, description: String? = null) =
|
||||||
|
argument(IpServiceParser, name, description)
|
||||||
|
|
||||||
|
fun OptionFactory.ipService(vararg names: String, description: String? = null) =
|
||||||
|
option(IpServiceParser, *names, description = description)
|
||||||
19
src/commonMain/kotlin/com/infendro/ddns/parameter/Path.kt
Normal file
19
src/commonMain/kotlin/com/infendro/ddns/parameter/Path.kt
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
package com.infendro.ddns.parameter
|
||||||
|
|
||||||
|
import com.infendro.cli.command.argument.ArgumentFactory
|
||||||
|
import com.infendro.cli.command.argument.argument
|
||||||
|
import com.infendro.cli.command.option.OptionFactory
|
||||||
|
import com.infendro.cli.command.option.option
|
||||||
|
import com.infendro.cli.parser.Parser
|
||||||
|
import kotlinx.io.files.Path
|
||||||
|
|
||||||
|
object PathParser : Parser<Path>(Path::class) {
|
||||||
|
override fun parse(text: String) =
|
||||||
|
success(Path(text))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun ArgumentFactory.path(name: String, description: String? = null) =
|
||||||
|
argument(PathParser, name, description)
|
||||||
|
|
||||||
|
fun OptionFactory.path(vararg names: String, description: String? = null) =
|
||||||
|
option(PathParser, *names, description = description)
|
||||||
Reference in New Issue
Block a user