From d3cb8a32efe2f4f257fc55500fd6139d2dc5a156 Mon Sep 17 00:00:00 2001
From: InsanusMokrassar <ovsyannikov.alexey95@gmail.com>
Date: Tue, 4 Apr 2023 01:01:22 +0600
Subject: [PATCH 1/9] add partially working native sample

---
 NativeRandomFileSenderBot/README.md           |   9 ++
 NativeRandomFileSenderBot/build.gradle        |  45 ++++++++
 .../nativeMain/kotlin/RandomFileSenderBot.kt  | 109 ++++++++++++++++++
 3 files changed, 163 insertions(+)
 create mode 100644 NativeRandomFileSenderBot/README.md
 create mode 100644 NativeRandomFileSenderBot/build.gradle
 create mode 100644 NativeRandomFileSenderBot/src/nativeMain/kotlin/RandomFileSenderBot.kt

diff --git a/NativeRandomFileSenderBot/README.md b/NativeRandomFileSenderBot/README.md
new file mode 100644
index 0000000..4765c04
--- /dev/null
+++ b/NativeRandomFileSenderBot/README.md
@@ -0,0 +1,9 @@
+# RandomFileSenderBot
+
+This bot will send random file from input folder OR from bot working folder
+
+## Launch
+
+```bash
+../gradlew run --args="BOT_TOKEN[ optional/folder/path]"
+```
diff --git a/NativeRandomFileSenderBot/build.gradle b/NativeRandomFileSenderBot/build.gradle
new file mode 100644
index 0000000..93a2e0b
--- /dev/null
+++ b/NativeRandomFileSenderBot/build.gradle
@@ -0,0 +1,45 @@
+buildscript {
+    repositories {
+        mavenCentral()
+    }
+
+    dependencies {
+        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
+    }
+}
+
+plugins {
+    id "org.jetbrains.kotlin.multiplatform"
+}
+
+
+kotlin {
+    def hostOs = System.getProperty("os.name")
+    def isMingwX64 = hostOs.startsWith("Windows")
+    def nativeTarget
+    if (hostOs == "Linux") nativeTarget = linuxX64("native") { binaries { executable() } }
+    else if (isMingwX64) nativeTarget = mingwX64("native") { binaries { executable() } }
+    else throw new GradleException("Host OS is not supported in Kotlin/Native.")
+
+    sourceSets {
+        commonMain {
+            dependencies {
+                implementation kotlin('stdlib')
+
+                api "dev.inmo:tgbotapi:$telegram_bot_api_version"
+            }
+        }
+
+        nativeMain {
+            dependencies {
+                def engine
+
+                if (hostOs == "Linux") engine = "curl"
+                else if (isMingwX64) engine = "winhttp"
+                else throw new GradleException("Host OS is not supported in Kotlin/Native.")
+
+                api "io.ktor:ktor-client-$engine:$ktor_version"
+            }
+        }
+    }
+}
diff --git a/NativeRandomFileSenderBot/src/nativeMain/kotlin/RandomFileSenderBot.kt b/NativeRandomFileSenderBot/src/nativeMain/kotlin/RandomFileSenderBot.kt
new file mode 100644
index 0000000..29bf284
--- /dev/null
+++ b/NativeRandomFileSenderBot/src/nativeMain/kotlin/RandomFileSenderBot.kt
@@ -0,0 +1,109 @@
+import dev.inmo.micro_utils.common.MPPFile
+import dev.inmo.micro_utils.common.filesize
+import dev.inmo.micro_utils.coroutines.runCatchingSafely
+import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions
+import dev.inmo.tgbotapi.bot.ktor.telegramBot
+import dev.inmo.tgbotapi.bot.TelegramBot
+import dev.inmo.tgbotapi.extensions.api.bot.getMe
+import dev.inmo.tgbotapi.extensions.api.bot.setMyCommands
+import dev.inmo.tgbotapi.extensions.api.send.*
+import dev.inmo.tgbotapi.extensions.api.send.media.sendDocument
+import dev.inmo.tgbotapi.extensions.api.send.media.sendDocumentsGroup
+import dev.inmo.tgbotapi.extensions.behaviour_builder.buildBehaviourWithLongPolling
+import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onCommandWithArgs
+import dev.inmo.tgbotapi.requests.abstracts.asMultipartFile
+import dev.inmo.tgbotapi.types.BotCommand
+import dev.inmo.tgbotapi.types.chat.Chat
+import dev.inmo.tgbotapi.types.files.DocumentFile
+import dev.inmo.tgbotapi.types.media.TelegramMediaDocument
+import dev.inmo.tgbotapi.types.mediaCountInMediaGroup
+import kotlinx.coroutines.runBlocking
+import okio.FileSystem
+import okio.Path.Companion.toPath
+
+private const val command = "send_file"
+
+/**
+ * This bot will send files inside of working directory OR from directory in the second argument.
+ * You may send /send_file command to this bot to get random file from the directory OR
+ * `/send_file $number` when you want to receive required number of files. For example,
+ * /send_file and `/send_file 1` will have the same effect - bot will send one random file.
+ * But if you will send `/send_file 5` it will choose 5 random files and send them as group
+ */
+fun main(args: Array<String>) = runBlocking {
+    val botToken = args.first()
+    val directoryOrFile = args.getOrNull(1) ?.toPath() ?: "".toPath()
+
+    fun pickFile(currentRoot: MPPFile = directoryOrFile): MPPFile? {
+        if (FileSystem.SYSTEM.exists(currentRoot) && FileSystem.SYSTEM.listOrNull(currentRoot) == null) {
+            return currentRoot
+        } else {
+            return pickFile(FileSystem.SYSTEM.list(currentRoot).takeIf { it.isNotEmpty() } ?.random() ?: return null)
+        }
+    }
+
+    suspend fun TelegramBot.sendFiles(chat: Chat, files: List<MPPFile>) {
+        when (files.size) {
+            1 -> {
+                sendDocument(
+                    chat.id,
+                    files.first().asMultipartFile(),
+                    protectContent = true
+                )
+            }
+            else -> sendDocumentsGroup(
+                chat,
+                files.map { TelegramMediaDocument(it.asMultipartFile()) },
+                protectContent = true
+            )
+        }
+    }
+
+    val bot = telegramBot(botToken)
+
+    bot.buildBehaviourWithLongPolling (defaultExceptionsHandler = { it.printStackTrace() }) {
+        onCommandWithArgs(command) { message, args ->
+            withUploadDocumentAction(message.chat) {
+                val count = args.firstOrNull() ?.toIntOrNull() ?: 1
+                var sent = false
+
+                var left = count
+                val chosen = mutableListOf<MPPFile>()
+
+                while (left > 0) {
+                    val picked = pickFile() ?.takeIf { it.filesize > 0 } ?: continue
+                    chosen.add(picked)
+                    left--
+                    if (chosen.size >= mediaCountInMediaGroup.last) {
+                        runCatchingSafely {
+                            sendFiles(message.chat, chosen)
+                        }.onFailure {
+                            it.printStackTrace()
+                        }
+                        chosen.clear()
+                        sent = true
+                    }
+                }
+
+                if (chosen.isNotEmpty()) {
+                    sendFiles(message.chat, chosen)
+                    sent = true
+                }
+
+                if (!sent) {
+                    reply(message, "Nothing selected :(")
+                }
+            }
+        }
+
+        setMyCommands(
+            BotCommand(command, "Send some random file in picker directory")
+        )
+
+        allUpdatesFlow.subscribeSafelyWithoutExceptions(this) {
+            println(it)
+        }
+
+        println(getMe())
+    }.join()
+}

From 9b10749411780732679ef4668b3a502854344c6d Mon Sep 17 00:00:00 2001
From: InsanusMokrassar <ovsyannikov.alexey95@gmail.com>
Date: Tue, 4 Apr 2023 01:02:18 +0600
Subject: [PATCH 2/9] update dependencies and other attributes

---
 README.md         | 2 ++
 gradle.properties | 4 ++--
 settings.gradle   | 1 +
 3 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/README.md b/README.md
index 7256736..26ea126 100644
--- a/README.md
+++ b/README.md
@@ -4,6 +4,8 @@ This repository contains several examples of simple bots which are using Telegra
 
 ## How to use this repository
 
+***TO RUN NATIVE TARGETS ON LINUX YOU SHOULD INSTALL CURL LIBRARY. FOR EXAMPLE: `sudo apt install libcurl4-gnutls-dev`***
+
 This repository contains several important things:
 
 * Example subprojects
diff --git a/gradle.properties b/gradle.properties
index 699bec0..0f263bb 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -5,7 +5,7 @@ org.gradle.jvmargs=-Xmx1g
 
 
 kotlin_version=1.8.10
-telegram_bot_api_version=7.0.1
-micro_utils_version=0.17.5
+telegram_bot_api_version=7.0.2-branch_7.0.2-build1571
+micro_utils_version=0.17.6-branch_0.17.6-build419
 serialization_version=1.5.0
 ktor_version=2.2.4
diff --git a/settings.gradle b/settings.gradle
index dde1eba..ab1214f 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1,6 +1,7 @@
 include ":ForwardInfoSenderBot"
 
 include ":RandomFileSenderBot"
+include ":NativeRandomFileSenderBot"
 
 include ":HelloBot"
 

From bf499ee780b156d4d43519c85779adf0250c0862 Mon Sep 17 00:00:00 2001
From: InsanusMokrassar <ovsyannikov.alexey95@gmail.com>
Date: Tue, 4 Apr 2023 01:45:15 +0600
Subject: [PATCH 3/9] Update gradle.properties

---
 gradle.properties | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/gradle.properties b/gradle.properties
index 0f263bb..49b404c 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -6,6 +6,6 @@ org.gradle.jvmargs=-Xmx1g
 
 kotlin_version=1.8.10
 telegram_bot_api_version=7.0.2-branch_7.0.2-build1571
-micro_utils_version=0.17.6-branch_0.17.6-build419
+micro_utils_version=0.17.6-branch_0.17.6-build420
 serialization_version=1.5.0
 ktor_version=2.2.4

From fca8704cec1409653bf94ca6913669da18c5183c Mon Sep 17 00:00:00 2001
From: InsanusMokrassar <ovsyannikov.alexey95@gmail.com>
Date: Tue, 4 Apr 2023 09:56:41 +0600
Subject: [PATCH 4/9] Update build.yml

---
 .github/workflows/build.yml | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 65f648c..0cc162d 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -8,6 +8,9 @@ jobs:
 
     steps:
       - uses: actions/checkout@v2
+      - name: Install dependencies
+        run: |
+          sudo apt-get install libcurl4-openssl-dev
       - name: Set up JDK 11
         uses: actions/setup-java@v1
         with:

From 8fdf715419e366ee17d948a302e44c83aa009b03 Mon Sep 17 00:00:00 2001
From: InsanusMokrassar <ovsyannikov.alexey95@gmail.com>
Date: Tue, 4 Apr 2023 09:57:28 +0600
Subject: [PATCH 5/9] Update build.yml

---
 .github/workflows/build.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 0cc162d..69d1cb8 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -10,7 +10,7 @@ jobs:
       - uses: actions/checkout@v2
       - name: Install dependencies
         run: |
-          sudo apt-get install libcurl4-openssl-dev
+          sudo apt install -y libcurl4-openssl-dev
       - name: Set up JDK 11
         uses: actions/setup-java@v1
         with:

From 4e3c1869522d4f02c69d292fff2f972634db63c4 Mon Sep 17 00:00:00 2001
From: InsanusMokrassar <ovsyannikov.alexey95@gmail.com>
Date: Tue, 18 Apr 2023 03:17:04 +0600
Subject: [PATCH 6/9] update dependencies

---
 NativeRandomFileSenderBot/build.gradle | 6 +++++-
 gradle.properties                      | 6 +++---
 2 files changed, 8 insertions(+), 4 deletions(-)

diff --git a/NativeRandomFileSenderBot/build.gradle b/NativeRandomFileSenderBot/build.gradle
index 93a2e0b..d3569cf 100644
--- a/NativeRandomFileSenderBot/build.gradle
+++ b/NativeRandomFileSenderBot/build.gradle
@@ -12,6 +12,10 @@ plugins {
     id "org.jetbrains.kotlin.multiplatform"
 }
 
+repositories {
+    maven { url "https://maven.pkg.jetbrains.space/public/p/ktor/eap/" }
+}
+
 
 kotlin {
     def hostOs = System.getProperty("os.name")
@@ -38,7 +42,7 @@ kotlin {
                 else if (isMingwX64) engine = "winhttp"
                 else throw new GradleException("Host OS is not supported in Kotlin/Native.")
 
-                api "io.ktor:ktor-client-$engine:$ktor_version"
+                api "io.ktor:ktor-client-$engine:2.3.0-eap-638"
             }
         }
     }
diff --git a/gradle.properties b/gradle.properties
index 49b404c..ffb21b7 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -4,8 +4,8 @@ org.gradle.parallel=true
 org.gradle.jvmargs=-Xmx1g
 
 
-kotlin_version=1.8.10
-telegram_bot_api_version=7.0.2-branch_7.0.2-build1571
-micro_utils_version=0.17.6-branch_0.17.6-build420
+kotlin_version=1.8.20
+telegram_bot_api_version=7.0.2-branch_7.0.2-build1583
+micro_utils_version=0.17.6
 serialization_version=1.5.0
 ktor_version=2.2.4

From 7b996fe1defd1396341eb746757ff9ace3c8fb10 Mon Sep 17 00:00:00 2001
From: InsanusMokrassar <ovsyannikov.alexey95@gmail.com>
Date: Tue, 18 Apr 2023 11:31:28 +0600
Subject: [PATCH 7/9] rollback ktor version in native sample

---
 NativeRandomFileSenderBot/build.gradle | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/NativeRandomFileSenderBot/build.gradle b/NativeRandomFileSenderBot/build.gradle
index d3569cf..0f5d51a 100644
--- a/NativeRandomFileSenderBot/build.gradle
+++ b/NativeRandomFileSenderBot/build.gradle
@@ -42,7 +42,7 @@ kotlin {
                 else if (isMingwX64) engine = "winhttp"
                 else throw new GradleException("Host OS is not supported in Kotlin/Native.")
 
-                api "io.ktor:ktor-client-$engine:2.3.0-eap-638"
+                api "io.ktor:ktor-client-$engine:$ktor_version"
             }
         }
     }

From c6019b1862f718ebd1710a41697eb567b9283bab Mon Sep 17 00:00:00 2001
From: InsanusMokrassar <ovsyannikov.alexey95@gmail.com>
Date: Wed, 19 Apr 2023 20:20:11 +0600
Subject: [PATCH 8/9] complete sample with native

---
 NativeRandomFileSenderBot/README.md           |   9 --
 .../nativeMain/kotlin/RandomFileSenderBot.kt  | 109 ------------------
 RandomFileSenderBot/build.gradle              |  39 ++++++-
 .../kotlin/Bot.kt}                            |  31 ++---
 .../src/commonMain/kotlin/PickFile.kt         |   0
 .../src/jvmMain/kotlin/ActualPickFile.kt      |  10 ++
 .../src/jvmMain/kotlin/RandomFileSenderBot.kt |   5 +
 .../src/nativeMain/kotlin/ActualPickFile.kt   |  10 ++
 .../nativeMain/kotlin/RandomFileSenderBot.kt  |   8 ++
 ResenderBot/ResenderBotLib/build.gradle       |   2 +
 .../src/commonMain/kotlin/ResenderBot.kt      |   9 +-
 .../native_launcher}/build.gradle             |   7 +-
 .../src/nativeMain/kotlin/ResenderBot.kt      |   9 ++
 gradle.properties                             |   8 +-
 settings.gradle                               |   2 +-
 15 files changed, 100 insertions(+), 158 deletions(-)
 delete mode 100644 NativeRandomFileSenderBot/README.md
 delete mode 100644 NativeRandomFileSenderBot/src/nativeMain/kotlin/RandomFileSenderBot.kt
 rename RandomFileSenderBot/src/{main/kotlin/RandomFileSenderBot.kt => commonMain/kotlin/Bot.kt} (77%)
 create mode 100644 RandomFileSenderBot/src/commonMain/kotlin/PickFile.kt
 create mode 100644 RandomFileSenderBot/src/jvmMain/kotlin/ActualPickFile.kt
 create mode 100644 RandomFileSenderBot/src/jvmMain/kotlin/RandomFileSenderBot.kt
 create mode 100644 RandomFileSenderBot/src/nativeMain/kotlin/ActualPickFile.kt
 create mode 100644 RandomFileSenderBot/src/nativeMain/kotlin/RandomFileSenderBot.kt
 rename {NativeRandomFileSenderBot => ResenderBot/native_launcher}/build.gradle (87%)
 create mode 100644 ResenderBot/native_launcher/src/nativeMain/kotlin/ResenderBot.kt

diff --git a/NativeRandomFileSenderBot/README.md b/NativeRandomFileSenderBot/README.md
deleted file mode 100644
index 4765c04..0000000
--- a/NativeRandomFileSenderBot/README.md
+++ /dev/null
@@ -1,9 +0,0 @@
-# RandomFileSenderBot
-
-This bot will send random file from input folder OR from bot working folder
-
-## Launch
-
-```bash
-../gradlew run --args="BOT_TOKEN[ optional/folder/path]"
-```
diff --git a/NativeRandomFileSenderBot/src/nativeMain/kotlin/RandomFileSenderBot.kt b/NativeRandomFileSenderBot/src/nativeMain/kotlin/RandomFileSenderBot.kt
deleted file mode 100644
index 29bf284..0000000
--- a/NativeRandomFileSenderBot/src/nativeMain/kotlin/RandomFileSenderBot.kt
+++ /dev/null
@@ -1,109 +0,0 @@
-import dev.inmo.micro_utils.common.MPPFile
-import dev.inmo.micro_utils.common.filesize
-import dev.inmo.micro_utils.coroutines.runCatchingSafely
-import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions
-import dev.inmo.tgbotapi.bot.ktor.telegramBot
-import dev.inmo.tgbotapi.bot.TelegramBot
-import dev.inmo.tgbotapi.extensions.api.bot.getMe
-import dev.inmo.tgbotapi.extensions.api.bot.setMyCommands
-import dev.inmo.tgbotapi.extensions.api.send.*
-import dev.inmo.tgbotapi.extensions.api.send.media.sendDocument
-import dev.inmo.tgbotapi.extensions.api.send.media.sendDocumentsGroup
-import dev.inmo.tgbotapi.extensions.behaviour_builder.buildBehaviourWithLongPolling
-import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onCommandWithArgs
-import dev.inmo.tgbotapi.requests.abstracts.asMultipartFile
-import dev.inmo.tgbotapi.types.BotCommand
-import dev.inmo.tgbotapi.types.chat.Chat
-import dev.inmo.tgbotapi.types.files.DocumentFile
-import dev.inmo.tgbotapi.types.media.TelegramMediaDocument
-import dev.inmo.tgbotapi.types.mediaCountInMediaGroup
-import kotlinx.coroutines.runBlocking
-import okio.FileSystem
-import okio.Path.Companion.toPath
-
-private const val command = "send_file"
-
-/**
- * This bot will send files inside of working directory OR from directory in the second argument.
- * You may send /send_file command to this bot to get random file from the directory OR
- * `/send_file $number` when you want to receive required number of files. For example,
- * /send_file and `/send_file 1` will have the same effect - bot will send one random file.
- * But if you will send `/send_file 5` it will choose 5 random files and send them as group
- */
-fun main(args: Array<String>) = runBlocking {
-    val botToken = args.first()
-    val directoryOrFile = args.getOrNull(1) ?.toPath() ?: "".toPath()
-
-    fun pickFile(currentRoot: MPPFile = directoryOrFile): MPPFile? {
-        if (FileSystem.SYSTEM.exists(currentRoot) && FileSystem.SYSTEM.listOrNull(currentRoot) == null) {
-            return currentRoot
-        } else {
-            return pickFile(FileSystem.SYSTEM.list(currentRoot).takeIf { it.isNotEmpty() } ?.random() ?: return null)
-        }
-    }
-
-    suspend fun TelegramBot.sendFiles(chat: Chat, files: List<MPPFile>) {
-        when (files.size) {
-            1 -> {
-                sendDocument(
-                    chat.id,
-                    files.first().asMultipartFile(),
-                    protectContent = true
-                )
-            }
-            else -> sendDocumentsGroup(
-                chat,
-                files.map { TelegramMediaDocument(it.asMultipartFile()) },
-                protectContent = true
-            )
-        }
-    }
-
-    val bot = telegramBot(botToken)
-
-    bot.buildBehaviourWithLongPolling (defaultExceptionsHandler = { it.printStackTrace() }) {
-        onCommandWithArgs(command) { message, args ->
-            withUploadDocumentAction(message.chat) {
-                val count = args.firstOrNull() ?.toIntOrNull() ?: 1
-                var sent = false
-
-                var left = count
-                val chosen = mutableListOf<MPPFile>()
-
-                while (left > 0) {
-                    val picked = pickFile() ?.takeIf { it.filesize > 0 } ?: continue
-                    chosen.add(picked)
-                    left--
-                    if (chosen.size >= mediaCountInMediaGroup.last) {
-                        runCatchingSafely {
-                            sendFiles(message.chat, chosen)
-                        }.onFailure {
-                            it.printStackTrace()
-                        }
-                        chosen.clear()
-                        sent = true
-                    }
-                }
-
-                if (chosen.isNotEmpty()) {
-                    sendFiles(message.chat, chosen)
-                    sent = true
-                }
-
-                if (!sent) {
-                    reply(message, "Nothing selected :(")
-                }
-            }
-        }
-
-        setMyCommands(
-            BotCommand(command, "Send some random file in picker directory")
-        )
-
-        allUpdatesFlow.subscribeSafelyWithoutExceptions(this) {
-            println(it)
-        }
-
-        println(getMe())
-    }.join()
-}
diff --git a/RandomFileSenderBot/build.gradle b/RandomFileSenderBot/build.gradle
index 946ccfc..70327df 100644
--- a/RandomFileSenderBot/build.gradle
+++ b/RandomFileSenderBot/build.gradle
@@ -8,14 +8,45 @@ buildscript {
     }
 }
 
-apply plugin: 'kotlin'
+plugins {
+    id "org.jetbrains.kotlin.multiplatform"
+}
+
 apply plugin: 'application'
 
 mainClassName="RandomFileSenderBotKt"
 
 
-dependencies {
-    implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
+kotlin {
+    def hostOs = System.getProperty("os.name")
+    def isMingwX64 = hostOs.startsWith("Windows")
+    def nativeTarget
+    if (hostOs == "Linux") nativeTarget = linuxX64("native") { binaries { executable() } }
+    else if (isMingwX64) nativeTarget = mingwX64("native") { binaries { executable() } }
+    else throw new GradleException("Host OS is not supported in Kotlin/Native.")
 
-    implementation "dev.inmo:tgbotapi:$telegram_bot_api_version"
+    jvm()
+
+    sourceSets {
+        commonMain {
+            dependencies {
+                implementation kotlin('stdlib')
+
+                api "dev.inmo:tgbotapi:$telegram_bot_api_version"
+            }
+        }
+
+        nativeMain {
+            dependencies {
+                def engine
+
+                if (hostOs == "Linux") engine = "curl"
+                else if (isMingwX64) engine = "winhttp"
+                else throw new GradleException("Host OS is not supported in Kotlin/Native.")
+
+                api "io.ktor:ktor-client-$engine:$ktor_version"
+            }
+        }
+    }
 }
+
diff --git a/RandomFileSenderBot/src/main/kotlin/RandomFileSenderBot.kt b/RandomFileSenderBot/src/commonMain/kotlin/Bot.kt
similarity index 77%
rename from RandomFileSenderBot/src/main/kotlin/RandomFileSenderBot.kt
rename to RandomFileSenderBot/src/commonMain/kotlin/Bot.kt
index 302200e..671d843 100644
--- a/RandomFileSenderBot/src/main/kotlin/RandomFileSenderBot.kt
+++ b/RandomFileSenderBot/src/commonMain/kotlin/Bot.kt
@@ -1,23 +1,25 @@
+import dev.inmo.micro_utils.common.MPPFile
 import dev.inmo.micro_utils.common.filesize
-import dev.inmo.tgbotapi.bot.ktor.telegramBot
 import dev.inmo.tgbotapi.bot.TelegramBot
 import dev.inmo.tgbotapi.extensions.api.bot.getMe
 import dev.inmo.tgbotapi.extensions.api.bot.setMyCommands
-import dev.inmo.tgbotapi.extensions.api.send.*
 import dev.inmo.tgbotapi.extensions.api.send.media.sendDocument
 import dev.inmo.tgbotapi.extensions.api.send.media.sendDocumentsGroup
+import dev.inmo.tgbotapi.extensions.api.send.reply
+import dev.inmo.tgbotapi.extensions.api.send.withUploadDocumentAction
+import dev.inmo.tgbotapi.extensions.api.telegramBot
 import dev.inmo.tgbotapi.extensions.behaviour_builder.buildBehaviourWithLongPolling
 import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onCommandWithArgs
 import dev.inmo.tgbotapi.requests.abstracts.asMultipartFile
 import dev.inmo.tgbotapi.types.BotCommand
 import dev.inmo.tgbotapi.types.chat.Chat
-import dev.inmo.tgbotapi.types.files.DocumentFile
 import dev.inmo.tgbotapi.types.media.TelegramMediaDocument
 import dev.inmo.tgbotapi.types.mediaCountInMediaGroup
-import java.io.File
 
 private const val command = "send_file"
 
+expect fun pickFile(currentRoot: MPPFile): MPPFile?
+
 /**
  * This bot will send files inside of working directory OR from directory in the second argument.
  * You may send /send_file command to this bot to get random file from the directory OR
@@ -25,19 +27,10 @@ private const val command = "send_file"
  * /send_file and `/send_file 1` will have the same effect - bot will send one random file.
  * But if you will send `/send_file 5` it will choose 5 random files and send them as group
  */
-suspend fun main(args: Array<String>) {
-    val botToken = args.first()
-    val directoryOrFile = args.getOrNull(1) ?.let { File(it) } ?: File("")
+suspend fun doRandomFileSenderBot(token: String, folder: MPPFile) {
+    val bot = telegramBot(token)
 
-    fun pickFile(currentRoot: File = directoryOrFile): File? {
-        if (currentRoot.isFile) {
-            return currentRoot
-        } else {
-            return pickFile(currentRoot.listFiles() ?.takeIf { it.isNotEmpty() } ?.random() ?: return null)
-        }
-    }
-
-    suspend fun TelegramBot.sendFiles(chat: Chat, files: List<File>) {
+    suspend fun TelegramBot.sendFiles(chat: Chat, files: List<MPPFile>) {
         when (files.size) {
             1 -> sendDocument(
                 chat.id,
@@ -52,8 +45,6 @@ suspend fun main(args: Array<String>) {
         }
     }
 
-    val bot = telegramBot(botToken)
-
     bot.buildBehaviourWithLongPolling (defaultExceptionsHandler = { it.printStackTrace() }) {
         onCommandWithArgs(command) { message, args ->
 
@@ -62,10 +53,10 @@ suspend fun main(args: Array<String>) {
                 var sent = false
 
                 var left = count
-                val chosen = mutableListOf<File>()
+                val chosen = mutableListOf<MPPFile>()
 
                 while (left > 0) {
-                    val picked = pickFile() ?.takeIf { it.filesize > 0 } ?: continue
+                    val picked = pickFile(folder) ?.takeIf { it.filesize > 0 } ?: continue
                     chosen.add(picked)
                     left--
                     if (chosen.size >= mediaCountInMediaGroup.last) {
diff --git a/RandomFileSenderBot/src/commonMain/kotlin/PickFile.kt b/RandomFileSenderBot/src/commonMain/kotlin/PickFile.kt
new file mode 100644
index 0000000..e69de29
diff --git a/RandomFileSenderBot/src/jvmMain/kotlin/ActualPickFile.kt b/RandomFileSenderBot/src/jvmMain/kotlin/ActualPickFile.kt
new file mode 100644
index 0000000..f453694
--- /dev/null
+++ b/RandomFileSenderBot/src/jvmMain/kotlin/ActualPickFile.kt
@@ -0,0 +1,10 @@
+import dev.inmo.micro_utils.common.MPPFile
+import java.io.File
+
+actual fun pickFile(currentRoot: MPPFile): File? {
+    if (currentRoot.isFile) {
+        return currentRoot
+    } else {
+        return pickFile(currentRoot.listFiles() ?.takeIf { it.isNotEmpty() } ?.random() ?: return null)
+    }
+}
diff --git a/RandomFileSenderBot/src/jvmMain/kotlin/RandomFileSenderBot.kt b/RandomFileSenderBot/src/jvmMain/kotlin/RandomFileSenderBot.kt
new file mode 100644
index 0000000..52d0e06
--- /dev/null
+++ b/RandomFileSenderBot/src/jvmMain/kotlin/RandomFileSenderBot.kt
@@ -0,0 +1,5 @@
+import dev.inmo.micro_utils.common.MPPFile
+
+suspend fun main(args: Array<String>) {
+    doRandomFileSenderBot(args.first(), MPPFile(args.getOrNull(1) ?: ""))
+}
diff --git a/RandomFileSenderBot/src/nativeMain/kotlin/ActualPickFile.kt b/RandomFileSenderBot/src/nativeMain/kotlin/ActualPickFile.kt
new file mode 100644
index 0000000..1b6386d
--- /dev/null
+++ b/RandomFileSenderBot/src/nativeMain/kotlin/ActualPickFile.kt
@@ -0,0 +1,10 @@
+import dev.inmo.micro_utils.common.MPPFile
+import okio.FileSystem
+
+actual fun pickFile(currentRoot: MPPFile): MPPFile? {
+    if (FileSystem.SYSTEM.exists(currentRoot) && FileSystem.SYSTEM.listOrNull(currentRoot) == null) {
+        return currentRoot
+    } else {
+        return pickFile(FileSystem.SYSTEM.list(currentRoot).takeIf { it.isNotEmpty() } ?.random() ?: return null)
+    }
+}
diff --git a/RandomFileSenderBot/src/nativeMain/kotlin/RandomFileSenderBot.kt b/RandomFileSenderBot/src/nativeMain/kotlin/RandomFileSenderBot.kt
new file mode 100644
index 0000000..4ef7710
--- /dev/null
+++ b/RandomFileSenderBot/src/nativeMain/kotlin/RandomFileSenderBot.kt
@@ -0,0 +1,8 @@
+import kotlinx.coroutines.runBlocking
+import okio.Path.Companion.toPath
+
+fun main(args: Array<String>) {
+    runBlocking {
+        doRandomFileSenderBot(args.first(), args.getOrNull(1) ?.toPath() ?: "".toPath())
+    }
+}
diff --git a/ResenderBot/ResenderBotLib/build.gradle b/ResenderBot/ResenderBotLib/build.gradle
index 1d40c3e..0530296 100644
--- a/ResenderBot/ResenderBotLib/build.gradle
+++ b/ResenderBot/ResenderBotLib/build.gradle
@@ -20,6 +20,8 @@ kotlin {
         browser()
         binaries.executable()
     }
+    linuxX64()
+    mingwX64()
 
     sourceSets {
         commonMain {
diff --git a/ResenderBot/ResenderBotLib/src/commonMain/kotlin/ResenderBot.kt b/ResenderBot/ResenderBotLib/src/commonMain/kotlin/ResenderBot.kt
index cec4079..fe604d8 100644
--- a/ResenderBot/ResenderBotLib/src/commonMain/kotlin/ResenderBot.kt
+++ b/ResenderBot/ResenderBotLib/src/commonMain/kotlin/ResenderBot.kt
@@ -15,11 +15,7 @@ suspend fun activateResenderBot(
     token: String,
     print: (Any) -> Unit
 ) {
-    val bot = telegramBot(token)
-
-    print(bot.getMe())
-
-    bot.buildBehaviourWithLongPolling(CoroutineScope(currentCoroutineContext() + SupervisorJob())) {
+    telegramBotWithBehaviourAndLongPolling(token, scope = CoroutineScope(currentCoroutineContext() + SupervisorJob())) {
         onContentMessage(
             subcontextUpdatesFilter = MessageFilterByChat,
         ) {
@@ -43,5 +39,6 @@ suspend fun activateResenderBot(
         allUpdatesFlow.subscribeSafelyWithoutExceptions(this) {
             println(it)
         }
-    }.join()
+        print(bot.getMe())
+    }.second.join()
 }
diff --git a/NativeRandomFileSenderBot/build.gradle b/ResenderBot/native_launcher/build.gradle
similarity index 87%
rename from NativeRandomFileSenderBot/build.gradle
rename to ResenderBot/native_launcher/build.gradle
index 0f5d51a..fa67557 100644
--- a/NativeRandomFileSenderBot/build.gradle
+++ b/ResenderBot/native_launcher/build.gradle
@@ -12,10 +12,6 @@ plugins {
     id "org.jetbrains.kotlin.multiplatform"
 }
 
-repositories {
-    maven { url "https://maven.pkg.jetbrains.space/public/p/ktor/eap/" }
-}
-
 
 kotlin {
     def hostOs = System.getProperty("os.name")
@@ -30,7 +26,7 @@ kotlin {
             dependencies {
                 implementation kotlin('stdlib')
 
-                api "dev.inmo:tgbotapi:$telegram_bot_api_version"
+                api project(":ResenderBot:ResenderBotLib")
             }
         }
 
@@ -47,3 +43,4 @@ kotlin {
         }
     }
 }
+
diff --git a/ResenderBot/native_launcher/src/nativeMain/kotlin/ResenderBot.kt b/ResenderBot/native_launcher/src/nativeMain/kotlin/ResenderBot.kt
new file mode 100644
index 0000000..29e16b1
--- /dev/null
+++ b/ResenderBot/native_launcher/src/nativeMain/kotlin/ResenderBot.kt
@@ -0,0 +1,9 @@
+import kotlinx.coroutines.runBlocking
+
+fun main(vararg args: String) {
+    runBlocking {
+        activateResenderBot(args.first()) {
+            println(it)
+        }
+    }
+}
diff --git a/gradle.properties b/gradle.properties
index ffb21b7..823884b 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,11 +1,11 @@
 kotlin.code.style=official
 org.gradle.parallel=true
 # Due to parallel compilation project require next amount of memory on full build
-org.gradle.jvmargs=-Xmx1g
+org.gradle.jvmargs=-Xmx2g
 
 
 kotlin_version=1.8.20
-telegram_bot_api_version=7.0.2-branch_7.0.2-build1583
-micro_utils_version=0.17.6
+telegram_bot_api_version=7.0.2
+micro_utils_version=0.17.8
 serialization_version=1.5.0
-ktor_version=2.2.4
+ktor_version=2.3.0
diff --git a/settings.gradle b/settings.gradle
index ab1214f..a665bb3 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1,7 +1,6 @@
 include ":ForwardInfoSenderBot"
 
 include ":RandomFileSenderBot"
-include ":NativeRandomFileSenderBot"
 
 include ":HelloBot"
 
@@ -13,6 +12,7 @@ include ":FilesLoaderBot"
 
 include ":ResenderBot:ResenderBotLib"
 include ":ResenderBot:jvm_launcher"
+include ":ResenderBot:native_launcher"
 
 include ":KeyboardsBot:KeyboardsBotLib"
 include ":KeyboardsBot:jvm_launcher"

From 3925ef942303020c3f775bf198f54d8866df602d Mon Sep 17 00:00:00 2001
From: InsanusMokrassar <ovsyannikov.alexey95@gmail.com>
Date: Wed, 19 Apr 2023 21:46:35 +0600
Subject: [PATCH 9/9] add opportunity to set port different with 8080 in
 WebAppServer sample

---
 WebApp/src/jvmMain/kotlin/WebAppServer.kt | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/WebApp/src/jvmMain/kotlin/WebAppServer.kt b/WebApp/src/jvmMain/kotlin/WebAppServer.kt
index 37acaef..0b800bf 100644
--- a/WebApp/src/jvmMain/kotlin/WebAppServer.kt
+++ b/WebApp/src/jvmMain/kotlin/WebAppServer.kt
@@ -43,14 +43,13 @@ suspend fun main(vararg args: String) {
     val bot = telegramBot(telegramBotAPIUrlsKeeper)
     createKtorServer(
         "0.0.0.0",
-        8080,
+        args.getOrNull(2) ?.toIntOrNull() ?: 8080,
         additionalEngineEnvironmentConfigurator = {
             parentCoroutineContext += Dispatchers.IO
         }
     ) {
         routing {
-            static {
-                files(File("WebApp/build/distributions"))
+            staticFiles("", File("WebApp/build/distributions")) {
                 default("WebApp/build/distributions/index.html")
             }
             post("inline") {