Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ftp self connect mode #1704

Closed
wants to merge 11 commits into from

Conversation

FanDjango
Copy link
Collaborator

@FanDjango FanDjango commented Jan 8, 2025

Referring to #683 (long read but important)

#683 reported that accessing certain properties (specifically Capabilities and Hash Algorithms) when the (async)client is not connected would cause a cross-Async->Sync call to (sync)Connect(). That analysis was correct (at that time).

This was a result of extensive code changes and additions in the async client.

The (rather quick) fix was to remove any call to connect() in the property getters.

Later on in the history of development, reconnects due to stale data and just generally allowing API calls without a preceeding connect led to a certain confusion about which APIs are needing a connect in the first place (or not).

#1698 Reported the errors that can occur when accessing properties without a prior connect.

Addressing these was a bit involved.

This PR brings back the premature removal of connect() calls in certain property getters and introduces a config setting to steer the availability of "automatic" (re-)connects. It overcomes the danger of a cross-Async->Sync call to (sync)Connect(), which was the original problem identified by #683, not by a quick fix of just removing the connect calls but rather coding them in such a way that correct functionality is guaranteed.

The new config setting:

		/// <summary>
		/// Configure the behaviour of the Self Connect feature for the control connection
		/// Always (default): If the control connection is needed to process an API process (either for entering commands to the server
		/// or to retrieve information about the server (FEAT capabilities, HASH algorithms, Current Working directory) it will be (re-)
		/// connected if not available.
		/// OnConnectionLost: As with "Always", BUT only if there had been a connection in the first place before it got lost.
		/// Never: Connections will not be made unless you explicitly call Connect(...) yourself. If a connection is needed and not
		/// established, your API processes will fail instead of attempting to (re-)connect.
		/// </summary>
		public FtpSelfConnectMode SelfConnectMode { get; set; } = FtpSelfConnectMode.Always;

The new config enum for client.Config.SelfConnectMode is the following and it keeps things ASIS as the default is "Always":

	public enum FtpSelfConnectMode {

		/// <summary>
		/// Always (default): If the control connection is needed to process an API process (either for entering commands to the server
		/// or to retrieve information about the server (FEAT capabilities, HASH algorithms, Current Working directory) it will be (re-)
		/// connected if not available.
		/// </summary>
		Always,

		/// <summary>
		/// OnConnectionLost: As with "Always", BUT only if there had been a connection in the first place before it got lost.
		/// </summary>
		OnConnectionLost,

		/// <summary>
		/// Never: Connections will not be made unless you explicitly call Connect(...) yourself. If a connection is needed and not
		/// established, your API processes will fail instead of attempting to (re-)connect.
		/// </summary>
		Never,
	}

As a second stage in the future, it will be necessary to migrate the two property getters, Capabilites and Hash Algorithms to be
methods instead of properties. Such a migration is also pending (as a further example) for the IsConnected property of the FTPSocketStream.

Such getters are not really supposed to invoke complex operations, although there is no formal rule against this. In all three cases (FtpSocketStream.IsConnected, client.Capabilites, client.HashAlgorithms) converting these to methods is quite involved).

@robinrodricks
Copy link
Owner

robinrodricks commented Jan 19, 2025

Yes absolutely. In principle you are right. I hated that "automatically connect on using an API" functionality from day 1, but it was inherited from the original code base (read: 10 years old).

I could never understand - if I want to perform an FTP operation, why should the client "auto connect" on its own? ("self connect" in your terminology.)

I am ok removing this self connect completely. If not connected we can throw an error saying ("You are not connected to the FTP Server! Please call client.Connect() before using this API!").

It will be a major version increment. But I would rather users connect intentionally and not a side effect of reading props or using any other API.

"Self Connect" sounds strange but is ok since "Auto Connect" means something else in our library. I like your enum. It fits with our design principles. If you needed approval, you have it. If this is to discuss, then I am in full agreement.

@FanDjango
Copy link
Collaborator Author

FanDjango commented Jan 20, 2025

Thanks @robinrodricks.

That leaves us to make a decision:

  1. Remove all implicit Connect(...)s alltogether, but keeping the one that **re-**connects on reaching the SSL transaction limit or spurious stale data on the connection (that one is inside Execute(...).
  2. Use the new PR's code but decide on which default behaviour would be the best.

Let's gently nudge people to need a connection before APIs are allowed (where applicable) and make the default be OnConnectionLost instead of Always.

The Never behaviour would literally turn off any re-connects on reaching the SSL transaction limit or spurious stale data on the connection and quite a few users would suddenly have processes that unexpectedly fail.

Those who would like complete absolute control of the protocol states would set "Never".

@FanDjango FanDjango closed this Jan 20, 2025
@FanDjango FanDjango deleted the FtpSelfConnectMode branch January 20, 2025 11:46
@robinrodricks
Copy link
Owner

Make the default OnConnectionLost instead of Always.

Yes, this sounds good.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants