Add location service (#29)

* Add location service

* Update README.md
This commit is contained in:
Asim Aslam
2020-11-17 22:22:33 +00:00
committed by GitHub
parent 8f8e9a3a06
commit 25ae1f2b98
15 changed files with 869 additions and 0 deletions

1
go.mod
View File

@@ -8,6 +8,7 @@ require (
github.com/golang/protobuf v1.4.3
github.com/google/uuid v1.1.2
github.com/gosimple/slug v1.9.0
github.com/hailocab/go-geoindex v0.0.0-20160127134810-64631bfe9711
github.com/micro/dev v0.0.0-20201111162228-80c2b20de2db
github.com/micro/go-micro/v2 v2.9.1 // indirect
github.com/micro/micro/v3 v3.0.0-beta.7

2
go.sum
View File

@@ -260,6 +260,8 @@ github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgf
github.com/grpc-ecosystem/grpc-gateway v1.8.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI=
github.com/hailocab/go-geoindex v0.0.0-20160127134810-64631bfe9711 h1:Oi8hPOZX0gaM2sPVXse2bMpfOjP47a7O61YuB6Z4sGk=
github.com/hailocab/go-geoindex v0.0.0-20160127134810-64631bfe9711/go.mod h1:+v2qJ3UZe4q2GfgZO4od004F/cMgJbmPSs7dD/ZMUkY=
github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM=
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=

2
location/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
location

3
location/Dockerfile Normal file
View File

@@ -0,0 +1,3 @@
FROM alpine
ADD location /location
ENTRYPOINT [ "/location" ]

22
location/Makefile Normal file
View File

@@ -0,0 +1,22 @@
GOPATH:=$(shell go env GOPATH)
.PHONY: init
init:
go get -u github.com/golang/protobuf/proto
go get -u github.com/golang/protobuf/protoc-gen-go
go get github.com/micro/micro/v3/cmd/protoc-gen-micro
.PHONY: proto
proto:
protoc --proto_path=. --micro_out=. --go_out=:. proto/location.proto
.PHONY: build
build:
go build -o location *.go
.PHONY: test
test:
go test -v ./... -cover
.PHONY: docker
docker:
docker build . -t location:latest

23
location/README.md Normal file
View File

@@ -0,0 +1,23 @@
# Location Service
A realtime GPS location tracking and search service
Generated with
```
micro new location
```
## Usage
Generate the proto code
```
make proto
```
Run the service
```
micro run .
```

104
location/domain/domain.go Normal file
View File

@@ -0,0 +1,104 @@
package domain
import (
"sync"
geo "github.com/hailocab/go-geoindex"
"github.com/micro/micro/v3/service/errors"
common "github.com/micro/services/location/proto"
)
var (
mtx sync.RWMutex
defaultIndex = geo.NewPointsIndex(geo.Km(0.5))
)
type Entity struct {
ID string
Type string
Latitude float64
Longitude float64
Timestamp int64
}
func (e *Entity) Id() string {
return e.ID
}
func (e *Entity) Lat() float64 {
return e.Latitude
}
func (e *Entity) Lon() float64 {
return e.Longitude
}
func (e *Entity) ToProto() *common.Entity {
return &common.Entity{
Id: e.ID,
Type: e.Type,
Location: &common.Point{
Latitude: e.Latitude,
Longitude: e.Longitude,
Timestamp: e.Timestamp,
},
}
}
func ProtoToEntity(e *common.Entity) *Entity {
return &Entity{
ID: e.Id,
Type: e.Type,
Latitude: e.Location.Latitude,
Longitude: e.Location.Longitude,
Timestamp: e.Location.Timestamp,
}
}
func Read(id string) (*Entity, error) {
mtx.RLock()
defer mtx.RUnlock()
p := defaultIndex.Get(id)
if p == nil {
return nil, errors.NotFound("location.read", "Not found")
}
entity, ok := p.(*Entity)
if !ok {
return nil, errors.InternalServerError("location.read", "Error reading entity")
}
return entity, nil
}
func Save(e *Entity) {
mtx.Lock()
defaultIndex.Add(e)
mtx.Unlock()
}
func Search(typ string, entity *Entity, radius float64, numEntities int) []*Entity {
mtx.RLock()
defer mtx.RUnlock()
points := defaultIndex.KNearest(entity, numEntities, geo.Meters(radius), func(p geo.Point) bool {
e, ok := p.(*Entity)
if !ok || e.Type != typ {
return false
}
return true
})
var entities []*Entity
for _, point := range points {
e, ok := point.(*Entity)
if !ok {
continue
}
entities = append(entities, e)
}
return entities
}

3
location/generate.go Normal file
View File

@@ -0,0 +1,3 @@
package main
//go:generate make proto

View File

@@ -0,0 +1,67 @@
package handler
import (
"context"
"log"
"github.com/micro/micro/v3/service"
"github.com/micro/micro/v3/service/errors"
"github.com/micro/services/location/domain"
loc "github.com/micro/services/location/proto"
"github.com/micro/services/location/subscriber"
)
type Location struct{}
func (l *Location) Read(ctx context.Context, req *loc.ReadRequest, rsp *loc.ReadResponse) error {
log.Print("Received Location.Read request")
id := req.Id
if len(id) == 0 {
return errors.BadRequest("location.read", "Require Id")
}
entity, err := domain.Read(id)
if err != nil {
return err
}
rsp.Entity = entity.ToProto()
return nil
}
func (l *Location) Save(ctx context.Context, req *loc.SaveRequest, rsp *loc.SaveResponse) error {
log.Print("Received Location.Save request")
entity := req.GetEntity()
if entity.GetLocation() == nil {
return errors.BadRequest("location.save", "Require location")
}
p := service.NewEvent(subscriber.Topic)
if err := p.Publish(ctx, entity); err != nil {
return errors.InternalServerError("location.save", err.Error())
}
return nil
}
func (l *Location) Search(ctx context.Context, req *loc.SearchRequest, rsp *loc.SearchResponse) error {
log.Print("Received Location.Search request")
entity := &domain.Entity{
Latitude: req.Center.Latitude,
Longitude: req.Center.Longitude,
}
entities := domain.Search(req.Type, entity, req.Radius, int(req.NumEntities))
for _, e := range entities {
rsp.Entities = append(rsp.Entities, e.ToProto())
}
return nil
}

24
location/main.go Normal file
View File

@@ -0,0 +1,24 @@
package main
import (
"log"
"github.com/micro/micro/v3/service"
"github.com/micro/services/location/handler"
pb "github.com/micro/services/location/proto"
"github.com/micro/services/location/subscriber"
)
func main() {
location := service.New(
service.Name("location"),
)
pb.RegisterLocationHandler(location.Server(), new(handler.Location))
service.Subscribe(subscriber.Topic, new(subscriber.Location))
if err := location.Run(); err != nil {
log.Fatal(err)
}
}

1
location/micro.mu Normal file
View File

@@ -0,0 +1 @@
service location

View File

@@ -0,0 +1,421 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: proto/location.proto
package location
import (
fmt "fmt"
proto "github.com/golang/protobuf/proto"
math "math"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
type Point struct {
Latitude float64 `protobuf:"fixed64,1,opt,name=latitude,proto3" json:"latitude,omitempty"`
Longitude float64 `protobuf:"fixed64,2,opt,name=longitude,proto3" json:"longitude,omitempty"`
Timestamp int64 `protobuf:"varint,3,opt,name=timestamp,proto3" json:"timestamp,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *Point) Reset() { *m = Point{} }
func (m *Point) String() string { return proto.CompactTextString(m) }
func (*Point) ProtoMessage() {}
func (*Point) Descriptor() ([]byte, []int) {
return fileDescriptor_1d9f8c6d814f264b, []int{0}
}
func (m *Point) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Point.Unmarshal(m, b)
}
func (m *Point) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_Point.Marshal(b, m, deterministic)
}
func (m *Point) XXX_Merge(src proto.Message) {
xxx_messageInfo_Point.Merge(m, src)
}
func (m *Point) XXX_Size() int {
return xxx_messageInfo_Point.Size(m)
}
func (m *Point) XXX_DiscardUnknown() {
xxx_messageInfo_Point.DiscardUnknown(m)
}
var xxx_messageInfo_Point proto.InternalMessageInfo
func (m *Point) GetLatitude() float64 {
if m != nil {
return m.Latitude
}
return 0
}
func (m *Point) GetLongitude() float64 {
if m != nil {
return m.Longitude
}
return 0
}
func (m *Point) GetTimestamp() int64 {
if m != nil {
return m.Timestamp
}
return 0
}
type Entity struct {
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
Type string `protobuf:"bytes,2,opt,name=type,proto3" json:"type,omitempty"`
Location *Point `protobuf:"bytes,3,opt,name=location,proto3" json:"location,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *Entity) Reset() { *m = Entity{} }
func (m *Entity) String() string { return proto.CompactTextString(m) }
func (*Entity) ProtoMessage() {}
func (*Entity) Descriptor() ([]byte, []int) {
return fileDescriptor_1d9f8c6d814f264b, []int{1}
}
func (m *Entity) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Entity.Unmarshal(m, b)
}
func (m *Entity) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_Entity.Marshal(b, m, deterministic)
}
func (m *Entity) XXX_Merge(src proto.Message) {
xxx_messageInfo_Entity.Merge(m, src)
}
func (m *Entity) XXX_Size() int {
return xxx_messageInfo_Entity.Size(m)
}
func (m *Entity) XXX_DiscardUnknown() {
xxx_messageInfo_Entity.DiscardUnknown(m)
}
var xxx_messageInfo_Entity proto.InternalMessageInfo
func (m *Entity) GetId() string {
if m != nil {
return m.Id
}
return ""
}
func (m *Entity) GetType() string {
if m != nil {
return m.Type
}
return ""
}
func (m *Entity) GetLocation() *Point {
if m != nil {
return m.Location
}
return nil
}
type ReadRequest struct {
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *ReadRequest) Reset() { *m = ReadRequest{} }
func (m *ReadRequest) String() string { return proto.CompactTextString(m) }
func (*ReadRequest) ProtoMessage() {}
func (*ReadRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_1d9f8c6d814f264b, []int{2}
}
func (m *ReadRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ReadRequest.Unmarshal(m, b)
}
func (m *ReadRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ReadRequest.Marshal(b, m, deterministic)
}
func (m *ReadRequest) XXX_Merge(src proto.Message) {
xxx_messageInfo_ReadRequest.Merge(m, src)
}
func (m *ReadRequest) XXX_Size() int {
return xxx_messageInfo_ReadRequest.Size(m)
}
func (m *ReadRequest) XXX_DiscardUnknown() {
xxx_messageInfo_ReadRequest.DiscardUnknown(m)
}
var xxx_messageInfo_ReadRequest proto.InternalMessageInfo
func (m *ReadRequest) GetId() string {
if m != nil {
return m.Id
}
return ""
}
type ReadResponse struct {
Entity *Entity `protobuf:"bytes,1,opt,name=entity,proto3" json:"entity,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *ReadResponse) Reset() { *m = ReadResponse{} }
func (m *ReadResponse) String() string { return proto.CompactTextString(m) }
func (*ReadResponse) ProtoMessage() {}
func (*ReadResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_1d9f8c6d814f264b, []int{3}
}
func (m *ReadResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ReadResponse.Unmarshal(m, b)
}
func (m *ReadResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ReadResponse.Marshal(b, m, deterministic)
}
func (m *ReadResponse) XXX_Merge(src proto.Message) {
xxx_messageInfo_ReadResponse.Merge(m, src)
}
func (m *ReadResponse) XXX_Size() int {
return xxx_messageInfo_ReadResponse.Size(m)
}
func (m *ReadResponse) XXX_DiscardUnknown() {
xxx_messageInfo_ReadResponse.DiscardUnknown(m)
}
var xxx_messageInfo_ReadResponse proto.InternalMessageInfo
func (m *ReadResponse) GetEntity() *Entity {
if m != nil {
return m.Entity
}
return nil
}
type SaveRequest struct {
Entity *Entity `protobuf:"bytes,1,opt,name=entity,proto3" json:"entity,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *SaveRequest) Reset() { *m = SaveRequest{} }
func (m *SaveRequest) String() string { return proto.CompactTextString(m) }
func (*SaveRequest) ProtoMessage() {}
func (*SaveRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_1d9f8c6d814f264b, []int{4}
}
func (m *SaveRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_SaveRequest.Unmarshal(m, b)
}
func (m *SaveRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_SaveRequest.Marshal(b, m, deterministic)
}
func (m *SaveRequest) XXX_Merge(src proto.Message) {
xxx_messageInfo_SaveRequest.Merge(m, src)
}
func (m *SaveRequest) XXX_Size() int {
return xxx_messageInfo_SaveRequest.Size(m)
}
func (m *SaveRequest) XXX_DiscardUnknown() {
xxx_messageInfo_SaveRequest.DiscardUnknown(m)
}
var xxx_messageInfo_SaveRequest proto.InternalMessageInfo
func (m *SaveRequest) GetEntity() *Entity {
if m != nil {
return m.Entity
}
return nil
}
type SaveResponse struct {
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *SaveResponse) Reset() { *m = SaveResponse{} }
func (m *SaveResponse) String() string { return proto.CompactTextString(m) }
func (*SaveResponse) ProtoMessage() {}
func (*SaveResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_1d9f8c6d814f264b, []int{5}
}
func (m *SaveResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_SaveResponse.Unmarshal(m, b)
}
func (m *SaveResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_SaveResponse.Marshal(b, m, deterministic)
}
func (m *SaveResponse) XXX_Merge(src proto.Message) {
xxx_messageInfo_SaveResponse.Merge(m, src)
}
func (m *SaveResponse) XXX_Size() int {
return xxx_messageInfo_SaveResponse.Size(m)
}
func (m *SaveResponse) XXX_DiscardUnknown() {
xxx_messageInfo_SaveResponse.DiscardUnknown(m)
}
var xxx_messageInfo_SaveResponse proto.InternalMessageInfo
type SearchRequest struct {
Center *Point `protobuf:"bytes,1,opt,name=center,proto3" json:"center,omitempty"`
Radius float64 `protobuf:"fixed64,2,opt,name=radius,proto3" json:"radius,omitempty"`
Type string `protobuf:"bytes,3,opt,name=type,proto3" json:"type,omitempty"`
NumEntities int64 `protobuf:"varint,4,opt,name=numEntities,proto3" json:"numEntities,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *SearchRequest) Reset() { *m = SearchRequest{} }
func (m *SearchRequest) String() string { return proto.CompactTextString(m) }
func (*SearchRequest) ProtoMessage() {}
func (*SearchRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_1d9f8c6d814f264b, []int{6}
}
func (m *SearchRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_SearchRequest.Unmarshal(m, b)
}
func (m *SearchRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_SearchRequest.Marshal(b, m, deterministic)
}
func (m *SearchRequest) XXX_Merge(src proto.Message) {
xxx_messageInfo_SearchRequest.Merge(m, src)
}
func (m *SearchRequest) XXX_Size() int {
return xxx_messageInfo_SearchRequest.Size(m)
}
func (m *SearchRequest) XXX_DiscardUnknown() {
xxx_messageInfo_SearchRequest.DiscardUnknown(m)
}
var xxx_messageInfo_SearchRequest proto.InternalMessageInfo
func (m *SearchRequest) GetCenter() *Point {
if m != nil {
return m.Center
}
return nil
}
func (m *SearchRequest) GetRadius() float64 {
if m != nil {
return m.Radius
}
return 0
}
func (m *SearchRequest) GetType() string {
if m != nil {
return m.Type
}
return ""
}
func (m *SearchRequest) GetNumEntities() int64 {
if m != nil {
return m.NumEntities
}
return 0
}
type SearchResponse struct {
Entities []*Entity `protobuf:"bytes,1,rep,name=entities,proto3" json:"entities,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *SearchResponse) Reset() { *m = SearchResponse{} }
func (m *SearchResponse) String() string { return proto.CompactTextString(m) }
func (*SearchResponse) ProtoMessage() {}
func (*SearchResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_1d9f8c6d814f264b, []int{7}
}
func (m *SearchResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_SearchResponse.Unmarshal(m, b)
}
func (m *SearchResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_SearchResponse.Marshal(b, m, deterministic)
}
func (m *SearchResponse) XXX_Merge(src proto.Message) {
xxx_messageInfo_SearchResponse.Merge(m, src)
}
func (m *SearchResponse) XXX_Size() int {
return xxx_messageInfo_SearchResponse.Size(m)
}
func (m *SearchResponse) XXX_DiscardUnknown() {
xxx_messageInfo_SearchResponse.DiscardUnknown(m)
}
var xxx_messageInfo_SearchResponse proto.InternalMessageInfo
func (m *SearchResponse) GetEntities() []*Entity {
if m != nil {
return m.Entities
}
return nil
}
func init() {
proto.RegisterType((*Point)(nil), "location.Point")
proto.RegisterType((*Entity)(nil), "location.Entity")
proto.RegisterType((*ReadRequest)(nil), "location.ReadRequest")
proto.RegisterType((*ReadResponse)(nil), "location.ReadResponse")
proto.RegisterType((*SaveRequest)(nil), "location.SaveRequest")
proto.RegisterType((*SaveResponse)(nil), "location.SaveResponse")
proto.RegisterType((*SearchRequest)(nil), "location.SearchRequest")
proto.RegisterType((*SearchResponse)(nil), "location.SearchResponse")
}
func init() { proto.RegisterFile("proto/location.proto", fileDescriptor_1d9f8c6d814f264b) }
var fileDescriptor_1d9f8c6d814f264b = []byte{
// 366 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x92, 0xb1, 0x4e, 0xf3, 0x30,
0x14, 0x85, 0xeb, 0xa6, 0x7f, 0x94, 0xde, 0xf4, 0x2f, 0xc8, 0x82, 0x12, 0x55, 0x20, 0x45, 0x59,
0xa8, 0x04, 0x2a, 0x52, 0x19, 0xca, 0x02, 0x1b, 0x1b, 0x03, 0x72, 0x27, 0x26, 0x64, 0x1a, 0x0b,
0x2c, 0x35, 0x76, 0x48, 0x1c, 0xa4, 0xbe, 0x00, 0x2f, 0xc5, 0xcb, 0xa1, 0xd8, 0x4e, 0x62, 0x5a,
0x06, 0xb6, 0xde, 0x7b, 0x7c, 0x4e, 0x8f, 0x3f, 0x07, 0x8e, 0xf2, 0x42, 0x2a, 0x79, 0xb5, 0x91,
0x6b, 0xaa, 0xb8, 0x14, 0x73, 0x3d, 0xe2, 0xa0, 0x99, 0x93, 0x67, 0xf8, 0xf7, 0x28, 0xb9, 0x50,
0x78, 0x0a, 0xc1, 0x86, 0x2a, 0xae, 0xaa, 0x94, 0x45, 0x28, 0x46, 0x33, 0x44, 0xda, 0x19, 0x9f,
0xc2, 0x70, 0x23, 0xc5, 0xab, 0x11, 0xfb, 0x5a, 0xec, 0x16, 0xb5, 0xaa, 0x78, 0xc6, 0x4a, 0x45,
0xb3, 0x3c, 0xf2, 0x62, 0x34, 0xf3, 0x48, 0xb7, 0x48, 0x9e, 0xc0, 0xbf, 0x17, 0x8a, 0xab, 0x2d,
0x1e, 0x43, 0x9f, 0xa7, 0x3a, 0x7b, 0x48, 0xfa, 0x3c, 0xc5, 0x18, 0x06, 0x6a, 0x9b, 0x9b, 0xc0,
0x21, 0xd1, 0xbf, 0xf1, 0x05, 0xb4, 0xd5, 0x74, 0x54, 0xb8, 0x38, 0x98, 0xb7, 0xdd, 0x75, 0x51,
0xd2, 0x75, 0x3f, 0x83, 0x90, 0x30, 0x9a, 0x12, 0xf6, 0x5e, 0xb1, 0x52, 0xed, 0xe6, 0x27, 0x37,
0x30, 0x32, 0x72, 0x99, 0x4b, 0x51, 0x32, 0x3c, 0x03, 0x9f, 0xe9, 0x26, 0xfa, 0x4c, 0xb8, 0x38,
0xec, 0x92, 0x4d, 0x43, 0x62, 0xf5, 0x64, 0x09, 0xe1, 0x8a, 0x7e, 0xb0, 0x26, 0xf8, 0xef, 0xc6,
0x31, 0x8c, 0x8c, 0xd1, 0xfc, 0x65, 0xf2, 0x89, 0xe0, 0xff, 0x8a, 0xd1, 0x62, 0xfd, 0xd6, 0x64,
0x9d, 0x83, 0xbf, 0x66, 0x42, 0xb1, 0xc2, 0x66, 0xed, 0x5d, 0xcf, 0xca, 0x78, 0x02, 0x7e, 0x41,
0x53, 0x5e, 0x95, 0x16, 0xb8, 0x9d, 0x5a, 0x6a, 0x9e, 0x43, 0x2d, 0x86, 0x50, 0x54, 0x99, 0xee,
0xc2, 0x59, 0x19, 0x0d, 0xf4, 0x1b, 0xb8, 0xab, 0xe4, 0x0e, 0xc6, 0x4d, 0x0f, 0x4b, 0xe3, 0x12,
0x02, 0xd6, 0x18, 0x50, 0xec, 0xfd, 0x7a, 0xad, 0xf6, 0xc4, 0xe2, 0x0b, 0x41, 0xf0, 0x60, 0x55,
0xbc, 0x84, 0x41, 0x0d, 0x16, 0x1f, 0x77, 0x06, 0xe7, 0x1d, 0xa6, 0x93, 0xdd, 0xb5, 0x85, 0xd1,
0xab, 0x8d, 0x35, 0x1e, 0xd7, 0xe8, 0x70, 0x76, 0x8d, 0x3f, 0x28, 0xf6, 0xf0, 0x2d, 0xf8, 0xa6,
0x3e, 0x3e, 0x71, 0xce, 0xb8, 0x60, 0xa7, 0xd1, 0xbe, 0xd0, 0xd8, 0x5f, 0x7c, 0xfd, 0xd5, 0x5f,
0x7f, 0x07, 0x00, 0x00, 0xff, 0xff, 0x84, 0x35, 0x27, 0xbf, 0x0d, 0x03, 0x00, 0x00,
}

View File

@@ -0,0 +1,127 @@
// Code generated by protoc-gen-micro. DO NOT EDIT.
// source: proto/location.proto
package location
import (
fmt "fmt"
proto "github.com/golang/protobuf/proto"
math "math"
)
import (
context "context"
api "github.com/micro/micro/v3/service/api"
client "github.com/micro/micro/v3/service/client"
server "github.com/micro/micro/v3/service/server"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
// Reference imports to suppress errors if they are not otherwise used.
var _ api.Endpoint
var _ context.Context
var _ client.Option
var _ server.Option
// Api Endpoints for Location service
func NewLocationEndpoints() []*api.Endpoint {
return []*api.Endpoint{}
}
// Client API for Location service
type LocationService interface {
Read(ctx context.Context, in *ReadRequest, opts ...client.CallOption) (*ReadResponse, error)
Save(ctx context.Context, in *SaveRequest, opts ...client.CallOption) (*SaveResponse, error)
Search(ctx context.Context, in *SearchRequest, opts ...client.CallOption) (*SearchResponse, error)
}
type locationService struct {
c client.Client
name string
}
func NewLocationService(name string, c client.Client) LocationService {
return &locationService{
c: c,
name: name,
}
}
func (c *locationService) Read(ctx context.Context, in *ReadRequest, opts ...client.CallOption) (*ReadResponse, error) {
req := c.c.NewRequest(c.name, "Location.Read", in)
out := new(ReadResponse)
err := c.c.Call(ctx, req, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *locationService) Save(ctx context.Context, in *SaveRequest, opts ...client.CallOption) (*SaveResponse, error) {
req := c.c.NewRequest(c.name, "Location.Save", in)
out := new(SaveResponse)
err := c.c.Call(ctx, req, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *locationService) Search(ctx context.Context, in *SearchRequest, opts ...client.CallOption) (*SearchResponse, error) {
req := c.c.NewRequest(c.name, "Location.Search", in)
out := new(SearchResponse)
err := c.c.Call(ctx, req, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// Server API for Location service
type LocationHandler interface {
Read(context.Context, *ReadRequest, *ReadResponse) error
Save(context.Context, *SaveRequest, *SaveResponse) error
Search(context.Context, *SearchRequest, *SearchResponse) error
}
func RegisterLocationHandler(s server.Server, hdlr LocationHandler, opts ...server.HandlerOption) error {
type location interface {
Read(ctx context.Context, in *ReadRequest, out *ReadResponse) error
Save(ctx context.Context, in *SaveRequest, out *SaveResponse) error
Search(ctx context.Context, in *SearchRequest, out *SearchResponse) error
}
type Location struct {
location
}
h := &locationHandler{hdlr}
return s.Handle(s.NewHandler(&Location{h}, opts...))
}
type locationHandler struct {
LocationHandler
}
func (h *locationHandler) Read(ctx context.Context, in *ReadRequest, out *ReadResponse) error {
return h.LocationHandler.Read(ctx, in, out)
}
func (h *locationHandler) Save(ctx context.Context, in *SaveRequest, out *SaveResponse) error {
return h.LocationHandler.Save(ctx, in, out)
}
func (h *locationHandler) Search(ctx context.Context, in *SearchRequest, out *SearchResponse) error {
return h.LocationHandler.Search(ctx, in, out)
}

View File

@@ -0,0 +1,48 @@
syntax = "proto3";
package location;
service Location {
rpc Read(ReadRequest) returns (ReadResponse) {}
rpc Save(SaveRequest) returns (SaveResponse) {}
rpc Search(SearchRequest) returns (SearchResponse) {}
}
message Point {
double latitude = 1;
double longitude = 2;
int64 timestamp = 3;
}
message Entity {
string id = 1;
string type = 2;
Point location = 3;
}
message ReadRequest {
string id = 1;
}
message ReadResponse {
Entity entity = 1;
}
message SaveRequest {
Entity entity = 1;
}
message SaveResponse {
}
message SearchRequest {
Point center = 1;
double radius = 2; // in meters
string type = 3;
int64 numEntities = 4;
}
message SearchResponse {
repeated Entity entities = 1;
}

View File

@@ -0,0 +1,21 @@
package subscriber
import (
"context"
"log"
"github.com/micro/services/location/domain"
proto "github.com/micro/services/location/proto"
)
var (
Topic = "location"
)
type Location struct{}
func (g *Location) Handle(ctx context.Context, e *proto.Entity) error {
log.Printf("Saving entity ID %s", e.Id)
domain.Save(domain.ProtoToEntity(e))
return nil
}