/*
* Copyright (c) 2019
* InterDigital Communications, Inc.
* All rights reserved.
*
* The information provided herein is the proprietary and confidential
* information of InterDigital Communications, Inc.
*/
package sbi
import (
"encoding/json"
"strings"
log "github.com/InterDigitalInc/AdvantEDGE/go-apps/meep-loc-serv/log"
db "github.com/InterDigitalInc/AdvantEDGE/go-apps/meep-loc-serv/redis2"
ceModel "github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-ctrl-engine-model"
)
const basepathURL = "http://meep-loc-serv/etsi-013/location/v1/"
const moduleCtrlEngine string = "ctrl-engine"
const moduleLocServ string = "loc-serv"
const typeZone = "zone"
const typeAccessPoint = "accessPoint"
const typeUser = "user"
const typeActive = "active"
const channelCtrlActive string = moduleCtrlEngine + "-" + typeActive
const locServChannel string = moduleLocServ
// Init - Location Service initialization
func Init() (err error) {
// Connect to Redis DB
err = db.RedisDBConnect()
if err != nil {
log.Error("Failed connection to Active DB in sbi. Error: ", err)
return err
}
log.Info("Connected to Active DB in sbi")
// Subscribe to Pub-Sub events for MEEP Controller
// NOTE: Current implementation is RedisDB Pub-Sub
err = db.Subscribe(channelCtrlActive)
if err != nil {
log.Error("Failed to subscribe to Pub/Sub events. Error: ", err)
return err
}
go Run()
return nil
}
// Run - MEEP Location Service execution
func Run() {
// Listen for subscribed events. Provide event handler method.
_ = db.Listen(eventHandler)
}
func eventHandler(channel string, payload string) {
// Handle Message according to Rx Channel
switch channel {
// MEEP Ctrl Engine active scenario update Channel
case channelCtrlActive:
log.Debug("Event received on channel: ", channelCtrlActive)
processActiveScenarioUpdate()
default:
log.Warn("Unsupported channel")
}
}
func processActiveScenarioUpdate() {
// Retrieve active scenario from DB
jsonScenario, err := db.DBJsonGetEntry(moduleCtrlEngine+":"+typeActive, ".")
if err != nil {
log.Error(err.Error())
//scenario being terminated, we just clear every loc-service entries from the DB
db.RedisDBFlush(moduleLocServ)
return
}
// Unmarshal Active scenario
var scenario ceModel.Scenario
err = json.Unmarshal([]byte(jsonScenario), &scenario)
if err != nil {
log.Error(err.Error())
return
}
// Parse scenario
parseScenario(scenario)
}
func parseScenario(scenario ceModel.Scenario) {
log.Debug("parseScenario")
// Store scenario Name
//scenarioName := scenario.Name
// Parse Domains
for _, domain := range scenario.Deployment.Domains {
// Parse Zones
for _, zone := range domain.Zones {
nbZoneUsers := 0
nbAccessPoints := 0
// Parse Network Locations
for _, nl := range zone.NetworkLocations {
nbApUsers := 0
// Parse Physical locations
for _, pl := range nl.PhysicalLocations {
// Parse Processes
for _, proc := range pl.Processes {
switch pl.Type_ {
case "UE":
oldZoneId, oldApId := getCurrentUserLocation(proc.Name)
updateUserInfo(proc.Name, zone.Name, nl.Name, basepathURL + "users/" + proc.Name)
nbApUsers++
_ = db.RedisDBPublish(locServChannel, oldZoneId+":"+zone.Name+":"+oldApId+":"+nl.Name+":"+proc.Name)
default:
}
}
}
switch nl.Type_ {
case "POA":
updateAccessPointInfo(zone.Name, nl.Name, WIFI, SERVICEABLE, nbApUsers, basepathURL + "zones/" + zone.Name + "/accessPoints/" + nl.Name)
nbAccessPoints++
nbZoneUsers += nbApUsers
default:
}
}
updateZoneInfo(zone.Name, nbAccessPoints, 0, nbZoneUsers, basepathURL + "zones/" + zone.Name )
}
}
}
func createUserInfo(address string, zoneId string, accessPointId string, resourceName string) {
userInfo := new(UserInfo)
userInfo.Address = address
userInfo.ZoneId = zoneId
userInfo.AccessPointId = accessPointId
userInfo.ResourceURL = resourceName
//unsued optional attributes
//userInfo.LocationInfo.Latitude,
//userInfo.LocationInfo.Longitude,
//userInfo.LocationInfo.Altitude,
//userInfo.LocationInfo.Accuracy,
//userInfo.ContextLocationInfo,
//userInfo.AncillaryInfo)
//update DB
db.DbJsonSet(address, convertUserInfoToJson(userInfo), moduleLocServ+":"+typeUser)
}
func getCurrentUserLocation(resourceName string) (string, string) {
jsonUserInfo := db.DbJsonGet(resourceName, moduleLocServ+":"+typeUser)
if jsonUserInfo != "" {
// Unmarshal UserInfo
var userInfo UserInfo
err := json.Unmarshal([]byte(jsonUserInfo), &userInfo)
if err == nil {
return userInfo.ZoneId, userInfo.AccessPointId
} else {
log.Error(err.Error())
}
}
return "", ""
}
func updateUserInfo(address string, zoneId string, accessPointId string, resourceName string) {
//get from DB
jsonUserInfo := db.DbJsonGet(address, moduleLocServ+":"+typeUser)
if jsonUserInfo != "" {
// Unmarshal UserInfo
var userInfo UserInfo
if zoneId != "" {
userInfo.ZoneId = zoneId
}
if accessPointId != "" {
userInfo.AccessPointId = accessPointId
}
//updateDB
db.DbJsonSet(address, jsonUserInfo/*convertUserInfoToJson(&userInfo)*/, moduleLocServ+":"+typeUser)
} else {
createUserInfo(address, zoneId, accessPointId, resourceName)
}
}
/* unused
func deleteUserInfo(address string) {
//delete from DB
_ = db.DbJsonDelete(address, moduleLocServ + ":" + typeUser)
}
*/
func createZoneInfo(zoneId string, nbAccessPoints int, nbUnsrvAccessPoints int, nbUsers int, resourceName string) {
zoneInfo := new(ZoneInfo)
zoneInfo.ZoneId = zoneId
zoneInfo.ResourceURL = resourceName
zoneInfo.NumberOfAccessPoints = uint32(nbAccessPoints)
zoneInfo.NumberOfUnservicableAccessPoints = uint32(nbUnsrvAccessPoints)
zoneInfo.NumberOfUsers = uint32(nbUsers)
//update DB
db.DbJsonSet(zoneId, convertZoneInfoToJson(zoneInfo), moduleLocServ+":"+typeZone)
}
func updateZoneInfo(zoneId string, nbAccessPoints int, nbUnsrvAccessPoints int, nbUsers int, resourceName string) {
if zoneId != "" && !strings.Contains(zoneId, "-COMMON") {
//get from DB
jsonZoneInfo := db.DbJsonGet(zoneId, moduleLocServ+":"+typeZone)
if jsonZoneInfo != "" {
// Unmarshal UserInfo
var zoneInfo ZoneInfo
if nbAccessPoints != -1 {
zoneInfo.NumberOfAccessPoints = uint32(nbAccessPoints)
}
if nbUnsrvAccessPoints != -1 {
zoneInfo.NumberOfUnservicableAccessPoints = uint32(nbUnsrvAccessPoints)
}
if nbUsers != -1 {
zoneInfo.NumberOfUsers = uint32(nbUsers)
}
//updateDB
db.DbJsonSet(zoneId, convertZoneInfoToJson(&zoneInfo), moduleLocServ+":"+typeZone)
} else {
createZoneInfo(zoneId, nbAccessPoints, nbUnsrvAccessPoints, nbUsers, resourceName)
}
}
}
/* unused
func deleteZoneInfo(zoneId string) {
//delete from DB
_ = db.DbJsonDelete(zoneId, moduleLocServ + ":" + typeZone)
}
*/
func createAccessPointInfo(zoneId string, apId string, conType ConnectionType, opStatus OperationStatus, nbUsers uint32, resourceName string) {
apInfo := new(AccessPointInfo)
apInfo.AccessPointId = apId
apInfo.ResourceURL = resourceName
apInfo.ConnectionType = &conType
apInfo.OperationStatus = &opStatus
apInfo.NumberOfUsers = nbUsers
//unsued optional attributes
//apInfo.LocationInfo.Latitude
//apInfo.LocationInfo.Longitude
//apInfo.LocationInfo.Altitude
//apInfo.LocationInfo.Accuracy
//apInfo.Timezone
//apInfo.InterestRealm
//update DB
db.DbJsonSet(apId, convertAccessPointInfoToJson(apInfo), moduleLocServ+":"+typeZone+":"+zoneId+":"+typeAccessPoint)
}
func updateAccessPointInfo(zoneId string, apId string, conType ConnectionType, opStatus OperationStatus, nbUsers int, resourceName string) {
//get from DB
jsonApInfo := db.DbJsonGet(apId, moduleLocServ+":"+typeZone+":"+zoneId+":"+typeAccessPoint)
if jsonApInfo != "" {
// Unmarshal UserInfo
var apInfo AccessPointInfo
if opStatus != "" {
apInfo.OperationStatus = &opStatus
}
if nbUsers != -1 {
apInfo.NumberOfUsers = uint32(nbUsers)
}
//updateDB
db.DbJsonSet(apId, jsonApInfo/*convertAccessPointInfoToJson(&apInfo)*/, moduleLocServ+":"+typeZone+":"+zoneId+":"+typeAccessPoint)
} else {
//update DB
createAccessPointInfo(zoneId, apId, conType, opStatus, uint32(nbUsers), resourceName)
}
}
/* unused
func deleteAccessPointInfo(zoneId string, apId string) {
//delete from DB
_ = db.DbJsonDelete(apId, moduleLocServ + ":" + typeZone + ":" + zoneId + ":" + typeAccessPoint)
}
*/