#Region "Microsoft.VisualBasic::3447da10c11a58d70bb9d90fa11002d8, ossutil\FileSystem.vb"
' Author:
'
' asuka (amethyst.asuka@gcmodeller.org)
' xie (genetics@smrucc.org)
' xieguigang (xie.guigang@live.com)
'
' Copyright (c) 2018 GPL3 Licensed
'
'
' GNU GENERAL PUBLIC LICENSE (GPL3)
'
'
' This program is free software: you can redistribute it and/or modify
' it under the terms of the GNU General Public License as published by
' the Free Software Foundation, either version 3 of the License, or
' (at your option) any later version.
'
' This program is distributed in the hope that it will be useful,
' but WITHOUT ANY WARRANTY; without even the implied warranty of
' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
' GNU General Public License for more details.
'
' You should have received a copy of the GNU General Public License
' along with this program. If not, see .
' /********************************************************************************/
' Summaries:
' Class FileSystem
'
' Properties: Bucket, CurrentDirectory, Objects
'
' Constructor: (+3 Overloads) Sub New
'
' Function: [Get], ChangeDirectory, FilesTree, GetContext, GetTarget
' ToString
'
' Sub: Put
'
' /********************************************************************************/
#End Region
Imports System.Runtime.CompilerServices
Imports Microsoft.VisualBasic.Data.GraphTheory
Imports Microsoft.VisualBasic.Language
Imports Microsoft.VisualBasic.Language.Default
Imports ThinkVB.FileSystem.OSS.Model
'''
''' 对阿里云OSS文件系统进行抽象的线程不安全的OSS文件系统对象
'''
Public Class FileSystem
'''
''' OSS cloud file system I/O driver
'''
Dim driver As CLI
'''
''' The tree graph of the
'''
Dim tree As Tree(Of [Object])
'''
''' 在oss文件系统之中的当前的路径
'''
'''
Public ReadOnly Property CurrentDirectory As [Object]
Get
Return tree.Data
End Get
End Property
'''
''' File system root entry/device entry
'''
'''
Public ReadOnly Property Bucket As Bucket
'''
''' Jump points
'''
'''
Public ReadOnly Property Objects As [Object]()
'''
'''
'''
''' Bucket name
''' The root directory
''' ossutil cli tool model
Sub New(bucket$, directory$, driver As CLI)
Me.driver = driver
Me.Bucket = driver.GetBucketStorageDeviceList _
.Where(Function(b)
Return b.BucketName.TextEquals(bucket)
End Function) _
.FirstOrDefault
If Me.Bucket Is Nothing Then
Throw New InvalidExpressionException($"Bucket name `{bucket}` is invalid or invalid ossfs credential info!")
Else
Objects = driver _
.ListObjects(Me.Bucket.URI(directory)) _
.ToArray
tree = FilesTree(Objects, Me.Bucket.BucketName)
End If
End Sub
'''
''' 测试用
'''
'''
'''
'''
Sub New(bucket As Bucket, objects As [Object](), driver As CLI)
Me.driver = driver
Me.Bucket = bucket
Me.Objects = objects
tree = FilesTree(objects, bucket.BucketName)
End Sub
'''
''' Clone
'''
'''
'''
'''
Sub New(bucket As Bucket, objects As [Object](), tree As Tree(Of [Object]), driver As CLI)
Me.Bucket = bucket
Me.Objects = objects
Me.driver = driver
Me.tree = tree
End Sub
Private Shared Function FilesTree(objects As [Object](), bucketName$) As Tree(Of [Object])
Dim tokenTuples = objects.Select(Function(obj)
Dim path$() = obj.ObjectName _
.Split("/"c) _
.Skip(3) _
.ToArray
Return (path:=path, [Object]:=obj)
End Function) _
.OrderBy(Function(obj) obj.path.Length) _
.ToArray
Dim node As Tree(Of [Object])
Dim key$
Dim root As New Tree(Of [Object])("/") With {
.Label = $"oss://{bucketName}",
.Childs = New Dictionary(Of String, Tree(Of [Object])),
.Data = New [Object] With {
.meta = New Dictionary(Of String, String) From {
{NameOf([Object].ObjectName), "/"}
}
}
}
For Each obj As (path As String(), obj As [Object]) In tokenTuples
node = root
With obj.path
For i As Integer = 0 To .Length - 1
key = .ByRef(i)
If key.StringEmpty AndAlso i = .Length - 1 AndAlso obj.obj.IsDirectory Then
node.Data = obj.obj
Else
If Not node.Childs.ContainsKey(key) Then
Dim newNode As New Tree(Of [Object])("/") With {
.Label = key,
.Childs = New Dictionary(Of String, Tree(Of [Object])),
.Parent = node
}
If i = .Length - 1 Then
' 这是一个新的文件节点
newNode.Data = obj.obj
End If
node.Childs.Add(key, newNode)
End If
node = node.Childs(key)
End If
Next
End With
Next
Return root
End Function
'''
'''
'''
'''
''' 相对路径或者绝对路径
'''
'''
'''
''' 所有使用``/``起始的都是绝对路径
'''
'''
Public Function ChangeDirectory(directory As String) As FileSystem
Return New FileSystem(Bucket, Objects, GetTarget(path:=directory), driver)
End Function
Private Function GetTarget(path As String) As Tree(Of [Object])
' context已经是一个经过归一化处理的完整路径了
Dim context$() = GetContext(tree.Data, path)
' 绝对路径从root开始访问
Return tree.BacktrackingRoot.VisitTree(context)
End Function
Private Shared Function GetContext(current As [Object], path$) As String()
Dim context As List(Of String)
path = path _
.Replace("\", "/") _
.StringReplace("[/]{2,}", "/")
If path.First = "/"c Then
' 绝对路径
' 不进行任何处理??
context = New List(Of String)
Else
' 需要将相对路径转换为绝对路径
context = current.ObjectName _
.SplitPath _
.Skip(2) _
.AsList
End If
For Each name As String In path.SplitPath
If name = "." Then
' 不进行任何处理
ElseIf name = ".." Then
' 访问父目录
context.Pop()
Else
context += name
End If
Next
Return context
End Function
ReadOnly populateTempFile As Func(Of String) =
Function() As String
Return App.GetAppSysTempFile(".tmp", App.PID)
End Function
ReadOnly tempFile As New DefaultValue(Of String) With {
.LazyValue = New Lazy(Of String)(populateTempFile)
}
'''
''' Get file from OSS
'''
''' 远程对象的相对路径或者绝对路径,要求这个远程对象必须要存在
'''
'''
Public Function [Get](path$, Optional save$ = Nothing) As String
Dim target As Tree(Of [Object]) = GetTarget(path)
With save Or tempFile
driver.Copy(from:=target.QualifyName, [to]:= .ByRef)
' returns normalized local filesystem full path
path = .GetFullPath
End With
Return path
End Function
'''
'''
'''
'''
''' 不要求远程对象必须要存在
Public Sub Put(local$, remote$)
Dim context = GetContext(path:=remote, current:=CurrentDirectory)
remote = context.JoinBy("/")
remote = Bucket.URI(remote)
driver.Copy(from:=local, [to]:=remote)
End Sub
Public Overrides Function ToString() As String
Return CurrentDirectory.ToString
End Function
End Class