constellation/debugd/internal/debugd/info/info.go
2023-01-25 09:58:56 +01:00

128 lines
2.6 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
Copyright (c) Edgeless Systems GmbH
SPDX-License-Identifier: AGPL-3.0-only
*/
// Package info implements the info map that is
// used to distribute keyvalue pair between debugd instances.
package info
import (
"errors"
"sync"
servicepb "github.com/edgelesssys/constellation/v2/debugd/service"
)
// Map is a thread-safe map of info, with triggers that are run
// when the map is set.
type Map struct {
m map[string]string
received bool
mux sync.RWMutex
onReceiveTrigger []func(*Map)
}
// NewMap creates a new Map object.
func NewMap() *Map {
return &Map{
m: make(map[string]string),
}
}
// Received returns true if the info map has been set.
func (i *Map) Received() bool {
i.mux.RLock()
defer i.mux.RUnlock()
return i.received
}
// Get returns the value of the info with the given key.
func (i *Map) Get(key string) (string, bool, error) {
i.mux.RLock()
defer i.mux.RUnlock()
if !i.received {
return "", false, errors.New("info not set yet")
}
value, ok := i.m[key]
return value, ok, nil
}
// GetCopy returns a copy of the info map.
func (i *Map) GetCopy() (map[string]string, error) {
i.mux.RLock()
defer i.mux.RUnlock()
if !i.received {
return nil, errors.New("info not set yet")
}
m := make(map[string]string)
for k, v := range i.m {
m[k] = v
}
return m, nil
}
// SetProto sets the info map to the given infos proto slice.
// It returns an error if the info map has already been set.
// Registered triggers are run after the info map is set.
func (i *Map) SetProto(infos []*servicepb.Info) error {
i.mux.Lock()
defer i.mux.Unlock()
if i.received {
return ErrInfoAlreadySet
}
infoMap := make(map[string]string)
for _, info := range infos {
infoMap[info.Key] = info.Value
}
i.m = infoMap
i.received = true
for _, trigger := range i.onReceiveTrigger {
trigger(i)
}
return nil
}
// RegisterOnReceiveTrigger registers a function that is called when the info map is set.
// The function mustn't block or be long-running.
func (i *Map) RegisterOnReceiveTrigger(f func(*Map)) {
i.mux.Lock()
defer i.mux.Unlock()
if i.received {
f(i)
return
}
i.onReceiveTrigger = append(i.onReceiveTrigger, f)
}
// GetProto returns the info map as a slice of info proto.
func (i *Map) GetProto() ([]*servicepb.Info, error) {
i.mux.RLock()
defer i.mux.RUnlock()
if !i.received {
return nil, errors.New("info not set yet")
}
var infos []*servicepb.Info
for key, value := range i.m {
infos = append(infos, &servicepb.Info{Key: key, Value: value})
}
return infos, nil
}
// ErrInfoAlreadySet is returned if the info map has already been set.
var ErrInfoAlreadySet = errors.New("info already set")