From 006f4e94e78d8fea4e96daaa14fe99742ec6b5e5 Mon Sep 17 00:00:00 2001
From: Rowdy Mitchell Chotkan <rowdy_chotkan@msn.com>
Date: Mon, 19 Aug 2024 17:39:11 +0200
Subject: [PATCH 1/2] Make `createIntroductionRequest` public

---
 ipv8/src/main/java/nl/tudelft/ipv8/Community.kt | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/Community.kt b/ipv8/src/main/java/nl/tudelft/ipv8/Community.kt
index 8629351a..ad972e2e 100644
--- a/ipv8/src/main/java/nl/tudelft/ipv8/Community.kt
+++ b/ipv8/src/main/java/nl/tudelft/ipv8/Community.kt
@@ -1,6 +1,9 @@
 package nl.tudelft.ipv8
 
-import kotlinx.coroutines.*
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.SupervisorJob
 import mu.KotlinLogging
 import nl.tudelft.ipv8.exception.PacketDecodingException
 import nl.tudelft.ipv8.keyvault.PrivateKey
@@ -182,7 +185,7 @@ abstract class Community : Overlay {
     /**
      * Introduction and puncturing requests creation
      */
-    internal fun createIntroductionRequest(
+    fun createIntroductionRequest(
         socketAddress: IPv4Address,
         extraBytes: ByteArray = byteArrayOf()
     ): ByteArray {

From d790e0d505fe351d24663d22d35e08eabf098a28 Mon Sep 17 00:00:00 2001
From: Rowdy Mitchell Chotkan <rowdy_chotkan@msn.com>
Date: Mon, 19 Aug 2024 17:39:23 +0200
Subject: [PATCH 2/2] Add force walk example

---
 .../force_walk/ConnectionCommunity.kt         |  15 +++
 .../jvm/demo/examples/force_walk/ForceWalk.kt | 102 ++++++++++++++++++
 2 files changed, 117 insertions(+)
 create mode 100644 demo-jvm/src/main/java/nl/tudelft/ipv8/jvm/demo/examples/force_walk/ConnectionCommunity.kt
 create mode 100644 demo-jvm/src/main/java/nl/tudelft/ipv8/jvm/demo/examples/force_walk/ForceWalk.kt

diff --git a/demo-jvm/src/main/java/nl/tudelft/ipv8/jvm/demo/examples/force_walk/ConnectionCommunity.kt b/demo-jvm/src/main/java/nl/tudelft/ipv8/jvm/demo/examples/force_walk/ConnectionCommunity.kt
new file mode 100644
index 00000000..f8abbf14
--- /dev/null
+++ b/demo-jvm/src/main/java/nl/tudelft/ipv8/jvm/demo/examples/force_walk/ConnectionCommunity.kt
@@ -0,0 +1,15 @@
+package nl.tudelft.ipv8.jvm.demo.examples.force_walk
+
+import nl.tudelft.ipv8.Community
+import nl.tudelft.ipv8.IPv4Address
+
+class ConnectionCommunity : Community() {
+    override val serviceId = "02313685c1912a141279f8248fc8db5899c5df5b"
+
+    override fun walkTo(address: IPv4Address) {
+        val packet = createIntroductionRequest(address)
+        this.endpoint.send(address, packet)
+    }
+
+}
+
diff --git a/demo-jvm/src/main/java/nl/tudelft/ipv8/jvm/demo/examples/force_walk/ForceWalk.kt b/demo-jvm/src/main/java/nl/tudelft/ipv8/jvm/demo/examples/force_walk/ForceWalk.kt
new file mode 100644
index 00000000..c8dcd670
--- /dev/null
+++ b/demo-jvm/src/main/java/nl/tudelft/ipv8/jvm/demo/examples/force_walk/ForceWalk.kt
@@ -0,0 +1,102 @@
+package nl.tudelft.ipv8.jvm.demo.examples.force_walk
+
+import kotlinx.coroutines.*
+import mu.KotlinLogging
+import nl.tudelft.ipv8.*
+import nl.tudelft.ipv8.keyvault.JavaCryptoProvider
+import nl.tudelft.ipv8.messaging.EndpointAggregator
+import nl.tudelft.ipv8.messaging.udp.UdpEndpoint
+import java.net.InetAddress
+import java.util.*
+import kotlin.math.roundToInt
+
+class Application {
+
+    private val scope = CoroutineScope(Dispatchers.Default)
+    private val logger = KotlinLogging.logger {}
+    lateinit var ipv8: IPv8
+
+    fun run() {
+        startIpv8()
+    }
+
+    private fun createConnectionCommunity(): OverlayConfiguration<ConnectionCommunity> {
+        // Add no walkers on purpose.
+        return OverlayConfiguration(
+            Overlay.Factory(ConnectionCommunity::class.java), listOf()
+        )
+    }
+
+    private fun startIpv8() {
+        val myKey = JavaCryptoProvider.generateKey()
+        val myPeer = Peer(myKey)
+        val udpEndpoint = UdpEndpoint(8090, InetAddress.getByName("0.0.0.0"))
+        val endpoint = EndpointAggregator(udpEndpoint, null)
+
+        val config = IPv8Configuration(
+            overlays = listOf(
+                createConnectionCommunity()
+            ), walkerInterval = 1.0
+        )
+
+        this.ipv8 = IPv8(endpoint, config, myPeer)
+        this.ipv8.start()
+
+        scope.launch {
+            while (true) {
+                for ((_, overlay) in ipv8.overlays) {
+                    printPeersInfo(overlay)
+                }
+                logger.info("===")
+                delay(5000)
+            }
+        }
+
+        while (ipv8.isStarted()) {
+            Thread.sleep(1000)
+        }
+    }
+
+    private fun printPeersInfo(overlay: Overlay) {
+        val peers = overlay.getPeers()
+        logger.info(overlay::class.simpleName + ": ${peers.size} peers")
+        for (peer in peers) {
+            val avgPing = peer.getAveragePing()
+            val lastRequest = peer.lastRequest
+            val lastResponse = peer.lastResponse
+
+            val lastRequestStr =
+                if (lastRequest != null) "" + ((Date().time - lastRequest.time) / 1000.0).roundToInt() + " s" else "?"
+
+            val lastResponseStr =
+                if (lastResponse != null) "" + ((Date().time - lastResponse.time) / 1000.0).roundToInt() + " s" else "?"
+
+            val avgPingStr = if (!avgPing.isNaN()) "" + (avgPing * 1000).roundToInt() + " ms" else "? ms"
+            logger.info("${peer.mid} (S: ${lastRequestStr}, R: ${lastResponseStr}, ${avgPingStr})")
+        }
+    }
+}
+
+fun main(): Unit = runBlocking {
+    // Start two peers
+    val peer0 = Application()
+    val peer1 = Application()
+
+    val scope = CoroutineScope(Dispatchers.Default)
+
+    scope.launch { peer0.run() }
+    scope.launch { peer1.run() }
+
+    // Wait for the peers to start
+    delay(1000)
+
+    // Walk to each other
+    val peer0Address = peer0.ipv8.getOverlay<ConnectionCommunity>()!!.myEstimatedLan
+    val peer1Address = peer1.ipv8.getOverlay<ConnectionCommunity>()!!.myEstimatedLan
+
+    peer0.ipv8.getOverlay<ConnectionCommunity>()!!.walkTo(peer1Address)
+    peer1.ipv8.getOverlay<ConnectionCommunity>()!!.walkTo(peer0Address)
+
+    // Wait forever
+    delay(Long.MAX_VALUE)
+}