update structure

This commit is contained in:
2024-04-21 09:36:33 +02:00
parent 34fa5fbffe
commit fd701f3615
24 changed files with 57 additions and 290 deletions

View File

@@ -0,0 +1,8 @@
Public Class MinecraftProfileChecker
Public Shared Function CheckProfile(folderPath As string) As Boolean
'Todo: Adds some checks to verify, if the current folder is a minecraft folder.
Return True
End Function
End Class

View File

@@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<RootNamespace>ModpackUpdater.Manager</RootNamespace>
<TargetFramework>net8.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="WebDav.Client" Version="2.8.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ModpackUpdater.Model\ModpackUpdater.Model.vbproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,23 @@
Imports ModpackUpdater.Model
Public Class UpdateCheckResult
Public Property IsLegacy As Boolean
Public ReadOnly Property SyncFiles As New List(Of UpdateSyncFile)
Public Property CurrentVersion As Version
Public Property LatestVersion As Version
Public ReadOnly Property UpdateActions As New List(Of UpdateAction)
Public Property HasError As Boolean
Public ReadOnly Property HasUpdates As Boolean
Get
If IsLegacy Then
Return SyncFiles.Where(Function(n) n.SyncAction <> UpdateSyncAction.None).Any
Else
Return CurrentVersion < LatestVersion
End If
End Get
End Property
End Class

View File

@@ -0,0 +1,268 @@
Imports System.IO
Imports System.Net
Imports System.Net.Http
Imports ModpackUpdater.Model
Imports WebDav
Public Class UpdateInstaller
Public Event InstallProgessUpdated(result As UpdateCheckResult, processedSyncs As Integer)
Public Event CheckingProgressUpdated(toCheck As Integer, processed As Integer)
Private ReadOnly updateConfig As UpdateConfig
Private ReadOnly localPath As String
Private webdavClient As WebDavClient = Nothing
Private httpClient As New HttpClient
Public Sub New(updateConfig As UpdateConfig, localPath As String)
Me.updateConfig = updateConfig
Me.localPath = localPath
End Sub
Protected Overrides Sub Finalize()
httpClient.Dispose()
MyBase.Finalize()
End Sub
Private Function CreateClient() As WebDavClient
If webdavClient Is Nothing Then
Dim params As New WebDavClientParams With {
.BaseAddress = New Uri(updateConfig.WebdavURL),
.Credentials = New NetworkCredential(updateConfig.WebdavUsername, updateConfig.WebdavPassword)
}
webdavClient = New WebDavClient(params)
End If
Return webdavClient
End Function
Private Async Function DownloadUpdateInfos() As Task(Of UpdateInfos)
Dim content As String = Await httpClient.GetStringAsync(updateConfig.UpdateUrl)
Return UpdateInfos.Parse(content)
End Function
Public Async Function CheckForUpdates(ignoreRevmoedFiles As Boolean) As Task(Of UpdateCheckResult)
Dim infos As UpdateInfos = Await DownloadUpdateInfos()
Dim result As New UpdateCheckResult
If infos IsNot Nothing AndAlso infos.Updates.Any Then
Dim updatesOrderes = infos.Updates.OrderByDescending(Function(n) n.Version)
result.LatestVersion = updatesOrderes.First.Version
If ModpackInfo.HasModpackInfo(localPath) Then
Dim modpackInfo As ModpackInfo = ModpackInfo.Load(localPath)
result.CurrentVersion = modpackInfo.Version
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.UpdateActions.Any(Function(n) n.DestPath = action.DestPath) Then
actionsToAdd.Add(action)
End If
Next
result.UpdateActions.InsertRange(0, actionsToAdd)
checkingVersionIndex += 1
checkingVersion = updatesOrderes.ElementAtOrDefault(checkingVersionIndex)
Loop
Else
Await CheckForUpdatesLegacy(result, ignoreRevmoedFiles)
End If
End If
Return result
End Function
Private Async Function CheckForUpdatesLegacy(result As UpdateCheckResult, ignoreRevmoedFiles As Boolean) As Task
Dim client As WebDavClient = CreateClient()
Dim resTopFolder As WebDavResource = Nothing
Dim checkedFiles = New List(Of String)()
Dim responseSuccessfull As Boolean = False
result.CurrentVersion = New Version("0.0.0.0")
result.IsLegacy = True
'Check for new & updated files
Dim response = Await client.Propfind(String.Empty, New PropfindParameters() With {.ApplyTo = ApplyTo.Propfind.ResourceAndAncestors})
If resTopFolder Is Nothing AndAlso response.IsSuccessful AndAlso response.Resources.Any() Then
resTopFolder = response.Resources.ElementAtOrDefault(0)
responseSuccessfull = True
End If
If responseSuccessfull AndAlso response.Resources.Count > 1 Then
Dim i As Integer = 1
Dim loopTo As Integer = response.Resources.Count - 1
Do While i <= loopTo
Dim res = response.Resources.ElementAtOrDefault(i)
Dim isFolder As Boolean = res.Uri.EndsWith("/")
If Not isFolder Then
Dim syncAction? As UpdateSyncAction = Nothing
Dim localFile As String
Dim remoteFile As String
'Get remote file path
remoteFile = res.Uri
'Get local file path
localFile = Path.Combine(localPath, Uri.UnescapeDataString(res.Uri.Substring(resTopFolder.Uri.Length)).Replace("/", "\"))
'Check action
If File.Exists(localFile) Then
If File.GetLastWriteTime(localFile) < res.LastModifiedDate = True Then
syncAction = UpdateSyncAction.UpdatedFile
End If
Else
syncAction = UpdateSyncAction.NewFile
End If
'Add to list
checkedFiles.Add(localFile)
If syncAction IsNot Nothing Then
result.SyncFiles.Add(New UpdateSyncFile(syncAction, localFile, remoteFile))
End If
End If
i += 1
RaiseEvent CheckingProgressUpdated(loopTo, i)
Loop
End If
'Find all old files to remove
If responseSuccessfull Then
Dim allLocalFiles = Directory.GetFiles(localPath, "*", SearchOption.AllDirectories)
For Each lf As String In allLocalFiles
Dim isKnown As Boolean = False
For Each checkedFile As String In checkedFiles
If Not isKnown AndAlso If(checkedFile, "") = If(lf, "") Then
isKnown = True
End If
Next
If Not isKnown Then
result.SyncFiles.Add(New UpdateSyncFile(If(ignoreRevmoedFiles, UpdateSyncAction.None, UpdateSyncAction.RemovedFile), lf, String.Empty))
End If
Next
End If
End Function
Public Async Function InstallUpdates(checkResult As UpdateCheckResult, Optional ignoreActions As UpdateSyncAction = UpdateSyncAction.None) As Task(Of Boolean?)
Dim isSuccessfully As Boolean
Dim modpackInfo As ModpackInfo
If ModpackInfo.HasModpackInfo(localPath) Then
modpackInfo = ModpackInfo.Load(localPath)
Else
modpackInfo = New ModpackInfo
End If
If checkResult.IsLegacy Then
isSuccessfully = Await InstallUpdatesLegacy(checkResult, ignoreActions)
Else
Dim processed As Integer = 0
For Each action As UpdateAction In checkResult.UpdateActions
Dim destFilePath As String = Path.Combine(localPath, action.DestPath)
Select Case action.Type
Case UpdateActionType.Update
Directory.CreateDirectory(Path.GetDirectoryName(destFilePath))
Dim sRemote As Stream = Await httpClient.GetStreamAsync(action.DownloadUrl)
Dim fs As New FileStream(destFilePath, FileMode.Create, FileAccess.ReadWrite)
Await sRemote.CopyToAsync(fs)
sRemote.Close()
fs.Close()
Case UpdateActionType.Delete
If action.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, action.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, action.SrcPath)
If File.Exists(srcFilePath) Then
Directory.CreateDirectory(Path.GetDirectoryName(destFilePath))
File.Move(srcFilePath, destFilePath, True)
End If
End Select
processed += 1
RaiseEvent InstallProgessUpdated(checkResult, processed)
Next
isSuccessfully = True
End If
If isSuccessfully Then
modpackInfo.Version = checkResult.LatestVersion
modpackInfo.Save(localPath)
End If
Return isSuccessfully
End Function
Private Async Function InstallUpdatesLegacy(checkResult As UpdateCheckResult, Optional ignoreActions As UpdateSyncAction = UpdateSyncAction.None) As Task(Of Boolean?)
Dim client As WebDavClient = CreateClient()
Dim success As Boolean? = False
Dim processed As Integer = 0
'Init process update
RaiseEvent InstallProgessUpdated(checkResult, processed)
For Each syncFile In checkResult.SyncFiles
If syncFile.SyncAction <> (ignoreActions And syncFile.SyncAction) Then
If syncFile.SyncAction = UpdateSyncAction.UpdatedFile OrElse
syncFile.SyncAction = UpdateSyncAction.RemovedFile Then
If File.Exists(syncFile.LocalFile) Then
File.Delete(syncFile.LocalFile)
End If
End If
If syncFile.SyncAction = UpdateSyncAction.UpdatedFile OrElse
syncFile.SyncAction = UpdateSyncAction.NewFile Then
Dim response = Await client.GetProcessedFile(syncFile.RemoveFile)
Dim dirParent As New DirectoryInfo(Path.GetDirectoryName(syncFile.LocalFile))
If response.IsSuccessful Then
If Not dirParent.Exists Then
dirParent.Create()
End If
Dim fs As New FileStream(syncFile.LocalFile, FileMode.Create, FileAccess.Write)
response.Stream.CopyTo(fs)
fs.Close()
success = True
End If
End If
End If
processed += 1
RaiseEvent InstallProgessUpdated(checkResult, processed)
Next
Return success
End Function
End Class

View File

@@ -0,0 +1,11 @@
Imports Newtonsoft.Json
Imports Newtonsoft.Json.Converters
<JsonConverter(GetType(StringEnumConverter))>
<Flags>
Public Enum UpdateSyncAction
None
NewFile
RemovedFile
UpdatedFile = 4
End Enum

View File

@@ -0,0 +1,13 @@
Public Class UpdateSyncFile
Public ReadOnly Property SyncAction As UpdateSyncAction
Public ReadOnly Property LocalFile As string
Public ReadOnly Property RemoveFile As string
Public Sub New(syncAction As UpdateSyncAction, localFile As string, remoteFile As string)
Me.SyncAction = syncAction
Me.LocalFile = localFile
Me.RemoveFile = remoteFile
End Sub
End Class