refactoring
This commit is contained in:
@@ -23,7 +23,7 @@ func NewSolidarityServiceServer(handler *handler.SolidarityServiceHandler) *Soli
|
||||
|
||||
func Run(done chan error, cfg *viper.Viper, handler *handler.SolidarityServiceHandler) {
|
||||
var (
|
||||
address = ":" + cfg.GetString("services.grpc.port")
|
||||
address = cfg.GetString("services.grpc.ip") + ":" + cfg.GetString("services.grpc.port")
|
||||
)
|
||||
|
||||
server := grpc.NewServer()
|
||||
|
||||
@@ -6,10 +6,12 @@ import (
|
||||
"github.com/golang/protobuf/ptypes/timestamp"
|
||||
"github.com/paulmach/orb"
|
||||
"github.com/paulmach/orb/geojson"
|
||||
"github.com/rs/zerolog/log"
|
||||
"solidarity-service/internal"
|
||||
"solidarity-service/servers/grpc/proto"
|
||||
"solidarity-service/utils"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
func (s *SolidarityServiceServerImpl) SetDriverRegularAvailabilities(ctx context.Context, req *proto.DriverRegularAvailabilities) (resp *proto.DriverAvailabilitiesResponse, err error) {
|
||||
@@ -78,9 +80,6 @@ func (s *SolidarityServiceServerImpl) SetDriverRegularAvailabilities(ctx context
|
||||
|
||||
err = s.Handler.SetDriverAvailabilities(context.Background(), driver)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), utils.SQL_DUPLICATE) {
|
||||
err = errors.New("ID is already used")
|
||||
}
|
||||
return &proto.DriverAvailabilitiesResponse{
|
||||
Success: false,
|
||||
}, err
|
||||
@@ -156,9 +155,6 @@ func (s *SolidarityServiceServerImpl) SetDriverPunctualAvailabilities(ctx contex
|
||||
|
||||
err = s.Handler.SetDriverAvailabilities(context.Background(), driver)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), utils.SQL_DUPLICATE) {
|
||||
err = errors.New("ID is already used")
|
||||
}
|
||||
return &proto.DriverAvailabilitiesResponse{
|
||||
Success: false,
|
||||
}, err
|
||||
@@ -169,7 +165,7 @@ func (s *SolidarityServiceServerImpl) SetDriverPunctualAvailabilities(ctx contex
|
||||
}
|
||||
|
||||
func (s *SolidarityServiceServerImpl) CreateBooking(ctx context.Context, req *proto.CreateBookingRequest) (resp *proto.CreateBookingResponse, err error) {
|
||||
if req.Booking.DriverId == "" || req.Booking.PassengerId == "" || req.Booking.Id == "" || req.Booking.Status.String() == "" {
|
||||
if req.Booking.DriverId == "" || req.Booking.PassengerId == "" || req.Booking.Id == "" || req.Booking.Status.String() == "" || req.Booking.DepartureAddress == nil || req.Booking.DestinationAddress == nil || req.Booking.PickupDate.Seconds == 0 {
|
||||
return nil, errors.New("missing required fields")
|
||||
}
|
||||
bookingRequest := internal.BookingRequest{
|
||||
@@ -177,6 +173,21 @@ func (s *SolidarityServiceServerImpl) CreateBooking(ctx context.Context, req *pr
|
||||
Passenger_id: req.Booking.PassengerId,
|
||||
Driver_id: req.Booking.DriverId,
|
||||
Status: internal.BookingStatus(req.Booking.Status.String()),
|
||||
Destination_address: &geojson.Feature{
|
||||
Type: "Feature",
|
||||
Geometry: orb.Geometry(orb.Point{req.Booking.DestinationAddress.Lat, req.Booking.DestinationAddress.Long}),
|
||||
Properties: geojson.Properties{
|
||||
"name": req.Booking.DestinationAddress.Address,
|
||||
},
|
||||
},
|
||||
Departure_address: &geojson.Feature{
|
||||
Type: "Feature",
|
||||
Geometry: orb.Geometry(orb.Point{req.Booking.DepartureAddress.Lat, req.Booking.DepartureAddress.Long}),
|
||||
Properties: geojson.Properties{
|
||||
"name": req.Booking.DepartureAddress.Address,
|
||||
},
|
||||
},
|
||||
Pickup_date: req.Booking.PickupDate.Seconds,
|
||||
}
|
||||
passenger, driver, err := s.Handler.CreateBooking(context.Background(), bookingRequest)
|
||||
if err != nil {
|
||||
@@ -185,11 +196,11 @@ func (s *SolidarityServiceServerImpl) CreateBooking(ctx context.Context, req *pr
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
duration, err := s.Handler.CalculateDurationBetweenFeatures(passenger.Passenger_departure_address, passenger.Passenger_destination_address)
|
||||
duration, err := s.Handler.CalculateDurationBetweenFeatures(bookingRequest.Departure_address, bookingRequest.Destination_address)
|
||||
if err != nil {
|
||||
duration = 0
|
||||
}
|
||||
distance := s.Handler.CalculateDistanceBetweenFeatures(passenger.Passenger_departure_address, passenger.Passenger_destination_address)
|
||||
distance := s.Handler.CalculateDistanceBetweenFeatures(bookingRequest.Departure_address, bookingRequest.Destination_address)
|
||||
priceType := proto.PriceType_FREE
|
||||
resp = &proto.CreateBookingResponse{
|
||||
Booking: &proto.Booking{},
|
||||
@@ -217,17 +228,17 @@ func (s *SolidarityServiceServerImpl) CreateBooking(ctx context.Context, req *pr
|
||||
VerifiedIdentity: &passenger.Passenger.VerifiedIdentity,
|
||||
},
|
||||
PassengerPickupDate: ×tamp.Timestamp{
|
||||
Seconds: passenger.Passenger_pickup_date,
|
||||
Seconds: bookingRequest.Pickup_date,
|
||||
},
|
||||
PassengerDepartureRoute: &proto.Feature{
|
||||
Lat: passenger.Passenger_departure_address.Point().Lat(),
|
||||
Long: passenger.Passenger_departure_address.Point().Lon(),
|
||||
Address: passenger.Passenger_departure_address.Properties.MustString("name"),
|
||||
Lat: bookingRequest.Departure_address.Point().Lat(),
|
||||
Long: bookingRequest.Departure_address.Point().Lon(),
|
||||
Address: bookingRequest.Departure_address.Properties.MustString("name"),
|
||||
},
|
||||
PassengerDestinationRoute: &proto.Feature{
|
||||
Lat: passenger.Passenger_destination_address.Point().Lat(),
|
||||
Long: passenger.Passenger_destination_address.Point().Lon(),
|
||||
Address: passenger.Passenger_destination_address.Properties.MustString("name"),
|
||||
Lat: bookingRequest.Destination_address.Point().Lat(),
|
||||
Long: bookingRequest.Destination_address.Point().Lon(),
|
||||
Address: bookingRequest.Destination_address.Properties.MustString("name"),
|
||||
},
|
||||
Status: ConvertInternalToProtoBookingStatus(bookingRequest.Status),
|
||||
Duration: &duration,
|
||||
@@ -268,155 +279,211 @@ func (s *SolidarityServiceServerImpl) GetBooking(ctx context.Context, req *proto
|
||||
if req.BookingId == "" {
|
||||
return nil, errors.New("empty booking ID")
|
||||
}
|
||||
booking, passenger, driver, err := s.Handler.GetBooking(context.Background(), req.BookingId)
|
||||
booking, err := s.Handler.GetBooking(context.Background(), req.BookingId)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), utils.SQL_NO_ROWS) {
|
||||
err = errors.New("invalid ID")
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
duration, err := s.Handler.CalculateDurationBetweenFeatures(passenger.Passenger_departure_address, passenger.Passenger_destination_address)
|
||||
if err != nil {
|
||||
duration = 0
|
||||
}
|
||||
resp = &proto.GetBookingResponse{
|
||||
Booking: &proto.Booking{},
|
||||
}
|
||||
distance := s.Handler.CalculateDistanceBetweenFeatures(passenger.Passenger_departure_address, passenger.Passenger_destination_address)
|
||||
priceType := proto.PriceType_FREE
|
||||
driver, err := s.Handler.GetDriver(context.Background(), booking.Driver.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
car := driver.Car
|
||||
distance := int64(booking.Distance)
|
||||
resp.Booking = &proto.Booking{
|
||||
Id: booking.ID,
|
||||
Driver: &proto.User{
|
||||
Id: driver.Driver.ID,
|
||||
Alias: driver.Driver.Alias,
|
||||
FirstName: &driver.Driver.FirstName,
|
||||
LastName: &driver.Driver.LastName,
|
||||
Grade: &driver.Driver.Grade,
|
||||
Picture: &driver.Driver.Picture,
|
||||
Gender: &driver.Driver.Gender,
|
||||
VerifiedIdentity: &driver.Driver.VerifiedIdentity,
|
||||
Id: booking.Driver.ID,
|
||||
Alias: booking.Driver.Alias,
|
||||
FirstName: &booking.Driver.FirstName,
|
||||
LastName: &booking.Driver.LastName,
|
||||
Grade: &booking.Driver.Grade,
|
||||
Picture: &booking.Driver.Picture,
|
||||
Gender: &booking.Driver.Gender,
|
||||
VerifiedIdentity: &booking.Driver.VerifiedIdentity,
|
||||
},
|
||||
Passenger: &proto.User{
|
||||
Id: passenger.Passenger.ID,
|
||||
Alias: passenger.Passenger.Alias,
|
||||
FirstName: &passenger.Passenger.FirstName,
|
||||
LastName: &passenger.Passenger.LastName,
|
||||
Grade: &passenger.Passenger.Grade,
|
||||
Picture: &passenger.Passenger.Picture,
|
||||
Gender: &passenger.Passenger.Gender,
|
||||
VerifiedIdentity: &passenger.Passenger.VerifiedIdentity,
|
||||
Id: booking.Passenger.ID,
|
||||
Alias: booking.Passenger.Alias,
|
||||
FirstName: &booking.Passenger.FirstName,
|
||||
LastName: &booking.Passenger.LastName,
|
||||
Grade: &booking.Passenger.Grade,
|
||||
Picture: &booking.Passenger.Picture,
|
||||
Gender: &booking.Passenger.Gender,
|
||||
VerifiedIdentity: &booking.Passenger.VerifiedIdentity,
|
||||
},
|
||||
PassengerPickupDate: ×tamp.Timestamp{
|
||||
Seconds: passenger.Passenger_pickup_date,
|
||||
Seconds: booking.Pickup_date,
|
||||
},
|
||||
PassengerDepartureRoute: &proto.Feature{
|
||||
Lat: passenger.Passenger_departure_address.Point().Lat(),
|
||||
Long: passenger.Passenger_departure_address.Point().Lon(),
|
||||
Address: passenger.Passenger_departure_address.Properties.MustString("name"),
|
||||
Lat: booking.PassengerPickupAddress.Point().Lat(),
|
||||
Long: booking.PassengerPickupAddress.Point().Lon(),
|
||||
Address: booking.PassengerPickupAddress.Properties.MustString("name"),
|
||||
},
|
||||
PassengerDestinationRoute: &proto.Feature{
|
||||
Lat: passenger.Passenger_destination_address.Point().Lat(),
|
||||
Long: passenger.Passenger_destination_address.Point().Lon(),
|
||||
Address: passenger.Passenger_destination_address.Properties.MustString("name"),
|
||||
Lat: booking.PassengerDropAddress.Point().Lat(),
|
||||
Long: booking.PassengerDropAddress.Point().Lon(),
|
||||
Address: booking.PassengerDropAddress.Properties.MustString("name"),
|
||||
},
|
||||
Status: ConvertInternalToProtoBookingStatus(booking.Status),
|
||||
Duration: &duration,
|
||||
Duration: &booking.Duration,
|
||||
Distance: &distance,
|
||||
Car: &proto.Car{
|
||||
Model: &car.Model,
|
||||
Brand: &car.Brand,
|
||||
},
|
||||
Price: &proto.Price{
|
||||
Type: &priceType,
|
||||
},
|
||||
Car: &proto.Car{
|
||||
Model: &driver.Car.Model,
|
||||
Brand: &driver.Car.Brand,
|
||||
},
|
||||
}
|
||||
return resp, nil
|
||||
|
||||
}
|
||||
|
||||
func (s *SolidarityServiceServerImpl) GetBookingsByStatus(ctx context.Context, req *proto.GetBookingsByStatusRequest) (resp *proto.GetBookingsByStatusResponse, err error) {
|
||||
if req.Type.String() == "" || req.Status.String() == "" || req.UserId == "" {
|
||||
return nil, errors.New("missing required fields")
|
||||
}
|
||||
bookings, err := s.Handler.GetBookingsByStatus(context.Background(), req.Status.String(), req.Type.String(), req.UserId)
|
||||
|
||||
bookings, err := s.Handler.GetBookingsByStatus(ctx, req.Status.String(), req.Type.String(), req.UserId)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), utils.SQL_NO_ROWS) {
|
||||
err = errors.New("invalid ID")
|
||||
return nil, errors.New("invalid ID")
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
resp = &proto.GetBookingsByStatusResponse{
|
||||
Booking: []*proto.Booking{},
|
||||
|
||||
// Use a goroutine to concurrently convert bookings to proto
|
||||
respChan := make(chan []*proto.Booking, 1)
|
||||
go func() {
|
||||
respChan <- convertInternalBookingsToProto(s, bookings, 50)
|
||||
}()
|
||||
|
||||
select {
|
||||
case convertedBookings := <-respChan:
|
||||
close(respChan)
|
||||
|
||||
resp = &proto.GetBookingsByStatusResponse{
|
||||
Booking: convertedBookings,
|
||||
}
|
||||
return resp, nil
|
||||
|
||||
case <-ctx.Done():
|
||||
// If the context is canceled, return an error
|
||||
return nil, ctx.Err()
|
||||
}
|
||||
responses := []*proto.Booking{}
|
||||
}
|
||||
|
||||
func convertInternalBookingsToProto(s *SolidarityServiceServerImpl, bookings []internal.Booking, maxGoroutines int) []*proto.Booking {
|
||||
var responses []*proto.Booking
|
||||
var wg sync.WaitGroup
|
||||
var mu sync.Mutex
|
||||
semaphore := make(chan struct{}, maxGoroutines)
|
||||
|
||||
for _, v := range bookings {
|
||||
passenger, err := s.Handler.GetPassenger(context.Background(), v.Passenger.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
driver, err := s.Handler.GetDriver(context.Background(), v.Driver.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
duration, err := s.Handler.CalculateDurationBetweenFeatures(passenger.Passenger_departure_address, passenger.Passenger_destination_address)
|
||||
if err != nil {
|
||||
duration = 0
|
||||
}
|
||||
priceType := proto.PriceType_FREE
|
||||
distance := s.Handler.CalculateDistanceBetweenFeatures(passenger.Passenger_departure_address, passenger.Passenger_destination_address)
|
||||
responses = append(responses, &proto.Booking{
|
||||
Id: v.ID,
|
||||
Status: ConvertInternalToProtoBookingStatus(v.Status),
|
||||
Driver: &proto.User{
|
||||
Id: v.Driver.ID,
|
||||
Alias: driver.Driver.Alias,
|
||||
FirstName: &driver.Driver.FirstName,
|
||||
LastName: &driver.Driver.LastName,
|
||||
Grade: &driver.Driver.Grade,
|
||||
Picture: &driver.Driver.Picture,
|
||||
Gender: &driver.Driver.Gender,
|
||||
VerifiedIdentity: &driver.Driver.VerifiedIdentity,
|
||||
},
|
||||
Passenger: &proto.User{
|
||||
Id: v.Passenger.ID,
|
||||
Alias: passenger.Passenger.Alias,
|
||||
FirstName: &passenger.Passenger.FirstName,
|
||||
LastName: &passenger.Passenger.LastName,
|
||||
Grade: &passenger.Passenger.Grade,
|
||||
Picture: &passenger.Passenger.Picture,
|
||||
Gender: &passenger.Passenger.Gender,
|
||||
VerifiedIdentity: &passenger.Passenger.VerifiedIdentity,
|
||||
},
|
||||
PassengerPickupDate: ×tamp.Timestamp{
|
||||
Seconds: passenger.Passenger_pickup_date,
|
||||
},
|
||||
PassengerDepartureRoute: &proto.Feature{
|
||||
Lat: passenger.Passenger_departure_address.Point().Lat(),
|
||||
Long: passenger.Passenger_departure_address.Point().Lon(),
|
||||
Address: passenger.Passenger_departure_address.Properties.MustString("name"),
|
||||
},
|
||||
PassengerDestinationRoute: &proto.Feature{
|
||||
Lat: passenger.Passenger_destination_address.Point().Lat(),
|
||||
Long: passenger.Passenger_destination_address.Point().Lon(),
|
||||
Address: passenger.Passenger_destination_address.Properties.MustString("name"),
|
||||
},
|
||||
Duration: &duration,
|
||||
Distance: &distance,
|
||||
Car: &proto.Car{
|
||||
Model: &driver.Car.Model,
|
||||
Brand: &driver.Car.Brand,
|
||||
},
|
||||
Price: &proto.Price{
|
||||
Type: &priceType,
|
||||
},
|
||||
})
|
||||
wg.Add(1)
|
||||
semaphore <- struct{}{}
|
||||
|
||||
go func(booking internal.Booking) {
|
||||
defer func() {
|
||||
<-semaphore
|
||||
wg.Done()
|
||||
}()
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
var driver internal.Driver
|
||||
var driverErr error
|
||||
driverCh := make(chan struct {
|
||||
Driver internal.Driver
|
||||
Err error
|
||||
})
|
||||
|
||||
go func() {
|
||||
d, err := s.Handler.GetDriver(ctx, booking.Driver.ID)
|
||||
driverCh <- struct {
|
||||
Driver internal.Driver
|
||||
Err error
|
||||
}{Driver: d, Err: err}
|
||||
}()
|
||||
|
||||
driverRes := <-driverCh
|
||||
driver = driverRes.Driver
|
||||
driverErr = driverRes.Err
|
||||
|
||||
if driverErr != nil {
|
||||
log.Error().Err(driverErr).Msg("Error getting driver")
|
||||
return
|
||||
}
|
||||
|
||||
car := driver.Car
|
||||
|
||||
priceType := proto.PriceType_FREE
|
||||
distance := int64(booking.Distance)
|
||||
protoBooking := &proto.Booking{
|
||||
Id: booking.ID,
|
||||
Status: ConvertInternalToProtoBookingStatus(booking.Status),
|
||||
Driver: convertInternalUserToProtoUser(driver.Driver),
|
||||
Passenger: convertInternalUserToProtoUser(booking.Passenger),
|
||||
PassengerPickupDate: ×tamp.Timestamp{
|
||||
Seconds: booking.Pickup_date,
|
||||
},
|
||||
PassengerDepartureRoute: convertInternalFeatureToProtoFeature(booking.PassengerPickupAddress),
|
||||
PassengerDestinationRoute: convertInternalFeatureToProtoFeature(booking.PassengerDropAddress),
|
||||
Duration: &booking.Duration,
|
||||
Distance: &distance,
|
||||
Car: &proto.Car{
|
||||
Model: &car.Model,
|
||||
Brand: &car.Brand,
|
||||
},
|
||||
Price: &proto.Price{
|
||||
Type: &priceType,
|
||||
},
|
||||
}
|
||||
|
||||
// Use a mutex to safely append to the responses slice
|
||||
mu.Lock()
|
||||
responses = append(responses, protoBooking)
|
||||
mu.Unlock()
|
||||
}(v)
|
||||
}
|
||||
|
||||
// Wait for all goroutines to finish before returning
|
||||
wg.Wait()
|
||||
|
||||
close(semaphore)
|
||||
|
||||
return responses
|
||||
}
|
||||
|
||||
func convertInternalUserToProtoUser(user internal.User) *proto.User {
|
||||
return &proto.User{
|
||||
Id: user.ID,
|
||||
Alias: user.Alias,
|
||||
FirstName: &user.FirstName,
|
||||
LastName: &user.LastName,
|
||||
Grade: &user.Grade,
|
||||
Picture: &user.Picture,
|
||||
Gender: &user.Gender,
|
||||
VerifiedIdentity: &user.VerifiedIdentity,
|
||||
}
|
||||
}
|
||||
|
||||
func convertInternalFeatureToProtoFeature(feature *geojson.Feature) *proto.Feature {
|
||||
return &proto.Feature{
|
||||
Lat: feature.Point().Lat(),
|
||||
Long: feature.Point().Lon(),
|
||||
Address: feature.Properties.MustString("name"),
|
||||
}
|
||||
resp.Booking = responses
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (s *SolidarityServiceServerImpl) DriverJourneys(ctx context.Context, req *proto.DriverJourneysRequest) (resp *proto.DriverJourneysResponse, err error) {
|
||||
|
||||
if req.DepartureDate.Seconds == 0 || req.Departure == nil {
|
||||
return nil, errors.New("missing required fields")
|
||||
}
|
||||
@@ -507,33 +574,14 @@ func (s *SolidarityServiceServerImpl) DriverJourneys(ctx context.Context, req *p
|
||||
return resp, nil
|
||||
}
|
||||
func (s *SolidarityServiceServerImpl) SetPassengerTrip(ctx context.Context, req *proto.PassengerTripRequest) (resp *proto.PassengerTripResponse, err error) {
|
||||
if req.Passenger.Id == "" || req.Passenger.Alias == "" || req.PassengerPickupDate.Seconds == 0 || req.PassengerDestinationAddress == nil || req.PassengerDestinationAddress == nil {
|
||||
if req.Passenger.Id == "" || req.Passenger.Alias == "" {
|
||||
return &proto.PassengerTripResponse{
|
||||
Success: false,
|
||||
}, errors.New("missing required fields")
|
||||
}
|
||||
passenger := internal.Passenger{
|
||||
Passenger_departure_address: &geojson.Feature{
|
||||
Type: "Feature",
|
||||
Geometry: orb.Geometry(orb.Point{req.PassengerDepartureAddress.Lat, req.PassengerDepartureAddress.Long}),
|
||||
Properties: geojson.Properties{
|
||||
"name": req.PassengerDepartureAddress.Address,
|
||||
},
|
||||
},
|
||||
Passenger_destination_address: &geojson.Feature{
|
||||
Type: "Feature",
|
||||
Geometry: orb.Geometry(orb.Point{req.PassengerDestinationAddress.Lat, req.PassengerDestinationAddress.Long}),
|
||||
Properties: geojson.Properties{
|
||||
"name": req.PassengerDestinationAddress.Address,
|
||||
},
|
||||
},
|
||||
Passenger_pickup_date: req.PassengerPickupDate.Seconds,
|
||||
Passenger: internal.User{
|
||||
ID: req.Passenger.Id,
|
||||
Alias: req.Passenger.Alias,
|
||||
},
|
||||
}
|
||||
|
||||
passenger := internal.Passenger{}
|
||||
passenger.Passenger.ID = req.Passenger.Id
|
||||
passenger.Passenger.Alias = req.Passenger.Alias
|
||||
if req.Passenger.FirstName != nil {
|
||||
passenger.Passenger.FirstName = *req.Passenger.FirstName
|
||||
}
|
||||
@@ -564,9 +612,6 @@ func (s *SolidarityServiceServerImpl) SetPassengerTrip(ctx context.Context, req
|
||||
|
||||
err = s.Handler.SetPassengerTrip(context.Background(), passenger)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), utils.SQL_DUPLICATE) {
|
||||
err = errors.New("ID is already used")
|
||||
}
|
||||
return &proto.PassengerTripResponse{
|
||||
Success: false,
|
||||
}, err
|
||||
|
||||
Reference in New Issue
Block a user