Skip to content

Commit

Permalink
Merge pull request #11 from eliona-smart-building-assistant/Periodica…
Browse files Browse the repository at this point in the history
…l-Configuration-Reading

Periodical configuration reading
  • Loading branch information
airvine-leicom authored Mar 23, 2023
2 parents 77bd5b0 + 4dc2f5d commit 2f6a68b
Show file tree
Hide file tree
Showing 7 changed files with 91 additions and 38 deletions.
2 changes: 1 addition & 1 deletion apiserver/model_configuration.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ type Configuration struct {
RequestTimeout int32 `json:"requestTimeout,omitempty"`

// Set to `true` by the app when running and to `false` when app is stopped
Active bool `json:"active,omitempty"`
Active *bool `json:"active,omitempty"`

// List of Eliona project ids for which this endpoint should collect data. For each project id all smart devices are automatically created as an asset in Eliona. The mapping between Eliona is stored as an asset mapping in the thingdust app and can be read with the SpaceMapping endpoint.
ProjIds *[]string `json:"projIds,omitempty"`
Expand Down
82 changes: 63 additions & 19 deletions app.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,69 @@ import (
"github.com/eliona-smart-building-assistant/go-utils/log"
)


func CheckConfigsandSetActiveState() {
configs, err := conf.GetConfigs(context.Background())
if err != nil {
log.Fatal("conf", "Couldn't read configs from DB: %v", err)
return
}

for _, config := range configs {
// Skip config if disabled and set inactive
if !conf.IsConfigEnabled(config) {
if conf.IsConfigActive(config) {
conf.SetConfigActiveState(config.ConfigId, false)
}
continue
}

// Signals that this config is active
if !conf.IsConfigActive(config) {
conf.SetConfigActiveState(config.ConfigId, true)
log.Info("conf", "Collecting initialized with Configuration %d:\n"+
"API Endpoint: %s\n"+
"API Key: %s\n"+
"Enable: %t\n"+
"Refresh Interval: %d\n"+
"Request Timeout: %d\n"+
"Active: %t\n"+
"Project IDs: %v\n",
config.ConfigId,
config.ApiEndpoint,
config.ApiKey,
*config.Enable,
config.RefreshInterval,
config.RequestTimeout,
*config.Active,
config.ProjIds)
}

// Runs the ReadNode. If the current node is currently running, skip the execution
// After the execution sleeps the configured timeout. During this timeout no further
// process for this config is started to read the data.
common.RunOnceWithParam(func(config apiserver.Configuration) {
log.Info("main", "Processing Spaces for Configuration with configId %d started", config.ConfigId)

processSpaces(config)

log.Info("main", "Processing Spaces for Configuration with configId %d finished", config.ConfigId)

time.Sleep(time.Second * time.Duration(config.RefreshInterval))
}, config, config.ConfigId)
}
}

// For each enabled configuration, processSpaces() performs Continuous Asset Creation
// for each project_id and space pair, and writes corresponding data to each asset.
func processSpaces(configId int64) {
config, spaces, err := fetchSpacesAndSetActiveState(configId)
func processSpaces(config apiserver.Configuration) {
spaces, err := fetchSpaces(config)
if err != nil {
return
}
if config.ProjIds != nil {
for _, projId := range *config.ProjIds {
log.Debug("projectid", "ProjId: %v", projId)
for spaceName := range spaces {
confSpace, err := getOrCreateMappingIfNecessary(config, projId, spaceName)
if err != nil {
Expand All @@ -54,29 +108,19 @@ func processSpaces(configId int64) {
}
}

func fetchSpacesAndSetActiveState(configId int64) (*apiserver.Configuration, thingdust.Spaces, error) {
config, err := conf.GetConfig(context.Background(), configId)
if err != nil {
log.Error("spaces", "Error reading configuration")
return nil, nil, err
}
if config.Enable == nil || !*config.Enable {
conf.SetConfigActiveState(config.ConfigId, false)
return nil, nil, err
}
conf.SetConfigActiveState(config.ConfigId, true)
func fetchSpaces(config apiserver.Configuration) (thingdust.Spaces, error) {
log.Debug("spaces", "Processing space with configID: %v", config.ConfigId)
request, err := http.NewRequestWithApiKey(config.ApiEndpoint + "/get_space_states", "X-API-KEY", config.ApiKey)
if err != nil {
log.Error("spaces", "Error with request: %v", err)
return nil, nil, err
return nil, err
}
spaces, err := http.Read[thingdust.Spaces](request, time.Duration(time.Duration.Seconds(1)), true)
if err != nil {
log.Error("spaces", "Error reading spaces: %v", err)
return nil, nil, err
return nil, err
}
return config, spaces, nil
return spaces, nil
}

func sendData(confSpace *apiserver.Space, spaces thingdust.Spaces, spaceName string) {
Expand All @@ -96,7 +140,7 @@ func sendData(confSpace *apiserver.Space, spaces thingdust.Spaces, spaceName str
}
}

func getOrCreateMappingIfNecessary(config *apiserver.Configuration, projId string, spaceName string) (*apiserver.Space, error) {
func getOrCreateMappingIfNecessary(config apiserver.Configuration, projId string, spaceName string) (*apiserver.Space, error) {
var confSpace *apiserver.Space
confSpace, err := conf.GetSpace(context.Background(), config.ConfigId, projId, spaceName)
if err != nil {
Expand Down Expand Up @@ -124,10 +168,10 @@ func getOrCreateMappingIfNecessary(config *apiserver.Configuration, projId strin
return confSpace, nil
}

func createAssetAndMapping(projId string, spaceName string, config *apiserver.Configuration) (*apiserver.Space, error) {
func createAssetAndMapping(projId string, spaceName string, config apiserver.Configuration) (*apiserver.Space, error) {
assetId, err := eliona.CreateNewAsset(projId, spaceName)
if err != nil {
log.Error("spaces", "Error when creating new asset")
log.Error("spaces", "Error when creating new asset: %v", err)
return nil, err
}
log.Debug("spaces", "AssetId %v assigned to space %v", assetId, spaceName)
Expand Down
18 changes: 16 additions & 2 deletions conf/conf.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ func apiConfigFromDbConfig(dbConfig *dbthingdust.Config) *apiserver.Configuratio
apiConfig.Enable = &dbConfig.Enable.Bool
apiConfig.RefreshInterval = dbConfig.RefreshInterval.Int32
apiConfig.RequestTimeout = dbConfig.RequestTimeout.Int32
apiConfig.Active = dbConfig.Active.Bool
apiConfig.Active = &dbConfig.Active.Bool
apiConfig.ProjIds = common.Ptr[[]string](dbConfig.ProjectIds)
return &apiConfig
}
Expand All @@ -157,7 +157,7 @@ func dbConfigFromApiConfig(apiConfig *apiserver.Configuration) *dbthingdust.Conf
dbConfig.Enable = null.BoolFromPtr(apiConfig.Enable)
dbConfig.RefreshInterval = null.Int32FromPtr(&apiConfig.RefreshInterval)
dbConfig.RequestTimeout = null.Int32FromPtr(&apiConfig.RequestTimeout)
dbConfig.Active = null.BoolFromPtr(&apiConfig.Active)
dbConfig.Active = null.BoolFromPtr(apiConfig.Active)
if apiConfig.ProjIds != nil {
dbConfig.ProjectIds = *apiConfig.ProjIds
}
Expand All @@ -171,3 +171,17 @@ func SetConfigActiveState(configID int64, state bool) (int64, error) {
dbthingdust.ConfigColumns.Active: state,
})
}

func IsConfigActive(config apiserver.Configuration) bool {
return config.Active == nil || *config.Active
}

func IsConfigEnabled(config apiserver.Configuration) bool {
return config.Enable == nil || *config.Enable
}

func SetAllConfigsInactive(ctx context.Context) (int64, error) {
return dbthingdust.Configs().UpdateAllG(ctx, dbthingdust.M{
dbthingdust.ConfigColumns.Active: false,
})
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ go 1.18
require (
github.com/eliona-smart-building-assistant/go-eliona v1.9.4
github.com/eliona-smart-building-assistant/go-eliona-api-client/v2 v2.4.8
github.com/eliona-smart-building-assistant/go-utils v1.0.17
github.com/eliona-smart-building-assistant/go-utils v1.0.18
github.com/friendsofgo/errors v0.9.2
github.com/gorilla/mux v1.8.0
github.com/volatiletech/null/v8 v8.1.2
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,8 @@ github.com/eliona-smart-building-assistant/go-eliona v1.9.4 h1:ejT0ekEp6itLXnSg9
github.com/eliona-smart-building-assistant/go-eliona v1.9.4/go.mod h1:ulSBkPPvjEXJBQEgZ+5/XLj/USrEFygj2EByr83f8dk=
github.com/eliona-smart-building-assistant/go-eliona-api-client/v2 v2.4.8 h1:nWKpz32tk5y/zY3cBpe9J1aAuH0R88JOGSAIQXYdURY=
github.com/eliona-smart-building-assistant/go-eliona-api-client/v2 v2.4.8/go.mod h1:AdhCjJsNuT2WA6HpC++Kf4SBO0ZDJhwc3QnYk59naFQ=
github.com/eliona-smart-building-assistant/go-utils v1.0.17 h1:bGNkuy2+/dja2nwH3Y9tBGi+5+MFqSrP6FLCLfBJLzQ=
github.com/eliona-smart-building-assistant/go-utils v1.0.17/go.mod h1:mDgXKlaqLWPdPu5QJVs7oxqRVqTKfgvmmqhMm1zFEyU=
github.com/eliona-smart-building-assistant/go-utils v1.0.18 h1:HwEmSKiMKyXVp2ZTMKOiluTdYzKsv8gX82CymfSTr+4=
github.com/eliona-smart-building-assistant/go-utils v1.0.18/go.mod h1:mDgXKlaqLWPdPu5QJVs7oxqRVqTKfgvmmqhMm1zFEyU=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
Expand Down
19 changes: 7 additions & 12 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,19 +41,14 @@ func main() {
conf.InitConfiguration,
eliona.InitEliona,
)
var functions []func()
functions = append(functions, listenApi)
configs, err := conf.GetConfigs(context.Background())
common.WaitForWithOs(
common.Loop(CheckConfigsandSetActiveState, time.Second),
listenApi,
)
// At the end set all configuration inactive
_, err := conf.SetAllConfigsInactive(context.Background())
if err != nil {
log.Error("Configurations", "Error retrieving configurations")
}
for _, config := range configs {
log.Debug("main", "Appending processSpaces() with configID: %v and refresh interval %v", config.ConfigId, config.RefreshInterval)
functions = append(functions, common.LoopWithParam(processSpaces, config.ConfigId, time.Duration(config.RefreshInterval)*time.Second))
}
common.WaitFor(functions...)
for _, config:= range configs {
conf.SetConfigActiveState(config.ConfigId, false)
log.Error("conf", "setting all configs inactive: %v", err)
}
log.Info("main", "Terminate the app.")
}
Expand Down
2 changes: 1 addition & 1 deletion openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ components:
type: boolean
readOnly: true
description: Set to `true` by the app when running and to `false` when app is stopped
nullable: false
nullable: true
projIds:
type: array
description: List of Eliona project ids for which this endpoint should collect data. For each project id all smart devices are automatically created as an asset in Eliona. The mapping between Eliona is stored as an asset mapping in the thingdust app and can be read with the SpaceMapping endpoint.
Expand Down

0 comments on commit 2f6a68b

Please sign in to comment.