commit a5a5e459bda83fce660240c157b3bce7a0223f94 Author: Supan Adit Pratama Date: Sat Oct 19 23:38:38 2019 +0700 First Initialize diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d48c759 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.idea +.vscode \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..ebd434c --- /dev/null +++ b/README.md @@ -0,0 +1,35 @@ +# GEO Smart System +This is Tile38 Implementation for Golang, and also this software has a purpose to be real time tracking system +simulation such as Uber, Gojek, Grab, etc. The main feature of this software is that it must **lightweight**, +**less memory usage**, and **fast**, and for the live map it will integration with [Geo Smart Map](https://github.com/supanadit/geosmartmap) + +## Requirements +- [Tile38 Server](https://tile38.com/) +- [Golang](https://golang.org/) + +## Todo +- Work with Socket.IO (OK) +- Connect With Tile38 (OK) +- CORS Support (OK) +- Get Data From Tile38 by Command SCAN (OK) +- Set HOOK by GeoFencing Trigger +- Receive New Point by HTTP GET also By Socket.IO and Trigger by Socket.IO Only +- Send Realtime Point by Socket.IO +- Support Nearby Trigger Feature +- Support Enter Area Trigger Feature +- Support Exit Area Trigger Feature + +## License +Copyright 2019 Supan Adit Pratama + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. \ No newline at end of file diff --git a/main.go b/main.go new file mode 100644 index 0000000..3fccc89 --- /dev/null +++ b/main.go @@ -0,0 +1,75 @@ +package main + +import ( + "fmt" + "github.com/gin-contrib/cors" + "github.com/gin-gonic/gin" + "github.com/go-redis/redis" + socketio "github.com/googollee/go-socket.io" + "github.com/supanadit/geosmartsystem/model" + "log" +) + +func main() { + // Tile38 + client := redis.NewClient(&redis.Options{ + Addr: "localhost:9851", + }) + + router := gin.Default() + router.Use(cors.New(cors.Config{ + AllowOrigins: []string{"http://localhost:4200"}, + AllowMethods: []string{"PUT", "PATCH", "POST", "GET"}, + AllowHeaders: []string{"Origin"}, + ExposeHeaders: []string{"Content-Length"}, + AllowWebSockets: true, + AllowCredentials: true, + AllowWildcard: true, + })) + router.GET("/point", func(c *gin.Context) { + data, _ := model.FromScan(client, "sales") + c.JSON(200, data) + }) + // Socket.IO Start + server, err := socketio.NewServer(nil) + if err != nil { + log.Fatal(err) + } + server.OnConnect("/", func(s socketio.Conn) error { + s.SetContext("") + fmt.Println("Connected:", s.ID()) + return nil + }) + server.OnEvent("/", "message", func(s socketio.Conn, msg string) { + s.Emit("message", "have "+msg) + }) + server.OnEvent("/", "bye", func(s socketio.Conn) string { + last := s.Context().(string) + s.Emit("bye", last) + _ = s.Close() + return last + }) + server.OnError("/", func(e error) { + fmt.Println("Meet Error:", e) + }) + server.OnDisconnect("/", func(s socketio.Conn, msg string) { + fmt.Println("Closed", msg) + }) + router.GET("/socket.io/", gin.WrapH(server)) + router.POST("/socket.io/", gin.WrapH(server)) + router.Handle("WS", "/socket.io/", WebSocketIO(server)) + router.Handle("WSS", "/socket.io/", WebSocketIO(server)) + router.GET("/ws", func(c *gin.Context) { + server.ServeHTTP(c.Writer, c.Request) + }) + go server.Serve() + defer server.Close() + // End Socket.IO + _ = router.Run() +} + +func WebSocketIO(server *socketio.Server) gin.HandlerFunc { + return func(c *gin.Context) { + server.ServeHTTP(c.Writer, c.Request) + } +} diff --git a/model/tile38data.go b/model/tile38data.go new file mode 100644 index 0000000..97a9e5a --- /dev/null +++ b/model/tile38data.go @@ -0,0 +1,50 @@ +package model + +import ( + "encoding/json" + "github.com/go-redis/redis" + "github.com/tidwall/gjson" + "strconv" +) + +type Tile38Data struct { + Object []Tile38Object `json:"data"` +} + +func FromScan(client *redis.Client, name string) (Tile38Data, error) { + var tile38Data Tile38Data + var err error + v, err := client.Do("SCAN", name).Result() + if err == nil { + data, err := json.Marshal(v) + if err == nil { + jsonConverted := `{"data":` + string(data) + `}` + lengthData := gjson.Get(jsonConverted, "data.1.#") + if lengthData.Int() != 0 { + var x int64 = 0 + for x = 0; x < lengthData.Int(); x++ { + name := "data.1." + strconv.FormatInt(int64(x), 10) + idName := name + ".0" + contentName := name + ".1" + id := gjson.Get(jsonConverted, idName) + content := gjson.Get(jsonConverted, contentName) + var tile38Object Tile38Object + var tile38SubObject Tile38SubObject + err = json.Unmarshal([]byte(content.String()), &tile38SubObject) + if err == nil { + tile38Object.Id = id.String() + tile38Object.Object = tile38SubObject + tile38Data.Object = append(tile38Data.Object, tile38Object) + } + } + } + } + } + return tile38Data, err +} + +func (tile38Data Tile38Data) ToJsonString() (string, error) { + var err error + data, err := json.Marshal(tile38Data) + return string(data), err +} diff --git a/model/tile38object.go b/model/tile38object.go new file mode 100644 index 0000000..6257248 --- /dev/null +++ b/model/tile38object.go @@ -0,0 +1,6 @@ +package model + +type Tile38Object struct { + Id string `json:"id"` + Object Tile38SubObject `json:"object"` +} diff --git a/model/tile38subobject.go b/model/tile38subobject.go new file mode 100644 index 0000000..c3ad259 --- /dev/null +++ b/model/tile38subobject.go @@ -0,0 +1,14 @@ +package model + +type Tile38SubObject struct { + Type string `json:"type"` + Coordinates []float64 `json:"coordinates"` +} + +func (tile38SubObject Tile38SubObject) Lng() float64 { + return tile38SubObject.Coordinates[0] +} + +func (tile38SubObject Tile38SubObject) Lat() float64 { + return tile38SubObject.Coordinates[1] +}