Cleaned up how we interact with the storage system. Simplified storage configuration/init
This commit is contained in:
parent
b18fccc867
commit
f4e451d917
@ -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
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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))
|
||||
}
|
||||
|
||||
|
@ -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() {}
|
||||
}
|
@ -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()
|
||||
}
|
||||
}
|
@ -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()
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user