| // Package registrar provides name registration. It reserves a name to a given key. |
| package registrar |
| |
| import ( |
| "errors" |
| "sync" |
| ) |
| |
| var ( |
| // ErrNameReserved is an error which is returned when a name is requested to be reserved that already is reserved |
| ErrNameReserved = errors.New("name is reserved") |
| // ErrNameNotReserved is an error which is returned when trying to find a name that is not reserved |
| ErrNameNotReserved = errors.New("name is not reserved") |
| // ErrNoSuchKey is returned when trying to find the names for a key which is not known |
| ErrNoSuchKey = errors.New("provided key does not exist") |
| ) |
| |
| // Registrar stores indexes a list of keys and their registered names as well as indexes names and the key that they are registered to |
| // Names must be unique. |
| // Registrar is safe for concurrent access. |
| type Registrar struct { |
| idx map[string][]string |
| names map[string]string |
| mu sync.Mutex |
| } |
| |
| // NewRegistrar creates a new Registrar with the an empty index |
| func NewRegistrar() *Registrar { |
| return &Registrar{ |
| idx: make(map[string][]string), |
| names: make(map[string]string), |
| } |
| } |
| |
| // Reserve registers a key to a name |
| // Reserve is idempotent |
| // Attempting to reserve a key to a name that already exists results in an `ErrNameReserved` |
| // A name reservation is globally unique |
| func (r *Registrar) Reserve(name, key string) error { |
| r.mu.Lock() |
| defer r.mu.Unlock() |
| |
| if k, exists := r.names[name]; exists { |
| if k != key { |
| return ErrNameReserved |
| } |
| return nil |
| } |
| |
| r.idx[key] = append(r.idx[key], name) |
| r.names[name] = key |
| return nil |
| } |
| |
| // Release releases the reserved name |
| // Once released, a name can be reserved again |
| func (r *Registrar) Release(name string) { |
| r.mu.Lock() |
| defer r.mu.Unlock() |
| |
| key, exists := r.names[name] |
| if !exists { |
| return |
| } |
| |
| for i, n := range r.idx[key] { |
| if n != name { |
| continue |
| } |
| r.idx[key] = append(r.idx[key][:i], r.idx[key][i+1:]...) |
| break |
| } |
| |
| delete(r.names, name) |
| |
| if len(r.idx[key]) == 0 { |
| delete(r.idx, key) |
| } |
| } |
| |
| // Delete removes all reservations for the passed in key. |
| // All names reserved to this key are released. |
| func (r *Registrar) Delete(key string) { |
| r.mu.Lock() |
| for _, name := range r.idx[key] { |
| delete(r.names, name) |
| } |
| delete(r.idx, key) |
| r.mu.Unlock() |
| } |
| |
| // GetNames lists all the reserved names for the given key |
| func (r *Registrar) GetNames(key string) ([]string, error) { |
| r.mu.Lock() |
| defer r.mu.Unlock() |
| |
| names, exists := r.idx[key] |
| if !exists { |
| return nil, ErrNoSuchKey |
| } |
| return names, nil |
| } |
| |
| // Get returns the key that the passed in name is reserved to |
| func (r *Registrar) Get(name string) (string, error) { |
| r.mu.Lock() |
| key, exists := r.names[name] |
| r.mu.Unlock() |
| |
| if !exists { |
| return "", ErrNameNotReserved |
| } |
| return key, nil |
| } |
| |
| // GetAll returns all registered names |
| func (r *Registrar) GetAll() map[string][]string { |
| out := make(map[string][]string) |
| |
| r.mu.Lock() |
| // copy index into out |
| for id, names := range r.idx { |
| out[id] = names |
| } |
| r.mu.Unlock() |
| return out |
| } |