Author: Paolo Lulli <paolo@lulli.net>
Add Position
schema/schema.cql | 34 +++++++++++++++++++++++++++++ server/db/position.go | 29 +++++++++++++++++++++++++ server/geo/distances_test.go | 13 ++++++++-- server/model/models.go | 8 ++++++ server/rest/rest-position.go | 44 ++++++++++++++++++++++++++++++++++++++
diff --git a/schema/schema.cql b/schema/schema.cql index 0339be5f85ffc2b53ebda480318cfeff5fc0bb88..fad6b290beeea10d17dea832703fb5d4e851d1bf 100644 --- a/schema/schema.cql +++ b/schema/schema.cql @@ -24,6 +24,15 @@ name text, description text, PRIMARY KEY (id_client,name) ); +CREATE TABLE position ( + id_client text, + ptime timestamp, + lat double, + lon double, + name text, + PRIMARY KEY (id_client,ptime) +); + CREATE TABLE location ( hash text, lname text, @@ -42,3 +51,28 @@ ); // select * from location where lat='' and lon='' // select * from location where ltype='' and code='' order by cdist +CREATE TABLE location ( + ltype text, + code text, + cdist double, + hash text, + lat double, + lname text, + lon double, + PRIMARY KEY ((ltype, code), cdist) +) + +use case: +1) actual fixed locations ---> index with H3 + precision (or maidenhead + precision) +2) position points on a path with id_client and optionally a timestamp : no space partitioning +select * from location where hash='x' +select * from position where id_user='x' and timestamp>'x' + +CREATE TABLE position ( + id_client text, + ptime timestamp, + lat double, + lon double, + name text, + PRIMARY KEY (id_client,ptime) +); diff --git a/server/db/position.go b/server/db/position.go new file mode 100644 index 0000000000000000000000000000000000000000..2f1ca31efb2e7219870d1d81fd4a07e447e52d4d --- /dev/null +++ b/server/db/position.go @@ -0,0 +1,29 @@ +/** + * Yats - yats + * + * This file is licensed under the Affero General Public License version 3 or + * later. See the COPYING file. + * + * @author Paolo Lulli <kevwe.com> + * @copyright Paolo Lulli 2024 + */ + +package db + +import ( + "fmt" + "time" +) + +func SavePosition(idClient string, lat float64, lon float64, positionName string) { + q := fmt.Sprintf("insert into position ( id_client, ptime, lat, lon, name) values ('%s',toTimestamp(now()),'%f','%f','%s');", idClient, lat, lon, positionName) + fmt.Printf("q=%s", q) + Session.Query(q).Exec() +} + +func SavePositionAt(idClient string, lat float64, lon float64, tstamp time.Time, positionName string) { + timeAsBytes, _ := tstamp.UTC().MarshalText() + q := fmt.Sprintf("insert into position ( id_client, ptime, lat, lon, name) values ('%s','%s','%f','%f','%s');", idClient, string(timeAsBytes), lat, lon, positionName) + + Session.Query(q).Exec() +} diff --git a/server/geo/distances_test.go b/server/geo/distances_test.go index b326a82771e1254732dde9334d334b2df96b12d5..134dd875d8bbc5afed9cf4bc17e49690051d89fe 100644 --- a/server/geo/distances_test.go +++ b/server/geo/distances_test.go @@ -55,12 +55,19 @@ } func TestH3Cells(t *testing.T) { latLng := h3.NewLatLng(37.775938728915946, -122.41795063018799) - resolution := 9 // between 0 (biggest cell) and 15 (smallest cell) + //resolution := 15 // between 0 (biggest cell) and 15 (smallest cell) - cell := h3.LatLngToCell(latLng, resolution) + for i := 0; i < 16; i++ { + cell := h3.LatLngToCell(latLng, i) + fmt.Printf("Resolution: %d\t id: %s parent: %s\n", i, cell, cell.Parent(i-1)) + } - fmt.Printf("%s", cell) + var p = maidenhead.NewPoint(latLng.Lat, latLng.Lng) + for i := 0; i <= 5; i++ { + locator, _ := p.Locator(i) + fmt.Printf("Locator: %s\n", locator) + } // Output: // 8928308280fffff } diff --git a/server/model/models.go b/server/model/models.go index cd444369a594c4d3339530bee0c0ecda33fdcad6..beaf4bfebe0e9c0d3bcea80049a276510b853aa8 100644 --- a/server/model/models.go +++ b/server/model/models.go @@ -23,6 +23,14 @@ Etime int64 `json:"etime" parquet:"name=etime, type=INT64, convertedtype=TIMESTAMP_MILLIS"` Name string `json:"name" parquet:"name=name, type=BYTE_ARRAY, convertedtype=UTF8"` } +type PositionModel struct { + IdClient string `json:"id_client" parquet:"name=id_client, type=BYTE_ARRAY, convertedtype=UTF8"` + Ptime int64 `json:"ptime" parquet:"name=ptime, type=INT64, convertedtype=TIMESTAMP_MILLIS"` + Lon float64 `json:"lon" parquet:"name=lon, type=DOUBLE"` //TODO Check parquet types + Lat float64 `json:"lat" parquet:"name=lat, type=DOUBLE"` //TODO Check parquet types + Name string `json:"name" parquet:"name=name, type=BYTE_ARRAY, convertedtype=UTF8"` +} + type ClientInfo struct { ID string Created int64 diff --git a/server/rest/rest-position.go b/server/rest/rest-position.go new file mode 100644 index 0000000000000000000000000000000000000000..5300cf4f33637e7c03c2e38c1c93cfb8e7e84553 --- /dev/null +++ b/server/rest/rest-position.go @@ -0,0 +1,44 @@ +package rest + +import ( + "fmt" + "github.com/gin-gonic/gin" + "net/http" + "time" + "yats-server/config" + "yats-server/db" + "yats-server/model" +) + +// WritePosition godoc +// @Param X-SSL-Client-CN header string true "clientCN" +// @Summary write position to db +// @Schemes +// @Description store position +// @Tags Events +// @Accept json +// @Param position body model.PositionModel true "Position body data" +// @Produce json +// @Success 202 {string} WriteEvent +// @Router /position [post] +func WritePosition(cfg config.Configuration) gin.HandlerFunc { + return func(c *gin.Context) { + var position model.PositionModel + + if err := c.BindJSON(&position); err != nil { + c.IndentedJSON(http.StatusAccepted, gin.H{"ret": "-1"}) + return + } + + clientCN := GetClientCN(c, cfg) + fmt.Printf("%s / %s ", clientCN, position.Name) + if position.Ptime == 0 { + db.SavePosition(clientCN, position.Lat, position.Lon, position.Name) + + } else { + unixTimeUTC := time.Unix(position.Ptime, 0) + db.SavePositionAt(clientCN, position.Lat, position.Lon, unixTimeUTC, position.Name) + } + c.IndentedJSON(http.StatusAccepted, gin.H{"ret": "OK"}) + } +}