Organize and Optimize Code

This commit is contained in:
Supan Adit Pratama 2020-01-04 07:44:42 +07:00
parent 4f2a9128ed
commit bca8a676e5
7 changed files with 187 additions and 157 deletions

145
main.go
View File

@ -3,150 +3,21 @@ package main
import ( import (
"fmt" "fmt"
"github.com/gin-contrib/cors" "github.com/gin-contrib/cors"
"github.com/gin-contrib/sse"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/go-redis/redis" "github.com/go-redis/redis"
"github.com/gorilla/websocket" "github.com/supanadit/geo-smart-system/system"
"github.com/rs/xid"
"github.com/supanadit/geo-smart-system/model"
"github.com/supanadit/geo-smart-system/model/tile38"
"log"
"net/http"
"strings"
) )
func main() { func main() {
port := "8080" // Create Connection with Tile 38
client := redis.NewClient(&redis.Options{ client := redis.NewClient(&redis.Options{
Addr: "192.168.99.100:9851", Addr: system.GetTile38ConnectionAddress(),
}) })
// Create Gin Engine
r := gin.Default() r := gin.Default()
r.Use(cors.Default()) r.Use(cors.Default())
// Call Router
r.GET("/id/get/unique", func(c *gin.Context) { system.Router(r, client)
id := xid.New() // Run Server
c.JSON(200, gin.H{"id": id.String()}) _ = r.Run(fmt.Sprintf(":%s", system.ServerPort))
})
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"))
}
} }

View File

@ -7,12 +7,12 @@ import (
"strconv" "strconv"
) )
type Tile38Data struct { type Data struct {
Object []Tile38Object `json:"data"` Object []Object `json:"data"`
} }
func FromScan(client *redis.Client, name string) (Tile38Data, error) { func FromScan(client *redis.Client, name string) (Data, error) {
var tile38Data Tile38Data var tile38Data Data
var err error var err error
v, err := client.Do("SCAN", name).Result() v, err := client.Do("SCAN", name).Result()
if err == nil { if err == nil {
@ -28,8 +28,8 @@ func FromScan(client *redis.Client, name string) (Tile38Data, error) {
contentName := name + ".1" contentName := name + ".1"
id := gjson.Get(jsonConverted, idName) id := gjson.Get(jsonConverted, idName)
content := gjson.Get(jsonConverted, contentName) content := gjson.Get(jsonConverted, contentName)
var tile38Object Tile38Object var tile38Object Object
var tile38SubObject Tile38SubObject var tile38SubObject SubObject
err = json.Unmarshal([]byte(content.String()), &tile38SubObject) err = json.Unmarshal([]byte(content.String()), &tile38SubObject)
if err == nil { if err == nil {
tile38Object.Id = id.String() tile38Object.Id = id.String()
@ -43,7 +43,7 @@ func FromScan(client *redis.Client, name string) (Tile38Data, error) {
return tile38Data, err return tile38Data, err
} }
func (tile38Data Tile38Data) ToJsonString() (string, error) { func (tile38Data Data) ToJsonString() (string, error) {
var err error var err error
data, err := json.Marshal(tile38Data) data, err := json.Marshal(tile38Data)
return string(data), err return string(data), err

6
model/tile38/object.go Normal file
View File

@ -0,0 +1,6 @@
package tile38
type Object struct {
Id string `json:"id"`
Object SubObject `json:"object"`
}

View File

@ -8,21 +8,21 @@ import (
"strconv" "strconv"
) )
type Tile38SubObject struct { type SubObject struct {
Type string `json:"type"` Type string `json:"type"`
Coordinates []float64 `json:"coordinates"` Coordinates []float64 `json:"coordinates"`
} }
func (tile38SubObject Tile38SubObject) Lng() float64 { func (tile38SubObject SubObject) Lng() float64 {
return tile38SubObject.Coordinates[0] return tile38SubObject.Coordinates[0]
} }
func (tile38SubObject Tile38SubObject) Lat() float64 { func (tile38SubObject SubObject) Lat() float64 {
return tile38SubObject.Coordinates[1] return tile38SubObject.Coordinates[1]
} }
func FromLocation(location model.Location) Tile38SubObject { func FromLocation(location model.Location) SubObject {
var tile38SubObject Tile38SubObject var tile38SubObject SubObject
tile38SubObject.Type = "Point" tile38SubObject.Type = "Point"
lng, _ := strconv.ParseFloat(location.Lng, 64) lng, _ := strconv.ParseFloat(location.Lng, 64)
lat, _ := strconv.ParseFloat(location.Lat, 64) lat, _ := strconv.ParseFloat(location.Lat, 64)
@ -33,8 +33,8 @@ func FromLocation(location model.Location) Tile38SubObject {
return tile38SubObject return tile38SubObject
} }
func GetDataLocation(client *redis.Client, typeLocation string, id string) (Tile38Object, error) { func GetDataLocation(client *redis.Client, typeLocation string, id string) (Object, error) {
var tile38Object Tile38Object var tile38Object Object
var err error var err error
data, err := client.Do("GET", typeLocation, id).Result() data, err := client.Do("GET", typeLocation, id).Result()
if err == nil { if err == nil {

View File

@ -1,6 +0,0 @@
package tile38
type Tile38Object struct {
Id string `json:"id"`
Object Tile38SubObject `json:"object"`
}

19
system/constants.go Normal file
View File

@ -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)
}

140
system/router.go Normal file
View File

@ -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"))
}
}