/// <summary> /// The query data. /// </summary> /// <param name="request"> /// The request. /// </param> /// <param name="progressChangedHandler"> /// The progress changed handler. /// </param> /// <returns> /// The <see cref="DataRequestResult"/>. /// </returns> public override DataRequestResult QueryData(FlightFareRequest request, JourneyProgressChangedEventHandler progressChangedHandler) { byte[] postData = this._generator.GeneratePOSTData(request); var httpRequest = (this._request_ + "1").GetRequest("POST"); httpRequest.CookieContainer = new CookieContainer(); httpRequest.Referer = this._root_; httpRequest.ContentLength = postData.Length; Stream stream = httpRequest.GetRequestStream(); stream.Write(postData, 0, postData.Length); stream.Close(); string tokenId = null; string requestId = null; using (var response = (HttpWebResponse)httpRequest.GetResponse()) { string waitUri = response.ResponseUri.ToString(); requestId = this.GetTicketId(response); response.Close(); if (string.IsNullOrEmpty(requestId)) { return new DataRequestResult(DataRequestState.Failed, null); } var match = Regex.Match(waitUri, @"\?" + this._cookie_ + @"\=(?<id>.+?)\&", RegexOptions.IgnoreCase); if (match.Success) { tokenId = match.Groups["id"].Value; } else { var cookies = response.Cookies; foreach (Cookie c in cookies) { if (c.Name == this._cookie_) { tokenId = c.Value; break; } } } } DataRequestResult requestResult; do { requestResult = this.GetResult(requestId, tokenId, request); } while (requestResult.RequestState == DataRequestState.Pending || requestResult.RequestState == DataRequestState.Requested); return requestResult; }
/// <summary> /// The generate post data. /// </summary> /// <param name="request"> /// The request. /// </param> /// <returns> /// The <see cref="byte[]"/>. /// </returns> public byte[] GeneratePOSTData(FlightFareRequest request) { DateTime retDate = request.IsRoundTrip ? request.ReturnDate : request.DepartureDate.AddDays(7); string dataStr = "fly_radio_route_selection=" + (request.IsRoundTrip ? "both" : "oneway") + "&text_fly_from=" + this.Encode(request.Departure.IATA) + "&text_fly_to=" + this.Encode(request.Destination.IATA) + "&cal_pickdate1=" + request.DepartureDate.ToString("ddd+d.M.yyyy", FI_CULTURE) + "&cal_pickdate2=" + retDate.ToString("ddd+d.M.yyyy", FI_CULTURE) + "&fly_select_passengers_adults=1" + "&fly_select_passengers_children=0" + "&fly_age_select_1=&fly_age_select_2=&fly_age_select_3=&fly_age_select_4=&fly_age_select_5=" + "&from_IATA=" + "&to_IATA=" + "&search_type=01_flights&submit=Hae+lennot"; return Encoding.UTF8.GetBytes(dataStr); }
/// <summary> /// The get result. /// </summary> /// <param name="requestId">The request identifier.</param> /// <param name="requestToken">The request token.</param> /// <param name="request">The request.</param> /// <returns> /// The <see cref="DataRequestResult" />. /// </returns> private DataRequestResult GetResult(string requestId, string requestToken, FlightFareRequest request) { TravelRoute result = null; var cookies = new CookieContainer(); var cookie = new Cookie(this._cookie_, requestToken) { Domain = this._domain_ }; cookies.Add(cookie); for (var i = 0; i < 4; i++) { var requestUrl = string.Format(this._intermediateResult_, requestId, i); using(requestUrl.GetResponse("GET", cookies, this._resultReferal_)){} } var resultUrl = string.Format(this._result_, requestId); using (var response = resultUrl.GetResponse("GET", cookies, this._resultReferal_)) { using (var dataStream = response.GetResponseStream()) { if (dataStream != null) { var parser = this.GetParser(request); var dataResult = parser.ParseWebArchive(dataStream, response.GetEncoding()); if (dataResult.ResultState == DataResult.NotReady) { return new DataRequestResult(DataRequestState.Pending, dataResult.ResultRoute); // Data is not yet ready, return the current RequestState } result = dataResult.ResultRoute; dataStream.Close(); } } } var newState = result == null ? DataRequestState.Failed : (result.Journeys.Count < 1 || result.Journeys[0].Data.Count < 1 ? DataRequestState.NoData : DataRequestState.Ok); return new DataRequestResult(newState, result); }
/// <summary> /// The get parser. /// </summary> /// <param name="request">The request.</param> /// <returns> /// The <see cref="MatrixDataParser" />. /// </returns> private MatrixDataParser GetParser(FlightFareRequest request) { var parser = new MatrixDataParser(this._root_, this.Config.MaxFlightsPerAirline, this.Config.MaxAirlineCount, 1) { Departure = request.Departure, Destination = request.Destination }; return parser; }
/// <summary> /// Check if two requests are similar (same location and same travel time) /// </summary> /// <param name="other"> /// </param> /// <returns> /// The <see cref="bool"/>. /// </returns> public bool IsSame(FlightFareRequest other) { bool result; if (other == null) { result = false; } else { if (result = string.Equals(this.Departure.IATA, other.Departure.IATA, StringComparison.OrdinalIgnoreCase)) { if (result = string.Equals(this.Destination.IATA, other.Destination.IATA, StringComparison.OrdinalIgnoreCase)) { if (result = this.DepartureDate == other.DepartureDate) { result = this.ReturnDate == other.ReturnDate; } } } } return result; }
/// <summary> /// The do request data. /// </summary> /// <param name="request"> /// The request. /// </param> private void DoRequestData(FlightFareRequest request) { if (!Monitor.TryEnter(this._syncObject)) { return; } try { this.IsStopping = false; if (this.IsDestructed() || this.IsStopping) { return; } // First, reset all data this.Reset(); var reqName = StringUtil.GetPeriodString(request.DepartureDate, request.ReturnDate); this.lvFlightData.SafeInvoke( new Action( () => { this.lvFlightData.Name = reqName; this.lvFlightData.SetWatermark("Requesting data... Please wait..."); })); // Create a thread to get the data DataRequestResult dataRequestResult = DataRequestResult.Empty; var workResult = BackgroundThread.DoWork( () => { this.lvFlightData.SetWatermark( "Data request was started on " + DateTime.Now + Environment.NewLine + "Please wait while the application retrieves fare data..."); this.RequestState = DataRequestState.Requested; this.LastRequestStartedDate = DateTime.Now; dataRequestResult = this.DataHandler.QueryData(request, this.OnProgressChanged); }, this.TimeoutInSeconds, reqName, AppContext.Logger); if (workResult.Succeeded) { this.RequestState = dataRequestResult.ResultRoute == null ? DataRequestState.NoData : DataRequestState.Ok; } else { this.RequestState = DataRequestState.Failed; if (workResult.IsTimedout) { string err = "Request timed out after " + this.TimeoutInSeconds + "s"; this.LastException = new TimeoutException(err); this.Logger.ErrorFormat(err); } else if (workResult.Exception != null) { this.LastException = workResult.Exception; this.Logger.Error("Failed to request journey data: " + workResult.Exception.Message); } } this.RequestState = dataRequestResult.RequestState; this._lastRetrievedRoute = dataRequestResult.ResultRoute; if (this.RequestState > DataRequestState.Requested) { this.LastDataDate = DateTime.Now; if (this._lastRetrievedRoute != null && this._lastRetrievedRoute.Journeys.Count > 0) { foreach (var j in this._lastRetrievedRoute.Journeys) { foreach (var d in j.Data) { if (d.DataDate.IsUndefined()) { d.DataDate = this.LastDataDate; } } } } } } catch (Exception ex) { this.LastException = ex; this.RequestState = DataRequestState.Failed; this.Logger.Error("Failed to request data: " + ex); } finally { Monitor.Exit(this._syncObject); // Release the lock at the end this.OnGetJourneyCompleted(new JourneyEventArgs(this.LastRetrievedRoute, this.RequestState, this.LastRequestInitiatedDate)); this.IsStopping = false; } }
/// <summary> /// The request data async. /// </summary> /// <param name="request"> /// The request. /// </param> /// <returns> /// The <see cref="TravelRoute"/>. /// </returns> public TravelRoute RequestDataAsync(FlightFareRequest request) { ThreadPool.QueueUserWorkItem( o => { AppUtil.NameCurrentThread(this.GetType().Name + "-RequestDataAsync"); this.DoRequestData(request); }); return this.LastRetrievedRoute; }
/// <summary> /// Query fare data asynchronously /// </summary> /// <param name="request"> /// </param> /// <param name="progressChangedHandler"> /// The progress Changed Handler. /// </param> /// <returns> /// The <see cref="DataRequestResult"/>. /// </returns> public abstract DataRequestResult QueryData(FlightFareRequest request, JourneyProgressChangedEventHandler progressChangedHandler);
/// <summary> /// Initializes a new instance of the <see cref="JourneyProgressChangedEventArgs"/> class. /// </summary> /// <param name="percentage"> /// The percentage. /// </param> /// <param name="resultRoute"> /// The result route. /// </param> /// <param name="request"> /// The request. /// </param> /// <param name="stateObj"> /// The state obj. /// </param> public JourneyProgressChangedEventArgs(int percentage, TravelRoute resultRoute, FlightFareRequest request, object stateObj) : base(percentage, stateObj) { this.ResultRoute = resultRoute; this.Request = request; }