diff --git a/.gitignore b/.gitignore index 60ce4b6..a0a0e98 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ \.DS_Store +config.json diff --git a/config-template.json b/config-template.json new file mode 100644 index 0000000..1846113 --- /dev/null +++ b/config-template.json @@ -0,0 +1,12 @@ +{ + "database": { + "url": "", + "database": "" + }, + "api": { + "key": "" + }, + "server": { + "port": "" + } +} diff --git a/controller/api/config.go b/controller/api/config.go new file mode 100644 index 0000000..f9b34fc --- /dev/null +++ b/controller/api/config.go @@ -0,0 +1,13 @@ +package api + +import () + +var Api ApiInfo + +type ApiInfo struct { + Key string `json:"key"` +} + +func Configure(a ApiInfo) { + Api = a +} diff --git a/controller/api/sensor.go b/controller/api/sensor.go new file mode 100644 index 0000000..dea5a90 --- /dev/null +++ b/controller/api/sensor.go @@ -0,0 +1,210 @@ +package api + +import ( + "encoding/json" + "fmt" + "github.com/julienschmidt/httprouter" + "log" + "net/http" + "strconv" + "time" + + "github.com/mgerb42/mywebsite/model/daily_sensor" + "github.com/mgerb42/mywebsite/model/raw_sensor" +) + +// handle http request from sensors +func HandleSensorRequest(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { + + //store data from sensor in raw_sensor collection + //********************************************************************************** + key := r.URL.Query().Get("key") + w.Header().Set("Content-Type", "application/json") + + var message string + + if key == Api.Key { + + //get request parameters - convert temp to float64 + temperature, _ := strconv.ParseFloat(r.URL.Query().Get("temperature"), 64) + location := r.URL.Query().Get("location") + t := time.Now() + + store := raw_sensor.Data{"", temperature, location, t} + + err := store.StoreData() + + if err != nil { + message = "Failed to insert into database" + } else { + message = "Data inserted into database" + } + + //send response back + fmt.Fprint(w, "{ message : \""+message+"\"}") + + //compare current readings with dialy_sensor readings + //update daily_sensor readings if out of bounds + //********************************************************************************** + + storedData, err := daily_sensor.GetDailySensorInfo(location) + + if err != nil { + log.Println(err) + } + + //store data if nothing exists for the day + if storedData.Location == "" { + + storedData.ID = "" + storedData.Location = location + storedData.MaxTemp = temperature + storedData.MinTemp = temperature + storedData.Day = t.Day() + storedData.Month = t.Month().String() + storedData.Year = t.Year() + + err := storedData.StoreData() + + if err != nil { + log.Println(err) + } + + } else { + + performUpdate := false + + //check if values exceed max or min + if temperature > storedData.MaxTemp { + storedData.MaxTemp = temperature + performUpdate = true + } + if temperature < storedData.MinTemp { + storedData.MinTemp = temperature + performUpdate = true + } + + //store or update information if values have been changed + if performUpdate == true { + + err := storedData.UpdateData() + + if err != nil { + log.Println(err) + } + + } + } + } else { + message = "Incorrect api key" + } +} + +func HandleAllSensors(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { + + w.Header().Set("Content-Type", "application/json") + + s, err := raw_sensor.GetAllSensors() + + var response string + + if err != nil { + log.Println(err) + response = "{message : \"Error loading data from database\"" + } else { + js, err := json.MarshalIndent(s, "", " ") + + if err != nil { + log.Println(err) + response = "{message : \"Error loading data from database\"" + } else { + response = string(js) + } + } + + fmt.Fprint(w, response) +} + +func HandleSensorByLocation(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { + + location := ps.ByName("location") + + w.Header().Set("Content-Type", "application/json") + + s, err := daily_sensor.GetAllSensorInfo(location) + + var response string + + if err != nil { + log.Println(err) + response = "{message : \"Error loading data from database\"" + } else { + js, err := json.MarshalIndent(s, "", " ") + + if err != nil { + log.Println(err) + response = "{message : \"Error loading data from database\"" + } else { + response = string(js) + } + } + + fmt.Fprint(w, response) +} + +func HandleSensorByLocationYear(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { + + location := ps.ByName("location") + year, _ := strconv.Atoi(ps.ByName("year")) + + w.Header().Set("Content-Type", "application/json") + + s, err := daily_sensor.GetAllSensorInfoByYear(location, year) + + var response string + + if err != nil { + log.Println(err) + response = "{message : \"Error loading data from database\"" + } else { + js, err := json.MarshalIndent(s, "", " ") + + if err != nil { + log.Println(err) + response = "{message : \"Error loading data from database\"" + } else { + response = string(js) + } + } + + fmt.Fprint(w, response) +} + +func HandleSensorByLocationMonth(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { + + location := ps.ByName("location") + year, _ := strconv.Atoi(ps.ByName("year")) + month := ps.ByName("month") + + w.Header().Set("Content-Type", "application/json") + + s, err := daily_sensor.GetAllSensorInfoByMonth(location, year, month) + + var response string + + if err != nil { + log.Println(err) + response = "{message : \"Error loading data from database\"" + } else { + js, err := json.MarshalIndent(s, "", " ") + + if err != nil { + log.Println(err) + response = "{message : \"Error loading data from database\"" + } else { + response = string(js) + } + } + + fmt.Fprint(w, response) +} diff --git a/db/driver.go b/db/driver.go new file mode 100644 index 0000000..c5c877b --- /dev/null +++ b/db/driver.go @@ -0,0 +1,54 @@ +package db + +import ( + "gopkg.in/mgo.v2" + "log" + "time" +) + +var Mongo Driver + +type Driver struct { + Session *mgo.Session + Info DatabaseInfo +} + +type DatabaseInfo struct { + URL string `json:"url"` + Database string `json:"database"` + Username string `json:"username,omitempty"` + Password string `json:"password,omitempty"` +} + +func Configure(d DatabaseInfo) { + Mongo.Info = d +} + +func (d *Driver) Connect() { + // Connect to MongoDB + s, err := mgo.DialWithTimeout(d.Info.URL, 5*time.Second) + + if err != nil { + log.Println("MongoDB Driver Error", err) + return + } + + d.Session = s + + // Prevents these errors: read tcp 127.0.0.1:27017: i/o timeout + d.Session.SetSocketTimeout(10 * time.Second) + + // Check if is alive + if err = d.Session.Ping(); err != nil { + log.Println("Database Error", err) + } + + log.Println("Connected to database") +} + +func (d *Driver) Connected() bool { + if d.Session != nil { + return true + } + return false +} diff --git a/main.go b/main.go index 7191e14..ca9cdf9 100644 --- a/main.go +++ b/main.go @@ -1,27 +1,66 @@ package main import ( + "encoding/json" "fmt" - //"github.com/julienschmidt/httprouter" + "io/ioutil" "log" "net/http" + "os" - "github.com/mgerb42/mywebsite/model" + "github.com/mgerb42/mywebsite/controller/api" + "github.com/mgerb42/mywebsite/db" "github.com/mgerb42/mywebsite/route" ) +//structure for application configurations +type Config struct { + Database db.DatabaseInfo `json:"database"` + Api api.ApiInfo `json:"api"` + Server ServerConfig `json:"server"` +} + +//configuration settings for the web +type ServerConfig struct { + Port string `json:"port"` +} + func main() { - s := model.NewSession() + configurations := readConfig() - s.TestStore("Mit", "G") + db.Configure(configurations.Database) + api.Configure(configurations.Api) - var p []model.Person + db.Mongo.Connect() - p = s.SearchName("Mit") - - fmt.Println("Query: ") - fmt.Println(p[0].LastName) - - log.Fatal(http.ListenAndServe(":8080", route.Routes())) + log.Println("Starting Server...") + log.Println(http.ListenAndServe(":"+configurations.Server.Port, route.Routes())) +} + +//read the config file and return JsonObject struct +func readConfig() Config { + + log.Println("Reading config file...") + + file, e := ioutil.ReadFile("./config.json") + + if e != nil { + fmt.Printf("File error: %v\n", e) + os.Exit(1) + } + + fmt.Printf("%s\n", string(file)) + + //m := new(Dispatch) + //var m interface{} + var result Config + + err := json.Unmarshal(file, &result) + + if err != nil { + fmt.Println(err) + } + + return result } diff --git a/model/daily_sensor/daily_sensor.go b/model/daily_sensor/daily_sensor.go new file mode 100644 index 0000000..7d3c504 --- /dev/null +++ b/model/daily_sensor/daily_sensor.go @@ -0,0 +1,187 @@ +package daily_sensor + +import ( + "encoding/json" + "errors" + "fmt" + "github.com/mgerb42/mywebsite/db" + "gopkg.in/mgo.v2/bson" + "log" + "time" +) + +const ( + collection = "daily_sensor" +) + +type Data struct { + ID bson.ObjectId `bson:"_id,omitempty"` + MaxTemp float64 `json:"maxtemp" bson:"maxtemp"` + MinTemp float64 `json:"mintemp" bson:"mintemp"` + Location string `json:"location" bson:"location"` + Month string `json:"month" bson:"month"` + Day int `json:"day" bson:"day"` + Year int `json:"year" bson:"year"` +} + +//convert struct to json string +func (s *Data) toJson() string { + + b, err := json.MarshalIndent(s, "", " ") + + if err != nil { + fmt.Println(err.Error) + } + + return string(b) + +} + +func (s *Data) StoreData() error { + + if db.Mongo.Connected() { + + log.Println("Inserting data into " + collection) + + session := db.Mongo.Session.Copy() + defer session.Close() + + c := session.DB(db.Mongo.Info.Database).C(collection) + + // Insert Datas + err := c.Insert(s) + + if err != nil { + return err + } + } + + return nil +} + +func (s *Data) UpdateData() error { + + if db.Mongo.Connected() { + + log.Println("Updating data") + + session := db.Mongo.Session.Copy() + defer session.Close() + + c := session.DB(db.Mongo.Info.Database).C(collection) + + colQuerier := bson.M{"location": s.Location} + change := bson.M{"$set": bson.M{"maxtemp": s.MaxTemp, "mintemp": s.MinTemp}} + + err := c.Update(colQuerier, change) + + if err != nil { + return err + } + } + + return nil + +} + +func GetDailySensorInfo(sensor_location string) (Data, error) { + + d := Data{} + + day := time.Now().Day() + month := time.Now().Month().String() + year := time.Now().Year() + + if db.Mongo.Connected() == true { + + session := db.Mongo.Session.Copy() + defer session.Close() + + c := session.DB(db.Mongo.Info.Database).C(collection) + + err := c.Find(bson.M{"location": sensor_location, "day": day, "month": month, "year": year}).One(&d) + + if err != nil { + fmt.Println(err) + return d, nil + } + + return d, nil + + } else { + return d, errors.New("Query failed") + } + +} + +func GetAllSensorInfo(sensor_location string) ([]Data, error) { + d := []Data{} + + if db.Mongo.Connected() == true { + + session := db.Mongo.Session.Copy() + defer session.Close() + + c := session.DB(db.Mongo.Info.Database).C(collection) + + err := c.Find(bson.M{"location": sensor_location}).All(&d) + + if err != nil { + fmt.Println(err) + return d, nil + } + + return d, nil + + } else { + return d, errors.New("Query failed") + } +} + +func GetAllSensorInfoByYear(sensor_location string, year int) ([]Data, error) { + d := []Data{} + + if db.Mongo.Connected() == true { + + session := db.Mongo.Session.Copy() + defer session.Close() + + c := session.DB(db.Mongo.Info.Database).C(collection) + + err := c.Find(bson.M{"location": sensor_location, "year": year}).All(&d) + + if err != nil { + fmt.Println(err) + return d, nil + } + + return d, nil + + } else { + return d, errors.New("Query failed") + } +} + +func GetAllSensorInfoByMonth(sensor_location string, year int, month string) ([]Data, error) { + d := []Data{} + + if db.Mongo.Connected() == true { + + session := db.Mongo.Session.Copy() + defer session.Close() + + c := session.DB(db.Mongo.Info.Database).C(collection) + + err := c.Find(bson.M{"location": sensor_location, "year": year, "month": month}).All(&d) + + if err != nil { + fmt.Println(err) + return d, nil + } + + return d, nil + + } else { + return d, errors.New("Query failed") + } +} diff --git a/model/driver.go b/model/driver.go deleted file mode 100644 index 9e22db0..0000000 --- a/model/driver.go +++ /dev/null @@ -1,68 +0,0 @@ -package model - -import ( - "gopkg.in/mgo.v2" - "gopkg.in/mgo.v2/bson" - "time" -) - -const ( - DB_URL = "localhost" -) - -type DataStore struct { - session *mgo.Session -} - -func NewSession() *DataStore { - - d := new(DataStore) - s, err := mgo.Dial(DB_URL) - - if err != nil { - panic(err) - } - - d.session = s - - return d -} - -func (ds *DataStore) TestStore(fname string, lname string) { - session := ds.session.Copy() - defer session.Close() - - // Collection People - c := session.DB("test").C("people") - - // Insert Datas - c.Insert(&Person{FirstName: fname, LastName: lname, Timestamp: time.Now()}) - -} - -func (ds *DataStore) SearchName(fname string) []Person { - - session := ds.session.Copy() - defer session.Close() - - // Collection People - c := session.DB("test").C("people") - - var results []Person - - err := c.Find(bson.M{"firstname": fname}).All(&results) - - if err != nil { - panic(err) - } - - return results -} - -/*func (ds *DataStore) ucol() *mgo.Collection { - session = ds.session.Copy() - defer session.Close() -} -*/ - -//func (ds *DataStore) UserExist(user string) bool { ... } diff --git a/model/raw_sensor/raw_sensor.go b/model/raw_sensor/raw_sensor.go new file mode 100644 index 0000000..9b45391 --- /dev/null +++ b/model/raw_sensor/raw_sensor.go @@ -0,0 +1,149 @@ +package raw_sensor + +import ( + "encoding/json" + "errors" + "github.com/mgerb42/mywebsite/db" + "gopkg.in/mgo.v2/bson" + "log" + "time" +) + +const ( + collection = "temperatures" +) + +type Data struct { + ID bson.ObjectId `bson:"_id,omitempty"` + Temperature float64 `json:"temperature" bson:"temperature"` + Location string `json:"location" bson:"location"` + Updated time.Time `json:"updated" bson:"updated"` +} + +//convert struct to json string +func (s *Data) toJson() string { + + b, err := json.MarshalIndent(s, "", " ") + + if err != nil { + log.Println(err.Error) + } + + return string(b) + +} + +func (s *Data) StoreData() error { + + if db.Mongo.Connected() { + + log.Println("Inserting data into " + collection) + + session := db.Mongo.Session.Copy() + defer session.Close() + + c := session.DB(db.Mongo.Info.Database).C(collection) + + // Insert Datas + err := c.Insert(s) + + if err != nil { + return err + } + } + + return nil +} + +//handle queries for all sensors page +//******************************************************************************** +type DataStore_AllSensors struct { + ID string `json:"location" bson:"_id"` + Temperature float64 `json:"temperature" bson:"temperature"` + Updated time.Time `json:"updated" bson:"updated"` +} + +func GetAllSensors() ([]DataStore_AllSensors, error) { + + s := []DataStore_AllSensors{} + + if db.Mongo.Connected() == true { + + session := db.Mongo.Session.Copy() + defer session.Close() + + c := session.DB(db.Mongo.Info.Database).C(collection) + + err := c.Pipe([]bson.M{{"$group": bson.M{"_id": "$location", "temperature": bson.M{"$last": "$temperature"}, + "updated": bson.M{"$last": "$updated"}}}, + bson.M{"$sort": bson.M{"_id": 1}}}).All(&s) + + if err != nil { + return s, nil + } + + return s, nil + + } else { + return s, errors.New("Query failed") + } +} + +//******************************************************************************** + +//get sensor information by location +//******************************************************************************** +type DataStore_SensorByLocation struct { + Id sensorByLocation `json:"_id" bson:"_id"` +} + +type sensorByLocation struct { + Year int `json:"year" bson:"year"` + Month int `json:"month" bson:"month"` + Location string `json:"location" bson:"location"` +} + +/* +func GetSensorInfoByLocation(sensor_location string) ([]DataStore_SensorByLocation, error) { + + s := []DataStore_SensorByLocation{} + + if db.Mongo.Connected() == true { + + session := db.Mongo.Session.Copy() + defer session.Close() + + c := session.DB(db.Mongo.Info.Database).C(collection) + + err := c.Pipe([]bson.M{{"$project": bson.M{"location": "$location", "year": bson.M{"$year": "$updated"}, "month": bson.M{"$month": "$updated"}}}, + bson.M{"$match": bson.M{"location": sensor_location}}, + bson.M{"$group": bson.M{"_id": bson.M{"year": "$year", "month": "$month", "location": "$location"}}}, + bson.M{"$sort": bson.M{"_id.year": -1, "_id.month": -1}}}).All(&s) + + if err != nil { + log.Println(err) + return s, nil + } + + return s, nil + + } else { + return s, errors.New("Query failed") + } + +} +*/ + +//******************************************************************************** + +/************************* + +testStore := model.SensorData{ + ID: bson.NewObjectId(), + Temperature: 34.2, + Humidity: 33.22, + Location: "Grand Meadow", + Updated: time.Now(), +} + +**************************/ diff --git a/public/view/template.html b/public/view/template.html index 47739d6..f869a4c 100644 --- a/public/view/template.html +++ b/public/view/template.html @@ -49,7 +49,7 @@ Resume