fs2 ftp client built on top of Cats Effect, Fs2 and the sftp java client sshj and ftp/ftps client commons-net
//support scala 2.12 / 2.13
libraryDependencies += "com.github.regis-leray" %% "fs2-ftp" % "<version>"
import ray.fs2.ftp.FtpClient._
import ray.fs2.ftp.FtpSettings._
// FTP
val settings = UnsecureFtpSettings("127.0.0.1", 21, FtpCredentials("foo", "bar"))
// FTP-SSL
val settings = UnsecureFtpSettings.secure("127.0.0.1", 21, FtpCredentials("foo", "bar"))
connect(settings).use{
_.ls("/").compile.toList
}
import ray.fs2.ftp.FtpClient._
import ray.fs2.ftp.FtpSettings._
val settings = SecureFtpSettings("127.0.0.1", 22, FtpCredentials("foo", "bar"))
connect(settings).use(
_.ls("/").compile.toList
)
import ray.fs2.ftp.FtpClient._
import ray.fs2.ftp.FtpSettings._
import java.nio.file.Paths._
// Provide a SftpIdentity implementation
val keyFile = KeyFileSftpIdentity(Paths.get("privateKeyStringPath"))
val settings = SecureFtpSettings("127.0.0.1", 22, FtpCredentials("foo", ""), keyFile)
connect(settings).use(
_.ls("/").compile.toList
)
trait FtpClient[+A] {
def stat(path: String)(implicit cs: ContextShift[IO]): IO[Option[FtpResource]]
def readFile(path: String, chunkSize: Int = 2048)(implicit cs: ContextShift[IO]): fs2.Stream[IO, Byte]
def rm(path: String)(implicit cs: ContextShift[IO]): IO[Unit]
def rmdir(path: String)(implicit cs: ContextShift[IO]): IO[Unit]
def mkdir(path: String)(implicit cs: ContextShift[IO]): IO[Unit]
def ls(path: String)(implicit cs: ContextShift[IO]): fs2.Stream[IO, FtpResource]
def lsDescendant(path: String)(implicit cs: ContextShift[IO]): fs2.Stream[IO, FtpResource]
def upload(path: String, source: fs2.Stream[IO, Byte])(implicit cs: ContextShift[IO]): IO[Unit]
def execute[T](f: A => T)(implicit cs: ContextShift[IO]): IO[T]
}
All function required an implicit ContextShit[IO].
Since all (s)ftp command are IO bound task , it will be executed on specific blocking executionContext More information here https://typelevel.org/cats-effect/datatypes/contextshift.html
Here how to provide an ContextShit
- you can use the default one provided by
IOApp
object MyApp extends cats.effect.IOApp {
//by default an implicit ContextShit is available as an implicit variable
}
Or create your own ContextShit
import cats.effect.IO
import cats.effect.ContextShift
implicit val blockingIO = ExecutionContext.fromExecutor(Executors.newCachedThreadPool())
implicit val cs: ContextShit[IO] = IO.contextShift(blockingIO)
The underlying client is safely exposed and you have access to all possible ftp commands
import ray.fs2.ftp.FtpClient._
import ray.fs2.ftp.FtpSettings._
val settings = SecureFtpSettings("127.0.0.1", 22, FtpCredentials("foo", "bar"))
connect(settings).use(
_.execute(_.version())
)
- How to create a key to signed artifact
# generate key
$ gpg --gen-key
# list the keys
$ gpg --list-keys
/home/foo/.gnupg/pubring.gpg
------------------------------
pub rsa4096 2018-08-22 [SC]
1234517530FB96F147C6A146A326F592D39AAAAA
uid [ultimate] your name <you@example.com>
sub rsa4096 2018-08-22 [E]
#send key to server
$> gpg --keyserver hkp://ipv4.pool.sks-keyservers.net --send-keys $LONG_ID
# declare in travis (settings) PGP_SECRET in base64 (with no return carriage), dont put "" around the value !
gpg --armor --export-secret-keys $LONG_ID | base64 -w0 | pbcopy
# declare in travis (settings) PGP_PASSPHRASE in plain text
The randomly generated password you used to create a fresh gpg key
- create a tag and push
more information here => https://github.com/olafurpg/sbt-ci-release
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this project except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.