Files
services/test/routes/routes-server/handler/handler.go
Janos Dobronszki b24fd8c635 Fixing up services
2020-10-15 17:04:38 +02:00

114 lines
2.8 KiB
Go

package handler
import (
"context"
"io"
"sync"
"time"
"github.com/golang/protobuf/proto"
pb "github.com/micro/services/test/routes/proto"
)
// RouteGuide implements the route guide handler interface
type RouteGuide struct {
Features []*pb.Feature
Notes map[string][]*pb.RouteNote
NotesLock sync.Mutex
}
// GetFeature obtains the feature at a given position.
func (r *RouteGuide) GetFeature(ctx context.Context, point *pb.Point, feature *pb.Feature) error {
for _, f := range r.Features {
if proto.Equal(f.Location, point) {
*feature = *f
return nil
}
}
// No feature was found, return an unnamed feature
feature.Location = point
return nil
}
// ListFeatures obtains the Features available within the given Rectangle. Results are
// streamed rather than returned at once (e.g. in a response message with a
// repeated field), as the rectangle may cover a large area and contain a
// huge number of features.
func (r *RouteGuide) ListFeatures(ctx context.Context, rect *pb.Rectangle, stream pb.RouteGuide_ListFeaturesStream) error {
for _, f := range r.Features {
if inRange(f.Location, rect) {
if err := stream.Send(f); err != nil {
return err
}
}
}
return nil
}
// RecordRoute accepts a stream of Points on a route being traversed, returning a
// RouteSummary when traversal is completed.
func (r *RouteGuide) RecordRoute(ctx context.Context, stream pb.RouteGuide_RecordRouteStream) error {
var pointCount, featureCount, distance int32
var lastPoint *pb.Point
startTime := time.Now()
for {
point, err := stream.Recv()
if err == io.EOF {
endTime := time.Now()
return stream.SendAndClose(&pb.RouteSummary{
PointCount: pointCount,
FeatureCount: featureCount,
Distance: distance,
ElapsedTime: int32(endTime.Sub(startTime).Seconds()),
})
}
if err != nil {
return err
}
pointCount++
for _, f := range r.Features {
if proto.Equal(f.Location, point) {
featureCount++
}
}
if lastPoint != nil {
distance += calcDistance(lastPoint, point)
}
lastPoint = point
}
}
// RouteChat accepts a stream of RouteNotes sent while a route is being traversed,
// while receiving other RouteNotes (e.g. from other users).
func (r *RouteGuide) RouteChat(ctx context.Context, stream pb.RouteGuide_RouteChatStream) error {
for {
in, err := stream.Recv()
if err == io.EOF {
return nil
}
if err != nil {
return err
}
key := serialize(in.Location)
r.NotesLock.Lock()
r.Notes[key] = append(r.Notes[key], in)
// Note: this copy prevents blocking other clients while serving this one.
// We don't need to do a deep copy, because elements in the slice are
// insert-only and never modified.
rn := make([]*pb.RouteNote, len(r.Notes[key]))
copy(rn, r.Notes[key])
r.NotesLock.Unlock()
for _, note := range rn {
if err := stream.Send(note); err != nil {
return err
}
}
}
}