Cleaned up how we interact with the storage system. Simplified storage configuration/init

This commit is contained in:
nathan 2020-09-15 17:08:21 +02:00
parent b18fccc867
commit f4e451d917
6 changed files with 150 additions and 303 deletions

View File

@ -24,10 +24,8 @@ import dorkbox.network.aeron.CoroutineSleepingMillisIdleStrategy
import dorkbox.network.exceptions.ClientException import dorkbox.network.exceptions.ClientException
import dorkbox.network.exceptions.ServerException import dorkbox.network.exceptions.ServerException
import dorkbox.network.serialization.Serialization import dorkbox.network.serialization.Serialization
import dorkbox.network.storage.PropertyStore
import dorkbox.network.storage.SettingsStore import dorkbox.network.storage.SettingsStore
import dorkbox.os.OS import dorkbox.os.OS
import dorkbox.util.storage.StorageBuilder
import dorkbox.util.storage.StorageSystem import dorkbox.util.storage.StorageSystem
import io.aeron.driver.Configuration import io.aeron.driver.Configuration
import io.aeron.driver.MediaDriver import io.aeron.driver.MediaDriver
@ -226,18 +224,11 @@ open class Configuration {
} }
/** /**
* Allows the end user to change how endpoint settings are stored. For example, a custom database instead of the default. * Allows the end user to change how endpoint settings are stored.
*
* For example, a custom database instead of the default, in-memory storage. Another built-in option is StorageSystem.Disk()
*/ */
var settingsStore: SettingsStore = PropertyStore() var settingsStore: SettingsStore = SettingsStore(StorageSystem.Memory())
set(value) {
require(context == null) { errorMessage }
field = value
}
/**
* Specify the type of storage used for the endpoint settings , the options are Disk and Memory
*/
var settingsStorageSystem: StorageBuilder = StorageSystem.Memory()
set(value) { set(value) {
require(context == null) { errorMessage } require(context == null) { errorMessage }
field = value field = value

View File

@ -34,6 +34,7 @@ import dorkbox.network.serialization.Serialization
import dorkbox.network.storage.SettingsStore import dorkbox.network.storage.SettingsStore
import dorkbox.util.NamedThreadFactory import dorkbox.util.NamedThreadFactory
import dorkbox.util.exceptions.SecurityException import dorkbox.util.exceptions.SecurityException
import dorkbox.util.storage.StorageSystem
import io.aeron.Aeron import io.aeron.Aeron
import io.aeron.Publication import io.aeron.Publication
import io.aeron.driver.MediaDriver import io.aeron.driver.MediaDriver
@ -124,7 +125,13 @@ internal constructor(val type: Class<*>, internal val config: Configuration) : A
// we have to be able to specify WHAT property store we want to use, since it can change! // we have to be able to specify WHAT property store we want to use, since it can change!
settingsStore = config.settingsStore settingsStore = config.settingsStore
settingsStore.init(serialization, config.settingsStorageSystem.build()) settingsStore.init()
when (val builder = settingsStore.builder) {
is StorageSystem.DiskBuilder -> logger.info("Disk storage system initialized at: '${builder.file}'")
is StorageSystem.MemoryBuilder -> logger.info("Memory storage system initialized")
else -> logger.info("${builder::class.java.simpleName} storage system initialized")
}
crypto = CryptoManagement(logger, settingsStore, type, config) crypto = CryptoManagement(logger, settingsStore, type, config)

View File

@ -408,7 +408,7 @@ open class Serialization(private val references: Boolean = true, private val fac
return false return false
} }
settingsStore.getSerializationTypes().forEach { settingsStore.getSerializationRegistrations().forEach {
classesToRegister.add(ClassRegistration3(it)) classesToRegister.add(ClassRegistration3(it))
} }

View File

@ -1,73 +0,0 @@
/*
* Copyright 2020 dorkbox, llc
*
* Licensed 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 dorkbox.network.storage
import dorkbox.network.serialization.Serialization
import dorkbox.util.exceptions.SecurityException
import dorkbox.util.storage.Storage
import java.net.InetAddress
import java.security.SecureRandom
class NullSettingsStore : SettingsStore() {
private var serverSalt: ByteArray? = null
override fun init(serializationManager: Serialization, storage: Storage) {}
@Throws(SecurityException::class)
override fun getPrivateKey(): ByteArray {
TODO("not impl")
}
@Throws(SecurityException::class)
override fun savePrivateKey(serverPrivateKey: ByteArray) {
}
@Throws(SecurityException::class)
override fun getPublicKey(): ByteArray {
TODO("not impl")
}
@Throws(SecurityException::class)
override fun savePublicKey(serverPublicKey: ByteArray) {
}
override fun getSalt(): ByteArray {
if (serverSalt == null) {
val secureRandom = SecureRandom()
serverSalt = ByteArray(32)
secureRandom.nextBytes(serverSalt)
}
return serverSalt!!
}
@Throws(SecurityException::class)
override fun getRegisteredServerKey(hostAddress: InetAddress): ByteArray {
TODO("not impl")
}
@Throws(SecurityException::class)
override fun addRegisteredServerKey(hostAddress: InetAddress, publicKey: ByteArray) {
TODO("not impl")
}
@Throws(SecurityException::class)
override fun removeRegisteredServerKey(hostAddress: InetAddress): Boolean {
return true
}
override fun close() {}
}

View File

@ -1,178 +0,0 @@
/*
* Copyright 2020 dorkbox, llc
*
* Licensed 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 dorkbox.network.storage
import dorkbox.netUtil.IPv4
import dorkbox.netUtil.IPv6
import dorkbox.network.connection.CryptoManagement
import dorkbox.network.serialization.Serialization
import dorkbox.util.storage.Storage
import org.agrona.collections.Object2NullableObjectHashMap
import java.net.InetAddress
import java.security.SecureRandom
/**
* The property store is the DEFAULT type of store for the network stack.
*/
class PropertyStore : SettingsStore() {
private lateinit var storage: Storage
private lateinit var servers: Object2NullableObjectHashMap<InetAddress, DB_Server>
/**
* Address 0.0.0.0 or ::0 may be used as a source address for this host on this network.
*
* Because we assigned BOTH to the same thing, it doesn't matter which one we use
*/
private val ipv4Host = IPv4.WILDCARD
private val ipv6Host = IPv6.WILDCARD
/**
* Method of preference for creating/getting this connection store.
*
* @param serializationManager this is the serialization used for saving objects into the storage database
*/
override fun init(serializationManager: Serialization, storage: Storage) {
this.storage = storage
servers = this.storage.get(DB_Server.STORAGE_KEY, Object2NullableObjectHashMap())
// this will always be null and is here to help people that copy/paste code
var localServer = servers[ipv4Host]
if (localServer == null) {
localServer = DB_Server()
servers[ipv4Host] = localServer
// have to always specify what we are saving
this.storage.put(DB_Server.STORAGE_KEY, servers)
}
if (servers[ipv6Host] == null) {
servers[ipv6Host] = localServer
// have to always specify what we are saving
this.storage.put(DB_Server.STORAGE_KEY, servers)
}
}
/**
* Simple, property based method to getting the private key of the server
*/
@Synchronized
override fun getPrivateKey(): ByteArray? {
checkAccess(CryptoManagement::class.java)
return servers[ipv4Host]!!.privateKey
}
/**
* Simple, property based method for saving the private key of the server
*/
@Synchronized
override fun savePrivateKey(serverPrivateKey: ByteArray) {
checkAccess(CryptoManagement::class.java)
servers[ipv4Host]!!.privateKey = serverPrivateKey
// have to always specify what we are saving
storage.put(DB_Server.STORAGE_KEY, servers)
}
/**
* Simple, property based method to getting the public key of the server
*/
@Synchronized
override fun getPublicKey(): ByteArray? {
return servers[ipv4Host]!!.publicKey
}
/**
* Simple, property based method for saving the public key of the server
*/
@Synchronized
override fun savePublicKey(serverPublicKey: ByteArray) {
checkAccess(CryptoManagement::class.java)
servers[ipv4Host]!!.publicKey = serverPublicKey
// have to always specify what we are saving
storage.put(DB_Server.STORAGE_KEY, servers)
}
/**
* Simple, property based method to getting the server salt
*/
@Synchronized
override fun getSalt(): ByteArray {
val localServer = servers[ipv4Host]
var salt = localServer!!.salt
// we don't care who gets the server salt
if (salt == null) {
val secureRandom = SecureRandom()
// server salt is used to salt usernames and other various connection handshake parameters
val bytes = ByteArray(256)
secureRandom.nextBytes(bytes)
salt = bytes
localServer.salt = bytes
// have to always specify what we are saving
storage.put(DB_Server.STORAGE_KEY, servers)
}
return salt
}
/**
* Simple, property based method to getting a connected computer by host IP address
*/
@Synchronized
override fun getRegisteredServerKey(hostAddress: InetAddress): ByteArray? {
return servers[hostAddress]?.publicKey
}
/**
* Saves a connected computer by host IP address and public key
*/
@Synchronized
override fun addRegisteredServerKey(hostAddress: InetAddress, publicKey: ByteArray) {
// checkAccess(RegistrationWrapper.class);
var db_server = servers[hostAddress]
if (db_server == null) {
db_server = DB_Server()
}
db_server.publicKey = publicKey
servers[hostAddress] = db_server
// have to always specify what we are saving
storage.put(DB_Server.STORAGE_KEY, servers)
}
/**
* Deletes a registered computer by host IP address
*/
@Synchronized
override fun removeRegisteredServerKey(hostAddress: InetAddress): Boolean {
// checkAccess(RegistrationWrapper.class);
val db_server = servers.remove(hostAddress)
// have to always specify what we are saving
storage.put(DB_Server.STORAGE_KEY, servers)
return db_server != null
}
override fun close() {
storage.close()
}
}

View File

@ -15,89 +15,189 @@
*/ */
package dorkbox.network.storage package dorkbox.network.storage
import dorkbox.network.serialization.Serialization import dorkbox.netUtil.IPv4
import dorkbox.netUtil.IPv6
import dorkbox.network.connection.CryptoManagement
import dorkbox.util.bytes.ByteArrayWrapper import dorkbox.util.bytes.ByteArrayWrapper
import dorkbox.util.exceptions.SecurityException import dorkbox.util.exceptions.SecurityException
import dorkbox.util.storage.Storage import dorkbox.util.storage.Storage
import dorkbox.util.storage.StorageBuilder
import org.agrona.collections.Object2NullableObjectHashMap
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import java.net.InetAddress import java.net.InetAddress
import java.util.* import java.security.SecureRandom
/** /**
* This class provides a way for the network stack to use the server's database, instead of a property file (which it uses when stand-alone) * This class provides a way for the network stack to use the server's database, instead of a property file (which it uses when stand-alone)
* *
*
* A static "create" method, with any number of parameters, is required to create this class (which is done via reflection) * A static "create" method, with any number of parameters, is required to create this class (which is done via reflection)
*/ */
abstract class SettingsStore : AutoCloseable { open class SettingsStore(internal val builder: StorageBuilder) : AutoCloseable {
/** private lateinit var storage: Storage
* Initialize the settingsStore with the provided serialization manager. private lateinit var servers: Object2NullableObjectHashMap<InetAddress, DB_Server>
*/
abstract fun init(serializationManager: Serialization, storage: Storage)
fun getSerializationTypes(): List<Class<out Any>> { /**
* Address 0.0.0.0 or ::0 may be used as a source address for this host on this network.
*
* Because we assigned BOTH to the same thing, it doesn't matter which one we use
*/
private val ipv4Host = IPv4.WILDCARD
private val ipv6Host = IPv6.WILDCARD
/**
* Initialize using the provided serialization manager.
*/
fun init() {
this.storage = builder.build()
servers = this.storage.get(DB_Server.STORAGE_KEY, Object2NullableObjectHashMap())
// this will always be null and is here to help people that copy/paste code
var localServer = servers[ipv4Host]
if (localServer == null) {
localServer = DB_Server()
servers[ipv4Host] = localServer
// have to always specify what we are saving
this.storage.put(DB_Server.STORAGE_KEY, servers)
}
if (servers[ipv6Host] == null) {
servers[ipv6Host] = localServer
// have to always specify what we are saving
this.storage.put(DB_Server.STORAGE_KEY, servers)
}
}
/**
* Used to register the different serialization registrations for this store
*/
fun getSerializationRegistrations(): List<Class<out Any>> {
// make sure our custom types are registered // make sure our custom types are registered
// only register if not ALREADY initialized, since we can initialize in the server and in the client. This creates problems if // only register if not ALREADY initialized, since we can initialize in the server and in the client. This creates problems if
// running inside the same JVM // running inside the same JVM
return listOf(HashMap::class.java, return listOf(Object2NullableObjectHashMap::class.java,
ByteArrayWrapper::class.java, ByteArrayWrapper::class.java,
DB_Server::class.java DB_Server::class.java
) )
} }
/** /**
* Simple, property based method for saving the private key of the server * @return the private key of the server
*/ */
@Throws(SecurityException::class) @Synchronized
abstract fun getPrivateKey(): ByteArray? fun getPrivateKey(): ByteArray? {
checkAccess(CryptoManagement::class.java)
return servers[ipv4Host]!!.privateKey
}
/** /**
* Simple, property based method for saving the private key of the server * Saves the private key of the server
*/ */
@Throws(SecurityException::class) @Synchronized
abstract fun savePrivateKey(serverPrivateKey: ByteArray) fun savePrivateKey(serverPrivateKey: ByteArray) {
checkAccess(CryptoManagement::class.java)
servers[ipv4Host]!!.privateKey = serverPrivateKey
// have to always specify what we are saving
storage.put(DB_Server.STORAGE_KEY, servers)
}
/** /**
* Simple, property based method to getting the public key of the server * @return the public key of the server
*/ */
@Throws(SecurityException::class) @Synchronized
abstract fun getPublicKey(): ByteArray? fun getPublicKey(): ByteArray? {
return servers[ipv4Host]!!.publicKey
}
/** /**
* Simple, property based method for saving the public key of the server * Saves the public key of the server
*/ */
@Throws(SecurityException::class) @Synchronized
abstract fun savePublicKey(serverPublicKey: ByteArray) fun savePublicKey(serverPublicKey: ByteArray) {
checkAccess(CryptoManagement::class.java)
servers[ipv4Host]!!.publicKey = serverPublicKey
// have to always specify what we are saving
storage.put(DB_Server.STORAGE_KEY, servers)
}
/** /**
* @return the server salt * @return the server salt
*/ */
abstract fun getSalt(): ByteArray @Synchronized
fun getSalt(): ByteArray {
val localServer = servers[ipv4Host]
var salt = localServer!!.salt
// we don't care who gets the server salt
if (salt == null) {
val secureRandom = SecureRandom()
// server salt is used to salt usernames and other various connection handshake parameters
val bytes = ByteArray(256)
secureRandom.nextBytes(bytes)
salt = bytes
localServer.salt = bytes
// have to always specify what we are saving
storage.put(DB_Server.STORAGE_KEY, servers)
}
return salt
}
/** /**
* Gets a previously registered computer by host IP address * Gets a previously registered computer by host IP address
*/ */
@Throws(SecurityException::class) @Synchronized
abstract fun getRegisteredServerKey(hostAddress: InetAddress): ByteArray? fun getRegisteredServerKey(hostAddress: InetAddress): ByteArray? {
return servers[hostAddress]?.publicKey
}
/** /**
* Saves a registered computer by host IP address and public key * Saves a connected computer by host IP address and public key
*/ */
@Throws(SecurityException::class) @Synchronized
abstract fun addRegisteredServerKey(hostAddress: InetAddress, publicKey: ByteArray) fun addRegisteredServerKey(hostAddress: InetAddress, publicKey: ByteArray) {
// checkAccess(RegistrationWrapper.class);
var db_server = servers[hostAddress]
if (db_server == null) {
db_server = DB_Server()
}
db_server.publicKey = publicKey
servers[hostAddress] = db_server
// have to always specify what we are saving
storage.put(DB_Server.STORAGE_KEY, servers)
}
/** /**
* Deletes a registered computer by host IP address * Deletes a registered computer by host IP address
* *
* @return true if successful, false if there were problems (or it didn't exist) * @return true if successful, false if there were problems (or it didn't exist)
*/ */
@Throws(SecurityException::class) @Synchronized
abstract fun removeRegisteredServerKey(hostAddress: InetAddress): Boolean fun removeRegisteredServerKey(hostAddress: InetAddress): Boolean {
// checkAccess(RegistrationWrapper.class);
val db_server = servers.remove(hostAddress)
// have to always specify what we are saving
storage.put(DB_Server.STORAGE_KEY, servers)
return db_server != null
}
/** /**
* Take the proper steps to close the storage system. * Take the proper steps to close the storage system.
*/ */
abstract override fun close() override fun close() {
storage.close()
}
/** /**