【Rust】websocketのreceive

echoサーバにリクエストを送り、このレスポンスが、”foo”なので、received_msgがfooだと思っていたが、

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut ws = WebSocket::connect("wss://echo.websocket.org/").await?;
    ws.send_text("foo".to_string()).await?;
    ws.receive().await?;
    if let Frame::Text { payload: received_msg, .. } =  ws.receive().await? {
        println!("{}", received_msg);
    }
    ws.close(None).await?;
    Ok(())
}  

Finished `dev` profile [unoptimized + debuginfo] target(s) in 1.60s
Running `target/debug/app`
foo

以下のように書くと、”Request served by *****”がレスポンスで帰ってくる。websocketのreceiveは以下のように書くのが正解

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut ws = WebSocket::connect("wss://echo.websocket.org/").await?;
    ws.send_text("foo".to_string()).await?;
    if let Frame::Text { payload: received_msg, .. } =  ws.receive().await? {
        println!("{}", received_msg);
    }
    ws.close(None).await?;
    Ok(())
}   

Finished `dev` profile [unoptimized + debuginfo] target(s) in 2.07s
Running `target/debug/app`
Request served by 7811941c69e658

【Rust】ファイルの上書き処理

File::createとwrite_allで元のデータは上書かれる。
例えば、元データが4行で、上書きデータが2行だった場合でも、上書き後は2行になる。

{"family":"john","first":"fox"}
{"family":"adam","first":"can"}
{"family":"john","first":"fox"}
{"family":"adam","first":"can"}
use serde::{Serialize, Deserialize};
use std::path::Path;
use std::fs::{File};
use std::io::{Write};

#[derive(Serialize, Deserialize, Clone, Debug)]
struct Name {
    family: String,
    first: String,
}

#[tokio::main]
async fn main() {

    let name1 = Name {family:"yamada".to_string(), first: "taro".to_string()};
    let name2 = Name {family:"sato".to_string(), first: "kazuki".to_string()};

    let mut vect: Vec<Name> = Vec::new();
    vect.push(name1);
    vect.push(name2);

    let file_path = format!("./data/names.txt");
    let mut file = File::create(file_path.clone()).unwrap();
    for name in vect {
        let serialized: Vec<u8> = serde_json::to_vec(&name).unwrap();
        file.write_all(&serialized).expect("write failed");
        file.write_all(b"\n").expect("write failed");
    }
    println!("done");

}  
{"family":"yamada","first":"taro"}
{"family":"sato","first":"kazuki"}

なるほどね!

【AWS/EC2】EBSを拡張した後の割り当て処理

$ df
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/root 7034376 7015828 2164 100% /
tmpfs 232532 1052 231480 1% /dev/shm
tmpfs 93016 3224 89792 4% /run
tmpfs 5120 0 5120 0% /run/lock
/dev/xvda16 901520 80068 758324 10% /boot
/dev/xvda15 106832 6246 100586 6% /boot/efi
tmpfs 46504 12 46492 1% /run/user/1000


EBSの設定で20GBに拡張します。
$ sudo growpart /dev/xvda 1
$ sudo resize2fs /dev/root
$ df
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/root 19221248 7032216 12172648 37% /
tmpfs 232532 1052 231480 1% /dev/shm
tmpfs 93016 896 92120 1% /run
tmpfs 5120 0 5120 0% /run/lock
/dev/xvda16 901520 80068 758324 10% /boot
/dev/xvda15 106832 6246 100586 6% /boot/efi
tmpfs 46504 12 46492 1% /run/user/1000

ほう…

【ubuntu2204】error: linking with `cc` failed: exit status: 1

$ cargo run

error: linking with `cc` failed: exit status: 1
|
= note: LC_ALL=”C” PATH=”/home/ubuntu/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/bin:/home/ubuntu/.local/bin:/home/ubuntu/.cargo/bin:/usr/local/sbin:
//

“-nodefaultlibs”
= note: some arguments are omitted. use `–verbose` to show all linker arguments
= note: collect2: fatal error: ld terminated with signal 9 [Killed]
compilation terminated.

最後に、「collect2: fatal error: ld terminated with signal 9 [Killed]」と表示されていますが、これが、メモリ不足のエラーの模様
https://stackoverflow.com/questions/46259776/collect2-fatal-error-ld-terminated-with-signal-9-killed

swapファイルを作成すると、エラーが消えます。
$ sudo fallocate -l 1G /swapfile
$ ls -lh /swapfile
$ sudo chmod 600 /swapfile
$ sudo mkswap /swapfile
$ sudo swapon /swapfile
$ sudo swapon –show
$ free -h

【Python】error: externally-managed-environment

$ pip3 install psycopg2
error: externally-managed-environment

× This environment is externally managed
╰─> To install Python packages system-wide, try apt install
python3-xyz, where xyz is the package you are trying to
install.

プロジェクトごとに仮想環境を作って、そこでインストールすることが推奨されている。
$ python3 -m venv venv
$ source venv/bin/activate
$ python3 -V
$ pip3 install psycopg2 
$ pip3 install python-dotenv
$ cd assets
$ python3 migration.py
$ deactivate

### 仮想環境を作らない方法
$ pip3 install psycopg2 –break-system-packages
これでもいける。

【Rust】日にち、時間差の計算

Unix Timeに変換して計算する。UnixTimeは秒単位のため、1日の場合は、60 * 60 * 24 = 86400となる。

    let utc_datetime: DateTime<Utc> = DateTime::parse_from_rfc3339("2025-01-01T00:00:00Z").unwrap().into();
    println!("{}", utc_datetime.timestamp());
    let utc_datetime2: DateTime<Utc> = DateTime::parse_from_rfc3339("2025-01-02T00:00:00Z").unwrap().into();
    println!("{}", utc_datetime2.timestamp());

    // 86400
    println!("{}", utc_datetime2.timestamp() - utc_datetime.timestamp());

Finished `dev` profile [unoptimized + debuginfo] target(s) in 1.24s
Running `target/debug/app`
1735689600
1735776000
86400

経過時間は、unixtimeの差を86400で割れば日数となるので、

    let base_date = "2025-01-01T00:00:00Z".to_string();
    let utc_datetime: DateTime<Utc> = DateTime::parse_from_rfc3339(&base_date).unwrap().into();
    let utc_datetime2: DateTime<Utc> = Utc::now();
    println!("{}", utc_datetime2.timestamp());
    println!("{}", (utc_datetime2.timestamp() - utc_datetime.timestamp()) / 86400);

Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.67s
Running `target/debug/app`
1741587141
68

1月1日から、68日経過していることになる。

【Python】psycopg2で複数のsql文を同時に実行する

psycopg2 の execute は、commitの前に連続して実行できる。そのため、以下のように、sql文をforループで回すことができる。

import psycopg2
import os
from dotenv import load_dotenv

load_dotenv('../.env')
PSQL_PASSWORD = os.getenv('PSQL_PASSWORD')

connection = psycopg2.connect(
    host='localhost',
    user='postgres',
    password=PSQL_PASSWORD
)
cur = connection.cursor()

sql1 = "CREATE TABLE IF NOT EXISTS person1 ( \
            id SERIAL PRIMARY KEY, \
            name TEXT NOT NULL, \
            data BYTEA \
        );"
sql2 = "CREATE TABLE IF NOT EXISTS person2 ( \
            id SERIAL PRIMARY KEY, \
            name TEXT NOT NULL, \
            data BYTEA \
        );"
sqls = [sql1, sql2]

for sql in sqls:
    cur.execute(sql)

connection.commit()
cur.close()
connection.close()

$ python3 migration.py

# \dt
List of relations
Schema | Name | Type | Owner
——–+———-+——-+———-
public | person1 | table | postgres
public | person2 | table | postgres

なるほどー

.gitignoreでフォルダのみ生かしたい時

$ tree
.
├── config
│ ├── hoge.dat
│ └── secret.pem
├── index.html
├── log
│ └── log.txt
├── src
│ └── main.rs
└── target

.gitignore

target/
congif/
target/
log/*.txt
.env

git push

これだと、logやconfigの空フォルダが生成できない。
.gitkeepをフォルダの中に置いて、以下のように書く

!config/
config/*
!config/.gitkeep
!log/
log/*.txt
!log/.gitkeep
target/
.env

すると、logやconfigは空フォルダができるが、中のファイル群は更新されない。

OK!