Added basic ssh auth in rust without error handling
This commit is contained in:
parent
bb49e9482c
commit
6dee4fbc93
15 changed files with 239 additions and 267 deletions
|
@ -205,7 +205,7 @@ fun generateKotlinFromUdl() {
|
|||
workingDir = File(project.projectDir, "rs")
|
||||
commandLine = listOf(
|
||||
"cargo", "run", "--features=uniffi/cli",
|
||||
"--bin", "uniffi-bindgen", "generate", "src/repository_watcher.udl",
|
||||
"--bin", "uniffi-bindgen", "generate", "src/gitnuro.udl",
|
||||
"--language", "kotlin",
|
||||
"--out-dir", rustGeneratedSource
|
||||
)
|
||||
|
|
|
@ -13,6 +13,7 @@ name = "gitnuro_rs"
|
|||
uniffi = { version = "0.24.1" }
|
||||
notify = "6.0.1"
|
||||
thiserror = "1.0.43"
|
||||
libssh-rs = "0.2.1"
|
||||
|
||||
[build-dependencies]
|
||||
uniffi = { version = "0.24.1", features = [ "build" ] }
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
fn main() {
|
||||
uniffi::generate_scaffolding("src/repository_watcher.udl").unwrap();
|
||||
uniffi::generate_scaffolding("src/gitnuro.udl").unwrap();
|
||||
}
|
||||
|
|
46
rs/src/gitnuro.udl
Normal file
46
rs/src/gitnuro.udl
Normal file
|
@ -0,0 +1,46 @@
|
|||
namespace gitnuro {
|
||||
[Throws=WatcherInitError]
|
||||
void watch_directory(string path, WatchDirectoryNotifier checker);
|
||||
};
|
||||
|
||||
callback interface WatchDirectoryNotifier {
|
||||
boolean should_keep_looping();
|
||||
|
||||
void detected_change(sequence<string> paths);
|
||||
};
|
||||
|
||||
[Error]
|
||||
interface WatcherInitError {
|
||||
Generic(string error);
|
||||
Io(string error);
|
||||
PathNotFound();
|
||||
WatchNotFound();
|
||||
InvalidConfig();
|
||||
MaxFilesWatch();
|
||||
};
|
||||
|
||||
|
||||
interface Session {
|
||||
constructor();
|
||||
void setup(string host, string? user, i32 port);
|
||||
void public_key_auth();
|
||||
void password_auth(string password);
|
||||
void disconnect();
|
||||
};
|
||||
|
||||
interface Channel {
|
||||
constructor(Session session);
|
||||
void open_session();
|
||||
boolean is_open();
|
||||
void close();
|
||||
void request_exec(string command);
|
||||
boolean poll_has_bytes(boolean is_stderr);
|
||||
ReadResult read(boolean is_stderr, u64 len);
|
||||
void write_byte(i32 byte);
|
||||
void write_bytes(bytes data);
|
||||
};
|
||||
|
||||
dictionary ReadResult {
|
||||
u64 read_count;
|
||||
bytes data;
|
||||
};
|
129
rs/src/lib.rs
129
rs/src/lib.rs
|
@ -1,13 +1,18 @@
|
|||
extern crate notify;
|
||||
|
||||
use std::fmt::Debug;
|
||||
use std::io::{Write};
|
||||
use std::path::Path;
|
||||
use std::sync::mpsc::{channel, RecvTimeoutError};
|
||||
use std::sync::{Arc, RwLock};
|
||||
use std::time::Duration;
|
||||
|
||||
use libssh_rs::{PollStatus, SshOption};
|
||||
use notify::{Config, Error, ErrorKind, Event, RecommendedWatcher, RecursiveMode, Watcher};
|
||||
|
||||
uniffi::include_scaffolding!("repository_watcher");
|
||||
uniffi::include_scaffolding!("gitnuro");
|
||||
|
||||
const ACCEPTED_SSH_TYPES: &str = "ssh-ed25519,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,ssh-rsa,rsa-sha2-512,rsa-sha2-256,ssh-dss";
|
||||
|
||||
fn watch_directory(
|
||||
path: String,
|
||||
|
@ -114,3 +119,125 @@ impl WatcherInitErrorConverter for ErrorKind {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct Session {
|
||||
pub session: RwLock<libssh_rs::Session>,
|
||||
}
|
||||
|
||||
impl Session {
|
||||
fn new() -> Self {
|
||||
let session = libssh_rs::Session::new().unwrap();
|
||||
|
||||
Session {
|
||||
session: RwLock::new(session)
|
||||
}
|
||||
}
|
||||
|
||||
fn setup(&self, host: String, user: Option<String>, port: i32) {
|
||||
let session = self.session.write().unwrap();
|
||||
session.set_option(SshOption::Hostname(host)).unwrap();
|
||||
|
||||
if let Some(user) = user {
|
||||
session.set_option(SshOption::User(Some(user))).unwrap();
|
||||
}
|
||||
|
||||
if let Ok(port) = port.try_into() {
|
||||
session.set_option(SshOption::Port(port)).unwrap();
|
||||
}
|
||||
|
||||
session.set_option(SshOption::PublicKeyAcceptedTypes(ACCEPTED_SSH_TYPES.to_string())).unwrap();
|
||||
session.options_parse_config(None).unwrap();
|
||||
session.connect().unwrap();
|
||||
}
|
||||
|
||||
fn public_key_auth(&self) {
|
||||
let session = self.session.write().unwrap();
|
||||
session.userauth_public_key_auto(None, Some("")).unwrap();
|
||||
}
|
||||
|
||||
fn password_auth(&self, password: String) {
|
||||
let session = self.session.write().unwrap();
|
||||
session.userauth_password(None, Some(&password)).unwrap();
|
||||
}
|
||||
|
||||
fn disconnect(&self) {
|
||||
let session = self.session.write().unwrap();
|
||||
session.disconnect()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct Channel {
|
||||
channel: RwLock<libssh_rs::Channel>,
|
||||
}
|
||||
|
||||
unsafe impl Send for Channel {}
|
||||
unsafe impl Sync for Channel {}
|
||||
|
||||
impl Channel {
|
||||
fn new(session: Arc<Session>) -> Self {
|
||||
let session = session.session.write().unwrap();
|
||||
let channel = session.new_channel().unwrap();
|
||||
|
||||
Channel {
|
||||
channel: RwLock::new(channel)
|
||||
}
|
||||
}
|
||||
fn open_session(&self) {
|
||||
let channel = self.channel.write().unwrap();
|
||||
channel.open_session().unwrap();
|
||||
}
|
||||
fn is_open(&self) -> bool {
|
||||
let channel = self.channel.write().unwrap();
|
||||
channel.is_open()
|
||||
}
|
||||
|
||||
fn close(&self) {
|
||||
let channel = self.channel.write().unwrap();
|
||||
channel.close().unwrap();
|
||||
}
|
||||
|
||||
fn request_exec(&self, command: String) {
|
||||
let channel = self.channel.write().unwrap();
|
||||
channel.request_exec(&command).unwrap();
|
||||
}
|
||||
|
||||
fn poll_has_bytes(&self, is_stderr: bool) -> bool {
|
||||
let channel = self.channel.write().unwrap();
|
||||
let poll_timeout = channel.poll_timeout(is_stderr, None).unwrap();
|
||||
|
||||
match poll_timeout {
|
||||
PollStatus::AvailableBytes(count) => count > 0,
|
||||
PollStatus::EndOfFile => false
|
||||
}
|
||||
}
|
||||
|
||||
fn read(&self, is_stderr: bool, len: u64) -> ReadResult {
|
||||
let ulen = len as usize;
|
||||
|
||||
let channel = self.channel.write().unwrap();
|
||||
|
||||
let mut buffer = vec![0; ulen];
|
||||
let read = channel.read_timeout(&mut buffer, is_stderr, None).unwrap();
|
||||
|
||||
ReadResult {
|
||||
read_count: read as u64,
|
||||
data: buffer,
|
||||
}
|
||||
}
|
||||
|
||||
fn write_byte(&self, byte: i32) {
|
||||
let channel = self.channel.write().unwrap();
|
||||
channel.stdin().write_all(&byte.to_ne_bytes()).unwrap();
|
||||
}
|
||||
|
||||
fn write_bytes(&self, data: Vec<u8>) {
|
||||
let channel = self.channel.write().unwrap();
|
||||
channel.stdin().write_all(&data).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ReadResult {
|
||||
read_count: u64,
|
||||
data: Vec<u8>,
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
namespace gitnuro {
|
||||
[Throws=WatcherInitError]
|
||||
void watch_directory(string path, WatchDirectoryNotifier checker);
|
||||
};
|
||||
|
||||
callback interface WatchDirectoryNotifier {
|
||||
boolean should_keep_looping();
|
||||
|
||||
void detected_change(sequence<string> paths);
|
||||
};
|
||||
|
||||
[Error]
|
||||
interface WatcherInitError {
|
||||
Generic(string error);
|
||||
Io(string error);
|
||||
PathNotFound();
|
||||
WatchNotFound();
|
||||
InvalidConfig();
|
||||
MaxFilesWatch();
|
||||
};
|
|
@ -1,13 +1,14 @@
|
|||
package com.jetpackduba.gitnuro.credentials
|
||||
|
||||
import com.jetpackduba.gitnuro.ssh.libssh.LibSshChannel
|
||||
import com.jetpackduba.gitnuro.ssh.libssh.LibSshSession
|
||||
import uniffi.gitnuro.Channel
|
||||
import uniffi.gitnuro.Session
|
||||
import java.io.InputStream
|
||||
import java.io.OutputStream
|
||||
|
||||
class GProcessLibSsh : Process() {
|
||||
private lateinit var channel: LibSshChannel
|
||||
private lateinit var session: LibSshSession
|
||||
private lateinit var session: Session
|
||||
|
||||
private val outputStream by lazy {
|
||||
channel.outputStream
|
||||
|
@ -42,7 +43,9 @@ class GProcessLibSsh : Process() {
|
|||
check(!isRunning())
|
||||
println("exitValue called")
|
||||
|
||||
return channel.close()
|
||||
channel.close()
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
override fun destroy() {
|
||||
|
@ -57,8 +60,8 @@ class GProcessLibSsh : Process() {
|
|||
return channel.isOpen()
|
||||
}
|
||||
|
||||
fun setup(session: LibSshSession, commandName: String) {
|
||||
val channel = session.createChannel()
|
||||
fun setup(session: Session, commandName: String) {
|
||||
val channel = LibSshChannel(session)
|
||||
|
||||
channel.openSession()
|
||||
channel.requestExec(commandName)
|
||||
|
|
|
@ -1,21 +1,17 @@
|
|||
package com.jetpackduba.gitnuro.credentials
|
||||
|
||||
import com.jetpackduba.gitnuro.ssh.libssh.LibSshOptions
|
||||
import com.jetpackduba.gitnuro.ssh.libssh.LibSshSession
|
||||
import kotlinx.coroutines.CancellationException
|
||||
import org.eclipse.jgit.transport.RemoteSession
|
||||
import org.eclipse.jgit.transport.URIish
|
||||
import uniffi.gitnuro.Session
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Provider
|
||||
|
||||
|
||||
private const val DEFAULT_SSH_PORT = 22
|
||||
|
||||
class GRemoteSession @Inject constructor(
|
||||
private val processSession: Provider<LibSshSession>,
|
||||
private val credentialsStateManager: CredentialsStateManager,
|
||||
) : RemoteSession {
|
||||
private var session: LibSshSession? = null
|
||||
private var session: Session? = null
|
||||
|
||||
override fun exec(commandName: String, timeout: Int): Process {
|
||||
println("Running command $commandName")
|
||||
|
@ -32,44 +28,33 @@ class GRemoteSession @Inject constructor(
|
|||
}
|
||||
|
||||
fun setup(uri: URIish) {
|
||||
val session = processSession.get()
|
||||
session.setOptions(LibSshOptions.SSH_OPTIONS_HOST, uri.host)
|
||||
val session = Session()
|
||||
session.setup(uri.host, uri.user, uri.port)
|
||||
|
||||
uri.user?.let {
|
||||
session.setOptions(LibSshOptions.SSH_OPTIONS_USER, uri.user)
|
||||
}
|
||||
var result = session.publicKeyAuth()
|
||||
|
||||
session.setOptions(
|
||||
LibSshOptions.SSH_OPTIONS_PUBLICKEY_ACCEPTED_TYPES,
|
||||
"ssh-ed25519,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,ssh-rsa,rsa-sha2-512,rsa-sha2-256,ssh-dss"
|
||||
)
|
||||
session.loadOptionsFromConfig()
|
||||
|
||||
session.connect()
|
||||
var result = session.userAuthPublicKeyAuto(null, "")
|
||||
|
||||
if (result == 1) {
|
||||
credentialsStateManager.updateState(CredentialsRequested.SshCredentialsRequested)
|
||||
|
||||
var credentials = credentialsStateManager.currentCredentialsState
|
||||
while (credentials is CredentialsRequested) {
|
||||
credentials = credentialsStateManager.currentCredentialsState
|
||||
}
|
||||
|
||||
val password = if (credentials !is CredentialsAccepted.SshCredentialsAccepted)
|
||||
throw CancellationException("Credentials cancelled")
|
||||
else
|
||||
credentials.password
|
||||
|
||||
result = session.userAuthPublicKeyAuto(null, password)
|
||||
|
||||
if (result != 0) {
|
||||
result = session.userAuthPassword(password)
|
||||
}
|
||||
}
|
||||
|
||||
if (result != 0)
|
||||
throw Exception("Something went wrong with authentication. Code $result")
|
||||
// if (result == 1) {
|
||||
// credentialsStateManager.updateState(CredentialsRequested.SshCredentialsRequested)
|
||||
//
|
||||
// var credentials = credentialsStateManager.currentCredentialsState
|
||||
// while (credentials is CredentialsRequested) {
|
||||
// credentials = credentialsStateManager.currentCredentialsState
|
||||
// }
|
||||
//
|
||||
// val password = if (credentials !is CredentialsAccepted.SshCredentialsAccepted)
|
||||
// throw CancellationException("Credentials cancelled")
|
||||
// else
|
||||
// credentials.password
|
||||
//
|
||||
// result = session.userAuthPublicKeyAuto(null, password)
|
||||
//
|
||||
// if (result != 0) {
|
||||
// result = session.userAuthPassword(password)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if (result != 0)
|
||||
// throw Exception("Something went wrong with authentication. Code $result")
|
||||
|
||||
this.session = session
|
||||
}
|
||||
|
|
|
@ -3,30 +3,29 @@ package com.jetpackduba.gitnuro.ssh.libssh
|
|||
import com.jetpackduba.gitnuro.ssh.libssh.streams.LibSshChannelInputErrStream
|
||||
import com.jetpackduba.gitnuro.ssh.libssh.streams.LibSshChannelInputStream
|
||||
import com.jetpackduba.gitnuro.ssh.libssh.streams.LibSshChannelOutputStream
|
||||
import uniffi.gitnuro.Channel
|
||||
import uniffi.gitnuro.Session
|
||||
|
||||
class LibSshChannel internal constructor(sshSession: ssh_session) {
|
||||
private val sshLib = SSHLibrary.INSTANCE
|
||||
private var channel: ssh_channel = sshLib.ssh_channel_new(sshSession)
|
||||
class LibSshChannel internal constructor(sshSession: Session) {
|
||||
private var channel = Channel(sshSession)
|
||||
|
||||
val outputStream = LibSshChannelOutputStream(channel)
|
||||
val inputStream = LibSshChannelInputStream(channel)
|
||||
val errorOutputStream = LibSshChannelInputErrStream(channel)
|
||||
|
||||
|
||||
fun openSession() {
|
||||
sshLib.ssh_channel_open_session(channel)
|
||||
channel.openSession()
|
||||
}
|
||||
|
||||
fun requestExec(commandName: String) {
|
||||
sshLib.ssh_channel_request_exec(channel, commandName)
|
||||
channel.requestExec(commandName)
|
||||
}
|
||||
|
||||
fun isOpen(): Boolean {
|
||||
return sshLib.ssh_channel_is_open(channel) == 1
|
||||
return channel.isOpen()
|
||||
}
|
||||
|
||||
fun close(): Int {
|
||||
return sshLib.ssh_channel_close(channel)
|
||||
fun close() {
|
||||
channel.close()
|
||||
}
|
||||
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
package com.jetpackduba.gitnuro.ssh.libssh
|
||||
|
||||
/**
|
||||
* Enum based on the enum "ssh_options_e" of libssh/libssh.h
|
||||
*/
|
||||
enum class LibSshOptions {
|
||||
SSH_OPTIONS_HOST,
|
||||
SSH_OPTIONS_PORT,
|
||||
SSH_OPTIONS_PORT_STR,
|
||||
SSH_OPTIONS_FD,
|
||||
SSH_OPTIONS_USER,
|
||||
SSH_OPTIONS_SSH_DIR,
|
||||
SSH_OPTIONS_IDENTITY,
|
||||
SSH_OPTIONS_ADD_IDENTITY,
|
||||
SSH_OPTIONS_KNOWNHOSTS,
|
||||
SSH_OPTIONS_TIMEOUT,
|
||||
SSH_OPTIONS_TIMEOUT_USEC,
|
||||
SSH_OPTIONS_SSH1,
|
||||
SSH_OPTIONS_SSH2,
|
||||
SSH_OPTIONS_LOG_VERBOSITY,
|
||||
SSH_OPTIONS_LOG_VERBOSITY_STR,
|
||||
SSH_OPTIONS_CIPHERS_C_S,
|
||||
SSH_OPTIONS_CIPHERS_S_C,
|
||||
SSH_OPTIONS_COMPRESSION_C_S,
|
||||
SSH_OPTIONS_COMPRESSION_S_C,
|
||||
SSH_OPTIONS_PROXYCOMMAND,
|
||||
SSH_OPTIONS_BINDADDR,
|
||||
SSH_OPTIONS_STRICTHOSTKEYCHECK,
|
||||
SSH_OPTIONS_COMPRESSION,
|
||||
SSH_OPTIONS_COMPRESSION_LEVEL,
|
||||
SSH_OPTIONS_KEY_EXCHANGE,
|
||||
SSH_OPTIONS_HOSTKEYS,
|
||||
SSH_OPTIONS_GSSAPI_SERVER_IDENTITY,
|
||||
SSH_OPTIONS_GSSAPI_CLIENT_IDENTITY,
|
||||
SSH_OPTIONS_GSSAPI_DELEGATE_CREDENTIALS,
|
||||
SSH_OPTIONS_HMAC_C_S,
|
||||
SSH_OPTIONS_HMAC_S_C,
|
||||
SSH_OPTIONS_PASSWORD_AUTH,
|
||||
SSH_OPTIONS_PUBKEY_AUTH,
|
||||
SSH_OPTIONS_KBDINT_AUTH,
|
||||
SSH_OPTIONS_GSSAPI_AUTH,
|
||||
SSH_OPTIONS_GLOBAL_KNOWNHOSTS,
|
||||
SSH_OPTIONS_NODELAY,
|
||||
SSH_OPTIONS_PUBLICKEY_ACCEPTED_TYPES,
|
||||
SSH_OPTIONS_PROCESS_CONFIG,
|
||||
SSH_OPTIONS_REKEY_DATA,
|
||||
SSH_OPTIONS_REKEY_TIME,
|
||||
SSH_OPTIONS_RSA_MIN_SIZE,
|
||||
SSH_OPTIONS_IDENTITY_AGENT
|
||||
}
|
|
@ -1,62 +0,0 @@
|
|||
package com.jetpackduba.gitnuro.ssh.libssh
|
||||
|
||||
import com.jetpackduba.gitnuro.logging.printError
|
||||
import com.jetpackduba.gitnuro.ssh.libssh.streams.checkValidResult
|
||||
import javax.inject.Inject
|
||||
|
||||
private const val TAG = "LibSshSession"
|
||||
|
||||
class LibSshSession @Inject constructor() {
|
||||
private val sshLib = SSHLibrary.INSTANCE
|
||||
|
||||
private var session: ssh_session = sshLib.ssh_new()
|
||||
private var channel: LibSshChannel? = null
|
||||
|
||||
fun setOptions(option: LibSshOptions, value: String) {
|
||||
sshLib.ssh_options_set(session, option.ordinal, value)
|
||||
}
|
||||
|
||||
fun loadOptionsFromConfig() {
|
||||
checkValidResult("loadOptionsFromConfig", sshLib.ssh_options_parse_config(session, null))
|
||||
}
|
||||
|
||||
fun connect() {
|
||||
sshLib.ssh_connect(session)
|
||||
}
|
||||
|
||||
fun userAuthPublicKeyAuto(username: String?, password: String?): Int {
|
||||
val result = sshLib.ssh_userauth_publickey_auto(session, username, password)
|
||||
|
||||
if (result != 0)
|
||||
printError(TAG, "Result is: $result.\nError is: ${getError()}")
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
fun userAuthPassword(password: String): Int {
|
||||
val result = sshLib.ssh_userauth_password(session, null, password)
|
||||
|
||||
if (result != 0)
|
||||
printError(TAG, "Result is: $result.\nError is: ${getError()}")
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
fun createChannel(): LibSshChannel {
|
||||
val newChannel = LibSshChannel(session)
|
||||
|
||||
this.channel = newChannel
|
||||
|
||||
return newChannel
|
||||
}
|
||||
|
||||
private fun getError(): String {
|
||||
return sshLib.ssh_get_error(session)
|
||||
}
|
||||
|
||||
fun disconnect() {
|
||||
sshLib.ssh_disconnect(session)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
package com.jetpackduba.gitnuro.ssh.libssh
|
||||
|
||||
import com.sun.jna.Library
|
||||
import com.sun.jna.Native
|
||||
import com.sun.jna.PointerType
|
||||
|
||||
class ssh_session : PointerType()
|
||||
class ssh_channel : PointerType()
|
||||
|
||||
@Suppress("FunctionName")
|
||||
interface SSHLibrary : Library {
|
||||
fun ssh_new(): ssh_session
|
||||
fun ssh_disconnect(session: ssh_session): ssh_session
|
||||
fun ssh_options_set(session: ssh_session, enumValue: Int, value: String)
|
||||
|
||||
fun ssh_options_parse_config(session: ssh_session, fileName: String?): Int
|
||||
|
||||
fun ssh_connect(session: ssh_session): Int
|
||||
|
||||
fun ssh_userauth_publickey_auto(session: ssh_session, username: String?, password: String?): Int
|
||||
fun ssh_userauth_password(session: ssh_session, username: String?, password: String?): Int
|
||||
fun ssh_get_error(session: ssh_session): String
|
||||
|
||||
fun ssh_channel_new(sshSession: ssh_session): ssh_channel
|
||||
|
||||
fun ssh_channel_open_session(sshChannel: ssh_channel): Int
|
||||
|
||||
fun ssh_channel_request_exec(sshChannel: ssh_channel, command: String): Int
|
||||
|
||||
fun ssh_channel_read(sshChannel: ssh_channel, buffer: ByteArray, count: Int, isStderr: Int): Int
|
||||
|
||||
fun ssh_channel_poll(sshChannel: ssh_channel, isStderr: Int): Int
|
||||
|
||||
fun ssh_channel_write(sshChannel: ssh_channel, data: ByteArray, len: Int): Int
|
||||
|
||||
fun ssh_channel_close(sshChannel: ssh_channel): Int
|
||||
|
||||
fun ssh_channel_is_open(sshChannel: ssh_channel): Int
|
||||
|
||||
|
||||
companion object {
|
||||
val INSTANCE = Native.load("ssh", SSHLibrary::class.java) as SSHLibrary
|
||||
}
|
||||
}
|
|
@ -1,20 +1,17 @@
|
|||
package com.jetpackduba.gitnuro.ssh.libssh.streams
|
||||
|
||||
import com.jetpackduba.gitnuro.ssh.libssh.SSHLibrary
|
||||
import com.jetpackduba.gitnuro.ssh.libssh.ssh_channel
|
||||
import uniffi.gitnuro.Channel
|
||||
import java.io.InputStream
|
||||
|
||||
class LibSshChannelInputErrStream(private val sshChannel: ssh_channel) : InputStream() {
|
||||
class LibSshChannelInputErrStream(private val sshChannel: Channel) : InputStream() {
|
||||
private var cancelled = false
|
||||
private val sshLib = SSHLibrary.INSTANCE
|
||||
|
||||
override fun read(): Int {
|
||||
val buffer = ByteArray(1)
|
||||
return if (sshChannel.pollHasBytes(true)) {
|
||||
val read = sshChannel.read(true, 1u)
|
||||
val byteArray = read.data
|
||||
|
||||
return if (sshLib.ssh_channel_poll(sshChannel, 1) > 0) {
|
||||
sshLib.ssh_channel_read(sshChannel, buffer, 1, 1)
|
||||
|
||||
val first = buffer.first()
|
||||
val first = byteArray.first()
|
||||
|
||||
first.toInt()
|
||||
} else
|
||||
|
|
|
@ -1,28 +1,26 @@
|
|||
package com.jetpackduba.gitnuro.ssh.libssh.streams
|
||||
|
||||
import com.jetpackduba.gitnuro.ssh.libssh.SSHLibrary
|
||||
import com.jetpackduba.gitnuro.ssh.libssh.ssh_channel
|
||||
import uniffi.gitnuro.Channel
|
||||
import java.io.InputStream
|
||||
|
||||
class LibSshChannelInputStream(private val sshChannel: ssh_channel) : InputStream() {
|
||||
private val sshLib = SSHLibrary.INSTANCE
|
||||
|
||||
class LibSshChannelInputStream(private val sshChannel: Channel) : InputStream() {
|
||||
override fun read(b: ByteArray, off: Int, len: Int): Int {
|
||||
val byteArray = ByteArray(len)
|
||||
val result = sshLib.ssh_channel_read(sshChannel, byteArray, len, 0)
|
||||
val result = sshChannel.read(false, len.toULong())
|
||||
val byteArray = result.data
|
||||
val read = result.readCount
|
||||
|
||||
for (i in 0 until len) {
|
||||
b[off + i] = byteArray[i]
|
||||
}
|
||||
|
||||
return result
|
||||
return read.toInt()
|
||||
}
|
||||
|
||||
override fun read(): Int {
|
||||
val buffer = ByteArray(1)
|
||||
|
||||
sshLib.ssh_channel_read(sshChannel, buffer, 1, 0)
|
||||
val result = sshChannel.read(false, 1u)
|
||||
|
||||
val first = buffer.first()
|
||||
val first = result.data.first()
|
||||
|
||||
return first.toInt()
|
||||
}
|
||||
|
|
|
@ -1,26 +1,18 @@
|
|||
package com.jetpackduba.gitnuro.ssh.libssh.streams
|
||||
|
||||
import com.jetpackduba.gitnuro.ssh.libssh.SSHLibrary
|
||||
import com.jetpackduba.gitnuro.ssh.libssh.ssh_channel
|
||||
import uniffi.gitnuro.Channel
|
||||
import java.io.OutputStream
|
||||
|
||||
class LibSshChannelOutputStream(private val sshChannel: ssh_channel) : OutputStream() {
|
||||
private val sshLib = SSHLibrary.INSTANCE
|
||||
|
||||
class LibSshChannelOutputStream(private val sshChannel: Channel) : OutputStream() {
|
||||
override fun write(b: Int) {
|
||||
val byteArrayData = byteArrayOf(b.toByte())
|
||||
write(byteArrayData)
|
||||
}
|
||||
|
||||
override fun write(b: ByteArray) {
|
||||
sshLib.ssh_channel_write(sshChannel, b, b.size)
|
||||
sshChannel.writeBytes(b)
|
||||
}
|
||||
|
||||
override fun close() {
|
||||
}
|
||||
}
|
||||
|
||||
fun checkValidResult(tag: String, result: Int) {
|
||||
if (result != 0)
|
||||
throw Exception("$tag - Result is $result")
|
||||
}
|
Loading…
Reference in a new issue