Exemple #1
0
        /// <summary>
        ///  A function to retrieve flight's quotes from multiple web services concurrently.
        ///  The search response is then joined from each individual flight services once the all search is completed.
        /// </summary>
        /// <param name="modelQuoteRequest">A model encapsulating a flight request</param>
        /// <returns></returns>
        public IEnumerable <IFlightResponse> BrowseQuotes(IFlightRequest modelQuoteRequest)
        {
            var responses  = new List <IFlightResponse>();                 //response place holder
            var childTasks = new List <Task <List <IFlightResponse> > >(); //list of task running concurrently

            try
            {
                LogRequest(modelQuoteRequest);
                //parent task to hold response until all child task running are completed.
                var parentTask = StartSearch(modelQuoteRequest, childTasks);

                //wait for all child tasks to complete
                parentTask.Wait();

                //join search response form each collaborator
                childTasks.ForEach(_ => responses.AddRange(_.Result));
            }
            catch (Exception ex)
            {
                LogErrors(ex, childTasks);
            }

            Logger.Info($"All search completed: responses found ({responses.Count})");
            return(responses);
        }
Exemple #2
0
        private static Uri ParseApiRequestUri(IFlightRequest modelQuoteRequest)
        {
            var browseQuotesUrl = $"{ApiServiceUrl}/browsequotes/v1.0/US/USD/en-US";

            return(new Uri($"{browseQuotesUrl}/{modelQuoteRequest.Origin}/{modelQuoteRequest.Destination}" +
                           $"/{modelQuoteRequest.DepartDate}?inboundpartialdate={modelQuoteRequest.ReturnDate}"));
        }
        private static IFlightResponse ParseResponse(IFlightRequest modelQuoteRequest, SkyscannerBrowseQuoteResponse response,
                                                     Quote quote)
        {
            IFlightItinerary outboundItinerary = GetItinerary(response, quote.OutboundLeg);
            IFlightItinerary inboundItinerary  = GetItinerary(response, quote.InboundLeg);

            var flightItineraries = new List <IFlightItinerary>();

            if (inboundItinerary != null)
            {
                flightItineraries.Add(inboundItinerary);
            }
            if (outboundItinerary != null)
            {
                flightItineraries.Add(outboundItinerary);
            }

            IFlightResponse aFlightResponse = new FlightResponse()
            {
                QuoteSource       = "Skyscanner",
                TripTotalPrice    = TryGetCost(quote.MinPrice) ?? quote.MinPrice,
                BookingLink       = GetBookingLink(modelQuoteRequest),
                FlightItineraries = flightItineraries
            };

            return(aFlightResponse);
        }
Exemple #4
0
        private static HttpRequestMessage GetHttpRequestMessage(IFlightRequest modelQuoteRequest)
        {
            var httpRequest = new HttpRequestMessage()
            {
                Method = HttpMethod.Get,
            };

            httpRequest.Headers.Add(RapidApiHostAppSettingName, SecretRapidApiHost);
            httpRequest.Headers.Add(RapidApiKeyAppSettingName, SecretRapidApiKey);
            httpRequest.RequestUri = ParseApiRequestUri(modelQuoteRequest);
            return(httpRequest);
        }
Exemple #5
0
        /// <summary>
        ///  The URI used to perform the query
        /// </summary>
        /// <param name="modelQuoteRequest">User request</param>
        /// <returns>The Uri to perform flight request</returns>
        public string GetKayakUriForSearch(IFlightRequest modelQuoteRequest)
        {
            if (KayakFlightsUrl == null)
            {
                throw new Exception($"AppSettings '{KayakFlightUrlKey}' found found.");
            }
            var tripQuoteUrl = $"{KayakFlightsUrl}/{modelQuoteRequest.Origin}-{modelQuoteRequest.Destination}/" +
                               $"{modelQuoteRequest.DepartDate}";

            if (modelQuoteRequest.ReturnDate != null)
            {
                tripQuoteUrl = $"{tripQuoteUrl}/{modelQuoteRequest.ReturnDate}";
            }

            return($"{tripQuoteUrl}?sort=bestflight_a");
        }
        private void Validate(IFlightRequest flightRequest)
        {
            const int locationCodeLength = 3; //Find out the 3-letter code of a location (airport, city) or identify which airport or city uses a particular code

            if (flightRequest.Origin.IsNullOrEmpty() || flightRequest.Origin.Length < locationCodeLength)
            {
                ModelState.AddModelError("originPlace", "REQUIRED The origin place, minimum a 3-letter code of a location (airport, city)");
            }

            if (flightRequest.Destination.IsNullOrEmpty() || flightRequest.Destination.Length < locationCodeLength)
            {
                ModelState.AddModelError("destinationPlace", "REQUIRED The destination place, minimum a 3-letter code of a location (airport, city)");
            }

            //make sure depart/return dates make sense
            ValidateDates(flightRequest.DepartDate, flightRequest.ReturnDate);
        }
Exemple #7
0
        /// <summary>
        ///  Perform the actual web api search for flights sync
        /// </summary>
        /// <param name="modelQuoteRequest">model wrapping the actual user request</param>
        /// <returns></returns>
        public async Task <SkyscannerBrowseQuoteResponse> BrowseQuotesAsync(IFlightRequest modelQuoteRequest)
        {
            if (!ValidateApiSetting())
            {
                throw new Exception("Require skyscanner secret api host, key and url");
            }

            using (var httpRequest = GetHttpRequestMessage(modelQuoteRequest))
                using (var responseMessage = await LocalHttpClient.SendAsync(httpRequest)) {
                    if (!responseMessage.IsSuccessStatusCode)
                    {
                        throw new Exception($"Rapid Skyscanner-Flight search status code `{responseMessage.StatusCode}` Error:{responseMessage.ReasonPhrase}");
                    }
                    using (var readStream = new StreamReader(await responseMessage.Content.ReadAsStreamAsync(), Encoding.UTF8))
                        return(JsonConvert.DeserializeObject <SkyscannerBrowseQuoteResponse>(readStream.ReadToEnd()));
                }
        }
Exemple #8
0
        /// <summary>
        /// Browse for real-time flight quotes
        /// </summary>
        /// <param name="request">the user flight request</param>
        /// <returns></returns>
        public async Task <List <IFlightResponse> > BrowseQuotesAsync(IFlightRequest request)
        {
            var realTimeFlights = new List <IFlightResponse>();

            try
            {
                var numOfLodAttempts = 0;
                do //run query until result is found but not exceeding the maximum number of tries.
                {
                    await LoadQuotes(request, realTimeFlights);

                    numOfLodAttempts++;
                }while (ContinueSearch(realTimeFlights, numOfLodAttempts));
            }
            catch (Exception ex)
            {
                Logger.Error($"{ex.Message}|{ex.InnerException}");
            }

            return(realTimeFlights);
        }
        /// <summary>
        /// Browse for flights quotes from skyscanner Api
        /// </summary>
        /// <param name="request">An user flight request</param>
        /// <returns></returns>
        public async Task <List <IFlightResponse> > BrowseQuotesAsync(IFlightRequest request)
        {
            var flightResponses = new List <IFlightResponse>();

            try
            {
                //load flights from skyscanner api
                SkyscannerBrowseQuoteResponse response = await Loader.BrowseQuotesAsync(request);

                //parse flight response to the model shown to the user
                flightResponses.AddRange(response.Quotes.Select(quote => ParseResponse(request, response, quote)));
            }
            catch (Exception ex)
            {
                //log exception
                Logger.Error($"{ex.Message}|{ex.InnerException}");
            }

            //return flight response for one-was or round trip.
            return(flightResponses);
        }
Exemple #10
0
        /// <summary>
        /// Load real-time flights prices
        /// </summary>
        /// <param name="modelQuoteRequest">model representing the users flight request</param>
        /// <param name="flights">list of flight to append results to the end</param>
        /// <returns></returns>
        private async Task LoadQuotes(IFlightRequest modelQuoteRequest, List <IFlightResponse> flights)
        {
            var kayakLoader = new KayakLoader(modelQuoteRequest);

            IHtmlCollection <IElement> searchResults = await kayakLoader.GetFlightCollection();

            if (searchResults == null)
            {
                return;
            }
            foreach (IElement searchResult in searchResults)
            {
                var flight = new FlightResponse
                {
                    QuoteSource       = "Kayak",
                    TripTotalPrice    = KayakLoader.GetFlightCost(searchResult),
                    BookingLink       = kayakLoader.RequestUrl,
                    FlightItineraries = KayakLoader.GetFlightItineraries(searchResult)
                };

                flights.Add(flight);
            }
        }
Exemple #11
0
        private Task StartSearch(IFlightRequest modelQuoteRequest, ICollection <Task <List <IFlightResponse> > > childTasks)
        {
            return(Task.Factory.StartNew(() =>
            {
                var childFactory = new TaskFactory(TaskCreationOptions.AttachedToParent, TaskContinuationOptions.None);
                foreach (var service in _flightQuoteServiceCollaborators)
                {
                    var serviceName = service.GetType().Name;
                    Logger.Info($"{serviceName} initiate service quote search.");
                    childFactory.StartNew(() =>
                    {
                        //search for flights
                        var aTask = Task.Run(async() => await service.BrowseQuotesAsync(modelQuoteRequest));

                        //on search complete log search result count
                        aTask.GetAwaiter().OnCompleted(() =>
                                                       Logger.Info($"{serviceName} search completed. responses ({aTask.Result.Count})"));

                        //track child task
                        childTasks.Add(aTask);
                    });
                }
            }));
        }
Exemple #12
0
 private static void LogRequest(IFlightRequest modelQuoteRequest)
 {
     Logger.Info($"Initiating flight search from {modelQuoteRequest.Origin} to " +
                 $"{modelQuoteRequest.Destination} depart on {modelQuoteRequest.DepartDate} " +
                 $"return {modelQuoteRequest.ReturnDate}");
 }
Exemple #13
0
 /// <summary>
 /// Initialize url request using user search detail.
 /// </summary>
 /// <param name="modelQuoteRequest"></param>
 public KayakLoader(IFlightRequest modelQuoteRequest)
 {
     RequestUrl = GetKayakUriForSearch(modelQuoteRequest);
 }
 private static string GetBookingLink(IFlightRequest modelQuoteRequest)
 {
     return($"{Loader.GetBaseBookingUrl()}/{modelQuoteRequest.Origin}/{modelQuoteRequest.Destination}" +
            $"/{modelQuoteRequest.DepartDate}/{modelQuoteRequest.ReturnDate}");
 }