SFTP
This store is used to interface with SFTP servers. It’s built on JSch and abstracts a lot of quirks in addition to providing a pure functional interface.
import blobstore.sftp.SftpStore
import cats.ApplicativeThrow
import cats.effect.{Async, Resource}
import cats.syntax.all.*
import com.jcraft.jsch.JSch
import java.util.Properties
def createStore[F[_]: Async]: Resource[F, SftpStore[F]] = {
val createSession = ApplicativeThrow[F].catchNonFatal(new JSch().getSession("username", "host")).map { session =>
session.setTimeout(10000)
session.setPassword("password")
val config = new Properties
config.put("StrictHostKeyChecking", "no")
session.setConfig(config)
session // Let the store connect this session
}
SftpStore.resourceBuilder[F](createSession).build
}
SftpStore
creates a connection pool for JSch’s ChannelSftp
, this is exposed as a Resource[F, SftpStore[F]]
. You can control the size of this connection pool through the SftpStore
constructor.
Absolute- and rootless paths
Our Path[A]
implementation is a co-product of AbsolutePath[A]
and RootlessPath[A]
, the path constructor will do the right thing given a String
:
import blobstore.url.Path
import blobstore.url.Path.{AbsolutePath, RootlessPath}
Path("/foo/bar") == AbsolutePath.createFrom("/foo/bar")
// res0: Boolean = true
Path("foo/bar") == RootlessPath.createFrom("foo/bar")
// res1: Boolean = true
JSch uses SSH as the secure channel, and the semantics of relative paths is defined by SSH. Depending on how the SFTP server is configured, upon login you will either land in /
(if the server uses chroot) or /home/username/
(or anywhere else).
Rootless paths such as foo/bar.txt
are always relative to your home directory under SSH. We don’t expose any APIs for changing the current working directory, so ./foo/bar.txt
and foo/bar.txt
will always refer to the same object. In general, sticking to rootless paths is a good idea as you never risk to refer to anything outside the login directory.