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 — установка через proxy c выводом расширенной информации об установке

Пришлось извращаться с установкой внутри корп. сети с закрытым прямым доступом в Интернет и еще стала выпадать ошибка что на девайсе не достаточно места.

По умолчанию Rust для установки использует домашнюю директорию пользователя, поэтому если видите такую ошибку с местом — увеличьте размер тома.

Далее чтобы произвести установку через прокси нужно к стандартному curl-запросу добавить следующие параметры:

curl -x http://proxy.ru:port --proxy-user 'user:pass' --insecure --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -v -y

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 тут

RabbitMQ — отправка и чтение очереди через curl

Данный запрос можно делать даже из bash в Linux так как используются стандартные инструменты.

Все необходимое (обменник, очереди) можно создать через WEB-интерфейс RabbitMQ Managment. Предполагаем , что они уже созданы.

Отправляем сообщение в очередь.

В примере ниже :

vhost — имя хоста (exchanges)

delivery_mode 2 — записываем в режиме когда данные очереди сохраняются даже после падения сервера (сохраняются на диск)

routing_key — имя нашей очереди

payload — в данном случае строка , которую мы передаем в сообщении

%2F/amq.default — имя обменника внутри хоста

curl -s -u user:password -H "Accept: application/json" -H "Content-Type:application/json" -X POST -d'{
    "vhost": "Test_Virtual_Host",
    "properties": {
        "delivery_mode": 2,
        "headers": {}
    },
    "routing_key": "testqueues",
    "payload":"/dfgdfgfd/dfgdfg/dfgdfgfdg.dat",
    "headers": {},
    "props": {},
    "payload_encoding": "string"
}' http://127.0.0.1:15672/api/exchanges/%2F/amq.default/publish

Читаем сообщение.

curl -s -u user:password -H "content-type:application/json" -X POST -d'{
"count":2,
"ackmode":"ack_requeue_false",
"encoding":"auto",
"truncate":5000
}' http://127.0.0.1:15672/api/queues/%2F/testqueues/get

Удалить обменник через curl.

curl -s -u admin:1234567890 -X DELETE http://127.0.0.1:15672/api/vhosts/Test_Virtual_Host

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

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