Commit af0728d8 authored by M. Rehan Abbasi's avatar M. Rehan Abbasi
Browse files

add new tables and handler functions for traffic manager

parent 5c263328
Loading
Loading
Loading
Loading
+11 −3
Original line number Diff line number Diff line
@@ -149,12 +149,20 @@ func Init(cfg SbiCfg) (err error) {
	_ = sbi.trafficMgr.DeleteTables()

	// Create new tables
	err = sbi.trafficMgr.CreateTable()
	err = sbi.trafficMgr.CreateTables()
	if err != nil {
		log.Error("Failed to create table: ", err)
		log.Error("Failed to create tables: ", err)
		return err
	}
	log.Info("Created new VIS DB table")
	log.Info("Created new VIS DB tables")

	// Populate VIS DB Tables
	err = sbi.trafficMgr.PopulateCategoryTable()
	if err != nil {
		log.Error("Failed to populate categories table: ", err)
		return err
	}
	log.Info("Created new VIS DB categories table")

	// Initialize service
	processActiveScenarioUpdate()
+288 −97
Original line number Diff line number Diff line
@@ -43,39 +43,58 @@ const profiling = false
var profilingTimers map[string]time.Time

const (
	FieldId      = "id"
	FieldCategory              = "category"
	FieldPoaName               = "poaName"
	FieldTime1   = "time1"
	FieldTime2   = "time2"
	FieldTime3   = "time3"
	FieldTime4   = "time4"
	// FieldPath      = "path"
	// FieldMode      = "mode"
	// FieldVelocity  = "velocity"
	// FieldConnected = "connected"
	// FieldPriority  = "priority"
	// FieldSubtype   = "subtype"
	// FieldRadius    = "radius"
	FieldZeroToThree           = "0000-0300"
	FieldThreeToSix            = "0300-0600"
	FieldSixToNine             = "0600-0900"
	FieldNineToTwelve          = "0900-1200"
	FieldTwelveToFifteen       = "1200-1500"
	FieldFifteenToEighteen     = "1500-1800"
	FieldEighteenToTwentyOne   = "1800-2100"
	FieldTwentyOneToTwentyFour = "2100-2400"
)

// DB Table Names
const (
	GridTable     = "grid_map"
	CategoryTable = "categories"
	TrafficTable  = "traffic_patterns"
)

// Asset Types
const (
	TypePoa = "POA"
)

// POA Types
// const (
// 	PoaTypeGeneric      = "POA"
// 	PoaTypeCell4g       = "POA-4G"
// 	PoaTypeCell5g       = "POA-5G"
// 	PoaTypeWifi         = "POA-WIFI"
// 	PoaTypeDisconnected = "DISCONNECTED"
// )
// Category-wise Traffic Loads
var categoriesLoads = map[string]map[string]int32{
	"commercial": {
		"0000:0300": 1,
		"0300-0600": 3,
		"0600-0900": 8,
		"0900-1200": 12,
		"1200-1500": 15,
		"1500-1800": 10,
		"1800-2100": 5,
		"2100-2400": 2,
	},
	"residential": {
		"0000:0300": 5,
		"0300-0600": 2,
		"0600-0900": 10,
		"0900-1200": 8,
		"1200-1500": 5,
		"1500-1800": 12,
		"1800-2100": 15,
		"2100-2400": 8,
	},
	"beach": {
		"0000:0300": 2,
		"0300-0600": 5,
		"0600-0900": 8,
		"0900-1200": 10,
		"1200-1500": 20,
		"1500-1800": 15,
		"1800-2100": 5,
		"2100-2400": 2,
	},
}

// VIS Traffic Manager
type TrafficMgr struct {
@@ -91,13 +110,29 @@ type TrafficMgr struct {
	// updateCb  func(string, string)
}

type PoaTimes struct {
	Id      string
type PoaLoads struct {
	PoaName               string
	Time1   int32
	Time2   int32
	Time3   int32
	Time4   int32
	Category              string
	ZeroToThree           int32
	ThreeToSix            int32
	SixToNine             int32
	NineToTwelve          int32
	TwelveToFifteen       int32
	FifteenToEighteen     int32
	EighteenToTwentyOne   int32
	TwentyOneToTwentyFour int32
}

type CategoryLoads struct {
	Category              string
	ZeroToThree           int32
	ThreeToSix            int32
	SixToNine             int32
	NineToTwelve          int32
	TwelveToFifteen       int32
	FifteenToEighteen     int32
	EighteenToTwentyOne   int32
	TwentyOneToTwentyFour int32
}

// Profiling init
@@ -257,38 +292,73 @@ func (tm *TrafficMgr) DestroyDb(name string) (err error) {
	return nil
}

func (tm *TrafficMgr) CreateTable() (err error) {
func (tm *TrafficMgr) CreateTables() (err error) {
	_, err = tm.db.Exec("CREATE EXTENSION IF NOT EXISTS postgis")
	if err != nil {
		log.Error(err.Error())
		return err
	}

	_, err = tm.db.Exec(`CREATE TABLE ` + TrafficTable + ` (
	// Grid Table
	_, err = tm.db.Exec(`CREATE TABLE ` + GridTable + ` (
		id              varchar(36)             NOT NULL,
		poaName				  varchar(100)						NOT NULL UNIQUE,
		time1						integer									NOT NULL DEFAULT '0',
		time2						integer									NOT NULL DEFAULT '0',
		time3						integer									NOT NULL DEFAULT '0',
		time4						integer									NOT NULL DEFAULT '0',
		category				varchar(100)						NOT NULL,
		grid						geometry(POLYGON,4326),
		PRIMARY KEY (id)
	)`)
	if err != nil {
		log.Error(err.Error())
		return err
	}
	log.Info("Created Traffic table: ", TrafficTable)

	return nil
	log.Info("Created Grids table: ", GridTable)

	// Categories Table
	_, err = tm.db.Exec(`CREATE TABLE ` + CategoryTable + ` (
		category				varchar(100)						NOT NULL UNIQUE,
		"0000-0300"			integer									NOT NULL DEFAULT '0',
		"0300-0600"			integer									NOT NULL DEFAULT '0',
		"0600-0900"			integer									NOT NULL DEFAULT '0',
		"0900-1200"			integer									NOT NULL DEFAULT '0',
		"1200-1500"			integer									NOT NULL DEFAULT '0',
		"1500-1800"			integer									NOT NULL DEFAULT '0',
		"1800-2100"			integer									NOT NULL DEFAULT '0',
		"2100-2400"			integer									NOT NULL DEFAULT '0',
		PRIMARY KEY (category)
	)`)
	if err != nil {
		log.Error(err.Error())
		return err
	}
	log.Info("Created Categories table: ", CategoryTable)

// DeleteTables - Delete all postgis traffic tables
func (tm *TrafficMgr) DeleteTables() (err error) {
	err = tm.DeleteTable(TrafficTable)
	// Traffic Load Table
	_, err = tm.db.Exec(`CREATE TABLE ` + TrafficTable + ` (
		poa_name			  varchar(100)						NOT NULL UNIQUE,
		category				varchar(100)						NOT NULL,
		"0000-0300"			integer									NOT NULL DEFAULT '0',
		"0300-0600"			integer									NOT NULL DEFAULT '0',
		"0600-0900"			integer									NOT NULL DEFAULT '0',
		"0900-1200"			integer									NOT NULL DEFAULT '0',
		"1200-1500"			integer									NOT NULL DEFAULT '0',
		"1500-1800"			integer									NOT NULL DEFAULT '0',
		"1800-2100"			integer									NOT NULL DEFAULT '0',
		"2100-2400"			integer									NOT NULL DEFAULT '0',
		PRIMARY KEY (poa_name)
	)`)
	if err != nil {
		log.Error(err.Error())
		return err
	}
	log.Info("Created Traffic Loads table: ", TrafficTable)

	return nil
}

// DeleteTables - Delete all postgis traffic tables
func (tm *TrafficMgr) DeleteTables() (err error) {
	_ = tm.DeleteTable(GridTable)
	_ = tm.DeleteTable(CategoryTable)
	_ = tm.DeleteTable(TrafficTable)
	return nil
}

@@ -303,66 +373,94 @@ func (tm *TrafficMgr) DeleteTable(tableName string) (err error) {
	return nil
}

// CreatePoaLoad - Create new POA
func (tm *TrafficMgr) CreatePoaLoad(id string, poaName string, data map[string]interface{}) (err error) {
// CreateCategoryLoad - Create new Category Load
func (tm *TrafficMgr) CreateCategoryLoad(category string, data map[string]int32) (err error) {
	if profiling {
		profilingTimers["CreatePoaLoad"] = time.Now()
		profilingTimers["CreateCategoryLoad"] = time.Now()
	}

	var time1 int32
	var time2 int32
	var time3 int32
	var time4 int32
	var ok bool
	var loadTime []int32

	// Validate input
	if id == "" {
		return errors.New("Missing ID")
	if category == "" {
		return errors.New("Missing category name")
	}

	fields := []string{
		FieldZeroToThree,
		FieldThreeToSix,
		FieldSixToNine,
		FieldNineToTwelve,
		FieldTwelveToFifteen,
		FieldFifteenToEighteen,
		FieldEighteenToTwentyOne,
		FieldTwentyOneToTwentyFour,
	}
	for i, field := range fields {
		if _, found := data[field]; !found {
			return errors.New("Missing time field" + field)
		} else if loadTime[i] == 0 {
			return errors.New("Invalid " + field)
		}
	if poaName == "" {
		return errors.New("Missing POA Name")
	}

	// Get time1
	if dataTime1, found := data[FieldTime1]; !found {
		return errors.New("Missing subtype")
	} else if time1, ok = dataTime1.(int32); !ok {
		return errors.New("Invalid subtype data type")
	} else if time1 == 0 {
		return errors.New("Invalid time1")
	// Create Traffic Load entry
	query := `INSERT INTO ` + CategoryTable +
		` (category, "0000-0300", "0300-0600", "0600-0900", "0900-1200", "1200-1500", "1500-1800", "1800-2100", "2100-2400")
			VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)`
	_, err = tm.db.Exec(query, category, loadTime[0:8])
	if err != nil {
		log.Error(err.Error())
		return err
	}

	// Notify listener
	// tm.notifyListener(TypePoa, name)

	if profiling {
		now := time.Now()
		log.Debug("CreatePoaLoad: ", now.Sub(profilingTimers["CreatePoaLoad"]))
	}
	return nil
}

	// Get time2
	if dataTime2, found := data[FieldTime2]; !found {
		return errors.New("Missing subtype")
	} else if time2, ok = dataTime2.(int32); !ok {
		return errors.New("Invalid subtype data type")
	} else if time2 == 0 {
		return errors.New("Invalid time2")
// CreatePoaLoad - Create new POA Load
func (tm *TrafficMgr) CreatePoaLoad(poaName string, category string) (err error) {
	if profiling {
		profilingTimers["CreatePoaLoad"] = time.Now()
	}

	// Get time3
	if dataTime3, found := data[FieldTime3]; !found {
		return errors.New("Missing subtype")
	} else if time3, ok = dataTime3.(int32); !ok {
		return errors.New("Invalid subtype data type")
	} else if time3 == 0 {
		return errors.New("Invalid time3")
	// Validate input
	if poaName == "" {
		return errors.New("Missing POA Name")
	}
	if category == "" {
		return errors.New("Missing category name")
	}

	// Get time4
	if dataTime4, found := data[FieldTime4]; !found {
		return errors.New("Missing subtype")
	} else if time4, ok = dataTime4.(int32); !ok {
		return errors.New("Invalid subtype data type")
	} else if time4 == 0 {
		return errors.New("Invalid time4")
	// Get Load entry from Categories Table
	categoryLoads, err := tm.GetCategoryLoad(category)
	if err != nil {
		log.Error(err.Error())
		return err
	}

	loadTime := []int32{
		categoryLoads.ZeroToThree,
		categoryLoads.ThreeToSix,
		categoryLoads.SixToNine,
		categoryLoads.NineToTwelve,
		categoryLoads.TwelveToFifteen,
		categoryLoads.FifteenToEighteen,
		categoryLoads.EighteenToTwentyOne,
		categoryLoads.TwentyOneToTwentyFour,
	}

	// Create Traffic Load entry
	query := `INSERT INTO ` + TrafficTable + ` (id, poaName, time1, time2, time3, time4)
		VALUES ($1, $2, $3, $4, $5, $6)`
	_, err = tm.db.Exec(query, id, poaName, time1, time2, time3, time4)
	query := `INSERT INTO ` + TrafficTable +
		` (poa_name, category, "0000-0300", "0300-0600", "0600-0900", "0900-1200", "1200-1500", "1500-1800", "1800-2100", "2100-2400")
			VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)`
	_, err = tm.db.Exec(query, poaName, category, loadTime[0:8])
	if err != nil {
		log.Error(err.Error())
		return err
@@ -379,7 +477,7 @@ func (tm *TrafficMgr) CreatePoaLoad(id string, poaName string, data map[string]i
}

// GetPoaLoad - Get POA Load information
func (tm *TrafficMgr) GetPoaLoad(poaName string) (poaTimes *PoaTimes, err error) {
func (tm *TrafficMgr) GetPoaLoad(poaName string) (poaLoads *PoaLoads, err error) {
	if profiling {
		profilingTimers["GetPoaLoad"] = time.Now()
	}
@@ -393,7 +491,7 @@ func (tm *TrafficMgr) GetPoaLoad(poaName string) (poaTimes *PoaTimes, err error)
	// Get Poa entry
	var rows *sql.Rows
	rows, err = tm.db.Query(`
		SELECT id, name, time1, time2, time3, time4
		SELECT id, poa_name, category, "0000-0300", "0300-0600", "0600-0900", "0900-1200", "1200-1500", "1500-1800", "1800-2100", "2100-2400"
		FROM `+TrafficTable+`
		WHERE name = ($1)`, poaName)
	if err != nil {
@@ -404,8 +502,19 @@ func (tm *TrafficMgr) GetPoaLoad(poaName string) (poaTimes *PoaTimes, err error)

	// Scan result
	for rows.Next() {
		poaTimes = new(PoaTimes)
		err = rows.Scan(&poaTimes.Id, &poaTimes.PoaName, &poaTimes.Time1, &poaTimes.Time2, &poaTimes.Time3, &poaTimes.Time4)
		poaLoads = new(PoaLoads)
		err = rows.Scan(
			&poaLoads.PoaName,
			&poaLoads.Category,
			&poaLoads.ZeroToThree,
			&poaLoads.ThreeToSix,
			&poaLoads.SixToNine,
			&poaLoads.NineToTwelve,
			&poaLoads.TwelveToFifteen,
			&poaLoads.FifteenToEighteen,
			&poaLoads.EighteenToTwentyOne,
			&poaLoads.TwentyOneToTwentyFour,
		)
		if err != nil {
			log.Error(err.Error())
			return nil, err
@@ -417,8 +526,8 @@ func (tm *TrafficMgr) GetPoaLoad(poaName string) (poaTimes *PoaTimes, err error)
	}

	// Return error if not found
	if poaTimes == nil {
		err = errors.New("POA not found: " + poaName)
	if poaLoads == nil {
		err = errors.New("POA Load not found: " + poaName)
		return nil, err
	}

@@ -426,5 +535,87 @@ func (tm *TrafficMgr) GetPoaLoad(poaName string) (poaTimes *PoaTimes, err error)
		now := time.Now()
		log.Debug("GetPoaLoad: ", now.Sub(profilingTimers["GetPoaLoad"]))
	}
	return poaTimes, nil
	return poaLoads, nil
}

// GetCategoryLoad - Get POA Load information
func (tm *TrafficMgr) GetCategoryLoad(category string) (categoryLoads *CategoryLoads, err error) {
	if profiling {
		profilingTimers["GetCategoryLoad"] = time.Now()
	}

	// Validate input
	if category == "" {
		err = errors.New("Missing category name")
		return nil, err
	}

	// Get Category Load entry
	var rows *sql.Rows
	rows, err = tm.db.Query(`
		SELECT category, "0000-0300", "0300-0600", "0600-0900", "0900-1200", "1200-1500", "1500-1800", "1800-2100", "2100-2400"
		FROM `+CategoryTable+`
		WHERE category = ($1)`, category)
	if err != nil {
		log.Error(err.Error())
		return nil, err
	}
	defer rows.Close()

	// Scan result
	for rows.Next() {
		categoryLoads = new(CategoryLoads)
		err = rows.Scan(
			&categoryLoads.Category,
			&categoryLoads.ZeroToThree,
			&categoryLoads.ThreeToSix,
			&categoryLoads.SixToNine,
			&categoryLoads.NineToTwelve,
			&categoryLoads.TwelveToFifteen,
			&categoryLoads.FifteenToEighteen,
			&categoryLoads.EighteenToTwentyOne,
			&categoryLoads.TwentyOneToTwentyFour,
		)
		if err != nil {
			log.Error(err.Error())
			return nil, err
		}
	}
	err = rows.Err()
	if err != nil {
		log.Error(err)
	}

	// Return error if not found
	if categoryLoads == nil {
		err = errors.New("Category Load not found: " + category)
		return nil, err
	}

	if profiling {
		now := time.Now()
		log.Debug("GetCategoryLoad: ", now.Sub(profilingTimers["GetCategoryLoad"]))
	}
	return categoryLoads, nil
}

// PopulateCategoryTable - Populate the categories table
func (tm *TrafficMgr) PopulateCategoryTable() (err error) {
	if profiling {
		profilingTimers["PopulateCategoryTable"] = time.Now()
	}

	for category, loads := range categoriesLoads {
		err = tm.CreateCategoryLoad(category, loads)
		if err != nil {
			log.Error(err.Error())
			return err
		}
	}

	if profiling {
		now := time.Now()
		log.Debug("PopulateCategoryTable: ", now.Sub(profilingTimers["PopulateCategoryTable"]))
	}
	return nil
}