pinecone manager config tweaks + more comments

This is a bit uglier, but in exchange we get thread safety so it'll have
to do.
This commit is contained in:
0x1a8510f2 2022-06-10 00:23:10 +01:00
parent f8b2a0e1f7
commit ca2976a142
Signed by: 0x1a8510f2
GPG Key ID: 1C692E355D76775D

View File

@ -3,11 +3,58 @@ package pineconemanager
import (
"context"
"crypto/ed25519"
"fmt"
"log"
"net/http"
"sync"
)
type pineconeManagerConfOption int
const (
// The private key for this pinecone peer; effectively its "identity".
CONF_PINECONE_IDENTITY pineconeManagerConfOption = iota
// A logger instance which is passed on to pinecone.
CONF_LOGGER
// The address to listen on for incoming pinecone connections. If this
// is an empty string, the node does not listen for connections and
// multicast is also disabled (so the node can only connect to peers
// outbound and cannot receive peer connections).
CONF_INBOUND_ADDR
// The address to listen on for inbound HTTP. This allows peers to connect
// to this node over websockets and exposes a debugging endpoint if enabled
// via `WebserverDebugPath`. Additional routes can be configured via
// `WebserverHandlers`. The webserver is disabled if this option is an empty
// string.
CONF_WEBSERVER_ADDR
// A path on the webserver to expose debugging information at. If this is an
// empty string, the node does not expose debugging information. This setting
// depends on the webserver being enabled.
CONF_WEBSERVER_DEBUG_PATH
// Whether to advertise this peer on the local network via multicast. This allows
// for peers to find each other locally but may require modifications to firewall
// rules. This option is always disabled if `InboundAddr` is not set.
CONF_USE_MULTICAST
// A list of protocols to advertise as supported by this node over pinecone.
CONF_WRAPPED_PROTOS
// A list of pinecone nodes with known addresses which this node can connect to
// for a more stable connection to the network.
CONF_STATIC_PEERS
// Additional handlers added to the webserver. This option exists mainly for
// efficiency, to allow nodes which also need to run a regular webserver to
// use the one used by pinecone for websockets. This saves allocating another
// port and other system resources.
CONF_WEBSERVER_HANDLERS
)
type pineconeManager struct {
// Once instances ensuring that each method is only executed once at a given time.
startOnce sync.Once
@ -19,53 +66,124 @@ type pineconeManager struct {
ctxCancel context.CancelFunc
ctxLock sync.RWMutex
// A lock for the below config options
confLock sync.RWMutex
//
// Config options
//
// The private key for this pinecone peer; effectively its "identity".
PineconeIdentity ed25519.PrivateKey
// A logger instance which is passed on to pinecone.
Logger log.Logger
// The address to listen on for incoming pinecone connections. If this
// is an empty string, the node does not listen for connections and
// multicast is also disabled (so the node can only connect to peers
// outbound and cannot receive peer connections).
InboundAddr string
// The address to listen on for inbound HTTP. This allows peers to connect
// to this node over websockets and exposes a debugging endpoint if enabled
// via `WebserverManholePath`. Additional routes can be configured via
// `WebserverHandlers`. The webserver is disabled if this option is an empty
// string.
WebserverAddr string
// A path on the webserver to expose debugging information at. If this is an
// empty string, the node does not expose debugging information. This setting
// depends on the webserver being enabled.
WebserverManholePath string
// Whether to advertise this peer on the local network via multicast. This allows
// for peers to find each other locally but may require modifications to firewall
// rules. This option is always disabled if `InboundAddr` is not set.
UseMulticast bool
// A list of protocols supported by this node over pinecone.
WrappedProtos []string
// A list of pinecone nodes with known addresses which this node can connect to
// for a more stable connection to the network.
StaticPeers []string
// Additional handlers added to the webserver. This option exists mainly for
// efficiency, to allow nodes which also need to run a regular webserver to
// use the one used by pinecone for websockets. This saves allocating another
// port and other system resources.
WebserverHandlers map[string]http.Handler
pineconeIdentity ed25519.PrivateKey
logger log.Logger
inboundAddr string
webserverAddr string
webserverDebugPath string
useMulticast bool
wrappedProtos []string
staticPeers []string
webserverHandlers map[string]http.Handler
}
// Read a config option of the pinecone manager. This is thread-safe.
func (pm *pineconeManager) ConfGet(confId pineconeManagerConfOption) (any, error) {
defer pm.confLock.RUnlock()
pm.confLock.RLock()
switch confId {
case CONF_PINECONE_IDENTITY:
return pm.pineconeIdentity, nil
case CONF_LOGGER:
return pm.logger, nil
case CONF_INBOUND_ADDR:
return pm.inboundAddr, nil
case CONF_WEBSERVER_ADDR:
return pm.inboundAddr, nil
case CONF_WEBSERVER_DEBUG_PATH:
return pm.webserverDebugPath, nil
case CONF_USE_MULTICAST:
return pm.useMulticast, nil
case CONF_WRAPPED_PROTOS:
return pm.wrappedProtos, nil
case CONF_STATIC_PEERS:
return pm.staticPeers, nil
case CONF_WEBSERVER_HANDLERS:
return pm.webserverHandlers, nil
default:
return nil, fmt.Errorf("config option %d does not exist", confId)
}
}
// Set a config option of the pinecone manager. This is thead-safe. Note that the
// manager will need to be restarted for changes to take effect.
func (pm *pineconeManager) ConfSet(confId pineconeManagerConfOption, confVal any) error {
defer pm.confLock.Unlock()
pm.confLock.Lock()
invalidTypeErr := fmt.Errorf("invalid value type for config %d", confId)
switch confId {
case CONF_PINECONE_IDENTITY:
if val, ok := confVal.(ed25519.PrivateKey); ok {
pm.pineconeIdentity = val
} else {
return invalidTypeErr
}
case CONF_LOGGER:
if val, ok := confVal.(log.Logger); ok {
pm.logger = val
} else {
return invalidTypeErr
}
case CONF_INBOUND_ADDR:
if val, ok := confVal.(string); ok {
pm.inboundAddr = val
} else {
return invalidTypeErr
}
case CONF_WEBSERVER_ADDR:
if val, ok := confVal.(string); ok {
pm.webserverAddr = val
} else {
return invalidTypeErr
}
case CONF_WEBSERVER_DEBUG_PATH:
if val, ok := confVal.(string); ok {
pm.webserverDebugPath = val
} else {
return invalidTypeErr
}
case CONF_USE_MULTICAST:
if val, ok := confVal.(bool); ok {
pm.useMulticast = val
} else {
return invalidTypeErr
}
case CONF_WRAPPED_PROTOS:
if val, ok := confVal.([]string); ok {
pm.wrappedProtos = val
} else {
return invalidTypeErr
}
case CONF_STATIC_PEERS:
if val, ok := confVal.([]string); ok {
pm.staticPeers = val
} else {
return invalidTypeErr
}
case CONF_WEBSERVER_HANDLERS:
if val, ok := confVal.(map[string]http.Handler); ok {
pm.webserverHandlers = val
} else {
return invalidTypeErr
}
default:
return fmt.Errorf("config option %d does not exist", confId)
}
return nil
}
// Start the pinecone manager as configured. This blocks while the
// manager is running but can be started in a goroutine.
func (pm *pineconeManager) Start() {
// Only execute this once at a time.
pm.startOnce.Do(func() {
@ -88,6 +206,7 @@ func (pm *pineconeManager) Start() {
})
}
// Stop the pinecone manager.
func (pm *pineconeManager) Stop() {
// Only execute this once at a time.
pm.stopOnce.Do(func() {
@ -112,6 +231,7 @@ func (pm *pineconeManager) Stop() {
})
}
// Restart the pinecone manager. Equivalent to calling Stop() and Start().
func (pm *pineconeManager) Restart() {
// Only execute this once at a time.
pm.restartOnce.Do(func() {
@ -125,6 +245,7 @@ func (pm *pineconeManager) Restart() {
})
}
// Check whether the pinecone manager is currently running.
func (pm *pineconeManager) IsRunning() bool {
// Make sure the context isn't modified while we're checking it.
defer pm.ctxLock.RUnlock()
@ -147,6 +268,8 @@ func (pm *pineconeManager) IsRunning() bool {
var initonce sync.Once
var pineconeManagerInstance *pineconeManager = nil
// Get the instance of the pinecone manager. This instance is shared for
// the entire program and successive calls return the existing instance.
func GetInstance() *pineconeManager {
// Create and initialise an instance of pineconeManager only once.
initonce.Do(func() {