diff --git a/.gitignore b/.gitignore
index ba911f5..b255bd6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
# プロジェクトの除外パス
/.gradle/
-/build/
\ No newline at end of file
+/build/
+/DTempFiles/
\ No newline at end of file
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
index b589d56..fcb19bf 100644
--- a/.idea/compiler.xml
+++ b/.idea/compiler.xml
@@ -1,6 +1,6 @@
-
+
\ No newline at end of file
diff --git a/.idea/encodings.xml b/.idea/encodings.xml
new file mode 100644
index 0000000..b113d36
--- /dev/null
+++ b/.idea/encodings.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
index 88a580e..828e20b 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -7,7 +7,7 @@
-
+
\ No newline at end of file
diff --git a/.idea/remote-targets.xml b/.idea/remote-targets.xml
index 950c2b7..aff18d0 100644
--- a/.idea/remote-targets.xml
+++ b/.idea/remote-targets.xml
@@ -9,7 +9,7 @@
-
+
diff --git a/.idea/runConfigurations/.xml b/.idea/runConfigurations/.xml
new file mode 100644
index 0000000..0595098
--- /dev/null
+++ b/.idea/runConfigurations/.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/README.md b/README.md
index 63a00d5..0bd278f 100644
--- a/README.md
+++ b/README.md
@@ -2,6 +2,8 @@
Minecraftのサーバー公開に便利なツール
Minecraftのポート開放(UPnPを使用したNAT越え)ができます
+
+JDKの自動インストールもできる!
## 動作環境
Windows,Linux
@@ -23,4 +25,6 @@ Options:
- DDNSの設定
## Build
-`gradle jpackage`
\ No newline at end of file
+`./gradlew jpackage`
+
+`build/jpackage/{windows,linux}/`にインストーラーやJarが生成されます。
diff --git a/build.gradle.kts b/build.gradle.kts
index 6e83abc..3adb222 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -23,9 +23,11 @@ kotlin {
implementation("org.jetbrains.kotlinx:kotlinx-cli:0.3.4")
implementation("org.eclipse.jgit:org.eclipse.jgit:6.1.0.202203080745-r")
implementation("org.eclipse.jgit:org.eclipse.jgit.ssh.apache:6.1.0.202203080745-r")
- implementation ("net.mm2d.mmupnp:mmupnp:3.1.3")
+ implementation("net.mm2d.mmupnp:mmupnp:3.1.3")
+ implementation("com.squareup.okhttp3:okhttp:4.10.0")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.3")
+ implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.3")
}
}
}
@@ -37,31 +39,25 @@ tasks.withType {
application {
mainClass.set("MainKt")
}
-tasks.jar {
- manifest {
- attributes["Main-Class"] = "MainKt"
- }
- configurations["compileClasspath"].forEach { file: File ->
- from(zipTree(file.absoluteFile))
- }
- duplicatesStrategy = DuplicatesStrategy.INCLUDE
-}
-runtime {
- additive.set(true)
+runtime {
jpackage {
val currentOs = org.gradle.internal.os.OperatingSystem.current()
- // skipInstaller=true
-
- imageName="mstools"
- mainClass="MainKt"
- when{
- currentOs.isWindows->{
- imageOptions = listOf("--win-console")
+ imageName = "mstools"
+ mainClass = "MainKt"
+ installerOptions.add("--verbose")
+ when {
+ currentOs.isWindows -> {
+ resourceDir = file("$rootDir/res/windows")
+ imageOptions.add("--win-console")
+ outputDir = "jpackage/windows"
}
- currentOs.isLinux->{
+ currentOs.isLinux -> {
+ resourceDir = file("$rootDir/res/linux")
+ installerType = "deb"
+ outputDir = "jpackage/linux"
}
}
}
diff --git a/docs/ConfigFile.md b/docs/ConfigFile.md
new file mode 100644
index 0000000..9432d17
--- /dev/null
+++ b/docs/ConfigFile.md
@@ -0,0 +1,8 @@
+# 設定ファイルの書き方
+## 生成方法
+`mstools init`
+
+質問に答えながら設定できます。
+
+`-d`で質問を省略し、デフォルト設定のファイルを生成します。
+
diff --git a/How To Use.md b/docs/HowToUse.md
similarity index 98%
rename from How To Use.md
rename to docs/HowToUse.md
index 900d503..e6eed8c 100644
--- a/How To Use.md
+++ b/docs/HowToUse.md
@@ -3,7 +3,6 @@ Releaseにzipファイルがあるので自分のOSにあったものをダウ
JREが同梱されているのでJavaのインストールは不要です
# 使い方
-`cd bin`
`./mstools <引数> <オプション>`
とすることで使えます
diff --git a/docs/Initialize.md b/docs/Initialize.md
new file mode 100644
index 0000000..6cb09b1
--- /dev/null
+++ b/docs/Initialize.md
@@ -0,0 +1,9 @@
+# リポジトリの初期化(鯖管理者向け)
+生成した`mstools.config.json`には機密情報が含まれているので、`.gitignore`で除外しましょう。
+
+```gitignore
+mstools.config.json
+
+#オプション: 不必要なフォルダも別途除外
+./Logs
+```
\ No newline at end of file
diff --git a/docs/README.md b/docs/README.md
new file mode 100644
index 0000000..f418e41
--- /dev/null
+++ b/docs/README.md
@@ -0,0 +1,30 @@
+# どーきゅめーんと
+mstoolsの使い方を説明してます
+
+困ったらこのフォルダを漁りましょう。
+
+[基本的な使い方](HowToUse.md)
+
+[mstools.config.jsonの書き方](ConfigFile.md)
+
+[リポジトリの初期化方法(鯖管理者向け)](Initialize.md)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+---
+[~~いぬ~~](/dogs/README.md)
\ No newline at end of file
diff --git a/dogs/README.md b/dogs/README.md
new file mode 100644
index 0000000..1789f20
--- /dev/null
+++ b/dogs/README.md
@@ -0,0 +1,51 @@
+# イッヌたち
+🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶
+🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶
+🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶
+🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶
+🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶
+🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶
+🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶
+🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶
+🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶
+🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶
+🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶
+🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶
+🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶
+🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶
+🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶
+🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶
+🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶
+🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶
+🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶
+🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶
+🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶
+🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶
+🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶
+🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶
+🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶
+🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶
+🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶
+🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶
+🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶
+🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶
+🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶
+🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶
+🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶
+🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶
+🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶
+🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶
+🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶
+🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶
+🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶
+🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶
+🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶
+🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶
+
+DocsではなくDogsです
+
+騙されましたね!
+
+m9(^Д^)プギャー
+
+ドキュメントは[こちら](/docs)
\ No newline at end of file
diff --git a/res/linux/postinst b/res/linux/postinst
new file mode 100644
index 0000000..6d5f06e
--- /dev/null
+++ b/res/linux/postinst
@@ -0,0 +1,5 @@
+#!bin/sh
+
+echo /usr/bin/mstools にシンポジックリンクを作成します
+ln -s /opt/minecraft-server-tools/bin/mstools /usr/bin/mstools
+exit 0
diff --git a/res/linux/postrm b/res/linux/postrm
new file mode 100644
index 0000000..d2d3a77
--- /dev/null
+++ b/res/linux/postrm
@@ -0,0 +1,31 @@
+#!/bin/sh
+# postrm script for minecraft-server-tools
+#
+# see: dh_installdeb(1)
+
+set -e
+
+# summary of how this script can be called:
+# * `remove'
+# * `purge'
+# * `upgrade'
+# * `failed-upgrade'
+# * `abort-install'
+# * `abort-install'
+# * `abort-upgrade'
+# * `disappear'
+#
+# for details, see https://www.debian.org/doc/debian-policy/ or
+# the debian-policy package
+
+case "$1" in
+ purge|remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear)
+ ;;
+
+ *)
+ echo "postrm called with unknown argument \`$1'" >&2
+ exit 1
+ ;;
+esac
+rm /usr/bin/mstools
+exit 0
diff --git a/res/windows/main.wxs b/res/windows/main.wxs
new file mode 100644
index 0000000..1542d33
--- /dev/null
+++ b/res/windows/main.wxs
@@ -0,0 +1,129 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Not Installed
+ Not Installed
+ Not Installed
+ Not Installed
+
+ Not Installed
+
+
+ Not Installed
+
+
+ Not Installed
+
+
+
+ JP_UPGRADABLE_FOUND
+
+
+ JP_DOWNGRADABLE_FOUND
+
+
+
+
+
diff --git a/src/main/kotlin/API.kt b/src/main/kotlin/API.kt
new file mode 100644
index 0000000..e69de29
diff --git a/src/main/kotlin/BridgeServer.kt b/src/main/kotlin/BridgeServer.kt
new file mode 100644
index 0000000..f15f6e2
--- /dev/null
+++ b/src/main/kotlin/BridgeServer.kt
@@ -0,0 +1,89 @@
+import MSToolsProtocol.*
+import okhttp3.internal.isHealthy
+import java.io.BufferedReader
+import java.io.InputStream
+import java.io.OutputStream
+import java.io.PipedReader
+import java.io.PipedWriter
+import java.io.RandomAccessFile
+import java.net.ServerSocket
+import java.net.Socket
+
+//CAD!CAD!CAD!CAD!
+const val SOCKET_PORT = 0xCAD//3245
+
+//橋!
+class BridgeServer(
+ val serverSocket: ServerSocket,
+ val logFile: RandomAccessFile, val outputStream: OutputStream
+) : Thread() {
+ lateinit var socket: Socket
+ override fun run() {
+ println("Thread ${this.id}\n")
+ try {
+ socket = serverSocket.accept()
+ var sin = socket.getInputStream()
+ var sout = socket.getOutputStream()
+ while (!isInterrupted) {
+ if (sin.available() != 0) {
+ println("Recive")
+ val readByteArray = mutableListOf()
+ do {
+ val r = sin.read()
+ println(r)
+ if (r != DATA_END.ordinal) {
+ readByteArray.add(r.toByte())
+ }
+ } while (r != DATA_END.ordinal)
+ val msToolsProtocol = MSToolsProtocol.values()[readByteArray.first().toInt()]
+ val result = readByteArray.drop(1).toByteArray()
+ println("PROTOCOL:$msToolsProtocol")
+ println("RESULT:${result.decodeToString()}")
+ if (msToolsProtocol == GREETING) {//( `・∀・´)ノヨロシク
+ sout.write(logFileRead(0))
+ sout.write(DATA_END.ordinal)
+ sout.flush()
+ } else if (msToolsProtocol == EXECUTE) {
+ val p = logFile.length()
+ outputStream.write(result)
+ outputStream.write("\n".encodeToByteArray())
+ outputStream.flush()
+ println("---Wait!!!---")
+ sleep(1000)//おやすみ
+ println("---End Waiting!!!---")
+ sout.write(logFileRead(p))
+ sout.write(DATA_END.ordinal)
+ sout.flush()
+ }
+ }
+
+ if (!socket.isConnected) {
+ println("Closed")
+ socket = serverSocket.accept()
+ sin = socket.getInputStream()
+ sout = socket.getOutputStream()
+ }
+
+ }
+ } catch (e: Exception) {
+ e.printStackTrace()
+ } finally {
+ }
+ }
+
+ fun logFileRead(seek: Long): ByteArray {
+ var b: Byte
+ val a = mutableListOf()
+ logFile.seek(seek)
+ while (logFile.read().also { b = it.toByte() } != -1) {
+ a.add(b)
+ }
+ logFile.seek(logFile.length())
+ return a.toByteArray()
+ }
+
+ override fun interrupt() {
+ serverSocket.close()
+ super.interrupt()
+ }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/Config.kt b/src/main/kotlin/Config.kt
index 775d5ce..44cd230 100644
--- a/src/main/kotlin/Config.kt
+++ b/src/main/kotlin/Config.kt
@@ -1,34 +1,28 @@
-import java.net.Inet4Address
+import kotlinx.serialization.ExperimentalSerializationApi
+import kotlinx.serialization.json.Json
+import kotlinx.serialization.json.decodeFromStream
+import java.io.File
+val configFile = File("mstools.config.json")
+const val AUTO_IP = "auto"
+ val DEFAULT_ARGS=listOf("-Xmx2G","-Xms2G")
+
+@kotlinx.serialization.Serializable
data class Config(
- val gitRepo:String,
- val sshSecretKeyPath:String,
- val ipAddress: String="auto" ,//autoで自動判別
- val tcpPorts:Array,
- val udpPorts:Array
+ val serverDirectory: String = "./",
+ val gitRemoteRepo: String? = null,
+ val sshSecretKeyPath: String? = null,
+ val ddnsNowUser: String? = null,
+ val ddnsNowPassword: String? = null,
+ val ipAddress: String? = AUTO_IP,//AUTO_IPで自動判別
+ val tcpPorts: List = emptyList(),
+ val udpPorts: List = emptyList(),
+ val serverJar:String?=null,
+ val jvmArgs:List = DEFAULT_ARGS
) {
- //Auto Generated by いんてりじぇー
- override fun equals(other: Any?): Boolean {
- if (this === other) return true
- if (javaClass != other?.javaClass) return false
-
- other as Config
-
- if (gitRepo != other.gitRepo) return false
- if (sshSecretKeyPath != other.sshSecretKeyPath) return false
- if (ipAddress != other.ipAddress) return false
- if (!tcpPorts.contentEquals(other.tcpPorts)) return false
- if (!udpPorts.contentEquals(other.udpPorts)) return false
-
- return true
- }
-
- override fun hashCode(): Int {
- var result = gitRepo.hashCode()
- result = 31 * result + sshSecretKeyPath.hashCode()
- result = 31 * result + ipAddress.hashCode()
- result = 31 * result + tcpPorts.contentHashCode()
- result = 31 * result + udpPorts.contentHashCode()
- return result
+ companion object {
+ @OptIn(ExperimentalSerializationApi::class)
+ fun readConfig(): Config = Json.decodeFromStream(serializer(), configFile.inputStream())
}
}
+
diff --git a/src/main/kotlin/Connect.kt b/src/main/kotlin/Connect.kt
new file mode 100644
index 0000000..0f3df45
--- /dev/null
+++ b/src/main/kotlin/Connect.kt
@@ -0,0 +1,64 @@
+import MSToolsProtocol.*
+import kotlinx.cli.*
+import java.io.OutputStream
+import java.net.Socket
+
+
+//const val GREETING="MINECRAFT_SERVER_TOOLS_HANDSHAKE"
+//最初のデータ1Byteは以下の列挙型を使用して通信種別を表す。
+enum class MSToolsProtocol {
+ DATA_END,
+
+ GREETING,
+ EXECUTE,
+}
+
+@OptIn(ExperimentalCli::class)
+//え?コネクト?気持ち良すぎだろ!
+class Connect : Subcommand("connect", "Minecraft ServerにSocket通信します") {
+ private val server by option(ArgType.String, "server", "s").default("127.0.0.1")
+ private val commandArgs by argument(ArgType.String, "command").vararg().optional()
+
+ //private val oneShot by option(ArgType.Boolean,"once","o","一発限りのコマンドを実行します").default(false)
+ override fun execute() {
+ val command = commandArgs.joinToString(" ")
+ val socket = Socket(server, SOCKET_PORT)
+ val inputStream = socket.getInputStream()
+ val outputStream = socket.getOutputStream()
+ //はじめましてしましょうねー
+ outputStream.dataWrite(GREETING)
+ val readByteArray = mutableListOf()
+ do {
+ val i = inputStream.read()
+ if (i != DATA_END.ordinal) {
+ readByteArray.add(i.toByte())
+ }
+ } while (i != DATA_END.ordinal)
+ println(readByteArray.toByteArray().decodeToString())
+
+ if (commandArgs.isNotEmpty()) {
+ println("Run one shot command")
+ outputStream.dataWrite(EXECUTE,command.encodeToByteArray())
+ readByteArray.clear()
+ do {
+ val i = inputStream.read()
+ if (i != DATA_END.ordinal) {
+ readByteArray.add(i.toByte())
+ }
+ } while (i != DATA_END.ordinal)
+ println(readByteArray.toByteArray().decodeToString())
+ }
+ inputStream.close()
+ outputStream.close()
+ socket.close()
+ }
+
+ private fun OutputStream.dataWrite(type: MSToolsProtocol, data: ByteArray? = null) {
+ write(type.ordinal)
+ if (data != null) {
+ write(data)
+ }
+ write(DATA_END.ordinal)
+ flush()
+ }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/Main.kt b/src/main/kotlin/Main.kt
index 97f3631..deff661 100644
--- a/src/main/kotlin/Main.kt
+++ b/src/main/kotlin/Main.kt
@@ -1,286 +1,196 @@
-import NetworkMode.*
import kotlinx.cli.*
-import net.mm2d.log.Logger
-import net.mm2d.upnp.ControlPoint.DiscoveryListener
-import net.mm2d.upnp.ControlPointFactory
-import net.mm2d.upnp.Device
-import net.mm2d.upnp.Protocol
-import net.mm2d.upnp.Service
-import org.eclipse.jgit.api.Git
-import org.eclipse.jgit.lib.Constants
-import org.eclipse.jgit.lib.Repository
-import org.eclipse.jgit.storage.file.FileRepositoryBuilder
-import org.eclipse.jgit.transport.SshSessionFactory
-import org.eclipse.jgit.transport.SshTransport
-import org.eclipse.jgit.transport.sshd.SshdSessionFactory
-import java.io.File
-import java.io.IOException
-import java.net.InetAddress
-import java.nio.file.Files
-import java.nio.file.Path
-import java.nio.file.Paths
+import kotlinx.serialization.json.Json
+import okio.source
+import java.io.RandomAccessFile
+import java.lang.System.`in`
+import java.net.ServerSocket
+import java.util.concurrent.ExecutorService
+import java.util.concurrent.Executors
+import kotlin.concurrent.thread
+import kotlin.io.path.Path
+import kotlin.io.path.absolutePathString
+
+
+//じぇーそんのフォーマット
+private val json = Json {
+ prettyPrint = true
+ encodeDefaults = true
+}
+
+fun prompt(question: String): String? {
+ print(question)
+ return readlnOrNull()?.ifEmpty { null }
+}
@ExperimentalCli
fun main(args: Array) {
//ぼくのかんがえたさいきょうのなまえ
- println("Super Ultimate Max Large Big Long Ultra Powerful Useful Helpful Minecraft Server Tools Version Perfect Stable Created by @naotikikt")
+ println(
+ "Super Turbo Intelligent Ultimate Dynamite Max Large Big Long Ultra Powerful Useful Helpful Better Best Good God Delicious Beautiful Most Much Many Strong String Extend Infinity Legend Plus Power Fire Final Protected Defender Minecraft Server Tools Version Really Perfect Stable Long Term Support Professional Enterprise Edition"
+ )
val parser = ArgParser("mstools")
+ val isInitialized = configFile.exists()
+ val config = if (isInitialized) Config.readConfig() else null
class Debug : Subcommand("debug", "デバッグ用") {
- override fun execute() {
-
- }
-
- }
-
- class Sync : Subcommand("sync", "ワールドを同期するます") {
- val repoPath by option(ArgType.String, "repo", "r", "リポジトリの同期先を指定するます").default(Paths.get("").toString())
- val sshKeyPath by option(ArgType.String, "key-path", description = "SSH鍵のパスを指定します。")
- var result: Int = 0
+ val serverFile by argument(ArgType.String, "ServerFile", "マイクラサーバーのJarファイルを指定しましょう").optional()
+ .default(config?.serverJar.orEmpty())
override fun execute() {
- val builder = FileRepositoryBuilder()
- val repository: Repository =
- builder.setGitDir(File(repoPath + Constants.DOT_GIT)).readEnvironment().findGitDir().build()
-
- val git = Git(repository)
-
- git.push().setTransportConfigCallback {
- if (it is SshTransport) {
- it.sshSessionFactory = sshSessionFactory
+ if (serverFile.isEmpty()) {
+ throw IllegalArgumentException("サーバーファイルを指定しましょう")
+ }
+ val path = Path(serverFile).absolutePathString()
+ val p = ProcessBuilder("java", "-jar", path, "-nogui")
+ println("Run: ${p.command().joinToString(" ")}")
+ p.environment()
+ p.redirectInput(ProcessBuilder.Redirect.PIPE)
+ p.redirectOutput(ProcessBuilder.Redirect.PIPE)
+
+
+ val proccess = p.start()
+ val logFile = RandomAccessFile("MsToolsLog-${System.currentTimeMillis()}", "rwd")
+
+
+ /*TODO inputStreamを奪い合いしてる
+ * TODO inputStreamをコピーする?もしくは2つそれぞれつくる
+ * TODO BridgeServerにすべてバイパスさせる。---Agree!
+ * */
+ val t = BridgeServer(ServerSocket(SOCKET_PORT).apply {
+ reuseAddress = true
+ }, logFile, proccess.outputStream)
+ t.start()
+ val a = object : Thread() {
+ val consoleRead = `in`.buffered()
+ val out = proccess.outputStream.bufferedWriter()
+ override fun run() {
+ println("Started")
+ while (!isInterrupted) {
+ if (consoleRead.available() > 0) {
+ val bytes = mutableListOf()
+ var byte: Byte = 0
+ while (!bytes.toByteArray().decodeToString()
+ .contains("\r\n|[\n\r\u2028\u2029\u0085]".toRegex()) && consoleRead.read()
+ .also { byte = it.toByte() } != -1
+ ) {
+ bytes.add(byte)
+ }
+ val line = bytes.toByteArray().decodeToString()
+ out.write(line)
+ out.flush()
+ }
+ }
+ }
+ override fun interrupt() {
+ out.close()
+ super.interrupt()
}
- }.call()
+ }
+ a.start()
+ proccess.onExit().thenApply {
+ println("Clean UP")
+ a.interrupt()
+ t.interrupt()
+ proccess.outputStream.close()
+ proccess.inputStream.close()
+ logFile.close()
+ println("END")
+ }
+
+ val bufferedReader = proccess.inputStream.bufferedReader()
+ var line:String
+ while (bufferedReader.readLine().also { line =it}!=null){
+ println(line)
+ logFile.write((line+"\n").encodeToByteArray())
+ }
}
}
- class Network : Subcommand("network", "ネットワークの設定をするます") {
-
- val mode by argument(ArgType.Choice(), "mode")
-
-
- var ipv4 by option(ArgType.String, "ipv4", "i", "ぶち開けるipv4アドレスを指定します")
+ class Initialize : Subcommand("init", "設定ファイルをプロンプト形式で生成して初期化します") {
+ val default by option(ArgType.Boolean, "default", "d", "質問なしで設定ファイルを生成します").default(false)
override fun execute() {
- when {
- (mode == Open) || (mode == Close) -> {
- val supportedDevices = mutableListOf()
- val cp = ControlPointFactory.create(Protocol.IP_V4_ONLY).also { cp ->
- cp.addDiscoveryListener(object : DiscoveryListener {
- fun getService(device: Device) = device.findDeviceByTypeRecursively(
- "urn:schemas-upnp-org:device:WANConnectionDevice:1"
- )?.run {
- findServiceByType("urn:schemas-upnp-org:service:WANPPPConnection:1")
- ?: findServiceByType("urn:schemas-upnp-org:service:WANIPConnection:1")
- }
-
- override fun onDiscover(device: Device) {
-
- getService(device)?.let {
- if (it.findAction("AddPortMapping") != null &&
- it.findAction("DeletePortMapping") != null
- ) {
- //NATいけるデバイス
- println("発見:${device.udn}")
- supportedDevices.add(it)
- }
- }
- }
-
- override fun onLost(device: Device) {
- println("切断:${device.udn}")
- supportedDevices.remove(getService(device))
- }
-
- })
- cp.initialize()
- cp.start()
+ if (isInitialized) {
+ println(
+ """
+ すでに初期化されています。
+ ${configFile.absolutePath}を削除するか直接中身を書き換えてください
+ """.trimIndent()
+ )
+ } else {
+ println(
+ """
+ 設定ファイルを生成します
+ ${configFile.absolutePath}が生成されます
+ """.trimIndent()
+ )
+ val outFile = configFile.outputStream()
+ val conf = if (!default) {
+ //Git設定
+ val serverDirectory = prompt("同期するディレクトリの(絶対・相対)パスを入力(設定しない場合はそのままEnter):") ?: "./"
+ val gitRemoteRepo = prompt("GitリポジトリURLを入力 (設定しない場合はそのままEnter):")
+ val sshKeyPath = if (gitRemoteRepo != null) {
+ prompt("管理者から渡されたSSHキーを置いた(絶対・相対)パスを入力 (設定しない場合はそのままEnter):")
+ } else null
+ //DDNS now設定
+ val ddnsName = prompt("DDNS nowユーザー名を入力 (設定しない場合はそのままEnter):")
+ val ddnsPassword = if (ddnsName != null) {
+ prompt("DDNS nowパスワード(APIトークン)を入力 (設定しない場合はそのままEnter):")
+ } else null
+ val ipAddress = prompt("サーバーのIPv4アドレスを入力(デフォルトでは自動で設定されます):") ?: AUTO_IP
+ println("TCPのポート番号を指定してください (Enterで変更せずに続行)")
+ print("複数開ける場合は\",\"で区切ってください (例:80,8080) :")
+ val tcp = readlnOrNull()?.split(",")?.map { it.toIntOrNull() }?.filterNotNull().orEmpty()
+ if (tcp.isEmpty()) {
+ println("TCPポートを設定しません")
+ } else {
+ println("次のポートが設定されます =>${tcp.joinToString(",")}")
}
- fun getPorts(): Pair, List>? {
- println("TCPのポート番号を指定してください (Enterで開けずに続行)")
- print("複数開ける場合は\",\"で区切ってください (例:80,8080) :")
- val t = readlnOrNull()?.split(",")?.map { it.toIntOrNull() }?.filterNotNull().orEmpty()
- if (t.isEmpty()) {
- println("TCPポートを設定しません")
- } else {
- println("次のポートが設定されます =>${t.joinToString(",")}")
- }
-
- print("UDPのポート番号を指定してください (Enterで開けずに続行):")
- val u = readlnOrNull()?.split(",")?.map { it.toIntOrNull() }?.filterNotNull().orEmpty()
- if (u.isEmpty()) {
- println("UDPポートを設定しません")
- } else {
- println("次のポートが設定されます =>${u.joinToString(",")}")
- }
- if (t.isEmpty() && u.isEmpty()) {
- println("何しに来たの????????帰れ")//辛辣
- return null
- }
- return t to u
+ print("UDPのポート番号を指定してください (Enterで変更せずに続行):")
+ val udp = readlnOrNull()?.split(",")?.map { it.toIntOrNull() }?.filterNotNull().orEmpty()
+ if (udp.isEmpty()) {
+ println("UDPポートを設定しません")
+ } else {
+ println("次のポートが設定されます =>${udp.joinToString(",")}")
}
- when (mode) {
- Open -> {
- ipv4 = ipv4 ?: try {
- InetAddress.getLocalHost().hostAddress
- } catch (e: Exception) {
- println("What The Fuck !?!?")
- throw e
- }
- println("IPv4アドレス:$ipv4")
- print("Enterで続行 変更する場合は右にIPv4アドレスを入力:")
- ipv4 = readlnOrNull()?.ifEmpty { null } ?: ipv4
- println("IPv4アドレス $ipv4 で続行します")
- val (TCPPorts, UDPPorts) = getPorts() ?: run {
- cp.stop()
- cp.terminate()
- return
- }
-
- println("UPnPのNAT設定してぶち開けるます")
- Logger.setLogLevel(Logger.VERBOSE)
- //Logger.setSender(Senders.create())
-
- println("対応デバイスを検索中")
- cp.search("urn:schemas-upnp-org:service:WANPPPConnection:1")
- while (supportedDevices.isEmpty()) {
- print("")
- }
- println("対応デバイスが見つかりました")
- println("デバイス:${supportedDevices.first().device.ipAddress}のNATを設定します")
- supportedDevices.first().findAction("AddPortMapping")!!.also { action ->
- println("Action:AddPortMapping")
- TCPPorts.forEach {
- println("TCP Open:$it")
- println(
- action.invokeSync(
- mapOf(
- "NewExternalPort" to it.toString(),
- "NewInternalPort" to it.toString(),
- "NewEnabled" to "1",
- "NewPortMappingDescription" to "*TEST* Minecraft Server Tools",
- "NewProtocol" to "TCP",//UDP
- "NewLeaseDuration" to "0",//seconds
- "NewInternalClient" to ipv4
- )
- )
- )
- }
- UDPPorts.forEach {
- println("UDP Open:$it")
- println(
- action.invokeSync(
- mapOf(
- "NewExternalPort" to it.toString(),
- "NewInternalPort" to it.toString(),
- "NewEnabled" to "1",
- "NewPortMappingDescription" to "*TEST* Minecraft Server Tools",
- "NewProtocol" to "UDP",//UDP
- "NewLeaseDuration" to "0",//seconds
- "NewInternalClient" to ipv4
- )
- )
- )
- }
-
- }
- }
- Close -> {
- println("閉じます")
- val (TCPPorts, UDPPorts) = getPorts() ?: run {
- cp.stop()
- cp.terminate()
- return
- }
- println("対応デバイスを検索中")
- cp.search("urn:schemas-upnp-org:service:WANPPPConnection:1")
- while (supportedDevices.isEmpty()) {
- print("")
- }
- println("対応デバイスが見つかりました")
- println("デバイス:${supportedDevices.first().device.ipAddress}のNATを設定します")
- supportedDevices.first().findAction("DeletePortMapping")!!.also { action ->
- println("Action:DeletePortMapping")
- TCPPorts.forEach {
- println("TCP Close:$it")
- println(
- action.invokeSync(
- mapOf(
- "NewExternalPort" to it.toString(),
- "NewProtocol" to "TCP",//UDP
- )
- )
- )
- }
- UDPPorts.forEach {
- println("UDP Close:$it")
- println(
- action.invokeSync(
- mapOf(
- "NewExternalPort" to it.toString(),
- "NewProtocol" to "UDP",//UDP
- )
- )
- )
- }
-
- }
- }
- else -> {}
+ if (tcp.isEmpty() && udp.isEmpty()) {
+ println("なにも設定されせん")
}
- println("Clean Up")
- cp.stop()
- cp.terminate()
- }
- mode == DDNS -> TODO()
- mode == Check -> TODO()
+
+ val jarFile = prompt("マイクラサーバーのJARのパスを入力:")
+ val jvmArgs = prompt("サーバー起動時のJVM引数を入力「,」区切り(デフォルトでは$DEFAULT_ARGS):")?.split(",") ?: DEFAULT_ARGS
+
+ Config(
+ serverDirectory,
+ gitRemoteRepo,
+ sshKeyPath,
+ ddnsName,
+ ddnsPassword,
+ ipAddress,
+ tcp,
+ udp,
+ jarFile,
+ jvmArgs,
+ )
+
+ } else Config()
+ outFile.write(json.encodeToString(Config.serializer(), conf).encodeToByteArray())
+ outFile.close()
}
- return
+ println("設定ファイルの詳しい書き方は https://github.com/NITKC22s/minecraft-server-tools/tree/master/docs/ConfigFile.md を見てください")
}
+
}
- val sync = Sync()
+
+ val sync = Sync(config)
val debug = Debug()
- val network = Network()
- parser.subcommands(sync, debug, network)
+ val network = Network(config)
+ val init = Initialize()
+ val connect = Connect()
+ parser.subcommands(sync, debug, network, init, connect)
parser.parse(args)
return
}
-var sshSessionFactory: SshSessionFactory =
- object : SshdSessionFactory() {
- val SSH_DIR: Path = Path.of("")/* TODO(Super Max SSH Path) */
-
- private var privateKeyFile: Path? = null
- private var sshKey: ByteArray = byteArrayOf()
-
- fun CustomSshSessionFactory(sshKey: ByteArray) {
- this.sshKey = sshKey
- privateKeyFile = Path.of("mstools", SSH_DIR.toString())
- }
-
- override fun getSshDirectory(): File? {
- return try {
- Files.createDirectories(SSH_DIR).toFile()
- } catch (e: IOException) {
- e.printStackTrace()
- null
- }
- }
-
- override fun getDefaultIdentities(sshDir: File?): List? {
- try {
- Files.write(privateKeyFile, sshKey)
- return listOf(privateKeyFile)
- } catch (e: IOException) {
- e.printStackTrace()
- }
- return emptyList()
- }
- }
-enum class NetworkMode {
- Open,
- Close,
- DDNS,
- Check,
-}
\ No newline at end of file
diff --git a/src/main/kotlin/Network.kt b/src/main/kotlin/Network.kt
new file mode 100644
index 0000000..c32ca9e
--- /dev/null
+++ b/src/main/kotlin/Network.kt
@@ -0,0 +1,339 @@
+import NetworkMode.*
+import kotlinx.cli.*
+import net.mm2d.log.Logger
+import net.mm2d.upnp.*
+import okhttp3.OkHttpClient
+import okhttp3.Request
+import okio.IOException
+import java.io.InputStream
+import java.net.InetAddress
+
+enum class NetworkMode {
+ Open,
+ Close,
+ DDNS,
+ Check,
+}
+
+
+@ExperimentalCli
+class Network(val config: Config?) : Subcommand("network", "ネットワークの設定をするこまーんど") {
+
+ val mode by argument(ArgType.Choice(), "mode", "")
+
+
+ var ipv4 by option(ArgType.String, "ipv4", "i", "ぶち開けるipv4アドレスを指定します").default(config?.ipAddress.orEmpty())
+
+ var tcpPorts by option(ArgType.Int, "tcp", "t", "ぶち開けるTCPアドレスを指定 (','区切り)").delimiter(",")
+ var udpPorts by option(ArgType.Int, "udp", "u", "ぶち開けるUDPアドレスを指定 (','区切り)").delimiter(",")
+
+
+ var ddnsNowUser by option(ArgType.String, "dnuser", "n", "DDNS now ユーザー名").default(config?.ddnsNowUser.orEmpty())
+ var ddnsNowPassword by option(
+ ArgType.String,
+ "dnpass",
+ "p",
+ "DDNS now パスワード"
+ ).default(config?.ddnsNowPassword.orEmpty())
+
+
+ val ultimateCheck by option(ArgType.Boolean, "ultimate-check", "C", "サポートされていないデバイスも出力します。").default(false)
+
+ override fun execute() {
+ when {
+ (mode == Open) || (mode == Close) -> {
+ val supportedDevices = mutableListOf()
+ val cp = ControlPointFactory.create(Protocol.IP_V4_ONLY).also { cp ->
+ cp.addDiscoveryListener(object : ControlPoint.DiscoveryListener {
+ fun getService(device: Device) = device.findDeviceByTypeRecursively(
+ "urn:schemas-upnp-org:device:WANConnectionDevice:1"
+ )?.run {
+ findServiceByType("urn:schemas-upnp-org:service:WANPPPConnection:1")
+ ?: findServiceByType("urn:schemas-upnp-org:service:WANIPConnection:1")
+ }
+
+ override fun onDiscover(device: Device) {
+
+ getService(device)?.let {
+ if (it.findAction("AddPortMapping") != null &&
+ it.findAction("DeletePortMapping") != null
+ ) {
+ //NATいけるデバイス
+ println("発見:${device.udn}")
+ supportedDevices.add(it)
+ }
+ }
+ }
+
+ override fun onLost(device: Device) {
+ println("切断:${device.udn}")
+ supportedDevices.remove(getService(device))
+ }
+
+ })
+ cp.initialize()
+ cp.start()
+ }
+
+
+ when (mode) {
+ Open -> {
+ ipv4 = if (ipv4 == AUTO_IP) {
+ try {
+ InetAddress.getLocalHost().hostAddress
+ } catch (e: Exception) {
+ println("What The Fuck !?!?")
+ throw e
+ }
+ } else ipv4
+
+ if (ipv4.isBlank()) {
+
+ cp.stop()
+ cp.terminate()
+ throw IllegalArgumentException("IPアドレスが不正です")
+ }
+ println("IPv4アドレス $ipv4 で続行します")
+ if (tcpPorts.isEmpty() && udpPorts.isEmpty()) {
+ tcpPorts = config?.tcpPorts.orEmpty()
+ udpPorts = config?.udpPorts.orEmpty()
+ if (tcpPorts.isEmpty() && udpPorts.isEmpty()) {
+ cp.stop()
+ cp.terminate()
+ throw IllegalArgumentException("ポート指定しやがれ")
+ }
+ }
+
+
+ println("UPnPのNAT設定してぶち開けるます")
+ Logger.setLogLevel(Logger.VERBOSE)
+ //Logger.setSender(Senders.create())
+
+ println("対応デバイスを検索中")
+
+ cp.search("urn:schemas-upnp-org:service:WANPPPConnection:1")
+ while (supportedDevices.isEmpty()) {
+ print("")
+ }
+ println("対応デバイスが見つかりました")
+ println("デバイス:${supportedDevices.first().device.ipAddress}のNATを設定します")
+ supportedDevices.first().findAction("AddPortMapping")!!.also { action ->
+ println("Action:AddPortMapping")
+ try {
+ tcpPorts.forEach {
+ println("TCP Open:$it")
+ println(
+ action.invokeSync(
+ mapOf(
+ "NewExternalPort" to it.toString(),
+ "NewInternalPort" to it.toString(),
+ "NewEnabled" to "1",
+ "NewPortMappingDescription" to "*TEST* Minecraft Server Tools",
+ "NewProtocol" to "TCP",//UDP
+ "NewLeaseDuration" to "0",//seconds
+ "NewInternalClient" to ipv4
+ )
+ )
+ )
+ }
+ udpPorts.forEach {
+ println("UDP Open:$it")
+ println(
+ action.invokeSync(
+ mapOf(
+ "NewExternalPort" to it.toString(),
+ "NewInternalPort" to it.toString(),
+ "NewEnabled" to "1",
+ "NewPortMappingDescription" to "*TEST* Minecraft Server Tools",
+ "NewProtocol" to "UDP",//UDP
+ "NewLeaseDuration" to "0",//seconds
+ "NewInternalClient" to ipv4
+ )
+ )
+ )
+ }
+ } catch (e: IOException) {
+ println(
+ """
+ ポートがすでに別のIPで開けられている可能性があります。
+ mstools network closeを試して見ましょう
+ """.trimIndent()
+ )
+ throw e;
+ } catch (e: Exception) {
+ throw e
+ }
+
+ }
+ }
+ Close -> {
+ println("閉じます")
+ if (tcpPorts.isEmpty() && udpPorts.isEmpty()) {
+ tcpPorts = config?.tcpPorts.orEmpty()
+ udpPorts = config?.udpPorts.orEmpty()
+ if (tcpPorts.isEmpty() && udpPorts.isEmpty()) {
+ cp.stop()
+ cp.terminate()
+ throw IllegalArgumentException("ポート指定しやがれ")
+ }
+ }
+ println("対応デバイスを検索中")
+ cp.search("urn:schemas-upnp-org:service:WANPPPConnection:1")
+ while (supportedDevices.isEmpty()) {
+ print("")
+ }
+ println("対応デバイスが見つかりました")
+ println("デバイス:${supportedDevices.first().device.ipAddress}のNATを設定します")
+ supportedDevices.first().findAction("DeletePortMapping")!!.also { action ->
+ println("Action:DeletePortMapping")
+ tcpPorts.forEach {
+ println("TCP Close:$it")
+ println(
+ action.invokeSync(
+ mapOf(
+ "NewExternalPort" to it.toString(),
+ "NewProtocol" to "TCP",//UDP
+ )
+ )
+ )
+ }
+ udpPorts.forEach {
+ println("UDP Close:$it")
+ println(
+ action.invokeSync(
+ mapOf(
+ "NewExternalPort" to it.toString(),
+ "NewProtocol" to "UDP",//UDP
+ )
+ )
+ )
+ }
+
+ }
+ }
+
+ else -> {}
+ }
+ println("Clean Up")
+ cp.stop()
+ cp.terminate()
+ }
+ mode == Check -> {
+ if (ultimateCheck) println("Ultimate Check")
+
+ val supportedDevices = mutableListOf()
+ val listener=object : ControlPoint.DiscoveryListener {
+ fun getService(device: Device) = device.findDeviceByTypeRecursively(
+ "urn:schemas-upnp-org:device:WANConnectionDevice:1"
+ )?.run {
+ findServiceByType("urn:schemas-upnp-org:service:WANPPPConnection:1")
+ ?: findServiceByType("urn:schemas-upnp-org:service:WANIPConnection:1")
+ }
+
+ override fun onDiscover(device: Device) {
+ if (ultimateCheck) {
+ supportedDevices.add(device)
+ return
+ }
+
+ getService(device)?.let {
+ if (it.findAction("AddPortMapping") != null &&
+ it.findAction("DeletePortMapping") != null
+ ) {
+ //NATいけるデバイス
+ println("発見:${device.udn}")
+ supportedDevices.add(device)
+ }
+ }
+ }
+
+ override fun onLost(device: Device) {
+ println("切断:${device.udn}")
+ supportedDevices.remove(device)
+ }
+
+ }
+ val cp = ControlPointFactory.create(Protocol.IP_V4_ONLY).also { cp ->
+ cp.addDiscoveryListener(listener)
+ cp.initialize()
+ cp.start()
+ }
+ println("""
+ ネットワーク環境のチェックをします。
+ exitで終了
+ """.trimIndent())
+ // cp.search("urn:schemas-upnp-org:service:WANIPConnection:1")
+ if (ultimateCheck){
+ cp.search()
+ }else{
+
+ cp.search("urn:schemas-upnp-org:service:WANPPPConnection:1")
+ }
+
+ val inputStream=System.`in`.bufferedReader()
+
+ while (!inputStream.ready()||(inputStream.readLine()!="exit")) {
+
+ while (supportedDevices.isNotEmpty()) {
+ val device = supportedDevices.first()
+
+ device.apply {
+ println(
+ """
+ デバイスが見つかりました
+ デバイス情報
+ IP:$ipAddress
+ UDN:$udn
+ URL:$baseUrl
+ UPC:$upc
+ Type:$deviceType
+ Location:$location
+ Services:${serviceList.map { it.serviceType }}
+ ModelName:$modelName
+ Desc:$description
+ """.trimIndent()
+ )
+ }
+ supportedDevices.remove(device)
+ }
+ print("")
+ }
+ println("Clean Up - キレイキレイ (Wait a minute)")
+ cp.removeDiscoveryListener(listener)
+ cp.clearDeviceList()
+ cp.stop()
+ cp.terminate()
+ return
+ }
+ mode == DDNS -> {//Dynamicで動的でDNSなドメインネームサーバー
+ println("D!D!N!S!")
+ if (ddnsNowUser.isEmpty() || ddnsNowPassword.isEmpty())
+ throw IllegalArgumentException("ユーザー名かパスワードを指定しましょう")
+ val reqURL = "https://f5.si/update.php?domain=${ddnsNowUser}&password=${ddnsNowPassword}"
+ println("Requesting:$reqURL")
+ val client = OkHttpClient()
+
+ val request = Request.Builder()
+ .url(reqURL)
+ .build()
+
+ val r = try {
+ val response = client.newCall(request).execute()
+ response.body?.string()
+ } catch (e: IOException) {
+ throw e
+ }
+ println(r)
+ if (r == null || r.contains("ERROR")) {
+ println("エラーが発生しました。\nユーザー名やパスワードを確認しやがれください")
+ } else if (r.contains("OK")) {
+ println("正常に更新しました。")
+ }
+
+
+ }
+
+ }
+ return
+ }
+}
diff --git a/src/main/kotlin/Sync.kt b/src/main/kotlin/Sync.kt
new file mode 100644
index 0000000..305be08
--- /dev/null
+++ b/src/main/kotlin/Sync.kt
@@ -0,0 +1,214 @@
+import SyncMode.Pull
+import SyncMode.Push
+import kotlinx.cli.ArgType
+import kotlinx.cli.ExperimentalCli
+import kotlinx.cli.Subcommand
+import kotlinx.cli.default
+import org.eclipse.jgit.api.CheckoutCommand
+import org.eclipse.jgit.api.Git
+import org.eclipse.jgit.api.ResetCommand
+import org.eclipse.jgit.api.errors.CheckoutConflictException
+import org.eclipse.jgit.lib.Constants
+import org.eclipse.jgit.lib.Repository
+import org.eclipse.jgit.storage.file.FileRepositoryBuilder
+import org.eclipse.jgit.transport.PushResult
+import org.eclipse.jgit.transport.SshTransport
+import org.eclipse.jgit.transport.sshd.SshdSessionFactory
+import java.io.File
+import java.io.IOException
+import java.nio.file.Files
+import java.nio.file.LinkOption
+import java.nio.file.Path
+import kotlin.io.path.*
+
+@OptIn(ExperimentalCli::class)
+class Sync(config: Config?) : Subcommand("sync", "ワールドを同期するます") {
+ private val mode by argument(ArgType.Choice(), "Mode")
+ private val localServerPath by option(
+ ArgType.String,
+ "local",
+ "l",
+ "リポジトリの同期先を指定するます"
+ ).default(config?.serverDirectory.orEmpty())
+ val remoteRepo by option(ArgType.String, "remote", "r", "リモートリポジトリのURL").default(config?.gitRemoteRepo.orEmpty())
+ val sshKeyPath by option(
+ ArgType.String,
+ "key-path",
+ description = "SSH秘密鍵のパス"
+ ).default(config?.sshSecretKeyPath.orEmpty())
+
+ override fun execute() {
+ if (localServerPath.isEmpty() || remoteRepo.isEmpty()) {
+ println("パスが無効です。")
+ return
+ }
+ val local = Path(localServerPath)
+ when (mode) {
+ Pull -> {
+ //新規 Clone
+ if (!local.isDirectory(LinkOption.NOFOLLOW_LINKS)) {
+ if (local.exists()) {
+ println("${local.absolutePathString()}はディレクトリではありません")
+ return
+ }
+ println("${local.absolutePathString()}を新規作成します")
+ local.createDirectories()
+ }
+ if (local.listDirectoryEntries().isEmpty()) {
+ println("Cloneします")
+ Git.cloneRepository().setDirectory(local.toFile()).setBare(false).setURI(remoteRepo).call()
+ return
+ }
+ // 既存 PULL
+ val builder = FileRepositoryBuilder()
+ val repo =
+ builder.setGitDir(local.resolve(Constants.DOT_GIT).toFile()).readEnvironment().findGitDir().build()
+ val git = Git(repo)
+ try {
+ git.pull().setRemote("origin").setRemoteBranchName("main").call()
+ } catch (e: CheckoutConflictException) {
+ e.printStackTrace()
+ ultimateConflictSolver(e, repo, git)
+ } catch (e: Exception) {
+ println("ドッカン☆")
+ throw e
+ } finally {
+ git.close()
+ }
+ }
+ Push -> {
+ val builder = FileRepositoryBuilder()
+ val repo =
+ builder.setGitDir(local.resolve(Constants.DOT_GIT).toFile()).readEnvironment().findGitDir().build()
+ val git = Git(repo)
+ git.commit().setSign(false).setAll(true).setMessage("[MSTools] Sync")
+ .setAuthor("MSTools", "mstools@naotiki-apps.xyz").call()
+ git.status().paths.forEach {
+ println(it)
+ }
+
+ try {
+ superUltimateFinallyPowerfulPush(git)
+ } catch (e: CheckoutConflictException) {
+ e.printStackTrace()
+ ultimateConflictSolver(e, repo, git)
+ } catch (e: Exception) {
+ throw e
+ } finally {
+ git.close()
+ }
+ }
+ }
+
+ }
+
+ private fun ultimateConflictSolver(e: CheckoutConflictException, repo: Repository, git: Git) {
+ println(
+ """
+ ----!警告!----
+ コンフリクトが起きています
+ 破壊的な変更をする恐れがあるので慎重に操作を行いましょう
+ 意味がわからない場合は管理者に助けを求めましょう
+ ワールドデータ消えても知らんからな????
+
+ """.trimIndent()
+ )
+ print("続行しますか (\"I can solve\"で続行/それ以外でPullをキャンセル(当店おすすめ、これ一択、これしかない) ):")
+ if (readln() == "I can solve") {
+ println(
+ """
+ 言ったな???解決しろよ???壊すなよ???
+ ❤️----コンフリクト解決モード----❤️
+ 解消方法を以下から選ぶがよい
+ (one)ローカルの変更を優先しコミット(もとに戻せる)(書き込み権限が必要です)
+ (two)リモートの変更を優先し、自身の変更は破棄(自分の変更内容は失われます)
+ (cancel)キャンセル
+ """.trimIndent()
+ )
+ var selected = ""
+ while (!selected.lowercase().let {
+ it == "one" || it == "two" || it == "cancel"
+ }) {
+ print("どれにしますか?( one or two or cancel ):")
+ selected = readln()
+ }
+ when (selected) {
+ "one" -> {
+ println("選択:(one)ローカルの変更を優先しコミット(自分の変更を保持できる)")
+ val sshKey = File(sshKeyPath)
+ if (!sshKey.isFile) {
+ throw IllegalArgumentException("SSHキーのパスが正しく設定されていません")
+ }
+ git.checkout().addPaths(e.conflictingPaths).setStage(CheckoutCommand.Stage.OURS).call()
+ println("コンフリクトした愉快なメンバーたち")
+ git.add().apply {
+ e.conflictingPaths.forEach {
+ println(it)
+ addFilepattern(it)
+ }
+ }.call()
+ println("修正Commitします")
+ git.commit().setSign(false).setMessage("[MSTools] コンフリクト解決 (強制ローカルプッシュ)")
+ .setAuthor("MSTools", "mstools@naotiki-apps.xyz").call()
+ println("Pushします")
+ try {
+ superUltimateFinallyPowerfulPush(git)
+ } catch (e: Exception) {
+ println("おめぇの書き込み権限ねーから!!!!!!")
+ println("ドッカン☆")
+ throw e
+ }
+ println("たぶん解決")
+ }
+ "two" -> {
+ println("選択:(two)リモートの変更を優先し、自身の変更は破棄(今の変更内容は失われます)")
+ repo.writeMergeCommitMsg(null)
+ repo.writeMergeHeads(null)
+ Git.wrap(repo).reset().setMode(ResetCommand.ResetType.HARD).call()
+ }
+ "cancel" -> {
+ println("キャンセルします")
+ return
+ }
+ }
+ } else {
+ println("ナイスな判断!!")
+ println("キャンセルしました。必要なら管理者に助けを求めましょう")
+ return
+ }
+ }
+
+ //は?
+ private fun superUltimateFinallyPowerfulPush(git: Git): MutableIterable {
+ val sshKey = File(sshKeyPath)
+ if (!sshKey.isFile) {
+ throw IllegalArgumentException("SSHキーのパスが正しく設定されていません")
+ }
+ return git.push().setPushAll().setTransportConfigCallback {
+ if (it is SshTransport) {
+ it.sshSessionFactory = object : SshdSessionFactory() {
+ val SSH_DIR: Path = Path(".ssh")
+ private var privateKeyFile: Path? = Path(sshKeyPath)
+ override fun getSshDirectory(): File? {
+ return try {
+ Files.createDirectories(SSH_DIR).toFile()
+ } catch (e: IOException) {
+ e.printStackTrace()
+ null
+ }
+ }
+
+ override fun getDefaultIdentities(sshDir: File?): List {
+ return listOf(privateKeyFile)
+ }
+ }
+ }
+ }.call()
+ }
+}
+
+
+enum class SyncMode {
+ Pull,
+ Push,
+}
\ No newline at end of file