refactoring
This commit is contained in:
parent
3983a91475
commit
5aed4560e9
10 changed files with 167 additions and 143 deletions
|
@ -31,9 +31,10 @@ func NewRestAPI(connection string, weatherStorage storage.WeatherStorage, sensor
|
|||
//Start a new Rest-API instance
|
||||
func (api *weatherRestApi) Start() error {
|
||||
handler := api.handleRequests()
|
||||
return http.ListenAndServe(api.connection, handler) // http.ListenAndServe(api.connection, handler)
|
||||
return http.ListenAndServe(api.connection, handler)
|
||||
}
|
||||
|
||||
//Close the rest api
|
||||
func (api *weatherRestApi) Close() {
|
||||
}
|
||||
|
||||
|
@ -77,24 +78,24 @@ func (api *weatherRestApi) getData(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
data, err := api.weaterStorage.GetData(query)
|
||||
if err != nil {
|
||||
http.Error(w, "", http.StatusBadRequest)
|
||||
http.Error(w, "error executing query", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
res := storage.ToMap(storage.GetOnlyQueriedFields(data, query))
|
||||
json.NewEncoder(w).Encode(res)
|
||||
}
|
||||
|
||||
func (api *weatherRestApi) randomWeatherHandler(w http.ResponseWriter, r *http.Request) {
|
||||
datapoint := storage.NewRandomWeatherData(uuid.Nil)
|
||||
|
||||
w.Header().Add("content-type", "application/json")
|
||||
json.NewEncoder(w).Encode(datapoint)
|
||||
json.NewEncoder(w).Encode(storage.NewRandomWeatherData())
|
||||
}
|
||||
|
||||
func (api *weatherRestApi) randomWeatherListHandler(w http.ResponseWriter, r *http.Request) {
|
||||
var datapoints = make([]storage.WeatherData, 0)
|
||||
var datapoints = make([]*storage.WeatherData, 0)
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
datapoints = append(datapoints, storage.NewRandomWeatherData(uuid.Nil))
|
||||
datapoints = append(datapoints, storage.NewRandomWeatherData())
|
||||
}
|
||||
|
||||
w.Header().Add("content-type", "application/json")
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package storage
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"errors"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
@ -21,7 +21,7 @@ func (registry *inmemorySensorRegistry) RegisterSensorByName(name string) (*Weat
|
|||
return nil, err
|
||||
}
|
||||
if exist {
|
||||
return nil, fmt.Errorf("Sensorname already exists")
|
||||
return nil, errors.New("sensorname already exists")
|
||||
}
|
||||
sensor := new(WeatherSensor)
|
||||
sensor.Name = name
|
||||
|
@ -45,7 +45,7 @@ func (registry *inmemorySensorRegistry) ResolveSensorById(sensorId uuid.UUID) (*
|
|||
return s, nil
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("sensor does not exist")
|
||||
return nil, errors.New("sensor does not exist")
|
||||
}
|
||||
|
||||
func (registry *inmemorySensorRegistry) ExistSensor(sensor *WeatherSensor) (bool, error) {
|
|
@ -2,7 +2,7 @@ package storage
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"errors"
|
||||
"log"
|
||||
"time"
|
||||
"weather-data/config"
|
||||
|
@ -59,7 +59,7 @@ func (registry *mongodbSensorRegistry) RegisterSensorByName(name string) (*Weath
|
|||
return nil, err
|
||||
}
|
||||
if exist {
|
||||
return nil, fmt.Errorf("Sensorname already exists")
|
||||
return nil, errors.New("sensorname already exists")
|
||||
}
|
||||
sensor := new(WeatherSensor)
|
||||
sensor.Name = name
|
||||
|
@ -96,7 +96,7 @@ func (registry *mongodbSensorRegistry) ResolveSensorById(sensorId uuid.UUID) (*W
|
|||
return s, nil
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("sensor does not exist")
|
||||
return nil, errors.New("sensor does not exist")
|
||||
}
|
||||
|
||||
func (registry *mongodbSensorRegistry) ExistSensor(sensor *WeatherSensor) (bool, error) {
|
||||
|
|
20
storage/sensor-registry.go
Normal file
20
storage/sensor-registry.go
Normal file
|
@ -0,0 +1,20 @@
|
|||
package storage
|
||||
|
||||
import "github.com/google/uuid"
|
||||
|
||||
type SensorRegistry interface {
|
||||
RegisterSensorByName(string) (*WeatherSensor, error)
|
||||
ExistSensor(*WeatherSensor) (bool, error)
|
||||
ResolveSensorById(uuid.UUID) (*WeatherSensor, error)
|
||||
GetSensors() ([]*WeatherSensor, error)
|
||||
Close() error
|
||||
}
|
||||
|
||||
//WeatherSensor is the data for a new Sensorregistration
|
||||
type WeatherSensor struct {
|
||||
Name string
|
||||
Id uuid.UUID
|
||||
Location string
|
||||
Longitude float64
|
||||
Latitude float64
|
||||
}
|
|
@ -3,8 +3,6 @@ package storage
|
|||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
|
@ -28,28 +26,35 @@ func GetSensorValueTypes() []SensorValueType {
|
|||
return []SensorValueType{Temperature, Pressure, Humidity, Co2Level}
|
||||
}
|
||||
|
||||
//WeatherStorage interface for different storage-implementations of weather data
|
||||
type WeatherStorage interface {
|
||||
Save(WeatherData) error
|
||||
GetData(*WeatherQuery) ([]*WeatherData, error)
|
||||
Close() error
|
||||
}
|
||||
|
||||
type SensorRegistry interface {
|
||||
RegisterSensorByName(string) (*WeatherSensor, error)
|
||||
ExistSensor(*WeatherSensor) (bool, error)
|
||||
ResolveSensorById(uuid.UUID) (*WeatherSensor, error)
|
||||
GetSensors() ([]*WeatherSensor, error)
|
||||
Close() error
|
||||
}
|
||||
|
||||
//WeatherData type
|
||||
type WeatherData struct {
|
||||
Values map[SensorValueType]float64
|
||||
SensorId uuid.UUID `json:"sensorId"`
|
||||
TimeStamp time.Time `json:"timestamp"`
|
||||
SensorId uuid.UUID
|
||||
TimeStamp time.Time
|
||||
}
|
||||
|
||||
//NewRandomWeatherData creates random WeatherData
|
||||
func NewRandomWeatherData() *WeatherData {
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
var data = new(WeatherData)
|
||||
data.Values = make(map[SensorValueType]float64)
|
||||
data.Values[Humidity] = rand.Float64() * 100
|
||||
data.Values[Pressure] = rand.Float64()*80 + 960
|
||||
data.Values[Temperature] = rand.Float64()*40 - 5
|
||||
data.Values[Co2Level] = rand.Float64()*50 + 375
|
||||
data.SensorId = uuid.New()
|
||||
data.TimeStamp = time.Now()
|
||||
return data
|
||||
}
|
||||
|
||||
//NewRandomWeatherData creates random WeatherData
|
||||
func NewWeatherData() *WeatherData {
|
||||
var data = new(WeatherData)
|
||||
data.Values = make(map[SensorValueType]float64)
|
||||
return data
|
||||
}
|
||||
|
||||
//OnlyQueriedValues remove all values not contained by the WeatherQuery
|
||||
func (data *WeatherData) OnlyQueriedValues(query *WeatherQuery) *WeatherData {
|
||||
for _, sensorValueType := range GetSensorValueTypes() {
|
||||
if !query.Values[sensorValueType] {
|
||||
|
@ -59,19 +64,21 @@ func (data *WeatherData) OnlyQueriedValues(query *WeatherQuery) *WeatherData {
|
|||
return data
|
||||
}
|
||||
|
||||
//ToMap converts WeatherData to a map[string]interface{}
|
||||
func (data *WeatherData) ToMap() map[string]interface{} {
|
||||
mappedData := map[string]interface{}{
|
||||
"sensorId": data.SensorId.String(),
|
||||
"timeStamp": data.TimeStamp.String(),
|
||||
SensorId: data.SensorId.String(),
|
||||
TimeStamp: data.TimeStamp.String(),
|
||||
}
|
||||
|
||||
for sensorValueType, value := range data.Values {
|
||||
mappedData[string(sensorValueType)] = value //strconv.FormatFloat(value, 'f', -1, 64)
|
||||
mappedData[string(sensorValueType)] = value
|
||||
}
|
||||
|
||||
return mappedData
|
||||
}
|
||||
|
||||
//FromMap converts a map[string]interface{} to WeatherData
|
||||
func FromMap(value map[string]interface{}) (*WeatherData, error) {
|
||||
var data = new(WeatherData)
|
||||
data.Values = make(map[SensorValueType]float64)
|
||||
|
@ -113,6 +120,7 @@ func FromMap(value map[string]interface{}) (*WeatherData, error) {
|
|||
return data, nil
|
||||
}
|
||||
|
||||
//GetOnlyQueriedFields execute onlyQueriedValues on WeatherData slice an return this
|
||||
func GetOnlyQueriedFields(dataPoints []*WeatherData, query *WeatherQuery) []*WeatherData {
|
||||
for _, data := range dataPoints {
|
||||
data.OnlyQueriedValues(query)
|
||||
|
@ -120,6 +128,7 @@ func GetOnlyQueriedFields(dataPoints []*WeatherData, query *WeatherQuery) []*Wea
|
|||
return dataPoints
|
||||
}
|
||||
|
||||
//ToMap mapps all WeatherData of a slice ToMap
|
||||
func ToMap(dataPoints []*WeatherData) []map[string]interface{} {
|
||||
var result = make([]map[string]interface{}, 0)
|
||||
for _, data := range dataPoints {
|
||||
|
@ -127,77 +136,3 @@ func ToMap(dataPoints []*WeatherData) []map[string]interface{} {
|
|||
}
|
||||
return result
|
||||
}
|
||||
|
||||
//WeatherSensor is the data for a new Sensorregistration
|
||||
type WeatherSensor struct {
|
||||
Name string
|
||||
Id uuid.UUID
|
||||
Location string
|
||||
Longitude float64
|
||||
Latitude float64
|
||||
}
|
||||
|
||||
type WeatherQuery struct {
|
||||
Start time.Time
|
||||
End time.Time
|
||||
SensorId uuid.UUID
|
||||
Values map[SensorValueType]bool
|
||||
}
|
||||
|
||||
func (query *WeatherQuery) Init() {
|
||||
query.Start = time.Now().Add(-1 * time.Hour * 24 * 14)
|
||||
query.End = time.Now()
|
||||
query.SensorId = uuid.Nil
|
||||
query.Values = make(map[SensorValueType]bool)
|
||||
for _, sensorValueType := range GetSensorValueTypes() {
|
||||
query.Values[sensorValueType] = true
|
||||
}
|
||||
}
|
||||
|
||||
func ParseFromUrlQuery(query url.Values) (*WeatherQuery, error) {
|
||||
result := new(WeatherQuery)
|
||||
result.Init()
|
||||
|
||||
start := query.Get("start")
|
||||
end := query.Get("end")
|
||||
|
||||
if len(start) != 0 {
|
||||
if tval, err := time.Parse(time.RFC3339, start); err == nil {
|
||||
result.Start = tval
|
||||
} else if err != nil {
|
||||
fmt.Println(err)
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if len(end) != 0 {
|
||||
if tval, err := time.Parse(time.RFC3339, end); err == nil {
|
||||
result.End = tval
|
||||
} else if err != nil {
|
||||
fmt.Println(err)
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
for _, sensorValueType := range GetSensorValueTypes() {
|
||||
queryParam := query.Get(string(sensorValueType))
|
||||
if bval, err := strconv.ParseBool(queryParam); err == nil {
|
||||
result.Values[sensorValueType] = bval
|
||||
}
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
//NewRandomWeatherData creates random WeatherData with given Location
|
||||
func NewRandomWeatherData(sensorId uuid.UUID) WeatherData {
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
var data WeatherData
|
||||
data.Values[Humidity] = rand.Float64() * 100
|
||||
data.Values[Pressure] = rand.Float64()*80 + 960
|
||||
data.Values[Temperature] = rand.Float64()*40 - 5
|
||||
data.Values[Co2Level] = rand.Float64()*50 + 375
|
||||
data.SensorId = sensorId
|
||||
data.TimeStamp = time.Now()
|
||||
return data
|
||||
}
|
||||
|
|
68
storage/weather-query.go
Normal file
68
storage/weather-query.go
Normal file
|
@ -0,0 +1,68 @@
|
|||
package storage
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type WeatherQuery struct {
|
||||
Start time.Time
|
||||
End time.Time
|
||||
SensorId uuid.UUID
|
||||
Values map[SensorValueType]bool
|
||||
}
|
||||
|
||||
//NewWeatherQuery creates a new empty WeatherQuery
|
||||
func NewWeatherQuery() *WeatherQuery {
|
||||
query := new(WeatherQuery)
|
||||
query.Values = make(map[SensorValueType]bool)
|
||||
return query
|
||||
}
|
||||
|
||||
func (query *WeatherQuery) Init() {
|
||||
query.Start = time.Now().Add(-1 * time.Hour * 24 * 14)
|
||||
query.End = time.Now()
|
||||
query.SensorId = uuid.Nil
|
||||
for _, sensorValueType := range GetSensorValueTypes() {
|
||||
query.Values[sensorValueType] = true
|
||||
}
|
||||
}
|
||||
|
||||
func ParseFromUrlQuery(query url.Values) (*WeatherQuery, error) {
|
||||
result := NewWeatherQuery()
|
||||
result.Init()
|
||||
|
||||
start := query.Get("start")
|
||||
end := query.Get("end")
|
||||
|
||||
if len(start) != 0 {
|
||||
if tval, err := time.Parse(time.RFC3339, start); err == nil {
|
||||
result.Start = tval
|
||||
} else if err != nil {
|
||||
fmt.Println(err)
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if len(end) != 0 {
|
||||
if tval, err := time.Parse(time.RFC3339, end); err == nil {
|
||||
result.End = tval
|
||||
} else if err != nil {
|
||||
fmt.Println(err)
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
for _, sensorValueType := range GetSensorValueTypes() {
|
||||
queryParam := query.Get(string(sensorValueType))
|
||||
if bval, err := strconv.ParseBool(queryParam); err == nil {
|
||||
result.Values[sensorValueType] = bval
|
||||
}
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
8
storage/weather-storage.go
Normal file
8
storage/weather-storage.go
Normal file
|
@ -0,0 +1,8 @@
|
|||
package storage
|
||||
|
||||
//WeatherStorage interface for different storage-implementations of weather data
|
||||
type WeatherStorage interface {
|
||||
Save(WeatherData) error
|
||||
GetData(*WeatherQuery) ([]*WeatherData, error)
|
||||
Close() error
|
||||
}
|
|
@ -77,8 +77,7 @@ func (source *mqttWeatherSource) mqttMessageHandler() mqtt.MessageHandler {
|
|||
lastWeatherData, found := source.getUnwrittenDatapoints(sensorId)
|
||||
|
||||
if !found {
|
||||
lastWeatherData = new(storage.WeatherData)
|
||||
lastWeatherData.Values = make(map[storage.SensorValueType]float64)
|
||||
lastWeatherData = storage.NewWeatherData()
|
||||
lastWeatherData.SensorId = sensorId
|
||||
source.lastWeatherDataPoints = append(source.lastWeatherDataPoints, lastWeatherData)
|
||||
}
|
||||
|
@ -91,15 +90,6 @@ func (source *mqttWeatherSource) mqttMessageHandler() mqtt.MessageHandler {
|
|||
sensorValueType := storage.SensorValueType(regexTopic.FindStringSubmatch(msg.Topic())[3])
|
||||
lastWeatherData.Values[sensorValueType] = value
|
||||
lastWeatherData.TimeStamp = time.Now()
|
||||
|
||||
/* only use predefined sensorValueTypes
|
||||
for _, sensorValueType := range storage.GetSensorValueTypes() {
|
||||
if strings.HasSuffix(msg.Topic(), string(sensorValueType)) {
|
||||
lastWeatherData.Values[sensorValueType], _ = strconv.ParseFloat(string(msg.Payload()), 64)
|
||||
lastWeatherData.TimeStamp = time.Now()
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -107,7 +97,7 @@ func (source *mqttWeatherSource) publishDataValues() {
|
|||
for {
|
||||
for len(source.lastWeatherDataPoints) != 0 {
|
||||
current := *source.lastWeatherDataPoints[0]
|
||||
diff := time.Now().Sub(current.TimeStamp)
|
||||
diff := time.Since(current.TimeStamp)
|
||||
if diff >= source.config.MinDistToLastValue {
|
||||
if err := source.newWeatherData(current); err != nil {
|
||||
log.Fatal(err)
|
||||
|
@ -120,7 +110,6 @@ func (source *mqttWeatherSource) publishDataValues() {
|
|||
}
|
||||
time.Sleep(source.config.PublishInterval)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (source *mqttWeatherSource) getUnwrittenDatapoints(sensorId uuid.UUID) (*storage.WeatherData, bool) {
|
||||
|
|
24
weathersource/weather-source-base.go
Normal file
24
weathersource/weather-source-base.go
Normal file
|
@ -0,0 +1,24 @@
|
|||
package weathersource
|
||||
|
||||
import "weather-data/storage"
|
||||
|
||||
//WeatherSourceBase is the lowlevel-implementation of the WeatherSource interface, intended to used by highlevel-implementations
|
||||
type WeatherSourceBase struct {
|
||||
newWeatherDataCallbackFuncs []NewWeatherDataCallbackFunc
|
||||
}
|
||||
|
||||
//AddNewWeatherDataCallback adds a new callbackMethod for incoming weather data
|
||||
func (source *WeatherSourceBase) AddNewWeatherDataCallback(callback NewWeatherDataCallbackFunc) {
|
||||
source.newWeatherDataCallbackFuncs = append(source.newWeatherDataCallbackFuncs, callback)
|
||||
}
|
||||
|
||||
//NewWeatherData executes all newWeatherDataCallbackFuncs for this datapoint
|
||||
func (source *WeatherSourceBase) NewWeatherData(datapoint storage.WeatherData) error {
|
||||
for _, callback := range source.newWeatherDataCallbackFuncs {
|
||||
err := callback(datapoint)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -10,24 +10,3 @@ type WeatherSource interface {
|
|||
AddNewWeatherDataCallback(NewWeatherDataCallbackFunc)
|
||||
Close()
|
||||
}
|
||||
|
||||
//WeatherSourceBase is the lowlevel-implementation of the WeatherSource interface, intended to used by highlevel-implementations
|
||||
type WeatherSourceBase struct {
|
||||
newWeatherDataCallbackFuncs []NewWeatherDataCallbackFunc
|
||||
}
|
||||
|
||||
//AddNewWeatherDataCallback adds a new callbackMethod for incoming weather data
|
||||
func (source *WeatherSourceBase) AddNewWeatherDataCallback(callback NewWeatherDataCallbackFunc) {
|
||||
source.newWeatherDataCallbackFuncs = append(source.newWeatherDataCallbackFuncs, callback)
|
||||
}
|
||||
|
||||
//NewWeatherData executes all newWeatherDataCallbackFuncs for this datapoint
|
||||
func (source *WeatherSourceBase) NewWeatherData(datapoint storage.WeatherData) error {
|
||||
for _, callback := range source.newWeatherDataCallbackFuncs {
|
||||
err := callback(datapoint)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue