' ******************************************************************************
' **
' ** Yahoo Finance Managed
' ** Written by Marius Häusler 2010
' ** It would be pleasant, if you contact me when you are using this code.
' ** Contact: YahooFinanceManaged@gmail.com
' ** Project Home: http://code.google.com/p/yahoo-finance-managed/
' **
' ******************************************************************************
' **
' ** Copyright 2010 Marius Häusler
' **
' ** Licensed under the Apache License, Version 2.0 (the "License");
' ** you may not use this file except in compliance with the License.
' ** You may obtain a copy of the License at
' **
' ** http://www.apache.org/licenses/LICENSE-2.0
' **
' ** Unless required by applicable law or agreed to in writing, software
' ** distributed under the License is distributed on an "AS IS" BASIS,
' ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
' ** See the License for the specific language governing permissions and
' ** limitations under the License.
' **
' ******************************************************************************
Namespace Base
''' <summary>
''' Provides methods and properties for downloading data and controlling these download processes. This class must be inherited.
''' </summary>
''' <remarks>This class can not be instanced outside of the library</remarks>
Public MustInherit Class Download
Protected Event AsyncStreamDownloadCompleted(ByVal sender As Download, ByVal ba As StreamDownloadCompletedEventArgs)
Friend ReadOnly mHelper As New MyHelper
Private ReadOnly mWebClients As New List(Of TimeoutWebClient)
Private mProxy As IWebProxy = WebProxy.GetDefaultProxy
Private mTimeout As Integer = 30000
''' <summary>
''' Gets the user arguments of each download process.
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks>If you just need a single object, you should use UserArgs(Int32) property, because of higher performance.</remarks>
Public ReadOnly Property UserArgs() As Object()
Get
If mWebClients.Count > 0 Then
Dim lst(mWebClients.Count - 1) As Object
For i As Integer = 0 To mWebClients.Count - 1
Dim ea As DownloadEventArgs = TryCast(mWebClients(i).AsyncArgs, DownloadEventArgs)
If ea IsNot Nothing Then
lst(i) = ea.UserArgs
Else
lst(i) = mWebClients(i).AsyncArgs
End If
Next
Return lst
Else
Return New Object() {}
End If
End Get
End Property
''' <summary>
''' Gets the user argument of a download process at a specific index position.
''' </summary>
''' <param name="index">The index position of the download</param>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
Public ReadOnly Property UserArgs(ByVal index As Integer) As Object
Get
If index < 0 Or index > mWebClients.Count - 1 Then
Throw New IndexOutOfRangeException("The index is out of download list range.")
Else
Return Me.GetDeeperObject(mWebClients(index).AsyncArgs)
End If
End Get
End Property
''' <summary>
''' Gets or sets the time in miliseconds when the download will cancel if the time reached before it is completed.
''' </summary>
''' <value>Timeout in miliseconds. If value is '-1', the next download wont have a timeout.</value>
''' <returns>The timeout in miliseconds.</returns>
''' <remarks></remarks>
Public Property Timeout() As Integer
Get
Return mTimeout
End Get
Set(ByVal value As Integer)
If value >= 0 Then : mTimeout = value
Else : mTimeout = 0
End If
End Set
End Property
''' <summary>
''' Gets or sets the used proxy setting for download.
''' </summary>
''' <value></value>
''' <returns>The actual setted proxy</returns>
''' <remarks>Default value are proxy settings from Internet Explorer/Windows Internet Settings.</remarks>
Public Property Proxy() As IWebProxy
Get
Return mProxy
End Get
Set(ByVal value As IWebProxy)
mProxy = value
End Set
End Property
''' <summary>
''' Gets the number of actually running asynchronous downloads.
''' </summary>
''' <value></value>
''' <returns>The number of active downloads</returns>
''' <remarks></remarks>
Public ReadOnly Property AsyncDownloadsCount() As Integer
Get
Return mWebClients.Count
End Get
End Property
Protected Function Download(ByVal url As String) As StreamResponse
Try
Dim str As IO.Stream = Nothing
Using wc As New TimeoutWebClient(mTimeout)
If mProxy IsNot Nothing Then wc.Proxy = mProxy
Return wc.Download(url)
End Using
Catch ex As Exception
Return New StreamResponse(New ConnectionInfo(New Net.WebException("Unkonown Error occured", ex, WebExceptionStatus.UnknownError, Nothing), mTimeout, 0, Date.Now), Nothing)
End Try
End Function
Protected Sub DownloadAsync(ByVal url As String, ByVal args As Object)
Dim wc As New TimeoutWebClient(mTimeout)
If mProxy IsNot Nothing Then wc.Proxy = mProxy
AddHandler wc.AsyncDownloadCompleted, AddressOf Me.AsyncDownload_Completed
mWebClients.Add(wc)
wc.DownloadAsync(url, args)
End Sub
''' <summary>
''' Cancels all running downloads.
''' </summary>
''' <returns>TRUE, if all downloads were canceled. FALSE, if something goes wrong.</returns>
''' <remarks></remarks>
Public Function CancelAsyncAll() As Boolean
If mWebClients.Count > 0 Then
For i As Integer = mWebClients.Count - 1 To 0 Step -1
mWebClients(i).CancelAsync()
Next
End If
Return mWebClients.Count = 0
End Function
''' <summary>
''' Cancels all running downloads containing the passed user argument.
''' </summary>
''' <param name="userArgs">The user argument that the download object contains.</param>
''' <returns>The number of canceled downloads.</returns>
''' <remarks></remarks>
Public Function CancelAsync(ByVal userArgs As Object) As Integer
If mWebClients.Count > 0 Then
Dim count As Integer = 0
For i As Integer = mWebClients.Count To 0 Step -1
If Me.DeepUserArgsEqual(mWebClients(i).AsyncArgs, userArgs) Then
mWebClients(i).CancelAsync()
count += 1
End If
Next
Return count
Else
Return 0
End If
End Function
''' <summary>
''' Cancels a running download at specific index position.
''' </summary>
''' <param name="index">The index position of the download process in queue.</param>
''' <returns>TRUE, if the download at the index position was canceled, FALSE, if not.</returns>
''' <remarks></remarks>
Public Sub CancelAsyncAt(ByVal index As Integer)
mWebClients(index).CancelAsync()
End Sub
''' <summary>
''' Proves if the download processes contains the passed user argument.
''' </summary>
''' <param name="userArgs">Individual user argument that the download contains.</param>
''' <returns>The number of download processes containing the passed user argument.</returns>
''' <remarks></remarks>
Public Function Contains(ByVal userArgs As Object) As Integer
Dim count As Integer = 0
For Each wc As TimeoutWebClient In mWebClients
If Me.DeepUserArgsEqual(wc.AsyncArgs, userArgs) Then count += 1
Next
Return count
End Function
Private Sub AsyncDownload_Completed(ByVal sender As TimeoutWebClient, ByVal ea As StreamDownloadCompletedEventArgs)
RemoveHandler sender.AsyncDownloadCompleted, AddressOf AsyncDownload_Completed
If mWebClients.Contains(sender) Then mWebClients.Remove(sender)
sender.Dispose()
RaiseEvent AsyncStreamDownloadCompleted(Me, ea)
End Sub
Private Function DeepUserArgsEqual(ByVal argsX As Object, ByVal argsY As Object) As Boolean
Return Me.GetDeeperObject(argsX) Is Me.GetDeeperObject(argsY)
End Function
Private Function GetDeeperObject(ByVal args As Object) As Object
Dim deeperObj As Object = IIf(args IsNot Nothing AndAlso TypeOf args Is DownloadEventArgs, DirectCast(args, DownloadEventArgs).UserArgs, args)
If deeperObj IsNot Nothing AndAlso TypeOf deeperObj Is DownloadEventArgs Then deeperObj = Me.GetDeeperObject(deeperObj)
Return deeperObj
End Function
End Class
Public Class StreamDownloadCompletedEventArgs
Inherits DownloadCompletedEventArgs
Public Overloads ReadOnly Property Response() As StreamResponse
Get
Return DirectCast(MyBase.Response, StreamResponse)
End Get
End Property
Public Sub New(ByVal userArgs As Object, ByVal response As StreamResponse)
MyBase.New(userArgs, response)
End Sub
End Class
Public Class StreamResponse
Inherits Response
Public Overloads ReadOnly Property Result() As IO.MemoryStream
Get
Return TryCast(MyBase.Result, IO.MemoryStream)
End Get
End Property
Public Sub New(ByVal info As ConnectionInfo, ByVal result As IO.MemoryStream)
MyBase.New(info, result)
End Sub
End Class
End Namespace