orlandos-nl / Citadel

SSH Client & Server in Swift
MIT License
181 stars 32 forks source link

Interactive standard stream processing. #63

Open vsevolod-volkov opened 3 months ago

vsevolod-volkov commented 3 months ago

There is requirement in our project to catch script output it prints out to its STDOUT/STDERR and send response back to STDIN when it prompts for it.

Any solution allowing to catch STDOUT/STDERR stream output in realtime in couple with ability to immediately send data to ssh STDIN will satisfy us.

For now we implemented alternative ssh interaction based on low-level swift Process class. We transferring ssh command with arguments as Process.arguments then interacting with it like any other child UNIX process.

        task.executableURL = URL(fileURLWithPath: "/opt/homebrew/bin/sshpass")
        // https://github.com/hudochenkov/homebrew-sshpass
        // brew install hudochenkov/sshpass/sshpass
        task.arguments = [
            "-p", password,
            "ssh",
            "-o", "StrictHostKeyChecking no",
            "-o", "UserKnownHostsFile=/dev/null",
            "-q",
            "\(login)@\(host)",
        ]

We found this solution horrible especially in contrast with nice Citadel interface and still use Citadel for sftp, so we very appreciate you to implement real-time interaction in citadel.

Joannis commented 3 months ago

Hey! Just checking, but you're essentially looking for a bidirectional stream right? Writes are going to stdin and stdout/stderr are emitted back to you? That's super achievable. I can make a PR early next week, but please hop on the Discord if you're able to so we can make a small API design draft to get things sorted

Joannis commented 3 months ago

I'm thinking of mimicking the NIOAsyncChannel APIs

Joannis commented 2 months ago

Ping @vsevolod-volkov

vsevolod-volkov commented 2 months ago

I am very sorry for my disappear. I had trouble with my discord login then switched to other tasks and forgot. I still very interested with new async API in citadel. Just tried to connect you in Discord.

Joannis commented 2 months ago

@vsevolod-volkov I probably rejected your friend request because it was missing a message. I do tend to get some spam as well. Can you reach out again, or send a single message in the Citadel channel I have?

vsevolod-volkov commented 1 month ago

Unfortunately Citadel channel is not reachable for me.

image
Joannis commented 1 month ago

Are you in the orlandos-nl discord server, linked in the Citadel README? https://discord.com/invite/H6799jh

vsevolod-volkov commented 1 month ago

Yes, now I am there. But still fighting with discord client...

Joannis commented 1 month ago

No worries, I'm fighting with my network right now

Joannis commented 1 month ago
try await client.withRunningExectable(
  "/path/to/executable",
  "--flag",
  "--key", "value"
) { inbound, outbound in
  // outbound allows clients to write to `stdin` on the server
  try await outbound.write(...)
  // Inbound represents the incoming stream. I.E. `stdout` and `stderr` that the server's process emits
  for try await message in inbound {
    switch message {
    case .stdout(let buffer):
      () // you've received data on stdout
    case .stderr(let buffer):
      () // you've received data on stderr
    }
  }
}