Архив метки: rust

Rust — подготовленные запросы в PostgreSQL с указанием типа

cargo.toml


[dependencies]
postgres = { version = "0.19.9", features = ["with-uuid-1", "with-chrono-0_4"] }
uuid = { version = "1.11.0", features = ["v4"] }
chrono = "0.4.38"

main.rs

use postgres::{Client, NoTls};
use std::error::Error;
use uuid::Uuid;
use chrono::{NaiveDateTime};


fn main() -> Result<(), Box<dyn Error>> {
    let mut conn = Client::connect(
        "postgresql://postgres:jopa@localhost:5432/postgres",
        NoTls)
    .unwrap();

    let stuff_id = Uuid::new_v4();
    let date_str = "2020-04-12 22:10:57";
    let naive_datetime = NaiveDateTime::parse_from_str(date_str, "%Y-%m-%d %H:%M:%S").unwrap();

    conn.execute(
        "insert into test (stuff_id, naive_datetime) values ($1, $2)",
        &[&stuff_id, &naive_datetime],
    )?;

    Ok(())
}

Rust — SSH2 sftp download file

use std::net::TcpStream;
use std::io::Read;
use ssh2::Session;
use std::path::Path;

fn main() {
    let tcp = TcpStream::connect("127.0.0.1:22").unwrap();
    let mut sess = Session::new().unwrap();
sess.set_tcp_stream(tcp);
sess.handshake().unwrap();
sess.userauth_password("user", "password").unwrap();
    let mut contents:Vec<u8> = Vec::new();
    let sftp = sess.sftp().unwrap();
    let mut stream = sftp.open(Path::new("/tmp/test.txt")).unwrap();
             stream.read_to_end(&mut contents).unwrap();
             let _ = std::fs::write(r"/tmp/test_out.txt", &contents);
}

Rust — sftp upload file

use std::net::TcpStream;
use std::io::Write;
use std::io::Read;
use std::fs::File;
use ssh2::Session;
use std::path::Path;


fn main() {

    let tcp = TcpStream::connect("127.0.0.1:22").unwrap();
    let mut sess = Session::new().unwrap();
sess.set_tcp_stream(tcp);
sess.handshake().unwrap();
sess.userauth_password("user", "pass").unwrap();
     
     let sftp = sess.sftp().unwrap();
     let mut local_file = File::open("/tmp/test.txt").expect("no file found");  
     let mut buffer:Vec<u8> = Vec::new();
     let _ :u64 = local_file.read_to_end(&mut buffer).unwrap().try_into().unwrap();

sftp.create(&Path::new("/tmp/file.json"))
    .unwrap()
    .write_all(&buffer)
    .unwrap();
}

Решено! Rust — не собирается под musl — ругаeтся на openssl в Linux.

Если вы решили использовать в своем проекте то, что нужнается в Openssl — будьте готовы что можете столкнуться с кучей ошибок при сборке, особенно если собираете под стандартную реализацию libc в musl.

При сборке cargo вам вывалит что -то подобное:

OPENSSL_DIR unset
  cargo:rerun-if-env-changed=OPENSSL_NO_PKG_CONFIG
  cargo:rerun-if-env-changed=PKG_CONFIG_ALLOW_CROSS_x86_64-unknown-linux-musl
  cargo:rerun-if-env-changed=PKG_CONFIG_ALLOW_CROSS_x86_64_unknown_linux_musl
  cargo:rerun-if-env-changed=TARGET_PKG_CONFIG_ALLOW_CROSS
  cargo:rerun-if-env-changed=PKG_CONFIG_ALLOW_CROSS
  cargo:rerun-if-env-changed=PKG_CONFIG_x86_64-unknown-linux-musl
  cargo:rerun-if-env-changed=PKG_CONFIG_x86_64_unknown_linux_musl
  cargo:rerun-if-env-changed=TARGET_PKG_CONFIG
  cargo:rerun-if-env-changed=PKG_CONFIG
  cargo:rerun-if-env-changed=PKG_CONFIG_SYSROOT_DIR_x86_64-unknown-linux-musl
  cargo:rerun-if-env-changed=PKG_CONFIG_SYSROOT_DIR_x86_64_unknown_linux_musl
  cargo:rerun-if-env-changed=TARGET_PKG_CONFIG_SYSROOT_DIR
  cargo:rerun-if-env-changed=PKG_CONFIG_SYSROOT_DIR
  run pkg_config fail: pkg-config has not been configured to support cross-compilation.

  Install a sysroot for the target platform and configure it via
  PKG_CONFIG_SYSROOT_DIR and PKG_CONFIG_PATH, or install a
  cross-compiling wrapper for pkg-config and set it via
  PKG_CONFIG environment variable.

  --- stderr
  thread 'main' panicked at /home/.cargo/registry/src/index.crates.io-6f17d22bba15001f/openssl-sys-0.9.102/build/find_normal.rs:190:5:


  Could not find directory of OpenSSL installation, and this `-sys` crate cannot
  proceed without this knowledge. If OpenSSL is installed and this crate had
  trouble finding it,  you can set the `OPENSSL_DIR` environment variable for the
  compilation process.

  Make sure you also have the development packages of openssl installed.
  For example, `libssl-dev` on Ubuntu or `openssl-devel` on Fedora.

  If you're in a situation where you think the directory *should* be found
  automatically, please open a bug at https://github.com/sfackler/rust-openssl
  and include information about your system as well as this message.

  $HOST = x86_64-unknown-linux-gnu
  $TARGET = x86_64-unknown-linux-musl
  openssl-sys = 0.9.102

У меня такая фигня пошла, когда я решил добавить Sentry в свой проект.

Решение следующее:

Выполняем команды:

sudo apt-get update
sudo apt-get install -y musl-dev musl-tools linux-headers-$(uname -r)

sudo ln -s /usr/include/x86_64-linux-gnu/asm /usr/include/x86_64-linux-musl/asm && ln -s /usr/include/asm-generic /usr/include/x86_64-linux-musl/asm-generic && ln -s /usr/include/linux /usr/include/x86_64-linux-musl/linux
sudo mkdir /musl
wget https://github.com/openssl/openssl/archive/OpenSSL_1_1_1f.tar.gz
tar zxf OpenSSL_1_1_1f.tar.gz 
cd openssl-OpenSSL_1_1_1f/
CC="musl-gcc -fPIE -pie -static -idirafter /usr/include/ -idirafter /usr/include/x86_64-linux-gnu/" ./Configure no-shared no-async --prefix=/musl --openssldir=/musl/ssl linux-x86_64
make depend
make -j$(nproc)
sudo make install

Экспортируем переменные окружения:
export PKG_CONFIG_ALLOW_CROSS=1
export OPENSSL_STATIC=true
export OPENSSL_DIR=/musl

Пробуем выполнять сборку:
cargo build --release --target=x86_64-unknown-linux-musl

Rust — увеличить по счетчику значение в HashMap

Я использовал хэш-таблицу в качестве дедубликатора имени ключа. Аналог ассоциативного массива в PHP, когда есть имя ключа и его значение и необходимо добавлять новые значения по имени ключа, при этом нам не нужно каждый раз дублировать эти имена ключей- они должны быть уникальными. Но при этом нам нужно для каждого ключа увеличить его значение, например на +1.

use std::collections::HashMap;
fn main() { 
     
let mut fruits:HashMap<String, i32> = HashMap::new();  

fruits.insert(String::from("sds"), 122); 

fruits.insert(String::from("qqqq"), 22);    

fruits.entry("sds".to_string()).and_modify(|count| *count += 1).or_insert(0);  

let first_fruit = fruits.get("sds"); //123    

println!("{:?}", first_fruit);}

Пример на Replit тут

Rust — счетчик в ведущими нулями

Задача:  вывести счетчик с ведущими нулями, пример 0001, 0002 и т.д.

Задача не сложная, но не стандартная и предполагает несколько вариантов реализации. Мой вариант реализован на том, что мы считаем длину стандартного int счетчика и в зависимости от нее добавляем перед ним нужно количество нулей, которые у нас являются уже строкой.

fn main(){
  
  (1..1002).for_each(|n| {
        let _str: String = n.to_string();
        let lenght = _str.len();    
        let mut _zero = String::from("000");

        if lenght == 2{
            _zero = String::from("00");
        }
        else if lenght == 3{
            _zero = String::from("0");
        }
        else if lenght == 4{
            _zero = String::from("");
        }
    
      println!("{}{}",_zero, n);
});
  
    
}

Реализация этого же через match:

fn main(){
  
  (1..1002).for_each(|n| {
        let _str: String = n.to_string();
        let lenght = _str.len();    
        
    match lenght {
        2 => {println!("00{}", n);}
        3 => {println!("0{}", n);}
        4 => {println!("{}", n);}
        _ => {println!("000{}", n);}
    }
        
    
});
  
    
}

Rust — вырезать подстроку с начала и конца строки

fn main() {

    let str = "/app/dima/var/test_log.stat.json";  
    //cut "/app/dima/var/"
     let slice = &str[14..];
    //cut ".stat.json"
     let len = slice.len() - 10;
    let substr = &slice[..len];  
    
     println!("{}", substr);
}

Логика такая:

  1. сначала удаляем путь — он содержит в данном случае постоянную длину.
  2. удаляем путь
  3. вычисляем длину строки
  4. удаляем длину подстроки .stat.json

Пример работающего кода

Rust — вывести тип переменной

/*
show me type of variable
use example: println!("{}",variable.type_name());
*/
pub trait AnyExt {
    fn type_name(&self) -> &'static str;
}

impl<T> AnyExt for T {
    fn type_name(&self) -> &'static str {
        std::any::type_name::<T>()
    }
}

fn main() {
let num = 1; 
println!("{}",num.type_name());
}

Результат в данном случае будет :

i32

Rust — кросскомпиляция. Посмотреть набор инструментов.

Для кросскомпиляции в Rust нужно установить набор библиотек, необходимых для компиляции на определенной платформе.

Чтобы посмотреть установленные набор : rustup show

Чтобы добавит например musl , то делаем rustup target add x86_64-unknown-linux-musl

Смотрим rustup show

$ rustup show
.Default host: x86_64-unknown-linux-gnu
rustup home:  /home/dima/.rustup

installed targets for active toolchain
--------------------------------------

x86_64-unknown-linux-gnu
x86_64-unknown-linux-musl

active toolchain
----------------

stable-x86_64-unknown-linux-gnu (default)
rustc 1.40.0 (73528e339 2019-12-16)

Теперь компилируем

$ cargo run --target=x86_64-unknown-linux-musl
   Compiling cfg-if v0.1.10
   Compiling ppv-lite86 v0.2.6
   Compiling libc v0.2.66
   Compiling getrandom v0.1.13
   Compiling c2-chacha v0.2.3
   Compiling rand_core v0.5.1
   Compiling rand_chacha v0.2.1
   Compiling rand v0.7.2
   Compiling read_file v0.1.0 (/home/dima/Rust/read_file)
    Finished dev [unoptimized + debuginfo] target(s) in 36.55s
     Running `target/x86_64-unknown-linux-musl/debug/read_file`
Random u8: 252
Random u16: 4832
Random u32: 141195676
Random i32: -1677746107
Random float: 0.22141390568216823