diff --git a/main.go b/main.go index fb4913d..f4826a7 100644 --- a/main.go +++ b/main.go @@ -3,150 +3,21 @@ package main import ( "fmt" "github.com/gin-contrib/cors" - "github.com/gin-contrib/sse" "github.com/gin-gonic/gin" "github.com/go-redis/redis" - "github.com/gorilla/websocket" - "github.com/rs/xid" - "github.com/supanadit/geo-smart-system/model" - "github.com/supanadit/geo-smart-system/model/tile38" - "log" - "net/http" - "strings" + "github.com/supanadit/geo-smart-system/system" ) func main() { - port := "8080" - + // Create Connection with Tile 38 client := redis.NewClient(&redis.Options{ - Addr: "192.168.99.100:9851", + Addr: system.GetTile38ConnectionAddress(), }) - + // Create Gin Engine r := gin.Default() r.Use(cors.Default()) - - r.GET("/id/get/unique", func(c *gin.Context) { - id := xid.New() - c.JSON(200, gin.H{"id": id.String()}) - }) - - r.POST("/point/set", func(c *gin.Context) { - var location model.Location - err := c.BindJSON(&location) - client.Do("SET", location.Type, location.Id, "POINT", location.Lat, location.Lng) - var status map[string]interface{} - var httpStatus int - if err != nil { - status = gin.H{"status": "Unknown Error"} - httpStatus = http.StatusInternalServerError - } else { - status = gin.H{"status": "Ok"} - httpStatus = http.StatusOK - } - c.Writer.Header().Set("Content-Type", "application/json") - c.JSON(httpStatus, status) - }) - - r.POST("/point/unset", func(c *gin.Context) { - var location model.Location - err := c.BindJSON(&location) - client.Do("DEL", location.Type, location.Id) - var status map[string]interface{} - var httpStatus int - if err != nil { - status = gin.H{"status": "Unknown Error"} - httpStatus = http.StatusInternalServerError - } else { - status = gin.H{"status": "Ok"} - httpStatus = http.StatusOK - } - c.Writer.Header().Set("Content-Type", "application/json") - c.JSON(httpStatus, status) - }) - - r.GET("/point/get", func(c *gin.Context) { - t := c.DefaultQuery("type", "user") - data, _ := tile38.FromScan(client, t) - c.JSON(http.StatusOK, data) - }) - - r.GET("/point/get/stream", func(c *gin.Context) { - w := c.Writer - t := c.DefaultQuery("type", "user") - data, _ := tile38.FromScan(client, t) - - _ = sse.Encode(w, sse.Event{ - Event: "message", - Data: data, - }) - }) - - r.POST("/detection/set", func(c *gin.Context) { - var detection model.Detection - err := c.BindJSON(&detection) - hookID := "HOOK-" + xid.New().String() - hookURL := "http://192.168.99.1:" + port + "/detection/call?hook=" + hookID - trigger := strings.Join(detection.TriggerType, ",") - var status map[string]interface{} - var httpStatus int - if trigger == "" { - status = gin.H{"status": "Please include trigger type such as 'enter','cross','exit','inside' or 'outside'"} - httpStatus = http.StatusBadRequest - } else { - client.Do("SETHOOK", hookID, hookURL, "NEARBY", detection.Type, "FENCE", "DETECT", trigger, "COMMANDS", "set", "POINT", detection.Lat, detection.Lng) - if err != nil { - status = gin.H{"status": "Unknown Error"} - httpStatus = http.StatusInternalServerError - } else { - status = gin.H{"status": "Ok"} - httpStatus = http.StatusOK - } - } - c.Writer.Header().Set("Content-Type", "application/json") - c.JSON(httpStatus, status) - }) - - r.GET("/detection/call", func(c *gin.Context) { - hookID := c.Query("hook") - if hookID == "" { - c.JSON(http.StatusBadRequest, gin.H{"status": "Wrong Request"}) - } else { - client.Do("DELHOOK", hookID) - c.JSON(http.StatusOK, gin.H{"status": "OK"}) - } - }) - - r.GET("/ws", func(c *gin.Context) { - websocketHandler(c.Writer, c.Request) - }) - - r.Static("/public", "./public") - r.Static("/assets", "./assets") - - _ = r.Run(":" + port) -} - -var websocketUpgrade = websocket.Upgrader{ - ReadBufferSize: 1024, - WriteBufferSize: 1024, - CheckOrigin: func(r *http.Request) bool { - return true - }, -} - -func websocketHandler(w http.ResponseWriter, r *http.Request) { - conn, err := websocketUpgrade.Upgrade(w, r, nil) - if err != nil { - log.Println(err) - return - } - - for { - t, msg, err := conn.ReadMessage() - if err != nil { - break - } - fmt.Printf("Received : %s \n", msg) - _ = conn.WriteMessage(t, []byte("OK")) - } + // Call Router + system.Router(r, client) + // Run Server + _ = r.Run(fmt.Sprintf(":%s", system.ServerPort)) } diff --git a/model/tile38/tile38data.go b/model/tile38/data.go similarity index 77% rename from model/tile38/tile38data.go rename to model/tile38/data.go index a68d9ac..de8fb33 100644 --- a/model/tile38/tile38data.go +++ b/model/tile38/data.go @@ -7,12 +7,12 @@ import ( "strconv" ) -type Tile38Data struct { - Object []Tile38Object `json:"data"` +type Data struct { + Object []Object `json:"data"` } -func FromScan(client *redis.Client, name string) (Tile38Data, error) { - var tile38Data Tile38Data +func FromScan(client *redis.Client, name string) (Data, error) { + var tile38Data Data var err error v, err := client.Do("SCAN", name).Result() if err == nil { @@ -28,8 +28,8 @@ func FromScan(client *redis.Client, name string) (Tile38Data, error) { contentName := name + ".1" id := gjson.Get(jsonConverted, idName) content := gjson.Get(jsonConverted, contentName) - var tile38Object Tile38Object - var tile38SubObject Tile38SubObject + var tile38Object Object + var tile38SubObject SubObject err = json.Unmarshal([]byte(content.String()), &tile38SubObject) if err == nil { tile38Object.Id = id.String() @@ -43,7 +43,7 @@ func FromScan(client *redis.Client, name string) (Tile38Data, error) { return tile38Data, err } -func (tile38Data Tile38Data) ToJsonString() (string, error) { +func (tile38Data Data) ToJsonString() (string, error) { var err error data, err := json.Marshal(tile38Data) return string(data), err diff --git a/model/tile38/object.go b/model/tile38/object.go new file mode 100644 index 0000000..2ba9b11 --- /dev/null +++ b/model/tile38/object.go @@ -0,0 +1,6 @@ +package tile38 + +type Object struct { + Id string `json:"id"` + Object SubObject `json:"object"` +} diff --git a/model/tile38/tile38subobject.go b/model/tile38/subobject.go similarity index 73% rename from model/tile38/tile38subobject.go rename to model/tile38/subobject.go index fd37788..66156c9 100644 --- a/model/tile38/tile38subobject.go +++ b/model/tile38/subobject.go @@ -8,21 +8,21 @@ import ( "strconv" ) -type Tile38SubObject struct { +type SubObject struct { Type string `json:"type"` Coordinates []float64 `json:"coordinates"` } -func (tile38SubObject Tile38SubObject) Lng() float64 { +func (tile38SubObject SubObject) Lng() float64 { return tile38SubObject.Coordinates[0] } -func (tile38SubObject Tile38SubObject) Lat() float64 { +func (tile38SubObject SubObject) Lat() float64 { return tile38SubObject.Coordinates[1] } -func FromLocation(location model.Location) Tile38SubObject { - var tile38SubObject Tile38SubObject +func FromLocation(location model.Location) SubObject { + var tile38SubObject SubObject tile38SubObject.Type = "Point" lng, _ := strconv.ParseFloat(location.Lng, 64) lat, _ := strconv.ParseFloat(location.Lat, 64) @@ -33,8 +33,8 @@ func FromLocation(location model.Location) Tile38SubObject { return tile38SubObject } -func GetDataLocation(client *redis.Client, typeLocation string, id string) (Tile38Object, error) { - var tile38Object Tile38Object +func GetDataLocation(client *redis.Client, typeLocation string, id string) (Object, error) { + var tile38Object Object var err error data, err := client.Do("GET", typeLocation, id).Result() if err == nil { diff --git a/model/tile38/tile38object.go b/model/tile38/tile38object.go deleted file mode 100644 index 5185adc..0000000 --- a/model/tile38/tile38object.go +++ /dev/null @@ -1,6 +0,0 @@ -package tile38 - -type Tile38Object struct { - Id string `json:"id"` - Object Tile38SubObject `json:"object"` -} diff --git a/system/constants.go b/system/constants.go new file mode 100644 index 0000000..c8d7f76 --- /dev/null +++ b/system/constants.go @@ -0,0 +1,19 @@ +package system + +import "fmt" + +const ( + // Tile 38 + Tile38Address = "127.0.0.1" + Tile38Port = "9851" + // Server Port + ServerPort = "8080" +) + +func GetTile38ConnectionAddress() string { + return fmt.Sprintf("%s:%s", Tile38Address, Tile38Port) +} + +func GetTile38HookURL(hookID string) string { + return fmt.Sprintf("http://%s/detection/call?hook=%s", GetTile38ConnectionAddress(), hookID) +} diff --git a/system/router.go b/system/router.go new file mode 100644 index 0000000..31e5e37 --- /dev/null +++ b/system/router.go @@ -0,0 +1,140 @@ +package system + +import ( + "fmt" + "github.com/gin-contrib/sse" + "github.com/gin-gonic/gin" + "github.com/go-redis/redis" + "github.com/gorilla/websocket" + "github.com/rs/xid" + "github.com/supanadit/geo-smart-system/model" + "github.com/supanadit/geo-smart-system/model/tile38" + "log" + "net/http" + "strings" +) + +func Router(r *gin.Engine, client *redis.Client) { + r.GET("/id/get/unique", func(c *gin.Context) { + id := xid.New() + c.JSON(200, gin.H{"id": id.String()}) + }) + + r.POST("/point/set", func(c *gin.Context) { + var location model.Location + err := c.BindJSON(&location) + client.Do("SET", location.Type, location.Id, "POINT", location.Lat, location.Lng) + var status map[string]interface{} + var httpStatus int + if err != nil { + status = gin.H{"status": "Unknown Error"} + httpStatus = http.StatusInternalServerError + } else { + status = gin.H{"status": "Ok"} + httpStatus = http.StatusOK + } + c.Writer.Header().Set("Content-Type", "application/json") + c.JSON(httpStatus, status) + }) + + r.POST("/point/unset", func(c *gin.Context) { + var location model.Location + err := c.BindJSON(&location) + client.Do("DEL", location.Type, location.Id) + var status map[string]interface{} + var httpStatus int + if err != nil { + status = gin.H{"status": "Unknown Error"} + httpStatus = http.StatusInternalServerError + } else { + status = gin.H{"status": "Ok"} + httpStatus = http.StatusOK + } + c.Writer.Header().Set("Content-Type", "application/json") + c.JSON(httpStatus, status) + }) + + r.GET("/point/get", func(c *gin.Context) { + t := c.DefaultQuery("type", "user") + data, _ := tile38.FromScan(client, t) + c.JSON(http.StatusOK, data) + }) + + r.GET("/point/get/stream", func(c *gin.Context) { + w := c.Writer + t := c.DefaultQuery("type", "user") + data, _ := tile38.FromScan(client, t) + + _ = sse.Encode(w, sse.Event{ + Event: "message", + Data: data, + }) + }) + + r.POST("/detection/set", func(c *gin.Context) { + var detection model.Detection + err := c.BindJSON(&detection) + hookID := "HOOK-" + xid.New().String() + hookURL := system.GetTile38HookURL(hookID) + trigger := strings.Join(detection.TriggerType, ",") + var status map[string]interface{} + var httpStatus int + if trigger == "" { + status = gin.H{"status": "Please include trigger type such as 'enter','cross','exit','inside' or 'outside'"} + httpStatus = http.StatusBadRequest + } else { + client.Do("SETHOOK", hookID, hookURL, "NEARBY", detection.Type, "FENCE", "DETECT", trigger, "COMMANDS", "set", "POINT", detection.Lat, detection.Lng) + if err != nil { + status = gin.H{"status": "Unknown Error"} + httpStatus = http.StatusInternalServerError + } else { + status = gin.H{"status": "Ok"} + httpStatus = http.StatusOK + } + } + c.Writer.Header().Set("Content-Type", "application/json") + c.JSON(httpStatus, status) + }) + + r.GET("/detection/call", func(c *gin.Context) { + hookID := c.Query("hook") + if hookID == "" { + c.JSON(http.StatusBadRequest, gin.H{"status": "Wrong Request"}) + } else { + client.Do("DELHOOK", hookID) + c.JSON(http.StatusOK, gin.H{"status": "OK"}) + } + }) + + r.GET("/ws", func(c *gin.Context) { + websocketHandler(c.Writer, c.Request) + }) + + r.Static("/public", "./public") + r.Static("/assets", "./assets") +} + +var websocketUpgrade = websocket.Upgrader{ + ReadBufferSize: 1024, + WriteBufferSize: 1024, + CheckOrigin: func(r *http.Request) bool { + return true + }, +} + +func websocketHandler(w http.ResponseWriter, r *http.Request) { + conn, err := websocketUpgrade.Upgrade(w, r, nil) + if err != nil { + log.Println(err) + return + } + + for { + t, msg, err := conn.ReadMessage() + if err != nil { + break + } + fmt.Printf("Received : %s \n", msg) + _ = conn.WriteMessage(t, []byte("OK")) + } +}