Hacker News new | past | comments | ask | show | jobs | submit login
SwiftNIO SSH (swift.org)
98 points by hutattedonmyarm 3 days ago | hide | past | favorite | 55 comments

I've only very recently started programming in swift (started using it for an ios app) - having done backend development over the past years using primarily node and scala, I gotta say I really really enjoy using swift so far. Don't get me wrong, node and scala are both fun to program in. But swift types (especially) structs that implement immutability throughout, as well as a, let's say, slight 'functional' bias in the language without enforcing it too strictly has really made me want to use it more on the backend as well. I'll definitely check this one out.

Once async gets finalized and lands will be pretty sweet platform for backend development. (provided community develops enough to support decent size ecosystem).

It's brilliant for client side applications, it's starts to feel pretty awkward server side. At least right now. I wish the server side team and Vapor people all the best though and hope it gets more traction.

If you like swift you should seriously give kotlin a go. Kotlin on the backend has a quite mature ecosystem (mostly because of its java heritage) and the language is a delight to work with.

^ this but also try out Rust. Swift and Rust have a lot of ideas in common but Rust has a better backend story for the foreseeable future.

However I really can't speak more highly of Kotlin, it's the most productive language I have used in large part because of access to the massive JVM ecosystem but with a modern, highly expressive language with amazing tooling (IntelliJ, YourKit, lightRecorder) and excellent performance.

Rust has a worse story in development happiness for the forseeable future as well compared to those languages.

I want Swift-on-server to be a thing because context switching from UI to backend development is taxing enough, at least the language and some of the tooling could remain the same.

Maybe you can do that with JS+HTML+CSS on the front end and NodeJS on the backend but Swift is such a nice language to work with.

Here is Vapor, a web framework made with Swift: https://vapor.codes

> context switching from UI to backend development is taxing enough, at least the language and some of the tooling could remain the same.

I wish I had understood this sooner. Thank you for your comment!

What's your experience with Vapor? Suppose I've got a Linux box with a MySQL database, setup with a couple of tables. Maybe like a messageboard with Users, Posts and Comments. How many days would it take to implement a REST API for that? And a couple of simple web admin screens?

I am in the process of learning Vapor. You need to be comfortable with Swift closures as Vapor uses them everywhere. The SwiftNIO EventLoopFuture is prevalent too and there's a rich API over that which I'm still getting to grips with.

To my mind, the best learning resource is Tim Condon et. al.'s Server-Side Swift with Vapor (Ray Wenderlich publishing) but this book needs to be updated. Vapor 4 was released in April but the ORM (Fluent) and template engine (Leaf) weren't upgraded at the same time (June and November, respectively). The first half of the book was updated in September but everything else has been on hold waiting for the Leaf release. My progress through latter part of the book has been slow whilst I translate the examples and wrestle with the compiler errors brought on by my unamiliarity with the above concepts.

Tim C. is on the case and is very active and helpful on the forums so I expect the new version of his book will be finished quickly.

Anyway, to answer the question: Vapor should be nearly as productive as Rails once you become familiar with it. There's an offically supported MySQL driver for Fluent but no admin screen builder like you might find on Django, for example, so you'd have to put those together yourself.

Not much, unfortunately. Some of the integrations that I need, like firebase, don't have official frameworks for Swift beyond iOS.

For example, I need to be able connect to Firestore and listen continuously for new data and changes so I can fetch them, do some calculations and put the results back on Firestore. I am doing it with NodeJS because of the official support but I have to tell you that it melts my brain when I have to switch to NodeJS way of thinking and back again.

If I could have used Vapor, I would have been able to just use some the already implemented algorithms in the user facing App instead of re-implementing everything in again but this time in a NodeJS way.

It's a joke compared to the ruby on rails or node ecosystem.

It is about ecosystems, not languages.

Swift's ecosystem is Apple products. If you're not doing that, don't use Swift.

You will have to learn and use multiple languages and multiple ecosystems regardless because each ecosystem insists on using its own language and tools. So just use the most popular one for each - it will be the most polished with the fewest number of gotchas.

At this point, the clear winners for each ecosystem are Kotlin, Swift, Typescript, C# and C++ if you're doing games.

If you write a todo app on each platform, you'll realize you're using the same set of language features with different syntax - that should lessen the anxiety of learning a new language. Once you're free and nimble, you'd have to be nuts to choose anything but the right tool for the job or when in doubt, the most popular.

Why do you say it's a joke? Is it because of your experience with it, did you compare features, etc., what is the reason?

Its really fun to work with a shared foundation project containing all your Codable objects across the app and backend, then serialize / deserialize between the same actual class - with the transport being nice readable json.

I'd use Swift-on-server for web apps if there were a way to compile Swift to JS, like you can with Kotlin. As far as I know, there is not a good way to do this.

Gave SwiftWasm a try yet?

This sounds like a great addition for servers written in Swift. Pair it with the very easy to use and clean command line arguments package and it should be "trivial" to add management/diagnostic console full of commands to your server.

Traditionally for HTTP servers I carve off a URL prefix, e.g. /diagnostics/ or listen on a different port, and make handlers there to let me know how things are going. The downside is that I then have to protect those which collides with whatever other authentication is going on.

Moving that to a command console eliminates all those ways to screw up and let evil people into my diagnostic functions.

The command line parser package is trivial to use once you get the hang of it and generates acceptable "help" automatically, so you'll end up with a custom CLI of your diagnostic commands with a "help" function to remember them for essentially zero coding and maintenance effort.

Now I have to spend all day resisting the urge to weld this into my latest HTTP server to see how it goes.

Update: There is an example server in the Sources/NIOSSHServer directory of the repository. 5 files, about 500 lines total to implement a "bash" command executer and a remote port forwarder.

Update 2: 50 minutes in and I have an ssh server embedded in my server. Maybe. When I send a command it explodes my process with a Posix.close() to a bad file descriptor tripping a precondition check. So, maybe don't rush this to a live server.

For anyone following in these footsteps: It works well.

I spent more time fighting Swift Argument Parser than the NIOSSH. Fundamentally, there is not a way to pass context down to a command that is run. Fine when you are a whole program reading its commands and everything is implicitly global, but if you have a bunch of SSH connections coming in then just getting the output to the right one needs context.

I'm not real happy with my solution, but its clean and it works. Figure two days to get a usable subsystem working.

I have a few more things to try to clean up my mess. If it works I'll tidy up the package and publish it.

Two days in. The package is useful and mostly complete. See https://github.com/jimstudt/SSHConsole if you have needs, or just want to see another example of using NIOSS on the server. This one includes the public key authentication which in retrospect is trivial-ish.

Listing "EDCSA [sic, maybe wishful thinking it actually is an Ed25519-like scheme instead of ECDSA?] over secp256" (plus siblings) and AES-GCM as "Modern cryptographic primitives only" is genuinely funny. This library does not do Chapoly1305, which has largely been the default choice for SSH since a few years, since it's both fast and secure without dedicated instructions.


The dev said it's basically because Swift Crypto API does not support chacha20-poly1305@openssh.com, which is a non-standard construction (compared to chacha20-ietf-poly1305).

What are the benefits of chacha20-poly1305 over what’s currently implemented?

This is good. I've been searching around for a good SSH client library for an app I've been working on. I've used NMSSH for some time, but its Objective C and I'd like a more swift friendly implementation.

Now I just need to dust it off, it's been sitting on that code-shelf over there for 2 years.

Personally, I think that Rust is a way better language from a design point of view, but if you want to make a living, then Go and Swift are better.

Rust is also a much bigger investment for the developer to learn and master. Much of the beauty of Rust is in Swift -- heck, the same language designers have worked in both languages.

You mean Graydon moving from Rust to Swift? On Rust he had a tremendous influence, but while he was on the team, I'm not sure about his influence on Swift. I think Swift is more constrained, having to have good compatibility with objective C. Rust is only compatible with C, and thus has more freedom to do away with decisions that turned out to be bad.

Edit: probably Gankra too. IIRC she had an internship at mozilla designing important parts of the Rust standard library then later went to work at Apple.

Much of the beauty of ML is in Rust and Swift.

To some degree, yes. Until you try to write what would be idiomatic SML code in those and the lack of tracing GC comes to bite you.

Nevertheless, I guess it's good sum types are making it into the mainstream.

Agreed, that is also a reason why I think in the end GC by default (regardless of the algorithm) + affine types will win adoption across mainstream languages, and pure affine type languages like Rust will find their niche on scenarios like those where certifications like MISRA are required, or kernel stuff.

Rust is more advanced, but there is more to language design than technical cleverness.

Swift is miles ahead of Rust in terms of language usability and ergonomics.

You have any concrete examples? I'm not very familiar with swift, so I opened a random file in the project [0]. On the first glance it feels like the typical noisy OOP java code base. Probably most of it done with automated tools. Very weird were the named arguments repeating the same thing [1]. Would have been much shorter in Rust as it doesn't have named arguments (and IMO Rust should never get them). And on the first half of the file there are a bunch of POD struct definitions with a few init functions. In Rust, those POD structs where all members are public can be easily be initialized without having to create functions for it (but then you do have to name the "arguments", but for struct initializers I don't consider it to be a problem). So way less repetition.

[0]: https://github.com/apple/swift-nio-ssh/blob/main/Sources/NIO...

[1]: https://github.com/apple/swift-nio-ssh/blob/8a75ab90e1b12182...

Named arguments is a HUGE thing for ergonomics. It makes code many times more readable, since it automatically documents intent much more clearly. The code linked here is nowhere near representative of regular Swift code.

As a very basic made-up example, the real value of named arguments is code like this:

    FileManager.copy(path1, path2)
What does that do? There is no way to tell which file is copied to which. In Swift, this is written as:

    FileManager.copy(from: path1, to: path2)
Suddenly, there is no need to look up the function to figure out what it does. It is perfectly clear.

The first use I recall for named parameters was in Algol60. One could write:

Instead of:

  copyfile(path1, path2)
I always liked that idea, but found Objective-C’s version of this less attractive. Smalltalk had named parameters too. Algol60, to me, had the nicest syntax for this.

Swift has improved nicely on the Objective-C style, I think.

If you were being "idiomatic," you'd probably write it like so:

    MyOwnFileManager.copyFileFrom(_ path1: String, to path2: String)
Apple has started to make it like that.

No, that is the old Objective-C style. It is definitely not idiomatic.

In the more recent Swift and library releases, I have had to change my code to fit the above pattern, as I get deprecation errors all the time.

But you are correct that it started with ObjC. That doesn't make it a bad thing. It seems that Apple is starting to circle back.

I prefer the initial one that you posited. I'm pretty sure the Swift style guide suggests the way you mentioned, and not the ObjC way.

BTW: I deleted the post where I talk about where I saw this. It seems folks just want to argue, and that's not why I come here.

I've not seen any of these in years now. Where have they been popping up?

> and IMO Rust should never get them

I guess whatever floats your boat. Personally, I enjoy not having to write functions like doStuff(true, true, true, false) or alternatively define types for every single boolean flag I want to have. Terseness is a non goal for Swift.

> And on the first half of the file there are a bunch of POD struct definitions with a few init functions.

I don't know how rust handles this but in swift, each POD struct has an implicit member wise constructor visible from the file it's defined. This is for encapsulation purposes, as its signature of course changes if you add fields to the struct.

> Personally, I enjoy not having to write functions like doStuff(true, true, true, false)

Yeah that's not beautiful, but most of my code is rather

doStuff(foo, bar, baz)

where foo, bar and baz are descriptive variable names. I agree that it's hard to understand with literals, but in the rare cases you need such flags you can either have a config struct or use the builder pattern. Also, nowadays you can set up vscode to use the rust-analyzer LSP plugin, which shows you the types as well as the parameter names. But of course that doesn't work on Github and similar places.

IDK in general, the people who want named arguments outnumber the people who don't want them, at least in threads about the question, which obviously preselects the people who want them. Maybe eventually Rust will get them, no idea. But IMO that code shows how named arguments can make code more noisy than before.

> I don't know how rust handles this but in swift, each POD struct has an implicit member wise constructor visible from the file it's defined. This is for encapsulation purposes, as its signature of course changes if you add fields to the struct.

In Rust, POD structs can be constructed iff all their members are visible through the publicity system to the code that tries to construct them. If it's in a different crate, it's also important whether there is a #[non_exhaustive] attribute on the struct declaration or not.

> where foo, bar and baz are descriptive variable names

But descriptive variable names should describe what those variables ARE, not how they are going to be passed to a function.

So, does copy(tempFile, databaseFile) copy the temporary file over the database file, or vice versa?

"Typical noisy OOP java code base", without a single class in the whole file, only value types. As for automated tools, I think you're giving Xcode too much credit. It'll help you a bit, but not much.

Miles ahead? This is problem with hackernews? Where is proof? How is Swift miles ahead than Rust? Before claiming anything please give us proof? Putting Arc everywhere doesn't make lang miles ahead.

Arc is a technical feature, not ergonomics.

Ergonomics is things like the optional handling syntax in Swift, or named arguments.

So just for three thing you claimed "Swift is miles ahead of Rust in terms of language usability and ergonomics." Wow. Now let me tell you Why Rust is miles ahead than Swift.

1. Swift abstract away lot of memory management by defaulting to thread safe reference counting. In Rust you are free to use stack, heap and wide range of other option. Rust has a freedom here. ARC is basically a garbage collection whatever apple say.

2. Rust pattern matching is novel. You can see match on csharp, php because its so good.

3. Rust is far better in concurrency world.

4. Cross Platform support is Meh in Swift. Its starting but its too far. If you are writing ios app or anything for mac yes swift is ahead.

But in other field Rust is far ahead. See the link for fair comparison. I have used various PL in my life time from c, c++ , java, swift , rust etc. And I am not biased towards rust. But simply saying swift is miles ahead is totally unfair to me.


He/She was talking about developer ergonomics. And in that particular sense, while i have programmed in Swift and Rust, i completely agree with him/her.

In your disagreement you are pointing out how you think Rust is more _advanced_ than Swift. But this goes into a tangential topic, that was not what the parent was pointing out.

In developer productivity and ergonomics Rust is not far away from C++, and Swift is more akin to Kotlin, C# and Java, but it feels a little better like Typescript or Dart.

I wonder, why, so many times, Rust folks (Why to get tied to a tech, i also don't get it) gets so hostile and arrogant about the language, and to be fair this is some of the reasons i keep a certain distance from it, and i can imagine that im not the only one.

> Rust folks (Why to get tied to a tech, i also don't get it) gets so hostile and arrogant about the language

It's honestly crossed over from being a meme (rewrite it in Rust) into becoming obnoxious. Obviously a small, vocal minority as always.

Or it might have something to do with academic appealing programming languages as Haskell also comes to mind where this was some sort of a ritual within its followers.

Arc is not garbage collection. They have completely different implementations and performance profiles.

They are both forms of automatic memory management but that is about it.

There is nothing novel about pattern matching in rust, swift has pattern matching too, and both languages inherited it from Ocaml, and the ml family of languages in general.

The only one there that is a usability or ergonomics feature I can see is possibly pattern matching. I'm not familiar with it in Rust, what does Rust offer in pattern matching that Swift doesn't?

I don't know why he is being downvoted but I agree here. Rust is a novel lang. Its a general purpose lang unlike swift which is made specifically for Apple ecosystem.

Just because apple made a swift doesn't mean its design is better.

I downvoted because it is needlessly hostile without adding anything to the discussion.

The topic here is that Swift developers made a release of an open source software and it is not if Swift is the best or if Rust is better. Why would you try to steer it in that direction?

It's like having your friend serving you his Lasagne that worked on and is pride of, then have someone in the group saying that Brussels sprouts is a better meal but we are going to eat this because most people don't care enough about their health or don't know better. Don't be that person if you want to be likeable.

Almost all top comments in this thread are evaluating the Swift language instead of the library:

* https://news.ycombinator.com/item?id=25158147 spends 530 characters on their past programming life and an evaluation of the Swift language, and only then ends the comment with "I'll definitely check this one out."

* https://news.ycombinator.com/item?id=25157942 mostly talks about the language as well instead of this ssh library. It's a bit more on topic though as it talks about swift on the server, which this library can belong to (but doesn't have to, the library also has a ssh client part). Still, way offtopic if you are strict.

* https://news.ycombinator.com/item?id=25158932 alright so this comment is actually about the SSH library. Only barely has any replies though. Apparently hn'ers don't like to talk about the ssh library.

* And there is my comment https://news.ycombinator.com/item?id=25158334 which as of now has the most discussion, but it's downvoted at a -4 score ATM.

I actually came to this thread where these responses were the top replies (except for the single one which is actually on-topic, it wasn't present yet). So I thought I'd add my own.

Also it's sad how nobody replied to the second part of my post. I think that employability is a clear benefit of Swift and Go over Rust. If I check indeed Germany for "Swift Software", I get 596 results. If I check "Go Software" I get 2463 jobs. Checking "Rust Software" gives me 131 results. A big difference.

I’m not an authority, my opinion is that cold calls to pitch an alternative tools when people are discussing something is annoying and distracting and don’t bring anything to the discussion.

Talking about Swift is not irrelevant as it is a prerequisite to use the software in question.

I guess If you have replied to someone asking if Swift or something else is worth learning, I would have upvoted you.

The way it is just feels spammy.

I didn't downvote. But I think the downvotes are because it apprently isn't possible on HN to have a discussion about any language without Rust evangelists appearing. We get it, it's great and deserves it's praise but doesn't need to be mentioned everywhere. The topic also had nothing to do with language design.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact