Need to create a virtual file system based on data from backend

0 votes
asked Jan 12 by srikar (150 points)

Hi Team,
I need to create a virtual folder/file hierarchy based on JSON data from the backend. I also need to implement custom authentication; I have implemented custom authentication logic in the below event.

          var server = new FileServer();
        server.LogWriter = new ConsoleLogWriter(LogLevel.Debug);
        server.Bind(22, FileServerProtocol.Sftp);
        server.Keys.Add(new SshPrivateKey(@"C:\SFTPRebex\sftpppk.ppk"));
        server.PathAccessAuthorization += Server_PathAccessAuthorization;
        server.Authentication += Server_Authentication;

After authentication, subscribe to file system notifier to represent virtual directory/file structure as follows..

              string virtualRoot = @"D:\SFTPRebex\Test"; // a dummy directory.
        var localFS = new LocalFileSystemProvider(@"D:\SFTPRebex\Test", FileSystemType.ReadWrite);

        FileSystemNotifier notifier = localFS.GetFileSystemNotifier();
        notifier.GetAttributesCompleted += Notifier_GetAttributesCompleted;
        notifier.GetChildrenPreview += Notifier_GetChildrenPreview;
        notifier.GetChildrenSurrogate += Notifier_GetChildrenSurrogate;

In GetChildrenSurrogate event, created virtual structure as follows.

         private static void Notifier_GetChildrenSurrogate(object sender, GetChildrenEventArgs e)
    {
        // throw new NotImplementedException();
        List<NodeBase> basenode = new List<NodeBase>();
        NodeTimeInfo nodeTimeInfo = new NodeTimeInfo(DateTime.Now, DateTime.Now, DateTime.Now);
        var fileAttribute = new System.IO.FileAttributes();
        NodeAttributes nodeAttributes = new NodeAttributes(fileAttribute);
        NodeBase nodeBase = new DirectoryNode("VirtualDirectory", (DirectoryNode)e.Node, nodeTimeInfo, new NodeAttributes(fileAttribute));
        FileNode fileNode = new FileNode("VirtualFile.txt", (DirectoryNode)e.Node, nodeTimeInfo, nodeAttributes);

        basenode.Add(nodeBase);
        basenode.Add(fileNode);
        e.ResultChildren = basenode;
    }

The above structure worked and I can see the folder (“VirtualDirectory”) & file (“VirtualFile.txt”) in the SFTP Client.
which event will be triggered at server side when the client tries to download the file? I need to send the file stream to the client.

Which event will be triggered at server side when the client clicks on the directory? I need to represent file & directories inside the folder.

Thanks,
Srikar.

Applies to: Rebex SFTP

1 Answer

0 votes
answered Jan 12 by Lukas Matyska (61,230 points)
selected Jan 12 by srikar
 
Best answer

To implement your own Virtual File System, I suggest you to implement your own custom File System Provider. You can find inspiration at FileServerCustomFS sample, which contains two custom File System Providers.


If you still rather prefer event based API, you need to rewrite also:

  • GetNodeSurrogate - to resolve your custom nodes.
  • GetContentSurrogate - to provide your custom file content.
  • GetLengthSurrogate - to display correct content length.

Please note that items assigned in the GetChildrenSurrogate are not stored anywhere. If you want to keep them and use them later, you have to do it on our own.

The sample implementation using notifier can look like this:

private class MyDirectory : DirectoryNode
{
    public IEnumerable<NodeBase> Children { get; set; }

    public MyDirectory(string nodeName, DirectoryNode parent, NodeTimeInfo nodeTimeInfo = null, NodeAttributes attributes = null) : base(nodeName, parent, nodeTimeInfo, attributes)
    {
    }
}

private class MyFile : FileNode
{
    public MyFile(string nodeName, DirectoryNode parent, NodeTimeInfo nodeTimeInfo = null, NodeAttributes attributes = null) : base(nodeName, parent, nodeTimeInfo, attributes)
    {
    }

    public long GetLength()
    {
        return this.Path.StringPath.Length;
    }

    public NodeContent GetReadContent()
    {
        // generate file content on-the-fly or read it from DB
        var ms = new MemoryStream(Encoding.ASCII.GetBytes(this.Path.ToString()));
        return NodeContent.CreateReadOnlyContent(ms);

        // or open associated file on disk
        return NodeContent.CreateReadOnlyContent(File.OpenRead("..." + this.Path));
    }
}

private static IEnumerable<NodeBase> GenerateChildren(DirectoryNode parent, Dictionary<string, NodeBase> nodes)
{
    // generate some children for this node
    var d = new MyDirectory("level-" + parent.Path.PathPartsCount, parent);
    var f = new MyFile("level-" + parent.Path.PathPartsCount + ".txt", parent);

    // add them to global list
    nodes[d.Path.StringPath] = d;
    nodes[f.Path.StringPath] = f;

    // return as collection
    var children = new List<NodeBase>();
    children.Add(d);
    children.Add(f);
    return children;
}

...

var nodes = new Dictionary<string, NodeBase>(StringComparer.OrdinalIgnoreCase);

var vfs = new MountCapableFileSystemProvider();
var notifier = vfs.GetFileSystemNotifier();

notifier.GetChildrenSurrogate += (s, e) =>
{
    if (e.Node.IsRootDirectory)
    {
        if (e.Node.Context == null)
            e.Node.Context = GenerateChildren(e.Node as DirectoryNode, nodes);
        e.ResultChildren = e.Node.Context as IEnumerable<NodeBase>;
        return;
    }

    var mydir = e.Node as MyDirectory;
    if (mydir == null)
        return;

    if (mydir.Children == null)
        mydir.Children = GenerateChildren(mydir, nodes);

    e.ResultChildren = mydir.Children;
};

notifier.GetNodeSurrogate += (s, e) =>
{
    NodeBase node;
    if (nodes.TryGetValue(e.Path.StringPath, out node))
        e.ResultNode = node;
};

notifier.GetContentSurrogate += (s, e) =>
{
    var myfile = e.Node as MyFile;
    if (myfile == null)
        return;

    e.ResultContent = myfile.GetReadContent();
};

notifier.GetLengthSurrogate += (s, e) =>
{
    var myfile = e.Node as MyFile;
    if (myfile == null)
        return;

    e.ResultLength = myfile.GetLength();
};
commented Jan 12 by srikar (150 points)
Thank you for your quick response. I could not find any source code for the FileServerCustomFS sample. Can you please give me a link to download the source code?
commented 6 days ago by Lukas Matyska (61,230 points)
There is "DOWNLOAD" button on the right at the mentioned site https://www.rebex.net/sample/file-server-custom-file-system

Direct link to installation package, which includes samples for all  available platforms is https://www.rebex.net/download/file/RebexFileServer-R6.1-Trial.exe

For your comfort, I have extracted the sample source code for net-4.0 form the installation package. You can download it directly from https://www.rebex.net/getfile/4a6b3b7d65254bb2af690516944112db/FileServerCustomFS_CS.zip
commented 6 days ago by srikar (150 points)
Thank you. Is there any way to identify the number of active connections?
Ex: Let us say the client start downloading a file ~10GB. and it takes 15min to download the file. Within the 15min time, is there an event that indicates that there is 1 active connection?
commented 6 days ago by Lukas Matyska (61,230 points)
You can identify active connections using the FileServer's Authentication and Disconnected events.

If you want to identify active transfers, you can:
1. Either use FileServer's PathAccessAuthorization and FileUploaded/FileDownloaded events.
2. Or if you are working with NodeContent instances, you can simply detect when an instance of the NodeContent is created and when the associated stream is closed (this would typically require a stream wrapper).
commented 6 days ago by srikar (150 points)
Okay. What is the enterprise license cost?  
https://www.rebex.net/sftp.net/purchase.aspx, The link talk about per developer not for enterprise
commented 6 days ago by Frantisek Bosek (1,620 points)
Hi,

yes, Rebex components are licensed on a per-developer basis.
Enterprise licenses, i.e. licenses for many developers are not a part of our standard pricelist and are available under special agreements.
Please contact support@rebex.net and we will strive to prepare you an offer according your needs.
...