#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