Documentation
¶
Index ¶
- Constants
- func MapSlice[T, V any](ts []T, fn func(t T) V) []V
- type Announcement
- type AuthError
- type AuthErrorType
- type CityView
- type Dispatcher
- type Environment
- type GenericWorker
- type GeocodeCityView
- type JobHandler
- type JobStore
- type MinPriorityQueue
- type MultiDimIterator
- type MultiPlanningReq
- type MyPlanner
- func (p *MyPlanner) Destroy()
- func (p *MyPlanner) GetPlaceDetails(ctx *gin.Context)
- func (p *MyPlanner) Init(mapsClientApiKey string, redisURL *url.URL, redisStreamName string, ...)
- func (p *MyPlanner) ListPATs(ctx *gin.Context)
- func (p *MyPlanner) Planning(ctx context.Context, planningRequest *PlanningRequest, user string) (resp PlanningResponse)
- func (p *MyPlanner) ProcessPlanningEvent(worker int, wg *sync.WaitGroup)
- func (p *MyPlanner) RevokePAT(ctx *gin.Context)
- func (p *MyPlanner) SetPlanSavedStatusForUser(ctx *gin.Context, numResults int, resp PlanningResponse, uv user.View) error
- func (p *MyPlanner) SetupRouter(serverPort string) *http.Server
- func (p *MyPlanner) UrlMigrationHandler(ctx *gin.Context)
- func (p *MyPlanner) UserAuthentication(ctx *gin.Context, minimumUserLevel user.Level) (user.View, *AuthError)
- func (p *MyPlanner) UserEmailVerify(ctx *gin.Context)
- func (p *MyPlanner) UserRatingsTotalMigrationHandler(ctx *gin.Context)
- func (p *MyPlanner) UserSignup(ctx *gin.Context)
- type NewTokenInfo
- type PATView
- type PlaceDetailsResp
- type PlaceMatcher
- type PlacePlanningDetails
- type PlanningJobHandler
- type PlanningPostRequest
- type PlanningRequest
- type PlanningResp
- type PlanningResponse
- type PlanningSolution
- type PriorityJobQueue
- type PriorityQueueItem
- type ProfileView
- type RequestIdKey
- type RevokeTokenInfo
- type SlotRequest
- type Solver
- func (s *Solver) FindBestPlanningSolutions(ctx context.Context, placeClusters [][]matching.Place, ...) (resp *PlanningResp)
- func (s *Solver) FindOptimalPlan(placeClusters [][]matching.Place) ([]string, error)
- func (s *Solver) Init(poiSearcher *iowrappers.PoiSearcher, placeDedupeCountLimit int, ...)
- func (s *Solver) Solve(ctx context.Context, req *PlanningRequest) *PlanningResp
- func (s *Solver) SolveHungarianOptimal(ctx context.Context, req *PlanningRequest) ([]PlacePlanningDetails, error)
- func (s *Solver) SolveWithNearbyCities(ctx context.Context, req *MultiPlanningReq) *PlanningResp
- func (s *Solver) ValidateLocation(ctx context.Context, location *POI.Location) bool
- type TimeSectionPlace
- type TravelPlan
- type TripDetailResp
- type UserLoginResponse
- type Vertex
Constants ¶
const ( SolverTimeout = time.Second * 10 PhotoApiBaseURL = "https://maps.googleapis.com/maps/api/place/photo?maxwidth=400&photo_reference=%s&key=%s" )
const ( NumPlansDefault = 5 TopSolutionsCountDefault = 5 DefaultPlaceSearchRadius = 20000 // default to 20km (~12.43 miles) MaxSolutionsToSaveCount = 100 CategorizedPlaceIterInitFailureErrMsg = "categorized places iterator init failure" ErrMsgMismatchIterAndPlace = "mismatch in iterator status vector length" ErrMsgRepeatedPlaceInSameTrip = "repeated places in the same trip" )
const ( ValidSolutionFound = 200 InvalidRequestLocation = 400 NoValidSolution = 404 RequestTimeOut = 408 InternalError = 500 )
const NumWorkers = 10
const (
UseGeneratedImagesThreshold = 5
)
Variables ¶
This section is empty.
Functions ¶
Types ¶
type Announcement ¶
type AuthError ¶
type AuthError struct {
ErrType AuthErrorType
ErrMsg error
}
func (*AuthError) GetErrorMessage ¶
GetErrorMessage returns a user-friendly error message based on the auth type
func (*AuthError) IsCookieError ¶
IsCookieError returns true if the auth error is related to JWT cookie authentication
func (*AuthError) IsTokenError ¶
IsTokenError returns true if the auth error is related to PAT token authentication
type AuthErrorType ¶
type AuthErrorType string
const ( AuthErrorTypeToken AuthErrorType = "token" AuthErrorTypeCookie AuthErrorType = "cookie" )
type Dispatcher ¶
type Dispatcher struct {
JobQueue *PriorityJobQueue
// contains filtered or unexported fields
}
func NewDispatcher ¶
func NewDispatcher(s *Solver, c *iowrappers.RedisClient) *Dispatcher
func (*Dispatcher) Run ¶
func (d *Dispatcher) Run(ctx context.Context)
func (*Dispatcher) Stop ¶
func (d *Dispatcher) Stop()
func (*Dispatcher) Wait ¶
func (d *Dispatcher) Wait()
type Environment ¶
type Environment string
const ( ProductionEnvironment Environment = "production" StagingEnvironment Environment = "staging" TestingEnvironment Environment = "testing" DevelopmentEnvironment Environment = "development" )
type GenericWorker ¶
type GenericWorker struct {
// contains filtered or unexported fields
}
GenericWorker is a flexible worker that can handle jobs using registered JobHandlers
func NewGenericWorker ¶
func NewGenericWorker(idx int, jobQueue *PriorityJobQueue, wg *sync.WaitGroup) *GenericWorker
NewGenericWorker creates a new generic worker
func (*GenericWorker) RegisterHandler ¶
func (w *GenericWorker) RegisterHandler(handler JobHandler)
RegisterHandler registers a job handler for a specific job type
func (*GenericWorker) Run ¶
func (w *GenericWorker) Run(ctx context.Context)
Run starts the worker's processing loop
type GeocodeCityView ¶
type JobHandler ¶
type JobHandler interface {
// Execute processes a job and returns an error if execution fails
Execute(ctx context.Context, job *iowrappers.Job) error
// JobType returns the type of job this handler processes
JobType() string
}
JobHandler interface allows different job types to be executed by workers Implementing this interface enables adding new job types without modifying worker code
type JobStore ¶
type JobStore struct {
// contains filtered or unexported fields
}
JobStore tracks and deduplicates concurrent job executions
type MinPriorityQueue ¶
type MinPriorityQueue[T PriorityQueueItem] struct { // contains filtered or unexported fields }
func (*MinPriorityQueue[T]) Len ¶
func (pq *MinPriorityQueue[T]) Len() int
func (*MinPriorityQueue[T]) Less ¶
func (pq *MinPriorityQueue[T]) Less(i, j int) bool
func (*MinPriorityQueue[T]) Pop ¶
func (pq *MinPriorityQueue[T]) Pop() interface{}
func (*MinPriorityQueue[T]) Push ¶
func (pq *MinPriorityQueue[T]) Push(item interface{})
func (*MinPriorityQueue[T]) Swap ¶
func (pq *MinPriorityQueue[T]) Swap(i, j int)
type MultiDimIterator ¶
type MultiDimIterator struct {
Categories []POI.PlaceCategory
Status []int
Stop bool // indicate iterator is stopped
Size []int // number of items in each category
}
func (*MultiDimIterator) ClearStatus ¶
func (mdTagIter *MultiDimIterator) ClearStatus()
func (*MultiDimIterator) HasNext ¶
func (mdTagIter *MultiDimIterator) HasNext() bool
func (*MultiDimIterator) Init ¶
func (mdTagIter *MultiDimIterator) Init(categories []POI.PlaceCategory, placeClusters [][]matching.Place) error
func (*MultiDimIterator) Next ¶
func (mdTagIter *MultiDimIterator) Next() bool
type MultiPlanningReq ¶
type MultiPlanningReq struct {
// contains filtered or unexported fields
}
MultiPlanningReq can be used to represent a multi-day planning request for a single location or a group of requests for different locations
type MyPlanner ¶
type MyPlanner struct {
RedisClient *iowrappers.RedisClient
RedisStreamName string
PhotoClient iowrappers.PhotoClient
Solver Solver
ResultHTMLTemplate *template.Template
TripHTMLTemplate *template.Template
PlanningEvents chan iowrappers.PlanningEvent
Environment Environment
Configs map[string]interface{}
OAuth2Config *oauth2.Config
Mailer *iowrappers.Mailer
GeonamesApiKey string
MapsClientApiKey string
BlobBucket string
Dispatcher *Dispatcher
}
func (*MyPlanner) GetPlaceDetails ¶
func (*MyPlanner) Planning ¶
func (p *MyPlanner) Planning(ctx context.Context, planningRequest *PlanningRequest, user string) (resp PlanningResponse)
func (*MyPlanner) ProcessPlanningEvent ¶
func (*MyPlanner) SetPlanSavedStatusForUser ¶
func (*MyPlanner) UrlMigrationHandler ¶
func (*MyPlanner) UserAuthentication ¶
func (*MyPlanner) UserEmailVerify ¶
func (*MyPlanner) UserRatingsTotalMigrationHandler ¶
func (*MyPlanner) UserSignup ¶
type NewTokenInfo ¶
type PlaceDetailsResp ¶
type PlaceMatcher ¶
type PlaceMatcher struct {
// contains filtered or unexported fields
}
func NewPlaceMatcher ¶
func NewPlaceMatcher() *PlaceMatcher
func (*PlaceMatcher) MatchPlaces ¶
func (pm *PlaceMatcher) MatchPlaces(req *matching.FilterRequest, m matching.Matcher) ([]matching.Place, error)
MatchPlaces uses strategy pattern to match places at runtime
type PlacePlanningDetails ¶
type PlanningJobHandler ¶
type PlanningJobHandler struct {
// contains filtered or unexported fields
}
PlanningJobHandler implements JobHandler for planning solution jobs
func NewPlanningJobHandler ¶
func NewPlanningJobHandler(solver *Solver, store *JobStore, redis *iowrappers.RedisClient) *PlanningJobHandler
NewPlanningJobHandler creates a new planning job handler
func (*PlanningJobHandler) Execute ¶
func (h *PlanningJobHandler) Execute(ctx context.Context, job *iowrappers.Job) error
Execute processes a planning job
func (*PlanningJobHandler) JobType ¶
func (h *PlanningJobHandler) JobType() string
JobType returns the job type identifier
type PlanningPostRequest ¶
type PlanningRequest ¶
type PlanningRequest struct {
Location POI.Location `json:"location"`
Slots []SlotRequest `json:"slots"`
TravelDate string
NumPlans int
SearchRadius uint `json:"radius"`
PriceLevel POI.PriceLevel `json:"price_level"`
PreciseLocation bool
WithNearbyCities bool
// contains filtered or unexported fields
}
type PlanningResp ¶
type PlanningResp struct {
Solutions []PlanningSolution
Err error
ErrorCode int
}
type PlanningResponse ¶
type PlanningResponse struct {
TravelDestination string `json:"travel_destination"`
TravelPlans []TravelPlan `json:"travel_plans"`
TripDetailsURL []string `json:"trip_details_url"`
Err error `json:"error"`
StatusCode int `json:"status_code"`
}
type PlanningSolution ¶
type PlanningSolution struct {
ID string `json:"id"`
PlaceNames []string `json:"place_names"`
PlaceIDS []string `json:"place_ids"`
PlaceLocations [][2]float64 `json:"place_locations"` // lat,lng
PlaceAddresses []string `json:"place_addresses"`
PlaceURLs []string `json:"place_urls"`
PlaceCategories []POI.PlaceCategory `json:"place_categories"`
Score float64 `json:"score"`
ScoreOld float64 `json:"score_old"`
PlanSpec string `json:"plan_spec"`
}
func (PlanningSolution) Key ¶
func (ps PlanningSolution) Key() float64
type PriorityJobQueue ¶
type PriorityJobQueue struct {
// contains filtered or unexported fields
}
PriorityJobQueue manages jobs across three priority levels Workers always pull from high-priority queue first, then normal, then low
func NewPriorityJobQueue ¶
func NewPriorityJobQueue(bufferSize int) *PriorityJobQueue
NewPriorityJobQueue creates a new priority-based job queue bufferSize determines the capacity of each priority channel
func (*PriorityJobQueue) Close ¶
func (pq *PriorityJobQueue) Close()
Close closes all priority queues
func (*PriorityJobQueue) Dequeue ¶
func (pq *PriorityJobQueue) Dequeue() *iowrappers.Job
Dequeue retrieves the next job, prioritizing high > normal > low Returns nil when all queues are closed and empty
func (*PriorityJobQueue) Enqueue ¶
func (pq *PriorityJobQueue) Enqueue(job *iowrappers.Job) bool
Enqueue adds a job to the appropriate priority queue
func (*PriorityJobQueue) Len ¶
func (pq *PriorityJobQueue) Len() int
Len returns the approximate total number of jobs across all priorities Note: This is a snapshot and may not be accurate in concurrent scenarios
func (*PriorityJobQueue) Stats ¶
func (pq *PriorityJobQueue) Stats() (high, normal, low int)
Stats returns the number of jobs in each priority queue
type PriorityQueueItem ¶
type PriorityQueueItem interface {
Key() float64
}
type ProfileView ¶
type ProfileView struct {
Username string
TravelPlans []user.TravelPlanView
}
type RequestIdKey ¶
type RequestIdKey string
type RevokeTokenInfo ¶
type RevokeTokenInfo struct {
Name string `json:"name"`
}
type SlotRequest ¶
type SlotRequest struct {
Weekday POI.Weekday `json:"weekday"`
TimeSlot matching.TimeSlot `json:"time_slot"`
Category POI.PlaceCategory `json:"category"`
}
SlotRequest represents the properties of each row in the tabular travel plan, although not all of these are displayed to users
type Solver ¶
type Solver struct {
Searcher *iowrappers.PoiSearcher
// contains filtered or unexported fields
}
func (*Solver) FindBestPlanningSolutions ¶
func (s *Solver) FindBestPlanningSolutions(ctx context.Context, placeClusters [][]matching.Place, maxSolutionsToSaveCount int, iterator *MultiDimIterator, radius uint, spec string) (resp *PlanningResp)
func (*Solver) FindOptimalPlan ¶
func (*Solver) Init ¶
func (s *Solver) Init(poiSearcher *iowrappers.PoiSearcher, placeDedupeCountLimit int, nearbyCitiesCountLimit int)
func (*Solver) Solve ¶
func (s *Solver) Solve(ctx context.Context, req *PlanningRequest) *PlanningResp
func (*Solver) SolveHungarianOptimal ¶
func (s *Solver) SolveHungarianOptimal(ctx context.Context, req *PlanningRequest) ([]PlacePlanningDetails, error)
func (*Solver) SolveWithNearbyCities ¶
func (s *Solver) SolveWithNearbyCities(ctx context.Context, req *MultiPlanningReq) *PlanningResp
type TimeSectionPlace ¶
type TimeSectionPlace struct {
ID string `json:"id"`
PlaceName string `json:"place_name"`
Category POI.PlaceCategory `json:"category"`
StartTime POI.Hour `json:"start_time"`
EndTime POI.Hour `json:"end_time"`
Address string `json:"address"`
URL string `json:"url"`
PlaceIcon string `json:"place_icon_css_class"`
}
type TravelPlan ¶
type TravelPlan struct {
ID string `json:"id"`
Places []TimeSectionPlace `json:"places"`
Saved bool `json:"saved"`
PlanningSpec string `json:"planning_spec"`
}
type TripDetailResp ¶
type TripDetailResp struct {
OriginalPlanID string
LatLongs [][2]float64
PlaceCategories []POI.PlaceCategory
PlaceDetails []PlaceDetailsResp
ShownActive []bool
TravelDestination string
TravelDate string
Score float64
ScoreOld float64
ApiKey string
}
TODO: deprecate Score and ScoreOld fields