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.ServerException
import dorkbox.network.serialization.Serialization
import dorkbox.network.storage.PropertyStore
import dorkbox.network.storage.SettingsStore
import dorkbox.os.OS
import dorkbox.util.storage.StorageBuilder
import dorkbox.util.storage.StorageSystem
import io.aeron.driver.Configuration
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()
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()
var settingsStore: SettingsStore = SettingsStore(StorageSystem.Memory())
set(value) {
require(context == null) { errorMessage }
field = value

View File

@ -34,6 +34,7 @@ import dorkbox.network.serialization.Serialization
import dorkbox.network.storage.SettingsStore
import dorkbox.util.NamedThreadFactory
import dorkbox.util.exceptions.SecurityException
import dorkbox.util.storage.StorageSystem
import io.aeron.Aeron
import io.aeron.Publication
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!
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)

View File

@ -408,7 +408,7 @@ open class Serialization(private val references: Boolean = true, private val fac
return false
}
settingsStore.getSerializationTypes().forEach {
settingsStore.getSerializationRegistrations().forEach {
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
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.exceptions.SecurityException
import dorkbox.util.storage.Storage
import dorkbox.util.storage.StorageBuilder
import org.agrona.collections.Object2NullableObjectHashMap
import org.slf4j.LoggerFactory
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)
*
*
* A static "create" method, with any number of parameters, is required to create this class (which is done via reflection)
*/
abstract class SettingsStore : AutoCloseable {
/**
* Initialize the settingsStore with the provided serialization manager.
*/
abstract fun init(serializationManager: Serialization, storage: Storage)
open class SettingsStore(internal val builder: StorageBuilder) : AutoCloseable {
private lateinit var storage: Storage
private lateinit var servers: Object2NullableObjectHashMap<InetAddress, DB_Server>
fun getSerializationTypes(): List<Class<out Any>> {
// 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
// running inside the same JVM
return listOf(HashMap::class.java,
ByteArrayWrapper::class.java,
DB_Server::class.java
)
/**
* 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)
}
}
/**
* Simple, property based method for saving the private key of the server
* Used to register the different serialization registrations for this store
*/
@Throws(SecurityException::class)
abstract fun getPrivateKey(): ByteArray?
fun getSerializationRegistrations(): List<Class<out Any>> {
// 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
// running inside the same JVM
return listOf(Object2NullableObjectHashMap::class.java,
ByteArrayWrapper::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)
abstract fun savePrivateKey(serverPrivateKey: ByteArray)
@Synchronized
fun getPrivateKey(): ByteArray? {
checkAccess(CryptoManagement::class.java)
return servers[ipv4Host]!!.privateKey
}
/**
* Simple, property based method to getting the public key of the server
* Saves the private key of the server
*/
@Throws(SecurityException::class)
abstract fun getPublicKey(): ByteArray?
@Synchronized
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 for saving the public key of the server
* @return the public key of the server
*/
@Throws(SecurityException::class)
abstract fun savePublicKey(serverPublicKey: ByteArray)
@Synchronized
fun getPublicKey(): ByteArray? {
return servers[ipv4Host]!!.publicKey
}
/**
* Saves the public key of the server
*/
@Synchronized
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
*/
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
*/
@Throws(SecurityException::class)
abstract fun getRegisteredServerKey(hostAddress: InetAddress): ByteArray?
@Synchronized
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)
abstract fun addRegisteredServerKey(hostAddress: InetAddress, publicKey: ByteArray)
@Synchronized
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
*
* @return true if successful, false if there were problems (or it didn't exist)
*/
@Throws(SecurityException::class)
abstract fun removeRegisteredServerKey(hostAddress: InetAddress): Boolean
@Synchronized
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.
*/
abstract override fun close()
override fun close() {
storage.close()
}
/**