GetNodeSurrogate event handler.

0 votes
asked May 11 by dmitry.petrishin (400 points)

Hello, could you help me with an example of implementing GetNodeSurrogate event handler? I want to implement assignment to the e.ResultNode the value of the root directory. But when I do e.ResultNode = new DirectoryNode("/", null); The project is being frozen and after throws 'Session operation has timed out' in SSH.NET lib.

The main thing what I want to do: I want to process different paths and parse it. Based on the parsed data I will tranfer the stream in SetContentSurrogate event handler to different folders onto remote server. When I try to receive files with the path as /one/two/three/file.csv the client gives an exception Renci.SshNet.Common.SftpPathNotFoundException : Path not found. after GetNodeSurrogate event.

Thanks.

Applies to: Rebex SFTP

1 Answer

+1 vote
answered May 12 by renestein (2,310 points)
selected May 15 by dmitry.petrishin
 
Best answer

I think that this question is just a variation of your previous question ( http://forum.rebex.net/8366/how-to-open-filenode-in-stream-for-further-transition ).

Your implementation of the GetNodeSurrogate event handler leads directly to the realm of the undefined behavior. The DirectoryNode("/", null) is a pseudo-root node in the "detached" state. Detached state means that this node is not associated with any FileSystemProvider and such node is invalid. Exception or surprising behavior are direct consequences when a FileServer tries to use this "fake" node.
GetNodeSurrogate event can be called many times for single request (or path) and it is expected that the behavior of the GetNodeSurrogate is consistent (e. g. returning node with path "/" instead of the node with expected path "one/two/three/" is inconsistent) and unsurprising.
What is worse? GetNodeSurrogate event is not called for root path ("/").
We have GetRootDirectorySurrogate event in our internal API, but we intentionally hide it.

GetNodeSurrogate event is a very low-level event. E. g. GetNodeSurrogate event can be utilized in unit tests for the custom file system provider, because you return mock instead of the resource-hungry real objects, but I have serious doubts that GetNodeSurrogate is useful for your scenario. Surrogate event should be generally used for tweaking the behavior of the existing file system provider, not for heavy random hacking.

Let me summarize your real "business" problem and correct me, please, if I am wrong. Forget the GetNodeSurrogate event for now.

1) You need to save content of the uploaded file on the "remote" server.
2) You are using sftp client and sftp client expects full-fledged file system on "local" server. You have to respond on "get file" request etc.

Please note that I anticipated point 2 and I already wrote about it in my previous answer:

Please be aware that for the SFTP server you should have full-fledged file system (built-in LocalFileSystemProvider/MemoryFileSystemProvider or custom file system provider for the remote server or custom file system provider that combines characteristics of the local and remote file system behavior).

What are your options? I think that you still have the same options (http://forum.rebex.net/8366/how-to-open-filenode-in-stream-for-further-transition) and there is not magical shortcut based on erroneous implementation of the event handlers.

1) LocalFileSystemProvider ( https://www.rebex.net/file-server/features/virtual-file-systems.aspx#local-provider ) with persistent file system structure and file stubs (see my previous comments for pros and cons).

2) MemoryFileSystemProvider ( https://www.rebex.net/file-server/features/virtual-file-systems.aspx#memory-provider ) with transient file system structure and file stubs (see my previous comments for pros and cons).

3) Custom file system provider (sample https://www.rebex.net/sample/file-server-custom-file-system/ ) for special "local sftp server" and "remote content server" relationship.

commented May 12 by dmitry.petrishin (400 points)
Hello, I love you guys for real fast answers! :D Thanks!

1/2). Right, I need to receive file through SFTP and send the stream to the remote server.
I don't need file system at all I guess. If SFTP client wants to get directories I need to return always empty directories.
Furthermore, It's better to send the stream without creating empty file on the server, as it's going now by your suggestion in previous posts.
I think it's not good decision but it's business requirements, though and I need to do that :)

So if I receive the path like /one/two/three/ I need to return on client that this directory is exists and save the empty file in root for further catching of stream in SetContentSurrogate.

I hope it's clear.
Thanks.
commented May 12 by dmitry.petrishin (400 points)
I also thought to parse the path in GetNode or somewhere else and decide the parameters where to send the file.
commented May 12 by renestein (2,310 points)
edited May 12 by renestein
Hi dmitry, thanks for your kind words!

I don't understand.
You wrote:
" It's better to send the stream without creating empty file on the server, as it's going now by your suggestion in previous posts.:

And
"and save the empty file in root for further catching of stream
"
If you use MemoryFileSystemProvider, then *nothing is stored* on local physical file system.

"So if I receive the path like /one/two/three/ I need to return on client that this directory is exists"

You can use Preview events (Exists, GetNode) and build temporary file system structure in MemoryfileSystemProvider on the fly.  You must be very careful, because your event handler must be safe in case of the reentrant call (recursive call of the event handler).

You can implement own file system provider that will build temporary file system structure " on the fly".

Pay attention to the method Exists, GetChild and GetChildren.
http://help.rebex.net/##RebexTotalPack.chm/Html/Methods_T_Rebex_IO_FileSystem_ReadWriteFileSystemProvider.htm
commented May 12 by renestein (2,310 points)
edited May 12 by renestein
"I also thought to parse the path in GetNode or somewhere else and decide the parameters where to send the file."

You can associate custom data with Node.
Property Context
http://help.rebex.net/##RebexTotalPack.chm/Html/Properties_T_Rebex_IO_FileSystem_NodeBase.htm

e. g. in GetContentCompleted handler. I am assuming that method GetNode returns node.
commented May 12 by renestein (2,310 points)
"I don't need file system at all I guess. "
You don't need/want (local) file system, but sftp client assumes that your sftp server uses file system. Period. And really - *file* server without *file* system is contradictio in adiecto, isn't it? ;)
I think that the requirements are little bit convoluted...
commented May 12 by dmitry.petrishin (400 points)
I know, old sftp was written on node.js in one file like bedsheet :D. So it's not only one contradictio , as you said :)

Thanks for answers. I'll try to implement my own file system, then. And I'll be back there if I have some troubles :)
...