github.com/safing/portbase@v0.19.5/database/controllers.go (about)

     1  package database
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"sync"
     7  
     8  	"github.com/safing/portbase/database/storage"
     9  )
    10  
    11  // StorageTypeInjected is the type of injected databases.
    12  const StorageTypeInjected = "injected"
    13  
    14  var (
    15  	controllers     = make(map[string]*Controller)
    16  	controllersLock sync.RWMutex
    17  )
    18  
    19  func getController(name string) (*Controller, error) {
    20  	if !initialized.IsSet() {
    21  		return nil, errors.New("database not initialized")
    22  	}
    23  
    24  	// return database if already started
    25  	controllersLock.RLock()
    26  	controller, ok := controllers[name]
    27  	controllersLock.RUnlock()
    28  	if ok {
    29  		return controller, nil
    30  	}
    31  
    32  	controllersLock.Lock()
    33  	defer controllersLock.Unlock()
    34  
    35  	if shuttingDown.IsSet() {
    36  		return nil, ErrShuttingDown
    37  	}
    38  
    39  	// get db registration
    40  	registeredDB, err := getDatabase(name)
    41  	if err != nil {
    42  		return nil, fmt.Errorf("could not start database %s: %w", name, err)
    43  	}
    44  
    45  	// Check if database is injected.
    46  	if registeredDB.StorageType == StorageTypeInjected {
    47  		return nil, fmt.Errorf("database storage is not injected")
    48  	}
    49  
    50  	// get location
    51  	dbLocation, err := getLocation(name, registeredDB.StorageType)
    52  	if err != nil {
    53  		return nil, fmt.Errorf("could not start database %s (type %s): %w", name, registeredDB.StorageType, err)
    54  	}
    55  
    56  	// start database
    57  	storageInt, err := storage.StartDatabase(name, registeredDB.StorageType, dbLocation)
    58  	if err != nil {
    59  		return nil, fmt.Errorf("could not start database %s (type %s): %w", name, registeredDB.StorageType, err)
    60  	}
    61  
    62  	controller = newController(registeredDB, storageInt, registeredDB.ShadowDelete)
    63  	controllers[name] = controller
    64  	return controller, nil
    65  }
    66  
    67  // InjectDatabase injects an already running database into the system.
    68  func InjectDatabase(name string, storageInt storage.Interface) (*Controller, error) {
    69  	controllersLock.Lock()
    70  	defer controllersLock.Unlock()
    71  
    72  	if shuttingDown.IsSet() {
    73  		return nil, ErrShuttingDown
    74  	}
    75  
    76  	_, ok := controllers[name]
    77  	if ok {
    78  		return nil, fmt.Errorf(`database "%s" already loaded`, name)
    79  	}
    80  
    81  	registryLock.Lock()
    82  	defer registryLock.Unlock()
    83  
    84  	// check if database is registered
    85  	registeredDB, ok := registry[name]
    86  	if !ok {
    87  		return nil, fmt.Errorf("database %q not registered", name)
    88  	}
    89  	if registeredDB.StorageType != StorageTypeInjected {
    90  		return nil, fmt.Errorf("database not of type %q", StorageTypeInjected)
    91  	}
    92  
    93  	controller := newController(registeredDB, storageInt, false)
    94  	controllers[name] = controller
    95  	return controller, nil
    96  }
    97  
    98  // Withdraw withdraws an injected database, but leaves the database registered.
    99  func (c *Controller) Withdraw() {
   100  	if c != nil && c.Injected() {
   101  		controllersLock.Lock()
   102  		defer controllersLock.Unlock()
   103  
   104  		delete(controllers, c.database.Name)
   105  	}
   106  }