forked from jshiffer/matterbridge
202 lines
4.8 KiB
Go
202 lines
4.8 KiB
Go
package config
|
|
|
|
import (
|
|
"bytes"
|
|
"io"
|
|
"io/ioutil"
|
|
|
|
"github.com/xordataexchange/crypt/backend"
|
|
"github.com/xordataexchange/crypt/backend/consul"
|
|
"github.com/xordataexchange/crypt/backend/etcd"
|
|
"github.com/xordataexchange/crypt/encoding/secconf"
|
|
)
|
|
|
|
type KVPair struct {
|
|
backend.KVPair
|
|
}
|
|
|
|
type KVPairs []*KVPair
|
|
|
|
type configManager struct {
|
|
keystore []byte
|
|
store backend.Store
|
|
}
|
|
|
|
// A ConfigManager retrieves and decrypts configuration from a key/value store.
|
|
type ConfigManager interface {
|
|
Get(key string) ([]byte, error)
|
|
List(key string) (KVPairs, error)
|
|
Set(key string, value []byte) error
|
|
Watch(key string, stop chan bool) <-chan *Response
|
|
}
|
|
|
|
type standardConfigManager struct {
|
|
store backend.Store
|
|
}
|
|
|
|
func NewStandardConfigManager(client backend.Store) (ConfigManager, error) {
|
|
return standardConfigManager{client}, nil
|
|
}
|
|
|
|
func NewConfigManager(client backend.Store, keystore io.Reader) (ConfigManager, error) {
|
|
bytes, err := ioutil.ReadAll(keystore)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return configManager{bytes, client}, nil
|
|
}
|
|
|
|
// NewStandardEtcdConfigManager returns a new ConfigManager backed by etcd.
|
|
func NewStandardEtcdConfigManager(machines []string) (ConfigManager, error) {
|
|
store, err := etcd.New(machines)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return NewStandardConfigManager(store)
|
|
}
|
|
|
|
// NewStandardConsulConfigManager returns a new ConfigManager backed by consul.
|
|
func NewStandardConsulConfigManager(machines []string) (ConfigManager, error) {
|
|
store, err := consul.New(machines)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return NewStandardConfigManager(store)
|
|
}
|
|
|
|
// NewEtcdConfigManager returns a new ConfigManager backed by etcd.
|
|
// Data will be encrypted.
|
|
func NewEtcdConfigManager(machines []string, keystore io.Reader) (ConfigManager, error) {
|
|
store, err := etcd.New(machines)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return NewConfigManager(store, keystore)
|
|
}
|
|
|
|
// NewConsulConfigManager returns a new ConfigManager backed by consul.
|
|
// Data will be encrypted.
|
|
func NewConsulConfigManager(machines []string, keystore io.Reader) (ConfigManager, error) {
|
|
store, err := consul.New(machines)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return NewConfigManager(store, keystore)
|
|
}
|
|
|
|
// Get retrieves and decodes a secconf value stored at key.
|
|
func (c configManager) Get(key string) ([]byte, error) {
|
|
value, err := c.store.Get(key)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return secconf.Decode(value, bytes.NewBuffer(c.keystore))
|
|
}
|
|
|
|
// Get retrieves a value stored at key.
|
|
// convenience function, no additional value provided over
|
|
// `etcdctl`
|
|
func (c standardConfigManager) Get(key string) ([]byte, error) {
|
|
value, err := c.store.Get(key)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return value, err
|
|
}
|
|
|
|
// List retrieves and decodes all secconf value stored under key.
|
|
func (c configManager) List(key string) (KVPairs, error) {
|
|
list, err := c.store.List(key)
|
|
retList := make(KVPairs, len(list))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
for i, kv := range list {
|
|
retList[i].Key = kv.Key
|
|
retList[i].Value, err = secconf.Decode(kv.Value, bytes.NewBuffer(c.keystore))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
return retList, nil
|
|
}
|
|
|
|
// List retrieves all values under key.
|
|
// convenience function, no additional value provided over
|
|
// `etcdctl`
|
|
func (c standardConfigManager) List(key string) (KVPairs, error) {
|
|
list, err := c.store.List(key)
|
|
retList := make(KVPairs, len(list))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
for i, kv := range list {
|
|
retList[i].Key = kv.Key
|
|
retList[i].Value = kv.Value
|
|
}
|
|
return retList, err
|
|
}
|
|
|
|
// Set will put a key/value into the data store
|
|
// and encode it with secconf
|
|
func (c configManager) Set(key string, value []byte) error {
|
|
encodedValue, err := secconf.Encode(value, bytes.NewBuffer(c.keystore))
|
|
if err == nil {
|
|
err = c.store.Set(key, encodedValue)
|
|
}
|
|
return err
|
|
}
|
|
|
|
// Set will put a key/value into the data store
|
|
func (c standardConfigManager) Set(key string, value []byte) error {
|
|
err := c.store.Set(key, value)
|
|
return err
|
|
}
|
|
|
|
type Response struct {
|
|
Value []byte
|
|
Error error
|
|
}
|
|
|
|
func (c configManager) Watch(key string, stop chan bool) <-chan *Response {
|
|
resp := make(chan *Response, 0)
|
|
backendResp := c.store.Watch(key, stop)
|
|
go func() {
|
|
for {
|
|
select {
|
|
case <-stop:
|
|
return
|
|
case r := <-backendResp:
|
|
if r.Error != nil {
|
|
resp <- &Response{nil, r.Error}
|
|
continue
|
|
}
|
|
value, err := secconf.Decode(r.Value, bytes.NewBuffer(c.keystore))
|
|
resp <- &Response{value, err}
|
|
}
|
|
}
|
|
}()
|
|
return resp
|
|
}
|
|
|
|
func (c standardConfigManager) Watch(key string, stop chan bool) <-chan *Response {
|
|
resp := make(chan *Response, 0)
|
|
backendResp := c.store.Watch(key, stop)
|
|
go func() {
|
|
for {
|
|
select {
|
|
case <-stop:
|
|
return
|
|
case r := <-backendResp:
|
|
if r.Error != nil {
|
|
resp <- &Response{nil, r.Error}
|
|
continue
|
|
}
|
|
resp <- &Response{r.Value, nil}
|
|
}
|
|
}
|
|
}()
|
|
return resp
|
|
}
|