Skip to content
This repository has been archived by the owner on Aug 1, 2023. It is now read-only.

Commit

Permalink
move discovery code to kotlin
Browse files Browse the repository at this point in the history
  • Loading branch information
atoulme committed Oct 16, 2022
1 parent ea88cd7 commit 1fd174b
Show file tree
Hide file tree
Showing 7 changed files with 277 additions and 270 deletions.
2 changes: 2 additions & 0 deletions scuttlebutt-discovery/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ dependencies {
implementation project(':scuttlebutt')
implementation 'com.google.guava:guava'
implementation 'io.vertx:vertx-core'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core'
implementation 'io.vertx:vertx-lang-kotlin-coroutines'
implementation 'org.slf4j:slf4j-api'

testImplementation project(':junit')
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.tueni.scuttlebutt.discovery

import io.vertx.core.Vertx
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.delay
import kotlinx.coroutines.runBlocking
import org.apache.tuweni.crypto.sodium.Sodium
import org.apache.tuweni.junit.VertxExtension
import org.apache.tuweni.junit.VertxInstance
import org.apache.tuweni.scuttlebutt.Identity
import org.apache.tuweni.scuttlebutt.discovery.LocalIdentity
import org.apache.tuweni.scuttlebutt.discovery.ScuttlebuttLocalDiscoveryService
import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.Assumptions
import org.junit.jupiter.api.BeforeAll
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith
import java.util.concurrent.atomic.AtomicReference

@ExtendWith(VertxExtension::class)
internal class ScuttlebuttLocalDiscoveryServiceTest {
companion object {
@JvmStatic
@BeforeAll
fun checkAvailable() {
Assumptions.assumeTrue(Sodium.isAvailable(), "Sodium native library is not available")
}
}

@Test
@Throws(Exception::class)
fun startStop(@VertxInstance vertx: Vertx) = runBlocking {
val service = ScuttlebuttLocalDiscoveryService(vertx, 0, 0, "127.0.0.1", "233.0.10.0")
service.start()
service.stop()
}

@Test
@Throws(Exception::class)
fun startStart(@VertxInstance vertx: Vertx) = runBlocking {
val service = ScuttlebuttLocalDiscoveryService(vertx, 0, 0, "127.0.0.1", "233.0.10.0")
service.start()
service.start()
service.stop()
}

@Test
@Throws(Exception::class)
fun invalidMulticastAddress(@VertxInstance vertx: Vertx) {
Assertions.assertThrows(
IllegalArgumentException::class.java
) {
ScuttlebuttLocalDiscoveryService(
vertx,
8008, 0,
"127.0.0.1",
"10.0.0.0"
)
}
}

@Test
@Throws(Exception::class)
fun stopFirst(@VertxInstance vertx: Vertx) = runBlocking {
val service = ScuttlebuttLocalDiscoveryService(vertx, 0, 0, "127.0.0.1", "233.0.10.0")
service.stop()
service.start()
service.stop()
}

@Test
@Throws(Exception::class)
fun broadcastAndListen(@VertxInstance vertx: Vertx?) = runBlocking {
val service = ScuttlebuttLocalDiscoveryService(vertx!!, 18008, 18009, "127.0.0.1", "127.0.0.1", false)
val service2 = ScuttlebuttLocalDiscoveryService(vertx, 18009, 18008, "127.0.0.1", "127.0.0.1", false)
try {
service2.start()
val ref = AtomicReference<LocalIdentity?>()
service2.addListener { newValue: LocalIdentity? ->
ref.set(
newValue
)
}
val localId = LocalIdentity("10.0.0.1", 10000, Identity.random())
service.addIdentityToBroadcastList(localId)
service.start()
service.broadcast()
delay(1000)
Assertions.assertNotNull(ref.get())
Assertions.assertEquals(localId, ref.get())
} finally {
listOf(
async {
service2.stop()
},
async {
service.stop()
}
).awaitAll()
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,21 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.tuweni.scuttlebutt.discovery

import com.google.common.net.InetAddresses
import org.apache.tuweni.bytes.Bytes
import org.apache.tuweni.crypto.sodium.Signature
import org.apache.tuweni.scuttlebutt.Identity
Expand All @@ -13,10 +28,35 @@ import java.util.regex.Pattern
*
*
* See https://ssbc.github.io/scuttlebutt-protocol-guide/ for a detailed description of this identity.
*
* @param addr the address associated with this local identity
* @param id the identity
* @throws NumberFormatException if the port does not represent a number
* @throws IllegalArgumentException if the port is not in the valid port range 0-65536
*/
class LocalIdentity(addr: InetSocketAddress, id: Identity) {
private val id: Identity
private val addr: InetSocketAddress
class LocalIdentity(val addr: InetSocketAddress, val id: Identity) {

companion object {
private val regexpPattern = Pattern.compile("^net:(.*):(.*)~shs:(.*)$")

/**
* Create a local identity from a String of the form net:IP address:port~shs:base64 of public key
*
* @param str the String to interpret
* @return the identity or null if the string doesn't match the format.
*/
@JvmStatic
fun fromString(str: String?): LocalIdentity? {
val result = regexpPattern.matcher(str)
return if (!result.matches()) {
null
} else LocalIdentity(
result.group(1),
result.group(2),
Identity.fromPublicKey(Signature.PublicKey.fromBytes(Bytes.fromBase64String(result.group(3))))
)
}
}

/**
* Constructor for a local identity
Expand All @@ -27,7 +67,7 @@ class LocalIdentity(addr: InetSocketAddress, id: Identity) {
* @throws NumberFormatException if the port does not represent a number
* @throws IllegalArgumentException if the port is not in the valid port range 0-65536
*/
constructor(ip: String?, port: String?, id: Identity) : this(ip, Integer.valueOf(port), id) {}
constructor(ip: String, port: String, id: Identity) : this(ip, Integer.valueOf(port), id)

/**
* Constructor for a local identity
Expand All @@ -37,21 +77,7 @@ class LocalIdentity(addr: InetSocketAddress, id: Identity) {
* @param id the identity
* @throws IllegalArgumentException if the port is not in the valid port range 0-65536
*/
constructor(ip: String?, port: Int, id: Identity) : this(InetSocketAddress(ip, port), id) {}

/**
* Constructor for a local identity
*
* @param addr the address associated with this local identity
* @param id the identity
* @throws NumberFormatException if the port does not represent a number
* @throws IllegalArgumentException if the port is not in the valid port range 0-65536
*/
init {
InetAddresses.forString(addr.hostString)
this.addr = addr
this.id = id
}
constructor(ip: String, port: Int, id: Identity) : this(InetSocketAddress(ip, port), id)

/**
* The canonical form of an invite
Expand All @@ -76,25 +102,4 @@ class LocalIdentity(addr: InetSocketAddress, id: Identity) {
override fun toString(): String {
return toCanonicalForm()
}

companion object {
private val regexpPattern = Pattern.compile("^net:(.*):(.*)~shs:(.*)$")

/**
* Create a local identity from a String of the form net:IP address:port~shs:base64 of public key
*
* @param str the String to interpret
* @return the identity or null if the string doesn't match the format.
*/
fun fromString(str: String?): LocalIdentity? {
val result = regexpPattern.matcher(str)
return if (!result.matches()) {
null
} else LocalIdentity(
result.group(1),
result.group(2),
Identity.fromPublicKey(Signature.PublicKey.fromBytes(Bytes.fromBase64String(result.group(3))))
)
}
}
}
Loading

0 comments on commit 1fd174b

Please sign in to comment.