zio / zio-ftp Goto Github PK
View Code? Open in Web Editor NEWA simple, idiomatic (S)FTP client for ZIO
Home Page: https://zio.dev/zio-ftp
License: Apache License 2.0
A simple, idiomatic (S)FTP client for ZIO
Home Page: https://zio.dev/zio-ftp
License: Apache License 2.0
current download is not using the full capacity of the connection. Since FTP dont provide multi connection/channel for a single file, we cannot download at full speed.
We can replicate this Segmented download file, by opening multi connection and only read a part of the file by offset. Some tools already provide this ability like cyberduck (macOs FTP client)
Hi @jdegoes, @regis-leray, I tried to contribute by adding the command rename
for ftp and sftp client, but i'm not able to run the tests on my mac since I don't have any ftp / sftp server on it (maybe Im missing a step ?).
So I have open this pull-request (#232) to run the CI of the project with at least one test, but the checks are stuck at the license/cla
step, even if I've signed it.
Can you help me with it please ?
Thanks
Use same approach as https://github.com/zio/zio-optics/tree/master/.github
sshj
use slf4j-api and commons-net FtpClient
doesnt seems to use any logging framework
Scaladoc for all traits, classes, and methods
Hey all!
While using the zio-ftp I've recently faced an issue, when connection to a remote FTP failed with the FTP client error Host attempting data connection 1.2.3.4 is not same as server 5.6.7.8
. I assume it is related to the fact that the remote FTP is actually load balanced, as the stackoverflow post describes.
Would it be a good idea to enable a config to disable remote verification on FTP client via setRemoteVerificationEnabled
when creating it?
Best,
Ilia
While trying to figure out why my downloads weren't working, i traced through the code until I found the call to FTPClient.retrieveFileStream
, and saw that the javadocs say
To finalize the file transfer you must call
{@link #completePendingCommand completePendingCommand } and
check its return value to verify success.
I'm not sure of the best way to fix this, as I'm not a ZIO expert, perhaps there's a way to add a cleanup to a stream that only runs if the stream started? Or some way to do it with ZManaged?
In my code I did something like this
private def closeXfer[E, A](ftp: FtpAccessors[Client])(res: Either[E, A]) =
ftp.execute(_.completePendingCommand()).flatMap {
case false if res.isRight => ZIO.fail(new IOException("File transfer failed"))
case _ => ZIO.unit
}
...
ftp.readFile(path).run(sink).tapEither(closeXfer(ftp))
which consumes the stream and fails the ZIO if it had succeeded but completePendingCommand returns false
haven't done enough research on this yet to know exactly why/when it happens or how to fix it. But I saw an instance where i rebooted my router and a couple of downloads that were starting returned this error. There are many reasons why FTPClient can return null from retrieveFileStream, and not all of them indicate that it's an invalid path... but the library reports them all as that error.
in my case the server returns some messed up filenames when listing directories but then fails when trying to retrieve them (problem with their server software) so in the InvalidPathError case i give up on the file instead of retrying it later. but for these failures when it was beginning the downloads right when my machine lost internet, that error probably shouldn't have been returned because the server did retrieve them when i manually retried later.
anyway, I'll try at some point to track down some way of distinguishing the reason for the null response, but wanted to be sure to open an issue for posterity
On ZIO 1
Svedi export exited with failure* : Traced(Die(net.schmizz.sshj.sftp.SFTPException: EOF while reading packet),ZTrace(Id(1656419394410,4343),List(SourceLocation(ZManaged.scala,zio.ZManaged$,fromAutoCloseable,1876), SourceLocation(ZIO.scala,zio.ZIO$,effectSuspendTotal,2837), SourceLocation(ZIO.scala,zio.ZIO,bracket_,291), SourceLocation(FiberContext.scala,zio.internal.FiberContext,evaluateNow,559), SourceLocation(ZIO.scala,zio.ZIO,zipWith,2294), SourceLocation(ZIO.scala,zio.ZIO$,foreach,3028), SourceLocation(ZIO.scala,zio.ZIO,flatten,700), SourceLocation(ZRef.scala,zio.ZRef$Atomic,modify,215), SourceLocation(ZIO.scala,zio.ZIO$,effectSuspendTotal,2837), SourceLocation(ZManaged.scala,zio.ZManaged,use,1088), SourceLocation(ZIO.scala,zio.ZIO,run,1764), SourceLocation(FiberContext.scala,zio.internal.FiberContext$InterruptExit$,apply,153), SourceLocation(FiberContext.scala,zio.internal.FiberContext$InterruptExit$,apply,160), SourceLocation(FiberContext.scala,zio.internal.FiberContext$InterruptExit$,apply,153), SourceLocation(ZIO.scala,zio.ZIO$,effectSuspendTotal,2837), SourceLocation(ZIO.scala,zio.ZIO$,bracketExit,2437), SourceLocation(ZIO.scala,zio.ZIO$,effectSuspendTotal,2837), SourceLocation(ZManaged.scala,zio.ZManaged$ReleaseMap$$anon$1,releaseAll,1410), SourceLocation(ZIO.scala,zio.ZIO$,foreach,3030), SourceLocation(ZIO.scala,zio.ZIO$,foreach,3029), SourceLocation(ZIO.scala,zio.ZIO,run,1764), SourceLocation(FiberContext.scala,zio.internal.FiberContext$InterruptExit$,apply,160), SourceLocation(FiberContext.scala,zio.internal.FiberContext$InterruptExit$,apply,153), SourceLocation(ZIO.scala,zio.ZIO$,effectSuspendTotal,2837), SourceLocation(ZIO.scala,zio.ZIO$,bracketExit,2437), SourceLocation(FiberContext.scala,zio.internal.FiberContext,evaluateNow,563), SourceLocation(ZIO.scala,zio.ZIO$,effectSuspendTotal,2837), SourceLocation(ZIO.scala,zio.ZIO,bracket_,291), SourceLocation(ZIO.scala,zio.ZIO,run,1764), SourceLocation(FiberContext.scala,zio.internal.FiberContext$InterruptExit$,apply,160), SourceLocation(FiberContext.scala,zio.internal.FiberContext$InterruptExit$,apply,153), SourceLocation(ZManaged.scala,zio.ZManaged$,finalizerRef,1689), SourceLocation(ZRef.scala,zio.ZRef$Atomic,get,203), SourceLocation(ZIO.scala,zio.ZIO$,effectSuspendTotal,2837), SourceLocation(ZIO.scala,zio.ZIO,bracket_,291), SourceLocation(FiberContext.scala,zio.internal.FiberContext,evaluateNow,559), SourceLocation(ZIO.scala,zio.ZIO,zipWith,2294), SourceLocation(ZIO.scala,zio.ZIO$,foreach,3028), SourceLocation(ZIO.scala,zio.ZIO,flatten,700), SourceLocation(ZRef.scala,zio.ZRef$Atomic,modify,215), SourceLocation(ZIO.scala,zio.ZIO$,effectSuspendTotal,2837), SourceLocation(ZManaged.scala,zio.ZManaged,use,1088), SourceLocation(ZIO.scala,zio.ZIO,run,1764), SourceLocation(FiberContext.scala,zio.internal.FiberContext$InterruptExit$,apply,153), SourceLocation(ZManaged.scala,zio.ZManaged,use,1089), SourceLocation(FiberContext.scala,zio.internal.FiberContext$InterruptExit$,apply,160), SourceLocation(FiberContext.scala,zio.internal.FiberContext$InterruptExit$,apply,153), SourceLocation(ZIO.scala,zio.ZIO$,effectSuspendTotal,2837), SourceLocation(ZIO.scala,zio.ZIO$,bracketExit,2437), SourceLocation(FiberContext.scala,zio.internal.FiberContext,evaluateNow,563), SourceLocation(ZIO.scala,zio.ZIO$,effectSuspendTotal,2837), SourceLocation(ZIO.scala,zio.ZIO,bracket_,291), SourceLocation(ZIO.scala,zio.ZIO,run,1764), SourceLocation(FiberContext.scala,zio.internal.FiberContext$InterruptExit$,apply,153), SourceLocation(FiberContext.scala,zio.internal.FiberContext$InterruptExit$,apply,160), SourceLocation(FiberContext.scala,zio.internal.FiberContext$InterruptExit$,apply,153), SourceLocation(ZIO.scala,zio.ZIO$,effectSuspendTotal,2837), SourceLocation(ZIO.scala,zio.ZIO$,bracketExit,2437), SourceLocation(FiberContext.scala,zio.internal.FiberContext,evaluateNow,563), SourceLocation(ZIO.scala,zio.ZIO$,effectSuspendTotal,2837), SourceLocation(ZIO.scala,zio.ZIO,bracket_,291), SourceLocation(ZIO.scala,zio.ZIO,run,1764), SourceLocation(FiberContext.scala,zio.internal.FiberContext$InterruptExit$,apply,153), SourceLocation(ZManaged.scala,zio.ZManaged,mapM,517), SourceLocation(ZStream.scala,zio.stream.ZStream,runManaged,2653), SourceLocation(ZSink.scala,zio.stream.ZSink,dropLeftover,505), SourceLocation(ZSink.scala,zio.stream.ZSink$,foldChunksM,712), SourceLocation(ZRef.scala,zio.ZRef$Atomic,get,203), SourceLocation(ZStream.scala,zio.stream.ZStream,runManaged,2649), SourceLocation(ZIO.scala,zio.ZIO,flatten,700), SourceLocation(ZRef.scala,zio.ZRef$Atomic,modify,215), SourceLocation(ZIO.scala,zio.ZIO,flatten,700), SourceLocation(ZRef.scala,zio.ZRef$Atomic,modify,215), SourceLocation(ZStream.scala,zio.stream.ZStream,flatMap,1424), SourceLocation(ZIO.scala,zio.ZIO$,effectSuspendTotal,2837), SourceLocation(ZManaged.scala,zio.ZManaged$ReleaseMap$$anon$1,releaseAll,1410), SourceLocation(ZIO.scala,zio.ZIO$,foreach,3030), SourceLocation(ZIO.scala,zio.ZIO$,foreach,3029), SourceLocation(ZIO.scala,zio.ZIO,run,1764), SourceLocation(FiberContext.scala,zio.internal.FiberContext$InterruptExit$,apply,160), SourceLocation(FiberContext.scala,zio.internal.FiberContext$InterruptExit$,apply,153), SourceLocation(ZIO.scala,zio.ZIO$,effectSuspendTotal,2837), SourceLocation(ZIO.scala,zio.ZIO$,bracketExit,2437), SourceLocation(FiberContext.scala,zio.internal.FiberContext,evaluateNow,563), SourceLocation(ZIO.scala,zio.ZIO$,effectSuspendTotal,2837), SourceLocation(ZIO.scala,zio.ZIO,bracket_,291), SourceLocation(ZIO.scala,zio.ZIO,run,1764), SourceLocation(FiberContext.scala,zio.internal.FiberContext$InterruptExit$,apply,153), SourceLocation(ZManaged.scala,zio.ZManaged$,finalizerRef,1689), SourceLocation(ZRef.scala,zio.ZRef$Atomic,get,203), SourceLocation(ZIO.scala,zio.ZIO$,effectSuspendTotal,2837), SourceLocation(ZIO.scala,zio.ZIO,bracket_,291), SourceLocation(FiberContext.scala,zio.internal.FiberContext,evaluateNow,559), SourceLocation(ZIO.scala,zio.ZIO,zipWith,2294), SourceLocation(ZIO.scala,zio.ZIO$,foreach,3028), SourceLocation(ZIO.scala,zio.ZIO,flatten,700), SourceLocation(ZRef.scala,zio.ZRef$Atomic,modify,215), SourceLocation(ZStream.scala,zio.stream.ZStream,flatMap,1394), SourceLocation(ZRef.scala,zio.ZRef$Atomic,getAndSet,206), SourceLocation(ZStream.scala,zio.stream.ZStream,flatMap,1418)),List(SourceLocation(ZIO.scala,zio.ZIO,run,1764), SourceLocation(ZIO.scala,zio.ZIO,bracket_,291), SourceLocation(ZIO.scala,zio.ZIO,run,1764), SourceLocation(ZIO.scala,zio.ZIO$,foreach,3029), SourceLocation(ZIO.scala,zio.ZIO$,foreach,3030), SourceLocation(ZManaged.scala,zio.ZManaged$ReleaseMap$$anon$1,releaseAll,1410), SourceLocation(ZIO.scala,zio.ZIO$,bracketExit,2437), SourceLocation(SecureFtp.scala,zio.ftp.SecureFtp,upload,109), SourceLocation(SecureFtp.scala,zio.ftp.SecureFtp,upload,109), SourceLocation(SvediExporter.scala,io.dhlparcel.inventory.tasks.SvediExporter$,action,58), SourceLocation(SvediExporter.scala,io.dhlparcel.inventory.tasks.SvediExporter$,doExport,73), SourceLocation(ZIO.scala,zio.ZIO,run,1764), SourceLocation(ZIO.scala,zio.ZIO,bracket_,291), SourceLocation(ZIO.scala,zio.ZIO,run,1764), SourceLocation(ZManaged.scala,zio.ZManaged,use,1088), SourceLocation(ZIO.scala,zio.ZIO,retryOrElseEither,1704), SourceLocation(ZIO.scala,zio.ZIO,retryOrElseEither,1706), SourceLocation(ZIO.scala,zio.ZIO,retryOrElse,1690)),Some(ZTrace(Id(1656419394277,4336),List(SourceLocation(ServerInterpreter.scala,sttp.tapir.server.interpreter.ServerInterpreter$ResultOrValue,flatMap,230), SourceLocation(ServerInterpreter.scala,sttp.tapir.server.interpreter.ServerInterpreter$ResultOrValue,flatMap,230), SourceLocation(ServerInterpreter.scala,sttp.tapir.server.interpreter.ServerInterpreter$ResultOrValueFrom,apply,248), SourceLocation(ServerInterpreter.scala,sttp.tapir.server.interpreter.ServerInterpreter$ResultOrValue,flatMap,230), SourceLocation(ServerInterpreter.scala,sttp.tapir.server.interpreter.ServerInterpreter$$anonfun$$nestedInanonfun$tryServerEndpoint$6$1,apply,64), SourceLocation(ServerInterpreter.scala,sttp.tapir.server.interpreter.ServerInterpreter,tryServerEndpoint,108), SourceLocation(ServerInterpreter.scala,sttp.tapir.server.interpreter.ServerInterpreter$ResultOrValue,flatMap,230), SourceLocation(ServerInterpreter.scala,sttp.tapir.server.interpreter.ServerInterpreter$ResultOrValue,map,236), SourceLocation(ServerInterpreter.scala,sttp.tapir.server.interpreter.ServerInterpreter$ResultOrValue,flatMap,230), SourceLocation(ServerInterpreter.scala,sttp.tapir.server.interpreter.ServerInterpreter$ResultOrValue,flatMap,230)),List(SourceLocation(InternalRoutes.scala,io.dhlparcel.inventory.api.routes.InternalRoutes$,exportSVEDIRoute,45), SourceLocation(ZIO.scala,zio.ZIO$,zio$ZIO$$_succeedRight,4495), SourceLocation(ZIO.scala,zio.ZIO,unrefineWith,2183), SourceLocation(ServerInterpreter.scala,sttp.tapir.server.interpreter.ServerInterpreter$$anon$2,onDecodeSuccess,195), SourceLocation(ServerLogInterceptor.scala,sttp.tapir.server.interceptor.log.ServerLogInterceptor$$anon$1,onDecodeSuccess,19), SourceLocation(ServerLogInterceptor.scala,sttp.tapir.server.interceptor.log.ServerLogInterceptor$$anon$1$$anonfun$onDecodeSuccess$6,apply,12), SourceLocation(ExceptionInterceptor.scala,sttp.tapir.server.interceptor.exception.ExceptionInterceptor$$anon$1$$anonfun$onDecodeSuccess$2,apply,16), SourceLocation(ServerInterpreter.scala,sttp.tapir.server.interpreter.ServerInterpreter,tryServerEndpoint,130), SourceLocation(ServerInterpreter.scala,sttp.tapir.server.interpreter.ServerInterpreter$ResultOrValueFrom,value,265), SourceLocation(ServerInterpreter.scala,sttp.tapir.server.interpreter.ServerInterpreter$ResultOrValue,map,236)),Some(ZTrace(Id(1656419394277,4335),List(),List(SourceLocation(GenSpawn.scala,cats.effect.kernel.GenSpawn,race,321), SourceLocation(Http1ServerStage.scala,org.http4s.blaze.server.Http1ServerStage,raceTimeout,391), SourceLocation(http4s.scala,io.dhlparcel.seed.http4s.package$Http4s$$anon$1$$anonfun$apply$1,apply,96), SourceLocation(Http1ServerStage.scala,org.http4s.blaze.server.Http1ServerStage$$anon$2,run,209), SourceLocation(ZIO.scala,zio.ZIO$,zio$ZIO$$_succeedRight,4495), SourceLocation(Http1ServerStage.scala,org.http4s.blaze.server.Http1ServerStage$$anon$2,run,211), SourceLocation(Dispatcher.scala,cats.effect.std.Dispatcher$$anon$2,unsafeToFutureCancelable,193), SourceLocation(ApplicativeError.scala,cats.ApplicativeError,onError,241), SourceLocation(cats.scala,zio.interop.ZioMonadError,as,389), SourceLocation(ZIO.scala,zio.ZIO,ensuring,591)),Some(ZTrace(Id(1656419285093,95),List(SourceLocation(Supervisor.scala,cats.effect.std.Supervisor$$anon$1,supervise,135), SourceLocation(ZioAsync.scala,zio.interop.ZioAsync,unique,21), SourceLocation(Supervisor.scala,cats.effect.std.Supervisor$$anon$1,supervise,134), SourceLocation(cats.scala,zio.interop.ZioConcurrent,ref,209), SourceLocation(ZRef.scala,zio.ZRef$,make,756), SourceLocation(Dispatcher.scala,cats.effect.std.Dispatcher$,apply,162), SourceLocation(Dispatcher.scala,cats.effect.std.Dispatcher$,apply,148), SourceLocation(Dispatcher.scala,cats.effect.std.Dispatcher$,apply,145), SourceLocation(Dispatcher.scala,cats.effect.std.Dispatcher$,apply,145), SourceLocation(cats.scala,zio.interop.ZioMonadError,tailRecM,413)),List(SourceLocation(cats.scala,zio.interop.ZioConcurrent,start,215), SourceLocation(Supervisor.scala,cats.effect.std.Supervisor$$anon$1,supervise,138), SourceLocation(Dispatcher.scala,cats.effect.std.Dispatcher$,apply,175), SourceLocation(cats.scala,zio.interop.ZioMonadError,as,389), SourceLocation(cats.scala,zio.interop.ZioMonadError,as,389), SourceLocation(cats.scala,zio.interop.ZioMonadError,tailRecM,413)),Some(ZTrace(Id(1656419285092,94),List(SourceLocation(ZIO.scala,zio.ZIO$,effectSuspendTotal,2837), SourceLocation(ZIO.scala,<unknown>,<unknown>,0), SourceLocation(Resource.scala,cats.effect.kernel.Resource,allocatedCase,400), SourceLocation(Resource.scala,cats.effect.kernel.Resource$,apply,681), SourceLocation(Resource.scala,cats.effect.kernel.Resource$,make,755), SourceLocation(Dispatcher.scala,cats.effect.std.Dispatcher$,apply,138), SourceLocation(Resource.scala,cats.effect.kernel.Resource,allocatedCase,440), SourceLocation(ZioAsync.scala,zio.interop.ZioAsync,executionContext,18), SourceLocation(ZIO.scala,zio.ZIO$,executor,2879), SourceLocation(Resource.scala,cats.effect.kernel.Resource,allocatedCase,440)),List(SourceLocation(cats.scala,zio.interop.ZioConcurrent,start,215), SourceLocation(Resource.scala,cats.effect.kernel.Resource$,make,755), SourceLocation(Resource.scala,cats.effect.kernel.Resource$,apply,681), SourceLocation(Resource.scala,cats.effect.kernel.Resource,allocatedCase,400), SourceLocation(ZIO.scala,zio.ZIO,run,1764), SourceLocation(ZIO.scala,zio.ZIO,onExit,1053), SourceLocation(ApplicativeError.scala,cats.ApplicativeError,onError,241), SourceLocation(ZIO.scala,zio.ZIO,run,1764), SourceLocation(ZIO.scala,zio.ZIO,onExit,1053), SourceLocation(ApplicativeError.scala,cats.ApplicativeError,onError,241)),None))))))))))
Should not be overwrite, since our filename is based on a time stamp
In order to facilitate easier testing of code using ZIO FTP, we should expose connect
in an optional environment:
trait Ftp {
def ftp: Ftp.Service
}
object Ftp {
trait Service {
def connect(...): ...
}
}
Then we can make a TestFtp
that exposes a file system backed by a Ref[Map[...]]
.
Note: Environment encoding is changing from the above (module pattern) to a slightly different and simpler pattern. So this ticket should probably wait till then (a week or so).
ZIO 2.0 is at Milestone 4, with an RC expected in the next few weeks.
https://github.com/zio/zio/releases/tag/v2.0.0-M4
The API is nearly stable at this point, so any early migration work against this version should pay off towards the official 2.0 release.
The progress is being tracked here:
zio/zio#5470
The Stream Encoding work in progress is the only area where the API might still change before the RC.
We are actively working on a ScalaFix rule that will cover the bulk of the simple API changes:
https://github.com/zio/zio/blob/series/2.x/scalafix/rules/src/main/scala/fix/Zio2Upgrade.scala
We highly recommend starting with that, and then working through any remaining compilation errors :)
To assist with the rest of the migration, we have created this guide:
https://zio.dev/howto/migrate/zio-2.x-migration-guide/
If you would like assistance with the migration from myself or other ZIO contributors, please let us know!
final case class SecureFtpSettings(
host: String,
port: Int,
credentials: FtpCredentials,
strictHostKeyChecking: Boolean,
knownHosts: Option[String],
sftpIdentity: Option[SftpIdentity],
proxy: Option[Proxy],
sshConfig: SshConfig
) extends FtpSettings[JSFTPClient]
object Sftp{
def connect(settings: SecureFtpSettings) = {
settings.proxy.foreach(p => ssh.setSocketFactory(new DefaultSocketFactory(p)))
}
}
Using Implicit FTP over TLS
sometimes requires various "hackery".
i.e. apache-commons-net doesn't manage ssl session reuse which might be needed.
I had to create
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.InetAddress;
import java.net.Socket;
import java.util.Locale;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSessionContext;
import javax.net.ssl.SSLSocket;
import org.apache.commons.net.ftp.FTPSClient;
public class SSLSessionReuseFTPSClient extends FTPSClient {
public SSLSessionReuseFTPSClient(String protocol, boolean isImplicit) {
super(protocol, isImplicit);
}
@Override
protected void _prepareDataSocket_(Socket socket) throws IOException {
if (socket instanceof SSLSocket) {
// Control socket is SSL
final SSLSession session = ((SSLSocket)_socket_).getSession();
if (session.isValid()) {
final SSLSessionContext context = session.getSessionContext();
try {
final Field sessionHostPortCache = context.getClass().getDeclaredField("sessionHostPortCache");
sessionHostPortCache.setAccessible(true);
final Object cache = sessionHostPortCache.get(context);
final Method putMethod = cache.getClass().getDeclaredMethod("put", Object.class, Object.class);
putMethod.setAccessible(true);
Method getHostMethod;
try {
getHostMethod = socket.getClass().getMethod("getPeerHost");
}
catch (NoSuchMethodException e) {
// Running in IKVM
getHostMethod = socket.getClass().getDeclaredMethod("getHost");
}
getHostMethod.setAccessible(true);
Object peerHost = getHostMethod.invoke(socket);
InetAddress iAddr = socket.getInetAddress();
int port = socket.getPort();
putMethod.invoke(cache, String.format("%s:%s", peerHost, port).toLowerCase(Locale.ROOT), session);
putMethod.invoke(cache, String.format("%s:%s", iAddr.getHostName(), port).toLowerCase(Locale.ROOT), session);
putMethod.invoke(cache, String.format("%s:%s", iAddr.getHostAddress(), port).toLowerCase(Locale.ROOT), session);
}
catch (Exception e) {
throw new IOException(e);
}
}
else {
throw new IOException("Invalid SSL Session");
}
}
}
}
To "plugin" the socket reuse.
Currently zio-ftp
doesn't allow custom clients, so library cannot be used in these situations.
Another issue, for my use-case I also had to
System.setProperty("jdk.tls.client.enableSessionTicketExtension", "false")
System.setProperty("jdk.tls.useExtendedMasterSecret", "false")
albeit not sure if this can be covered by library.
Unfortunately I need my build to run on Windows as well as linux.
When using the ls
operation on the stub it blows up with:
UnsupportedOperationException
due to trying to read POSIX attributes.
dmijicToday at 4:10 PM
@here Just released snapshots for the following projects:
As there are quite a few projects in the organization nowadays, I'd like to ask maintainers of projects that has release process enabled to help @softinio and me by aligning their projects with the latest changes. The following PR can be used as an example: https://github.com/zio/interop-twitter/pull/75/files.
Creating the UnsecureFTP
assumes that the connection will be always "Explicit FTP over TLS"
/**
* Constructor for FTPSClient, using {@link #DEFAULT_PROTOCOL} - i.e. TLS
* Calls {@link #FTPSClient(String, boolean)}
* @param isImplicit The security mode (Implicit/Explicit).
*/
public FTPSClient(final boolean isImplicit) {
this(DEFAULT_PROTOCOL, isImplicit);
}
val ftpClient = if (settings.secure) new JFTPSClient() else new JFTPClient()
There is no way to configure for Implicit FTP over TLS
It would be worthwhile to expose this setting via the UnsecureFtpSettings
object.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.