Skip to content

Commit

Permalink
feat: initial implementation for oasis api
Browse files Browse the repository at this point in the history
issue: #128
  • Loading branch information
CodeBear801 committed Jan 9, 2020
1 parent a5c7887 commit 0babe83
Show file tree
Hide file tree
Showing 7 changed files with 301 additions and 0 deletions.
15 changes: 15 additions & 0 deletions integration/cmd/oasis/flags.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package main

import (
"flag"
)

var flags struct {
listenPort int
osrmBackendEndpoint string
}

func init() {
flag.IntVar(&flags.listenPort, "p", 8090, "Listen port.")
flag.StringVar(&flags.osrmBackendEndpoint, "osrm", "", "Backend OSRM-backend endpoint")
}
21 changes: 21 additions & 0 deletions integration/cmd/oasis/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package main

import (
"net/http"
"strconv"

"github.com/Telenav/osrm-backend/integration/oasis"
"github.com/golang/glog"
)

func main() {
mux := http.NewServeMux()

oasisService := oasis.New(flags.osrmBackendEndpoint)
mux.Handle("/oasis", oasisService)

// listen
listening := ":" + strconv.Itoa(flags.listenPort)
glog.Infof("Listening on %s", listening)
glog.Fatal(http.ListenAndServe(listening, mux))
}
54 changes: 54 additions & 0 deletions integration/oasis/handler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package oasis

import (
"encoding/json"
"net/http"

"github.com/Telenav/osrm-backend/integration/pkg/api/oasis"
)

type Handler struct {
osrmBackend string
}

func New(osrmBackend string) *Handler {
return &Handler{
osrmBackend,
}
}

func (h *Handler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
w.WriteHeader(200)
json.NewEncoder(w).Encode(generateFakeOasisResponse())
}

func generateFakeOasisResponse() *oasis.Response {
fakeSolution1 := new(oasis.Solution)
fakeSolution1.Distance = 90.0
fakeSolution1.Duration = 300.0
fakeSolution1.Weight = 300.0
fakeSolution1.WeightName = "duration"

fakeStation1 := new(oasis.ChargeStation)
fakeStation1.Location[0] = 13.39677
fakeStation1.Location[1] = 52.54366
fakeStation1.WaitTime = 30.0
fakeStation1.ChargeTime = 100.0
fakeStation1.ChargeRange = 100.0
fakeSolution1.ChargeStations = append(fakeSolution1.ChargeStations, fakeStation1)

fakeStation2 := new(oasis.ChargeStation)
fakeStation2.Location[0] = 13.40677
fakeStation2.Location[1] = 52.53333
fakeStation2.WaitTime = 100.0
fakeStation2.ChargeTime = 100.0
fakeStation2.ChargeRange = 100.0
fakeSolution1.ChargeStations = append(fakeSolution1.ChargeStations, fakeStation2)

r := new(oasis.Response)
r.Code = "200"
r.Message = "Optimized charge station selection result:"
r.Solutions = append(r.Solutions, fakeSolution1)

return r
}
8 changes: 8 additions & 0 deletions integration/pkg/api/oasis/genericoptions/values.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package genericoptions

const (
InvalidMaxRangeValue = -1.0 // default
InvalidCurrentRangeValue = -1.0 // default
DefaultPreferLevel = 100000 // unit:meters
DefaultSafeLevel = 100000 // unit:meters
)
8 changes: 8 additions & 0 deletions integration/pkg/api/oasis/options/options.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package options

const (
KeyMaxRange = "max_range"
KeyCurrRange = "curr_range"
KeyPreferLevel = "prefer_level"
KeySafeLevel = "safe_level"
)
168 changes: 168 additions & 0 deletions integration/pkg/api/oasis/request.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
package oasis

import (
"errors"
"fmt"
"math"
"net/url"
"strconv"
"strings"

"github.com/Telenav/osrm-backend/integration/pkg/api"
"github.com/Telenav/osrm-backend/integration/pkg/api/oasis/genericoptions"
"github.com/Telenav/osrm-backend/integration/pkg/api/oasis/options"
"github.com/Telenav/osrm-backend/integration/pkg/api/osrm/coordinate"
"github.com/golang/glog"
)

// Request for oasis service
type Request struct {
Service string
Version string
Profile string
Coordinates coordinate.Coordinates

MaxRange float64
CurrRange float64
PreferLevel float64
SafeLevel float64
}

// NewRequest create an empty oasis Request.
func NewRequest() *Request {
return &Request{
// Path
Service: "oasis",
Version: "v1",
Profile: "earliest",
Coordinates: coordinate.Coordinates{},

// generic options
MaxRange: genericoptions.InvalidMaxRangeValue,
CurrRange: genericoptions.InvalidCurrentRangeValue,
PreferLevel: genericoptions.DefaultPreferLevel,
SafeLevel: genericoptions.DefaultSafeLevel,
}
}

// ParseRequestURL parse Request URL to Request.
func ParseRequestURL(u *url.URL) (*Request, error) {
if u == nil {
return nil, fmt.Errorf("empty URL input")
}

req := NewRequest()

if err := req.parsePath(u.Path); err != nil {
return nil, err
}

params, err := url.ParseQuery(u.RawQuery)
if err != nil {
glog.Warning(err)
return nil, err
}

if err := req.parseQuery(params); err != nil {
glog.Warning(err)
return nil, err
}

if err := req.validate(); err != nil {
glog.Warning(err)
return nil, err
}

return req, nil
}

func (r *Request) parsePath(path string) error {
p := path
p = strings.TrimPrefix(p, api.Slash)
p = strings.TrimSuffix(p, api.Slash)

s := strings.Split(p, api.Slash)
if len(s) < 4 {
return fmt.Errorf("invalid path values %v parsed from %s", s, path)
}
r.Service = s[0]
r.Version = s[1]
r.Profile = s[2]

var err error
if r.Coordinates, err = coordinate.ParseCoordinates(s[3]); err != nil {
return err
}

return nil
}

func (r *Request) parseQuery(params url.Values) error {
for k, v := range params {
if len(v) <= 0 {
continue
}

var valfloat float64
if s, err := strconv.ParseFloat(v[0], 64); err != nil {
return err
} else {
valfloat = float64(s)
}

switch k {
case options.KeyMaxRange:
r.MaxRange = valfloat
case options.KeyCurrRange:
r.CurrRange = valfloat
case options.KeyPreferLevel:
r.PreferLevel = valfloat
case options.KeySafeLevel:
r.SafeLevel = valfloat
}
}

return nil
}

func (r *Request) validate() error {
// MaxRange must be set
if floatEquals(r.MaxRange, genericoptions.InvalidMaxRangeValue) || isFloatNegative(r.MaxRange) {
return errors.New("Invalid value for " + options.KeyMaxRange + ".")
}

// CurrRange must be set
if floatEquals(r.CurrRange, genericoptions.InvalidCurrentRangeValue) || isFloatNegative(r.CurrRange) {
return errors.New("Invalid value for " + options.KeyCurrRange + ".")
}

// CurrRange must be smaller or equal to MaxRange
if r.CurrRange > r.MaxRange {
return errors.New(options.KeyCurrRange + " must be smaller or equal to " + options.KeyMaxRange + ".")
}

// CurrRange must be smaller or equal to MaxRange
if r.PreferLevel > r.MaxRange {
return errors.New(options.KeyPreferLevel + " must be smaller or equal to " + options.KeyMaxRange + ".")
}

// CurrRange must be smaller or equal to MaxRange
if r.SafeLevel > r.MaxRange {
return errors.New(options.KeySafeLevel + " must be smaller or equal to " + options.KeyMaxRange + ".")
}

return nil
}

var epsilon float64 = 0.00000001

func floatEquals(a, b float64) bool {
if (a-b) < epsilon && (b-a) < epsilon {
return true
}
return false
}

func isFloatNegative(a float64) bool {
return !floatEquals(math.Abs(a), a)
}
27 changes: 27 additions & 0 deletions integration/pkg/api/oasis/response.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package oasis

import "github.com/Telenav/osrm-backend/integration/pkg/api/osrm/route"

// Response for oasis service
type Response struct {
Code string `json:"code"`
Message string `json:"message,omitempty"`
Solutions []*Solution `json:"solutions,omitempty"`
}

// Solution contains recommended charge stations
type Solution struct {
Distance float64 `json:"distance"`
Duration float64 `json:"duration"`
Weight float64 `json:"weight"`
WeightName string `json:"weight_name"`
ChargeStations []*ChargeStation `json:"charge_station"`
}

// ChargeStation contains location, time and energy level, could be used as waypoints for routing request
type ChargeStation struct {
route.Waypoint
WaitTime float64 `json:"wait_time"`
ChargeTime float64 `json:"charge_time"`
ChargeRange float64 `json:"charge_range"`
}

0 comments on commit 0babe83

Please sign in to comment.