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 }