So, I've been hammering away at this for some time now. I'm an amateur programmer, and so I don't always know what I'm doing wrong.
Anyhow, the premise of my recent project:
My friends and I regularly play MineCraft, but they're not terribly bright, and we're not always around to get the mods and send them links and whatnot. So I thought I'd program something to automatically pull down mods so they are synchronized with the server and get the server data at the same time.
I'm using a free FTP host, but I don't think that's the issue here, for reasons that will become clear.
Basically, I want to make use of a progressbar and ideally a label too in order to indicate the progress of the overall block of data (all mods together... not more than 1GB - quite a bit smaller). However, I seem to be running into a few issues regarding the Async option:
It will randomly opt to not download files it should be downloading
It may not download files in their entirety before claiming to be complete
The progressbar is maybe 50% full when the msgbox triggers saying that it is finished downloading all items.
However, while the progressbar doesn't work due to the reporting events for progress not existing in the synchronous use of Webclient, when I run the syncro in a BGworker, it downloads properly every time. However, I lose out on progress reporting, which is kind of important....
So, basically:
- Is there a better way to implement this?
This is the last chunk I need to get working before it's ready to go, so I'd really like to try and do that. Thank you for any assistance!
Edit: Updated with code:
Public Function GetDownloadSize(ByVal URL As String) As Long
Dim request As Net.FtpWebRequest = DirectCast(Net.WebRequest.Create(URL), Net.FtpWebRequest)
request.Method = Net.WebRequestMethods.Ftp.GetFileSize
request.Credentials = New Net.NetworkCredential(dl_user, dl_pass)
Dim response As Net.FtpWebResponse = DirectCast(request.GetResponse(), Net.FtpWebResponse)
Dim fileSize As Long = response.ContentLength
Return fileSize
End Function
Private Sub btn_sync_Click(sender As Object, e As EventArgs) Handles btn_sync.Click
Dim cont As DialogResult = MsgBox("Continue? " + (total_dl_size / 1000).ToString("N0") + " KB remain to be downloaded.", MsgBoxStyle.YesNo, "CAUTION!")
If cont = DialogResult.No Then
tb_warnings.AppendText("-ERR: User declined to synchronize files. Restart the application to sync.")
tb_warnings.AppendText(ControlChars.NewLine)
Label3.BackColor = Color.Firebrick
Return
End If
btn_sync.Enabled = False
btn_scan.Enabled = false
tb_warnings.AppendText("-Deleting outmoded/unused mods. Protected mods will be kept.")
For Each i As fdata_obj In deleted_files
My.Computer.FileSystem.DeleteFile(mc_dir + "\mods\" + i.name)
Next
tb_warnings.AppendText(ControlChars.NewLine)
tb_warnings.AppendText("-Deleting mod subdirectories to ensure no conflicts.")
tb_warnings.AppendText(ControlChars.NewLine)
For Each d In My.Computer.FileSystem.GetDirectories(mc_dir + "\mods")
My.Computer.FileSystem.DeleteDirectory(d, FileIO.DeleteDirectoryOption.DeleteAllContents)
Next
initialize_download()
End Sub
Private Sub initialize_download()
Dim wc As New System.Net.WebClient() ' SORRY, ASSUME THIS IS A PUBLIC VAR SO IT CAN BE REFERENCED ACROSS ITS OTHER METHODS
AddHandler wc.DownloadProgressChanged, AddressOf OnDownloadProgressChanged
AddHandler wc, AddressOf OnFileDownloadCompleted
Dim usr As String = "randouser"
Dim pass As String = "randopass"
For Each s In (From dl As fdata_obj In new_files Select dl_server + "/mods/" + mods_dir + "/" + dl.name).ToList
downloads.Enqueue(s)
Next
wc.Credentials = New Net.NetworkCredential(usr, pass)
Dim urix As String = downloads.Dequeue
Try
wc.DownloadFileasync(New Uri(urix), mc_dir + "\mods\" + IO.Path.GetFileName(urix))
Catch ex As Exception
MsgBox(ex.Message)
If tb_warnings.InvokeRequired = True Then
tb_warnings.Invoke(New tb_updater(AddressOf tb_update), "-ERR: Could not download file: " + urix, urix)
Else
tb_warnings.AppendText("-ERR: Could not download file: " + IO.Path.GetFileName(urix))
tb_warnings.AppendText(ControlChars.NewLine)
End If
end try
End Sub
Private Sub OnDownloadProgressChanged(ByVal sender As Object, ByVal e As System.Net.DownloadProgressChangedEventArgs)
MsgBox("This is happening!")
total_dl = total_dl + e.BytesReceived
Dim percentage As Integer = (CType((total_dl / total_dl_size), Integer) * 100)
if percentage > 100 then
percentage = 100
endif
prog_update(percentage)
End Sub
delegate sub progress_update(byval prog as integer)
' POTENTIAL ISSUES HERE???????
private sub prog_update(byval prog as integer)
if progressbar1.invokerequired then
progressbar1.invoke(new prog_update(addressof progress),prog)
else
progressbar1.value = prog
Private Sub OnFileDownloadCompleted(ByVal sender As Net.WebClient, ByVal e As System.ComponentModel.AsyncCompletedEventArgs)
If e.Cancelled Then
MsgBox(e.Cancelled)
ElseIf Not e.Error Is Nothing Then
MsgBox(e.Error.Message)
Else
if downloads.count > 0 then
Dim urix As String = downloads.Dequeue
Try
wc.DownloadFileasync(New Uri(urix), mc_dir + "\mods\" + IO.Path.GetFileName(urix))
Catch ex As Exception
MsgBox(ex.Message)
If tb_warnings.InvokeRequired = True Then
tb_warnings.Invoke(New tb_updater(AddressOf tb_update), "-ERR: Could not download file: " + urix, urix)
Else
tb_warnings.AppendText("-ERR: Could not download file: " + IO.Path.GetFileName(urix))
tb_warnings.AppendText(ControlChars.NewLine)
End If
End Try
End If
End Sub