Imports System.IO Imports System.IO.Compression Imports System.Net.Http Imports ModpackUpdater.Model Public Class ModpackInstaller Private Class LocalZipCacheEntry Public Property DownloadUrl As String Public Property ExtractedZipPath As String End Class Public Event InstallProgessUpdated(result As UpdateCheckResult, processedSyncs As Integer) Public Event CheckingProgressUpdated(toCheck As Integer, processed As Integer) Private ReadOnly updateConfig As ModpackConfig Private ReadOnly localPath As String Private httpClient As New HttpClient Public Sub New(updateConfig As ModpackConfig, localPath As String) Me.updateConfig = updateConfig Me.localPath = localPath End Sub Protected Overrides Sub Finalize() httpClient.Dispose() MyBase.Finalize() End Sub Private Async Function DownloadUpdateInfos() As Task(Of UpdateInfos) Dim content As String = Await httpClient.GetStringAsync(updateConfig.UpdateUrl) Return UpdateInfos.Parse(content) End Function Private Async Function DownloadInstallInfos() As Task(Of InstallInfos) Dim content As String = Await httpClient.GetStringAsync(updateConfig.InstallUrl) Return InstallInfos.Parse(content) End Function Public Async Function Check(ignoreRevmoedFiles As Boolean) As Task(Of UpdateCheckResult) Dim result As New UpdateCheckResult If ModpackInfo.HasModpackInfo(localPath) Then Dim infos As UpdateInfos = Await DownloadUpdateInfos() Dim modpackInfo As ModpackInfo = ModpackInfo.Load(localPath) If infos IsNot Nothing AndAlso infos.Updates.Count <> 0 Then Dim updatesOrderes = infos.Updates.OrderByDescending(Function(n) n.Version) result.LatestVersion = updatesOrderes.First.Version result.CurrentVersion = modpackInfo.Version result.IsInstalled = True Dim checkingVersionIndex As Integer = 0 Dim checkingVersion As UpdateInfo = updatesOrderes(checkingVersionIndex) Do While checkingVersion IsNot Nothing AndAlso checkingVersion.Version > result.CurrentVersion Dim actionsToAdd As New List(Of UpdateAction) For Each action In checkingVersion.Actions If Not result.Actions.Any(Function(n) n.DestPath = action.DestPath) Then actionsToAdd.Add(action) End If Next result.Actions.InsertRange(0, actionsToAdd) checkingVersionIndex += 1 checkingVersion = updatesOrderes.ElementAtOrDefault(checkingVersionIndex) Loop Else result.HasError = True End If End If If Not result.IsInstalled Then Dim infos As InstallInfos = Await DownloadInstallInfos() If infos IsNot Nothing AndAlso infos.Actions.Count <> 0 Then result.Actions.AddRange(infos.Actions) Else result.HasError = True End If End If Return result End Function Public Async Function Install(checkResult As UpdateCheckResult) As Task(Of Boolean?) Dim modpackInfo As ModpackInfo Dim processed As Integer = 0 Dim localZipCache As New List(Of LocalZipCacheEntry) If ModpackInfo.HasModpackInfo(localPath) Then modpackInfo = ModpackInfo.Load(localPath) Else modpackInfo = New ModpackInfo End If For Each iaction As InstallAction In checkResult.Actions Dim destFilePath As String = Path.Combine(localPath, iaction.DestPath) If TypeOf iaction Is UpdateAction Then Dim uaction As UpdateAction = iaction Select Case uaction.Type Case UpdateActionType.Update Await InstallFile(destFilePath, uaction.DownloadUrl, uaction.IsZip, uaction.ZipPath, localZipCache) Case UpdateActionType.Delete If uaction.IsDirectory Then If Directory.Exists(destFilePath) Then Directory.Delete(destFilePath, True) End If Else If File.Exists(destFilePath) Then File.Delete(destFilePath) End If End If Case UpdateActionType.Copy Dim srcFilePath As String = Path.Combine(localPath, uaction.SrcPath) If File.Exists(srcFilePath) Then Directory.CreateDirectory(Path.GetDirectoryName(destFilePath)) File.Copy(srcFilePath, destFilePath, True) End If Case UpdateActionType.Move Dim srcFilePath As String = Path.Combine(localPath, uaction.SrcPath) If File.Exists(srcFilePath) Then Directory.CreateDirectory(Path.GetDirectoryName(destFilePath)) File.Move(srcFilePath, destFilePath, True) End If End Select Else Await InstallFile(destFilePath, iaction.DownloadUrl, iaction.IsZip, iaction.ZipPath, localZipCache) End If processed += 1 RaiseEvent InstallProgessUpdated(checkResult, processed) Next modpackInfo.Version = checkResult.LatestVersion modpackInfo.Save(localPath) For Each task In localZipCache Directory.Delete(task.ExtractedZipPath, True) Next Return True End Function Private Async Function InstallFile(destFilePath As String, sourceUrl As String, isZip As Boolean, zipPath As String, localZipCache As List(Of LocalZipCacheEntry)) As Task Directory.CreateDirectory(Path.GetDirectoryName(destFilePath)) Dim fsDestinationPath As String = If(isZip, Path.Combine(Path.GetTempPath(), $"mc_update_file_{Date.Now.ToBinary}.zip"), destFilePath) Dim sRemote As Stream = Await httpClient.GetStreamAsync(sourceUrl) Dim fs As New FileStream(destFilePath, FileMode.Create, FileAccess.ReadWrite) Await sRemote.CopyToAsync(fs) sRemote.Close() fs.Close() If isZip Then Dim zipDir As String = $"{Path.GetFileNameWithoutExtension(fsDestinationPath)}_extracted" ZipFile.ExtractToDirectory(fsDestinationPath, zipDir) '... File.Delete(fsDestinationPath) localZipCache?.Add(New LocalZipCacheEntry With { .DownloadUrl = sourceUrl, .ExtractedZipPath = zipDir }) End If End Function End Class