0 votes
by (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

3 Answers

0 votes
by (62.7k points)
selected by
 
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();
};
by (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?
by (62.7k 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
by (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?
by (62.7k 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).
by (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
by (1.6k 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.
by (150 points)
Hi Team,
Is it possible to read the stream data directly as soon as chunk of data arrives at the server side?
We don’t want to save the uploaded file on disk. As and when SFTP clients sends a file in chunks, at server side we would like to send the chunk to our backend system.
At present, we use “Server_FileUploaded” to identify the file is uploaded but it will be fired when the file is completely uploaded into server’s hard disk.
by (62.7k points)
Yes, it is possible.
Which type of Virtual system are you using?
Did you write your own File System Provider as I suggested, or did you continue to use event-based API using FileSystemNotifier?
I will send you sample code for your case.
by (150 points)
Hi,
As suggested above, we are planning to use "DriveFileSystemProvider".
Can you send a sample code?
0 votes
by (150 points)
Hi,
We are okay with either event-based or custom File System Provider. Our requirement is as follows..
1) Read file chunks from the socket.
2) We need metadata related to the chunk like (chunk offset, chunk request-id/file info, identify the user details).

Please let us know which approach will suite to the above requirement?
0 votes
by (62.7k points)
edited by

The suggested way is to write your custom provider - similar to mentioned "DriveFileSystemProvider".

The content requested by the SFTP client is handled using the GetContent() method.
To transfer data directly to your backed (without storing it at the server), you need to use the NodeContent.CreateImmediateWriteContent(yourStream) method.
Then Read() and Write() methods are callend on the given yourStream instance depending whether the SFTP client is performing download or upload.

I have prepared "academic" sample of such functionality. Please download the modified sample.

The TcpFileSystemProvider.GetContent() shows how uploaded/downloaded data can be provided on-the-fly from your backend system using standard NetworkStream.

In your case, replace NetworkStream with your own stream with desired functionality ('chunk offset').
The 'chunk request-id/file info' can be identified by node.Path - the parameter of the GetContent() method.
To identify 'user details', you can use ServerSession.Current.

The modified sample also contains the Backend project, which is very simple application, which provides data for the presented TcpFileSystemProvider.

The modified sample works like this:
- The server has access to "c:/data/PC1", which contains only empty files.
- The Backend app has access to "c:/data/PC2", which contains data of the files.
- When a SFTP client requests download/upload of a file, the server requests data from Backend app using very simple protocol over TCP/IP.

...