yats.git

commit c8bfa41a9f98a934cf7d3a17aeefb1f46a83dbc2

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