yats.git

commit 7576451d2b0069e1686784552c10b4ade97a9a9f

Author: Paolo Lulli <paolo@lulli.net>

Add position gRPC service

 clients/rust/generate.sh | 21 -
 server/grpc/metric-grpc-server.go | 8 
 server/proto/yats-grpc.pb.go | 359 +++++++++++++++++++++++++++-----
 server/proto/yats-grpc_grpc.pb.go | 38 +++
 utils/generate.sh | 15 +
 utils/yats-grpc.proto | 67 ++++++


diff --git a/clients/rust/generate.sh b/clients/rust/generate.sh
deleted file mode 100755
index 01b19709e55524756ffa8352061ca55bb2ca6f61..0000000000000000000000000000000000000000
--- a/clients/rust/generate.sh
+++ /dev/null
@@ -1,21 +0,0 @@
-#! /bin/bash -x
-
-
-cd $(dirname $0)
-TARGET_DIR="../../server/proto/"
-
-SOURCES="../../protobuf/yats-grpc.proto"
-
-protoc --rust_out=./src \
-	--grpc_out=./src \
-	--plugin=protoc-gen-grpc=`which grpc_rust_plugin` \
-	--proto_path ../../protobuf/ \
-	../../protobuf/yats-grpc.proto
-exit 0
-for s in ${SOURCES}; do
-  protoc --go_out=${TARGET_DIR}\
-  --go_opt=paths=source_relative\
-  --go-grpc_out=${TARGET_DIR}\
-  --go-grpc_opt=paths=source_relative\
-  ${s}
-done




diff --git a/server/grpc/metric-grpc-server.go b/server/grpc/metric-grpc-server.go
index 7eea62f33c07c28dac2e6fe3455a5fc1a498d674..caa0b441bfe8806d52182ab6c07340881db4da3c 100644
--- a/server/grpc/metric-grpc-server.go
+++ b/server/grpc/metric-grpc-server.go
@@ -41,6 +41,14 @@ 	db.SaveEvent(clientCN, event.Name)
 	return &proto.CreateEventResponse{Event: event}, nil
 }
 
+func (s *server) Createposition(ctx context.Context, req *proto.CreatePositionRequest) (*proto.CreatePositionResponse, error) {
+	position := req.GetPosition()
+	clientCN := position.IdClient
+	fmt.Printf("%s / %s ", clientCN, position.Name)
+	db.SavePosition(clientCN, position.Lat, position.Lon, position.Name)
+	return &proto.CreatePositionResponse{Position: position}, nil
+}
+
 func RunYatsGrpcServer(address string) {
 	lis, err := net.Listen("tcp", address)
 	if err != nil {




diff --git a/server/proto/yats-grpc.pb.go b/server/proto/yats-grpc.pb.go
index cd1f73ce4f99c6c104ef0b799206b1d7d7a30483..657ab564710cd62a3bec309201ea875b302f2182 100644
--- a/server/proto/yats-grpc.pb.go
+++ b/server/proto/yats-grpc.pb.go
@@ -163,6 +163,85 @@ 	}
 	return ""
 }
 
+type Position struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	IdClient string  `protobuf:"bytes,1,opt,name=id_client,json=idClient,proto3" json:"id_client,omitempty"`
+	Ptime    int64   `protobuf:"varint,2,opt,name=ptime,proto3" json:"ptime,omitempty"`
+	Lat      float64 `protobuf:"fixed64,3,opt,name=lat,proto3" json:"lat,omitempty"`
+	Lon      float64 `protobuf:"fixed64,4,opt,name=lon,proto3" json:"lon,omitempty"`
+	Name     string  `protobuf:"bytes,5,opt,name=name,proto3" json:"name,omitempty"`
+}
+
+func (x *Position) Reset() {
+	*x = Position{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_yats_grpc_proto_msgTypes[2]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *Position) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Position) ProtoMessage() {}
+
+func (x *Position) ProtoReflect() protoreflect.Message {
+	mi := &file_yats_grpc_proto_msgTypes[2]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Position.ProtoReflect.Descriptor instead.
+func (*Position) Descriptor() ([]byte, []int) {
+	return file_yats_grpc_proto_rawDescGZIP(), []int{2}
+}
+
+func (x *Position) GetIdClient() string {
+	if x != nil {
+		return x.IdClient
+	}
+	return ""
+}
+
+func (x *Position) GetPtime() int64 {
+	if x != nil {
+		return x.Ptime
+	}
+	return 0
+}
+
+func (x *Position) GetLat() float64 {
+	if x != nil {
+		return x.Lat
+	}
+	return 0
+}
+
+func (x *Position) GetLon() float64 {
+	if x != nil {
+		return x.Lon
+	}
+	return 0
+}
+
+func (x *Position) GetName() string {
+	if x != nil {
+		return x.Name
+	}
+	return ""
+}
+
 type CreateMetricRequest struct {
 	state         protoimpl.MessageState
 	sizeCache     protoimpl.SizeCache
@@ -174,7 +253,7 @@
 func (x *CreateMetricRequest) Reset() {
 	*x = CreateMetricRequest{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_yats_grpc_proto_msgTypes[2]
+		mi := &file_yats_grpc_proto_msgTypes[3]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -187,7 +266,7 @@
 func (*CreateMetricRequest) ProtoMessage() {}
 
 func (x *CreateMetricRequest) ProtoReflect() protoreflect.Message {
-	mi := &file_yats_grpc_proto_msgTypes[2]
+	mi := &file_yats_grpc_proto_msgTypes[3]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -200,7 +279,7 @@ }
 
 // Deprecated: Use CreateMetricRequest.ProtoReflect.Descriptor instead.
 func (*CreateMetricRequest) Descriptor() ([]byte, []int) {
-	return file_yats_grpc_proto_rawDescGZIP(), []int{2}
+	return file_yats_grpc_proto_rawDescGZIP(), []int{3}
 }
 
 func (x *CreateMetricRequest) GetMetric() *Metric {
@@ -221,7 +300,7 @@
 func (x *CreateMetricResponse) Reset() {
 	*x = CreateMetricResponse{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_yats_grpc_proto_msgTypes[3]
+		mi := &file_yats_grpc_proto_msgTypes[4]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -234,7 +313,7 @@
 func (*CreateMetricResponse) ProtoMessage() {}
 
 func (x *CreateMetricResponse) ProtoReflect() protoreflect.Message {
-	mi := &file_yats_grpc_proto_msgTypes[3]
+	mi := &file_yats_grpc_proto_msgTypes[4]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -247,7 +326,7 @@ }
 
 // Deprecated: Use CreateMetricResponse.ProtoReflect.Descriptor instead.
 func (*CreateMetricResponse) Descriptor() ([]byte, []int) {
-	return file_yats_grpc_proto_rawDescGZIP(), []int{3}
+	return file_yats_grpc_proto_rawDescGZIP(), []int{4}
 }
 
 func (x *CreateMetricResponse) GetMetric() *Metric {
@@ -268,7 +347,7 @@
 func (x *CreateEventRequest) Reset() {
 	*x = CreateEventRequest{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_yats_grpc_proto_msgTypes[4]
+		mi := &file_yats_grpc_proto_msgTypes[5]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -281,7 +360,7 @@
 func (*CreateEventRequest) ProtoMessage() {}
 
 func (x *CreateEventRequest) ProtoReflect() protoreflect.Message {
-	mi := &file_yats_grpc_proto_msgTypes[4]
+	mi := &file_yats_grpc_proto_msgTypes[5]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -294,7 +373,7 @@ }
 
 // Deprecated: Use CreateEventRequest.ProtoReflect.Descriptor instead.
 func (*CreateEventRequest) Descriptor() ([]byte, []int) {
-	return file_yats_grpc_proto_rawDescGZIP(), []int{4}
+	return file_yats_grpc_proto_rawDescGZIP(), []int{5}
 }
 
 func (x *CreateEventRequest) GetEvent() *Event {
@@ -315,7 +394,7 @@
 func (x *CreateEventResponse) Reset() {
 	*x = CreateEventResponse{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_yats_grpc_proto_msgTypes[5]
+		mi := &file_yats_grpc_proto_msgTypes[6]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -328,7 +407,7 @@
 func (*CreateEventResponse) ProtoMessage() {}
 
 func (x *CreateEventResponse) ProtoReflect() protoreflect.Message {
-	mi := &file_yats_grpc_proto_msgTypes[5]
+	mi := &file_yats_grpc_proto_msgTypes[6]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -341,7 +420,7 @@ }
 
 // Deprecated: Use CreateEventResponse.ProtoReflect.Descriptor instead.
 func (*CreateEventResponse) Descriptor() ([]byte, []int) {
-	return file_yats_grpc_proto_rawDescGZIP(), []int{5}
+	return file_yats_grpc_proto_rawDescGZIP(), []int{6}
 }
 
 func (x *CreateEventResponse) GetEvent() *Event {
@@ -351,6 +430,100 @@ 	}
 	return nil
 }
 
+type CreatePositionRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Position *Position `protobuf:"bytes,1,opt,name=position,proto3" json:"position,omitempty"`
+}
+
+func (x *CreatePositionRequest) Reset() {
+	*x = CreatePositionRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_yats_grpc_proto_msgTypes[7]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *CreatePositionRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*CreatePositionRequest) ProtoMessage() {}
+
+func (x *CreatePositionRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_yats_grpc_proto_msgTypes[7]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use CreatePositionRequest.ProtoReflect.Descriptor instead.
+func (*CreatePositionRequest) Descriptor() ([]byte, []int) {
+	return file_yats_grpc_proto_rawDescGZIP(), []int{7}
+}
+
+func (x *CreatePositionRequest) GetPosition() *Position {
+	if x != nil {
+		return x.Position
+	}
+	return nil
+}
+
+type CreatePositionResponse struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Position *Position `protobuf:"bytes,1,opt,name=position,proto3" json:"position,omitempty"`
+}
+
+func (x *CreatePositionResponse) Reset() {
+	*x = CreatePositionResponse{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_yats_grpc_proto_msgTypes[8]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *CreatePositionResponse) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*CreatePositionResponse) ProtoMessage() {}
+
+func (x *CreatePositionResponse) ProtoReflect() protoreflect.Message {
+	mi := &file_yats_grpc_proto_msgTypes[8]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use CreatePositionResponse.ProtoReflect.Descriptor instead.
+func (*CreatePositionResponse) Descriptor() ([]byte, []int) {
+	return file_yats_grpc_proto_rawDescGZIP(), []int{8}
+}
+
+func (x *CreatePositionResponse) GetPosition() *Position {
+	if x != nil {
+		return x.Position
+	}
+	return nil
+}
+
 var File_yats_grpc_proto protoreflect.FileDescriptor
 
 var file_yats_grpc_proto_rawDesc = []byte{
@@ -366,35 +539,56 @@ 	0x0a, 0x05, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x69, 0x64, 0x5f, 0x63, 0x6c,
 	0x69, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x69, 0x64, 0x43, 0x6c,
 	0x69, 0x65, 0x6e, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x02, 0x20,
 	0x01, 0x28, 0x03, 0x52, 0x05, 0x65, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61,
-	0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x3b,
-	0x0a, 0x13, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x52, 0x65,
-	0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x24, 0x0a, 0x06, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x18,
-	0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x79, 0x61, 0x74, 0x73, 0x2e, 0x4d, 0x65, 0x74,
-	0x72, 0x69, 0x63, 0x52, 0x06, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x22, 0x3c, 0x0a, 0x14, 0x43,
-	0x72, 0x65, 0x61, 0x74, 0x65, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x52, 0x65, 0x73, 0x70, 0x6f,
-	0x6e, 0x73, 0x65, 0x12, 0x24, 0x0a, 0x06, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x18, 0x01, 0x20,
-	0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x79, 0x61, 0x74, 0x73, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69,
-	0x63, 0x52, 0x06, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x22, 0x37, 0x0a, 0x12, 0x43, 0x72, 0x65,
-	0x61, 0x74, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
-	0x21, 0x0a, 0x05, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0b,
-	0x2e, 0x79, 0x61, 0x74, 0x73, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x05, 0x65, 0x76, 0x65,
-	0x6e, 0x74, 0x22, 0x38, 0x0a, 0x13, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x45, 0x76, 0x65, 0x6e,
-	0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x21, 0x0a, 0x05, 0x65, 0x76, 0x65,
-	0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x79, 0x61, 0x74, 0x73, 0x2e,
-	0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x05, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x32, 0x9c, 0x01, 0x0a,
-	0x0f, 0x59, 0x61, 0x74, 0x73, 0x47, 0x72, 0x70, 0x63, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65,
-	0x12, 0x45, 0x0a, 0x0c, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63,
-	0x12, 0x19, 0x2e, 0x79, 0x61, 0x74, 0x73, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4d, 0x65,
-	0x74, 0x72, 0x69, 0x63, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x79, 0x61,
-	0x74, 0x73, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x52,
-	0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x42, 0x0a, 0x0b, 0x43, 0x72, 0x65, 0x61, 0x74,
-	0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x18, 0x2e, 0x79, 0x61, 0x74, 0x73, 0x2e, 0x43, 0x72,
-	0x65, 0x61, 0x74, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
-	0x1a, 0x19, 0x2e, 0x79, 0x61, 0x74, 0x73, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x45, 0x76,
-	0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x27, 0x0a, 0x17, 0x63,
-	0x6f, 0x6d, 0x2e, 0x6b, 0x65, 0x76, 0x77, 0x65, 0x2e, 0x79, 0x61, 0x74, 0x73, 0x2e, 0x70, 0x72,
-	0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x50, 0x01, 0x5a, 0x0a, 0x79, 0x61, 0x74, 0x73, 0x2f, 0x70,
-	0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+	0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x75,
+	0x0a, 0x08, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1b, 0x0a, 0x09, 0x69, 0x64,
+	0x5f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x69,
+	0x64, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x70, 0x74, 0x69, 0x6d, 0x65,
+	0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x10, 0x0a,
+	0x03, 0x6c, 0x61, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x01, 0x52, 0x03, 0x6c, 0x61, 0x74, 0x12,
+	0x10, 0x0a, 0x03, 0x6c, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x01, 0x52, 0x03, 0x6c, 0x6f,
+	0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52,
+	0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x3b, 0x0a, 0x13, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4d,
+	0x65, 0x74, 0x72, 0x69, 0x63, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x24, 0x0a, 0x06,
+	0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x79,
+	0x61, 0x74, 0x73, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x52, 0x06, 0x6d, 0x65, 0x74, 0x72,
+	0x69, 0x63, 0x22, 0x3c, 0x0a, 0x14, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4d, 0x65, 0x74, 0x72,
+	0x69, 0x63, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x24, 0x0a, 0x06, 0x6d, 0x65,
+	0x74, 0x72, 0x69, 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x79, 0x61, 0x74,
+	0x73, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x52, 0x06, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63,
+	0x22, 0x37, 0x0a, 0x12, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52,
+	0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x05, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x18,
+	0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x79, 0x61, 0x74, 0x73, 0x2e, 0x45, 0x76, 0x65,
+	0x6e, 0x74, 0x52, 0x05, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x22, 0x38, 0x0a, 0x13, 0x43, 0x72, 0x65,
+	0x61, 0x74, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
+	0x12, 0x21, 0x0a, 0x05, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32,
+	0x0b, 0x2e, 0x79, 0x61, 0x74, 0x73, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x05, 0x65, 0x76,
+	0x65, 0x6e, 0x74, 0x22, 0x43, 0x0a, 0x15, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x6f, 0x73,
+	0x69, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2a, 0x0a, 0x08,
+	0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e,
+	0x2e, 0x79, 0x61, 0x74, 0x73, 0x2e, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x08,
+	0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x44, 0x0a, 0x16, 0x43, 0x72, 0x65, 0x61,
+	0x74, 0x65, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
+	0x73, 0x65, 0x12, 0x2a, 0x0a, 0x08, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01,
+	0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x79, 0x61, 0x74, 0x73, 0x2e, 0x50, 0x6f, 0x73, 0x69,
+	0x74, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x32, 0xe9,
+	0x01, 0x0a, 0x0f, 0x59, 0x61, 0x74, 0x73, 0x47, 0x72, 0x70, 0x63, 0x53, 0x65, 0x72, 0x76, 0x69,
+	0x63, 0x65, 0x12, 0x45, 0x0a, 0x0c, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4d, 0x65, 0x74, 0x72,
+	0x69, 0x63, 0x12, 0x19, 0x2e, 0x79, 0x61, 0x74, 0x73, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65,
+	0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e,
+	0x79, 0x61, 0x74, 0x73, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4d, 0x65, 0x74, 0x72, 0x69,
+	0x63, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x42, 0x0a, 0x0b, 0x43, 0x72, 0x65,
+	0x61, 0x74, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x18, 0x2e, 0x79, 0x61, 0x74, 0x73, 0x2e,
+	0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65,
+	0x73, 0x74, 0x1a, 0x19, 0x2e, 0x79, 0x61, 0x74, 0x73, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65,
+	0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4b, 0x0a,
+	0x0e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12,
+	0x1b, 0x2e, 0x79, 0x61, 0x74, 0x73, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x6f, 0x73,
+	0x69, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x79,
+	0x61, 0x74, 0x73, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69,
+	0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x27, 0x0a, 0x17, 0x63, 0x6f,
+	0x6d, 0x2e, 0x6b, 0x65, 0x76, 0x77, 0x65, 0x2e, 0x79, 0x61, 0x74, 0x73, 0x2e, 0x70, 0x72, 0x6f,
+	0x74, 0x6f, 0x62, 0x75, 0x66, 0x50, 0x01, 0x5a, 0x0a, 0x79, 0x61, 0x74, 0x73, 0x2f, 0x70, 0x72,
+	0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
 }
 
 var (
@@ -409,29 +603,36 @@ 	})
 	return file_yats_grpc_proto_rawDescData
 }
 
-var file_yats_grpc_proto_msgTypes = make([]protoimpl.MessageInfo, 6)
+var file_yats_grpc_proto_msgTypes = make([]protoimpl.MessageInfo, 9)
 var file_yats_grpc_proto_goTypes = []interface{}{
-	(*Metric)(nil),               // 0: yats.Metric
-	(*Event)(nil),                // 1: yats.Event
-	(*CreateMetricRequest)(nil),  // 2: yats.CreateMetricRequest
-	(*CreateMetricResponse)(nil), // 3: yats.CreateMetricResponse
-	(*CreateEventRequest)(nil),   // 4: yats.CreateEventRequest
-	(*CreateEventResponse)(nil),  // 5: yats.CreateEventResponse
+	(*Metric)(nil),                 // 0: yats.Metric
+	(*Event)(nil),                  // 1: yats.Event
+	(*Position)(nil),               // 2: yats.Position
+	(*CreateMetricRequest)(nil),    // 3: yats.CreateMetricRequest
+	(*CreateMetricResponse)(nil),   // 4: yats.CreateMetricResponse
+	(*CreateEventRequest)(nil),     // 5: yats.CreateEventRequest
+	(*CreateEventResponse)(nil),    // 6: yats.CreateEventResponse
+	(*CreatePositionRequest)(nil),  // 7: yats.CreatePositionRequest
+	(*CreatePositionResponse)(nil), // 8: yats.CreatePositionResponse
 }
 var file_yats_grpc_proto_depIdxs = []int32{
 	0, // 0: yats.CreateMetricRequest.metric:type_name -> yats.Metric
 	0, // 1: yats.CreateMetricResponse.metric:type_name -> yats.Metric
 	1, // 2: yats.CreateEventRequest.event:type_name -> yats.Event
 	1, // 3: yats.CreateEventResponse.event:type_name -> yats.Event
-	2, // 4: yats.YatsGrpcService.CreateMetric:input_type -> yats.CreateMetricRequest
-	4, // 5: yats.YatsGrpcService.CreateEvent:input_type -> yats.CreateEventRequest
-	3, // 6: yats.YatsGrpcService.CreateMetric:output_type -> yats.CreateMetricResponse
-	5, // 7: yats.YatsGrpcService.CreateEvent:output_type -> yats.CreateEventResponse
-	6, // [6:8] is the sub-list for method output_type
-	4, // [4:6] is the sub-list for method input_type
-	4, // [4:4] is the sub-list for extension type_name
-	4, // [4:4] is the sub-list for extension extendee
-	0, // [0:4] is the sub-list for field type_name
+	2, // 4: yats.CreatePositionRequest.position:type_name -> yats.Position
+	2, // 5: yats.CreatePositionResponse.position:type_name -> yats.Position
+	3, // 6: yats.YatsGrpcService.CreateMetric:input_type -> yats.CreateMetricRequest
+	5, // 7: yats.YatsGrpcService.CreateEvent:input_type -> yats.CreateEventRequest
+	7, // 8: yats.YatsGrpcService.CreatePosition:input_type -> yats.CreatePositionRequest
+	4, // 9: yats.YatsGrpcService.CreateMetric:output_type -> yats.CreateMetricResponse
+	6, // 10: yats.YatsGrpcService.CreateEvent:output_type -> yats.CreateEventResponse
+	8, // 11: yats.YatsGrpcService.CreatePosition:output_type -> yats.CreatePositionResponse
+	9, // [9:12] is the sub-list for method output_type
+	6, // [6:9] is the sub-list for method input_type
+	6, // [6:6] is the sub-list for extension type_name
+	6, // [6:6] is the sub-list for extension extendee
+	0, // [0:6] is the sub-list for field type_name
 }
 
 func init() { file_yats_grpc_proto_init() }
@@ -465,7 +666,7 @@ 				return nil
 			}
 		}
 		file_yats_grpc_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*CreateMetricRequest); i {
+			switch v := v.(*Position); i {
 			case 0:
 				return &v.state
 			case 1:
@@ -477,7 +678,7 @@ 				return nil
 			}
 		}
 		file_yats_grpc_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*CreateMetricResponse); i {
+			switch v := v.(*CreateMetricRequest); i {
 			case 0:
 				return &v.state
 			case 1:
@@ -489,7 +690,7 @@ 				return nil
 			}
 		}
 		file_yats_grpc_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*CreateEventRequest); i {
+			switch v := v.(*CreateMetricResponse); i {
 			case 0:
 				return &v.state
 			case 1:
@@ -501,6 +702,18 @@ 				return nil
 			}
 		}
 		file_yats_grpc_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*CreateEventRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_yats_grpc_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
 			switch v := v.(*CreateEventResponse); i {
 			case 0:
 				return &v.state
@@ -512,6 +725,30 @@ 			default:
 				return nil
 			}
 		}
+		file_yats_grpc_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*CreatePositionRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_yats_grpc_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*CreatePositionResponse); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
 	}
 	type x struct{}
 	out := protoimpl.TypeBuilder{
@@ -519,7 +756,7 @@ 		File: protoimpl.DescBuilder{
 			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
 			RawDescriptor: file_yats_grpc_proto_rawDesc,
 			NumEnums:      0,
-			NumMessages:   6,
+			NumMessages:   9,
 			NumExtensions: 0,
 			NumServices:   1,
 		},




diff --git a/server/proto/yats-grpc_grpc.pb.go b/server/proto/yats-grpc_grpc.pb.go
index 2a1516696f714b60e27db889d88e409a02f89abe..71aadc11617e90f45d99a997ba1707e4fe3fdee4 100644
--- a/server/proto/yats-grpc_grpc.pb.go
+++ b/server/proto/yats-grpc_grpc.pb.go
@@ -11,7 +11,7 @@ )
 
 // This is a compile-time assertion to ensure that this generated file
 // is compatible with the grpc package it is being compiled against.
-const _ = grpc.SupportPackageIsVersion6
+const _ = grpc.SupportPackageIsVersion7
 
 // YatsGrpcServiceClient is the client API for YatsGrpcService service.
 //
@@ -19,6 +19,7 @@ // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
 type YatsGrpcServiceClient interface {
 	CreateMetric(ctx context.Context, in *CreateMetricRequest, opts ...grpc.CallOption) (*CreateMetricResponse, error)
 	CreateEvent(ctx context.Context, in *CreateEventRequest, opts ...grpc.CallOption) (*CreateEventResponse, error)
+	CreatePosition(ctx context.Context, in *CreatePositionRequest, opts ...grpc.CallOption) (*CreatePositionResponse, error)
 }
 
 type yatsGrpcServiceClient struct {
@@ -47,12 +48,22 @@ 	}
 	return out, nil
 }
 
+func (c *yatsGrpcServiceClient) CreatePosition(ctx context.Context, in *CreatePositionRequest, opts ...grpc.CallOption) (*CreatePositionResponse, error) {
+	out := new(CreatePositionResponse)
+	err := c.cc.Invoke(ctx, "/yats.YatsGrpcService/CreatePosition", in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
 // YatsGrpcServiceServer is the server API for YatsGrpcService service.
 // All implementations must embed UnimplementedYatsGrpcServiceServer
 // for forward compatibility
 type YatsGrpcServiceServer interface {
 	CreateMetric(context.Context, *CreateMetricRequest) (*CreateMetricResponse, error)
 	CreateEvent(context.Context, *CreateEventRequest) (*CreateEventResponse, error)
+	CreatePosition(context.Context, *CreatePositionRequest) (*CreatePositionResponse, error)
 	mustEmbedUnimplementedYatsGrpcServiceServer()
 }
 
@@ -65,6 +76,9 @@ 	return nil, status.Errorf(codes.Unimplemented, "method CreateMetric not implemented")
 }
 func (UnimplementedYatsGrpcServiceServer) CreateEvent(context.Context, *CreateEventRequest) (*CreateEventResponse, error) {
 	return nil, status.Errorf(codes.Unimplemented, "method CreateEvent not implemented")
+}
+func (UnimplementedYatsGrpcServiceServer) CreatePosition(context.Context, *CreatePositionRequest) (*CreatePositionResponse, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method CreatePosition not implemented")
 }
 func (UnimplementedYatsGrpcServiceServer) mustEmbedUnimplementedYatsGrpcServiceServer() {}
 
@@ -115,6 +129,24 @@ 	}
 	return interceptor(ctx, in, info, handler)
 }
 
+func _YatsGrpcService_CreatePosition_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(CreatePositionRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(YatsGrpcServiceServer).CreatePosition(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/yats.YatsGrpcService/CreatePosition",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(YatsGrpcServiceServer).CreatePosition(ctx, req.(*CreatePositionRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
 var _YatsGrpcService_serviceDesc = grpc.ServiceDesc{
 	ServiceName: "yats.YatsGrpcService",
 	HandlerType: (*YatsGrpcServiceServer)(nil),
@@ -126,6 +158,10 @@ 		},
 		{
 			MethodName: "CreateEvent",
 			Handler:    _YatsGrpcService_CreateEvent_Handler,
+		},
+		{
+			MethodName: "CreatePosition",
+			Handler:    _YatsGrpcService_CreatePosition_Handler,
 		},
 	},
 	Streams:  []grpc.StreamDesc{},




diff --git a/utils/generate.sh b/utils/generate.sh
new file mode 100755
index 0000000000000000000000000000000000000000..a7e28818d288f9a5e4fe4a420273f01243cf648e
--- /dev/null
+++ b/utils/generate.sh
@@ -0,0 +1,15 @@
+#! /bin/bash -x
+
+
+cd $(dirname $0)
+TARGET_DIR="../server/proto/"
+
+SOURCES="./yats-grpc.proto"
+
+for s in ${SOURCES}; do
+  protoc --go_out=${TARGET_DIR}\
+  --go_opt=paths=source_relative\
+  --go-grpc_out=${TARGET_DIR}\
+  --go-grpc_opt=paths=source_relative\
+  ${s}
+done




diff --git a/utils/yats-grpc.proto b/utils/yats-grpc.proto
new file mode 100644
index 0000000000000000000000000000000000000000..e4d1dab83fecabcdab3cc9c0af7c790b3646a48b
--- /dev/null
+++ b/utils/yats-grpc.proto
@@ -0,0 +1,67 @@
+/**
+ * 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
+ */
+
+syntax = "proto3";
+package yats;
+
+option java_package = "com.kevwe.yats.protobuf";
+option java_multiple_files = true;
+option go_package = "yats/proto";
+
+message Metric {
+  string id_client = 1;
+  int64 mtime = 2;
+  string name = 3;
+  string value = 4;
+}
+
+message Event {
+  string id_client = 1;
+  int64 etime = 2;
+  string name = 3;
+}
+
+message Position {
+  string id_client = 1;
+  int64 ptime = 2;
+  double lat = 3;
+  double lon = 4;
+  string name = 5;
+}
+
+message CreateMetricRequest {
+  Metric metric = 1;
+}
+
+message CreateMetricResponse {
+  Metric metric = 1;
+}
+
+message CreateEventRequest {
+  Event event = 1;
+}
+
+message CreateEventResponse {
+  Event event = 1;
+}
+
+message CreatePositionRequest {
+  Position position = 1;
+}
+
+message CreatePositionResponse {
+  Position position = 1;
+}
+
+service YatsGrpcService {
+  rpc CreateMetric(CreateMetricRequest) returns (CreateMetricResponse);
+  rpc CreateEvent(CreateEventRequest) returns (CreateEventResponse);
+  rpc CreatePosition(CreatePositionRequest) returns (CreatePositionResponse);
+}