diff --git a/app.go b/app.go index ef3e25f..49f70e6 100644 --- a/app.go +++ b/app.go @@ -18,6 +18,8 @@ package main import ( "booking-app/apiserver" "booking-app/apiservices" + "booking-app/conf" + "booking-app/eliona" "context" "net/http" @@ -28,6 +30,37 @@ import ( "github.com/eliona-smart-building-assistant/go-utils/log" ) +func manageOccupancy() { + common.RunOnce(func() { + if err := updateOccupancy(); err != nil { + return // Error is handled in the method itself. + } + }, 1) +} + +func updateOccupancy() error { + ctx := context.Background() + bookedAssets, err := conf.GetBookedAssetIDs(ctx) + if err != nil { + log.Error("conf", "getting booked asset IDs: %v", err) + return err + } + if err := eliona.SetAssetsBooked(true, bookedAssets); err != nil { + log.Error("eliona", "setting booked assets: %v", err) + return err + } + unbookedAssets, err := conf.GetUnbookedAssetIDs(ctx) + if err != nil { + log.Error("conf", "getting booked asset IDs: %v", err) + return err + } + if err := eliona.SetAssetsBooked(false, unbookedAssets); err != nil { + log.Error("eliona", "setting unbooked assets: %v", err) + return err + } + return nil +} + func initialization() { ctx := context.Background() diff --git a/conf/conf.go b/conf/conf.go index 30458a2..6fdf860 100644 --- a/conf/conf.go +++ b/conf/conf.go @@ -26,6 +26,7 @@ import ( "github.com/volatiletech/null/v8" "github.com/volatiletech/sqlboiler/v4/boil" + "github.com/volatiletech/sqlboiler/v4/queries" "github.com/volatiletech/sqlboiler/v4/queries/qm" ) @@ -181,3 +182,76 @@ func CancelEvent(ctx context.Context, eventID int64) error { return nil } + +// func GetCurrentEvents(ctx context.Context) ([]apiserver.Booking, error) { +// since := time.Now() +// until := since.Add(30 * time.Minute) +// events, err := appdb.Events( +// appdb.EventWhere.CancelledAt.IsNull(), +// appdb.EventWhere.EndTime.GTE(since), +// appdb.EventWhere.StartTime.LTE(until), +// ).AllG(ctx) +// if err != nil { +// return nil, fmt.Errorf("fetching events for asset: %v", err) +// } +// var apiBookings []apiserver.Booking +// for _, e := range events { +// b, err := dbEventToAPIBooking(ctx, *e) +// if err != nil { +// return nil, fmt.Errorf("dbEvent to API booking: %v", err) +// } +// apiBookings = append(apiBookings, b) +// } +// return apiBookings, nil +// } + +type AssetID struct { + AssetID int32 `boil:"asset_id"` +} + +func GetBookedAssetIDs(ctx context.Context) ([]int32, error) { + since := time.Now() + until := since.Add(30 * time.Minute) + var assetIDs []*AssetID + if err := queries. + RawG(` + SELECT DISTINCT er.asset_id + FROM booking.event_resource er + JOIN booking.event e ON e.id = er.event_id + WHERE e.cancelled_at IS NULL + AND e.start_time <= $1 + AND e.end_time >= $2 + `, until, since). + BindG(ctx, &assetIDs); err != nil { + return nil, fmt.Errorf("querying booked asset IDs: %v", err) + } + + ids := make([]int32, len(assetIDs)) + for i, assetID := range assetIDs { + ids[i] = assetID.AssetID + } + return ids, nil +} + +func GetUnbookedAssetIDs(ctx context.Context) ([]int32, error) { + since := time.Now() + until := since.Add(30 * time.Minute) + var assetIDs []*AssetID + if err := queries. + RawG(` + SELECT DISTINCT er.asset_id + FROM booking.event_resource er + JOIN booking.event e ON e.id = er.event_id + WHERE e.cancelled_at IS NOT NULL + OR e.start_time > $1 + OR e.end_time < $2 + `, until, since). + BindG(ctx, &assetIDs); err != nil { + return nil, fmt.Errorf("querying unbooked asset IDs: %v", err) + } + ids := make([]int32, len(assetIDs)) + for i, assetID := range assetIDs { + ids[i] = assetID.AssetID + } + return ids, nil +} diff --git a/eliona/data.go b/eliona/data.go new file mode 100644 index 0000000..e9f3054 --- /dev/null +++ b/eliona/data.go @@ -0,0 +1,46 @@ +// This file is part of the eliona project. +// Copyright © 2022 LEICOM iTEC AG. All Rights Reserved. +// ______ _ _ +// | ____| (_) +// | |__ | |_ ___ _ __ __ _ +// | __| | | |/ _ \| '_ \ / _` | +// | |____| | | (_) | | | | (_| | +// |______|_|_|\___/|_| |_|\__,_| +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING +// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NON INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +package eliona + +import ( + "fmt" + + "github.com/eliona-smart-building-assistant/go-eliona/asset" +) + +const ClientReference string = "booking-app" + +type BookableAsset struct { + Occupancy int `eliona:"occupancy" subtype:"input"` +} + +func SetAssetsBooked(booked bool, assetIDs []int32) error { + occupancy := 0 + if booked { + occupancy = 1 + } + for _, assetID := range assetIDs { + data := asset.Data{ + AssetId: assetID, + Data: BookableAsset{Occupancy: occupancy}, + ClientReference: ClientReference, + } + if err := asset.UpsertAssetDataIfAssetExists(data); err != nil { + return fmt.Errorf("upserting data: %v", err) + } + } + return nil +} diff --git a/main.go b/main.go index 4b1e0b3..f2040ea 100644 --- a/main.go +++ b/main.go @@ -16,6 +16,8 @@ package main import ( + "time" + "github.com/eliona-smart-building-assistant/go-eliona/app" "github.com/eliona-smart-building-assistant/go-utils/common" "github.com/eliona-smart-building-assistant/go-utils/db" @@ -44,6 +46,7 @@ func main() { // Starting the service to collect the data for this app. common.WaitForWithOs( listenApi, + common.Loop(manageOccupancy, time.Second), ) log.Info("main", "Terminate the app.")