diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f394ffe --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*.exe +.idea/* + diff --git a/README.md b/README.md index 863462b..08fb68f 100644 Binary files a/README.md and b/README.md differ diff --git a/dataTypes.go b/dataTypes.go new file mode 100644 index 0000000..580dff5 --- /dev/null +++ b/dataTypes.go @@ -0,0 +1,6 @@ +package main + +type StampedReading struct { + Timestamp int + Value interface{} +} diff --git a/hello.go b/hello.go deleted file mode 100644 index 17957ee..0000000 --- a/hello.go +++ /dev/null @@ -1,9 +0,0 @@ -package main - -import ( - "fmt" -) - -func main() { - fmt.Printf("hello, world\n") -} diff --git a/server.go b/server.go new file mode 100644 index 0000000..c60dbcb --- /dev/null +++ b/server.go @@ -0,0 +1,115 @@ +package main + +import ( + "bytes" + "encoding/json" + "fmt" + "math/rand" + "net/http" + "strconv" + "time" +) + +func main() { + dataReadChan := make(chan map[string]StampedReading) // Channel to handle data readings + dataBuffer := make(map[string][]StampedReading) // Map to store readings in until they are sent + + go dataReadLoop(dataReadChan) // Start our async read loop + dataSendTick := time.NewTicker(time.Second * 10) // Ticker to send data + + // Non-blocking channel reads + for { + select { + + case reading := <-dataReadChan: + // We got a data packet + fmt.Printf("New reading: %v\n", reading) + + // Put our reading in the map + for metric, value := range reading { + if record, found := dataBuffer[metric]; !found { + dataBuffer[metric] = []StampedReading{value} + } else { + dataBuffer[metric] = append(record, value) + } + } + + case <-dataSendTick.C: + // Time to send some data + if len(dataBuffer) > 0 { // Only send if we have data + if err := sendData(dataBuffer); err != nil { // Something went wrong + fmt.Printf("Error sending data: %v\n", err) + } else { // Data sent, clear the map + dataBuffer = make(map[string][]StampedReading) + } + } else { // There was no data to send + fmt.Println("Got data send signal but buffer is empty") + // TODO: manage the map so that it doesn't run out of memory and kill everything if we don't send data + } + + } + } +} + +func dataReadLoop(x chan map[string]StampedReading) { + for { + // Send our read packets down the channel + // TODO: error handling + x <- readData() + time.Sleep(time.Second) + } +} + +func readData() map[string]StampedReading { + // TODO: modbus + return map[string]StampedReading{ + "oil.temp": { + Timestamp: int(time.Now().Unix()), + Value: rand.Intn(150), + }, + "fuel.temp": { + Timestamp: int(time.Now().Unix()), + Value: rand.Intn(150), + }, + } +} + +func sendData(data map[string][]StampedReading) error { + + url := "http://localhost:8081/data" + jsonStr, err := json.Marshal(data) + if err != nil { + fmt.Printf("Error marshalling data: %v\n", err) + return err + } + + fmt.Printf("Sending json: %v\n", string(jsonStr)) + + req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonStr)) + fillHeader(req) + + client := &http.Client{} + resp, err := client.Do(req) + if err != nil { + return err + } + + defer func() { + if err := resp.Body.Close(); err != nil { + fmt.Printf("Error: %v", err) + } + }() + + fmt.Println("response Status:", resp.Status) + if resp.StatusCode != 200 { + fmt.Printf("Received a non-200 response: %v\n", resp.StatusCode) + } + + return nil +} + +func fillHeader(req *http.Request) { // Sets the uuid and timestamp for a request + req.Header.Set("Content-Type", "application/json") + req.Header.Set("uuid", "0000001bcd3f") // TODO: get this from somewhere + req.Header.Set("time", strconv.FormatInt(time.Now().Unix(), 10)) +}