【shell】基礎から立ちかえる3

function test_func() {
    local var1
    var1=aaa

    local var2=bbb
}
function echo_self_args()
{
    echo $1
    echo "$2"
    echo ${3}
    echo "${4}"
    echo $#
    echo "$@"
}

echo_self_args arg1 arg2 'arg3 arg4' arg5
function echo_value1()
{
    local var1=local1
    echo ${FUNCNAME[0]} ':$var1:1' $var1

    echo ${FUNCNAME[0]} ':$var2:1' $var1
}

function echo_value2()
{
    local var1=local2
    echo ${FUNCNAME[0]} ':$var1:1' $var1

    local var2=local2
    echo ${FUNCNAME[0]} ':$var2:1' $var1

    echo_value1
    echo ${FUNCNAME[0]} ':$var1:1' $var1
    echo ${FUNCNAME[0]} ':$var2:1' $var1
}

var1=global
echo 'global :$var1:1:' $var1
echo 'global :$var2:1:' $var2

echo_value2
echo 'global :$var1:2:' $var1
echo 'global :$var2:2:' $var2
function return_test()
{
    if [[ -z $1 ]]; then
        echo 'arg1 is empty.'
        return 1
    fi

    echo $1
}

return_test test
echo '終了ステータス': $?
echo ---
return_test 
echo '終了ステータス': $?
echo 'Hello' > hello.txt
ls /bin /error > bin.txt 2> error.txt
ls /bin /error &> result.txt
tr hoge fuga < hoge.txt
var1=value
text=$(cat << EOF
    arg1: $1
    var1: $var1
EOF
)
echo "$text"
echo first message1 > output.txt
echo second message1 >> output.txt
echo third message1 >> output.txt

{
    echo first message2
    echo second message2
    echo third message2
} > output.txt

{ echo first message3;echo second message3;echo third message3; } > output.txt
cd /bin
pwd
var1=value1
echo $var1

(
    cd /home/vagrant
    pwd
    echo $var1
    var1=value2
    echo $var1
)

pwd
echo $var1
set -e

ls /error
mkdir /error/dir1
set -u

rm -rf $work_dir/
set -C

touch test1.txt
echo "aaa" >| test1.txt
echo "bbb" >> test1.txt

touch test2.txt
echo "ccc" > test2.txt

【shell】基礎から立ちかえる2

array=(item1 item2 'item3 item4' item5)

echo '${array[0]}': ${array[0]}
echo '${array[1]}': ${array[1]}
echo '${array[2]}': ${array[2]}
echo '${array[3]}': ${array[3]}
array=(item1 item2 'item3 item4' item5)

echo ${#array[@]}
array=(item0 [2]=item2 [4]=item4)

echo ${#array[@]}
echo ${array[0]}
echo ${array[1]}
echo ${array[2]}
echo ${array[3]}
echo ${array[4]}
echo ------------------

array[1]=item1
array[2]=
echo ${#array[@]}
echo ${array[0]}
echo ${array[1]}
echo ${array[2]}
echo ${array[3]}
echo ${array[4]}
echo ------------------
array=(item1 item2 'item3 item4' item5)

function echo_array_items() {
    echo $1
    echo $2
    echo $3
    echo $4
    echo $5
    echo ------------------------
}

echo Use '"${array[@]}"'
echo_array_items "${array[@]}"

echo Use '"${array[*]}"'
echo_array_items "${array[*]}"

echo Use '${array[@]}'
echo_array_items ${array[@]}

echo Use '${array[*]}'
echo_array_items ${array[*]}
array=(item1 item2 item3)
echo "${array[@]}"

array2=(item_a item_b "${array[@]}")
echo "${array2[@]}"

array3=("${array[@]}" item_c item_d)
echo "${array3[@]}"

array+=(item_e item_f)
echo "${array[@]}"
array=(item0 [2]=item2 [4]=item4)
echo "${!array[@]}"
if grep -n test test.txt; then
    echo $?
    echo success
else
    echo $?
    echo fail
fi
test "$1" = "test"
echo 'test コマンドの終了ステータス': $?

["$1" = "test"]
echo '[ コマンドの終了ステータス':$?

if ["$1" = "test"]; then
    echo success
else
    echo fail
fi
if [ \( "$1" = "a" -o "$2" = "b" \) -a -f test.txt ]; then
    echo '第一引数がaまたは第二引数がbで、かつtest.txtが存在しています'
fi
if [[ ("$1" = "a" || "$2" = "b" ) && -f test.txt ]]; then
    echo '第一引数がaまたは第二引数がbで、かつtest.txtが存在しています'
fi
var=$1
if [[ $var = 'hoge fuga' ]]; then
    echo success
else
    echo fail
fiv
case "$file" in
    *.csv)
        echo this is csv
        ;;
    special-* | important-*)
        echo this is special file
        ;;
    *)
        echo "Invalid file: $file"
esac
for arg in "$@"; do
    echo $arg
done
array=(aaa 'bbb ccc' ddd)
for element in "${array[@]}"; do
    echo $element
done
while [[ $# -gt 0 ]]; do
    echo $1
    shift
done
until [[ $# -eq 0 ]]; do
    echo $1
    shift
done

【shell】基礎から立ちかえる1

#!/bin/bash

echo 'hello world!'

$ chmod +x stest.sh
$ ./stest.sh
hello world!

#!/bin/bash

echo 'hello world!'
pwd
echo \
    'I' \
    'love' \
    'shell' \
    'script' \
echo
'End world!'
#!/bin/bash

var='value'
echo $var

var='change'
echo $var
#!/bin/bash

readonly var='value'
var='fuga'
var='set'
echo $var
unset var
echo $var
var=value
echo $var
var='hoge fuga'
echo $var
var=hoge fuga
echo $var
empty=''
echo \$empty: $empty
empty=
echo \$empty: $empty
echo \$undefined: $undefined
var=value
echo $var
echo \$var
echo \$var $var
echo \\

var=hoge\ fuga
echo $var
var1=value
var2='${var1}'
echo $var2
var1=value
var2="${var1}"
echo $var2
var1='hoge''fuga'
echo '$var1': $var1

var2=hoge
var3=$var1$var2
echo '$var3': $var3

echo "\$var1hoge": $var1hoge
echo "\$var1'hoge'": $var1'hoge'
echo "\${var1}hoge": ${var1}hoge
echo "\${var1}'hoge'": ${var1}'hoge'
echo '$1': $1
echo '${1}': ${2}
echo '"$3"': "$3"
echo '${10}': ${10}
echo '${11}': ${11}
echo '$10': $10
echo $0
echo $1
echo '入力値' $1
exit $1
echo ----------
echo 引数の数 $#
echo '$1'の値 $1
echo '$2'の値 $2
shift
echo $?
echo ----------
echo 引数の数 $#
echo '$1'の値 $1
echo '$2'の値 $2
shift
echo $?
echo ----------
echo 引数の数 $#
echo '$1'の値 $1
echo '$2'の値 $2
shift
echo $?
echo ----------
function echo_args() {
    echo '引数の数' $#
    echo '$1'の値 $1
    echo '$2'の値 $2
    echo '$3'の値 $3
    echo ----------
}

echo '"$@"'の場合
echo_args "$@"
echo '"$*"'の場合
echo_args "$*"
echo $$

(sleep 10; echo 'end') &
echo $!
wait $!

【Rust】グローバル(static)で変更可能なベクタ

クラスの外部から静的メンバ変数を定義するには「クラス名+”::”+静的メンバ変数名」という名前のグローバル変数を定義する。

static data: &str = "this is static variable";

fn func1(){
    println!("func1: {:?}", data);
}

fn func2(){
    println!("func2: {:?}", data);
}

fn main(){
    
    func1();
    func2();
    println!("main: {:?}", data);
}

$ ./main
func1: “this is static variable”
func2: “this is static variable”
main: “this is static variable”
staticな変数を宣言することはできるが、mutableにできない。

### once_cell
once_cellを使用すると、mutableなstaticを作成できる。

use once_cell::sync::Lazy;
use std::sync::Mutex;

static ARRAY: Lazy<Mutex<Vec<u8>>> = Lazy::new(|| Mutex::new(vec![]));

fn do_a_call(){
    ARRAY.lock().unwrap().push(1);
}

fn main() {
    do_a_call();
    do_a_call();
    do_a_call();

    println!("called {}", ARRAY.lock().unwrap().len());
}

vectorの型をu8ではなく構造体にして、一定数以上になったら関数を実行するように編集する

use once_cell::sync::Lazy;
use std::sync::Mutex;

struct Transaction {
    x: String,
    y: String,
    z: u32,
}

static Pool: Lazy<Mutex<Vec<Transaction>>> = Lazy::new(|| Mutex::new(vec![]));

fn make_block (){
    println!("blockを作成しました。");
    Pool.lock().unwrap().clear();

}

fn do_a_call(){
    let t = Transaction { x: "A".to_string(), y: "B".to_string(), z: 10};
    if Pool.lock().unwrap().len() > 4 {
        make_block();
    }
    Pool.lock().unwrap().push(t);
}

fn main() {
    do_a_call();
    do_a_call();
    do_a_call();
    do_a_call();
    do_a_call();
    do_a_call();
    do_a_call();

    println!("called {}", Pool.lock().unwrap().len());
}

Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.25s
Running `target/debug/my_web_app`
blockを作成しました。
called 2

なるほど、やりたいことはできました。これをPostされたトランザクションに対して、トランザクションプールに入れるように実装します。

static Pool: Lazy<Mutex<Vec<SignedTransaction>>> = Lazy::new(|| Mutex::new(vec![]));

fn make_block (){
    println!("blockを作成しました。");
    Pool.lock().unwrap().clear();
}

#[post("/handshake")]
async fn handshake(req_body: String)-> impl Responder {
    let req : SignedTransaction = serde_json::from_str(&req_body).unwrap();
    Pool.lock().unwrap().push(req.clone());
    if Pool.lock().unwrap().len() > 1 {
        make_block();
    }
    println!("{}", req.signature);
    HttpResponse::Ok().body(req_body)

}

Finished `dev` profile [unoptimized + debuginfo] target(s) in 4.94s
Running `target/debug/hoge`
8000E340A55A517D0F27F3A63FBE39ED576BA491DFAC89B44654AB147EC66B206B054BAAF53E318EB2721DC892B4736630F400547989AE9F7C069034ECB4DF98
blockを作成しました。
8000E340A55A517D

おおおおおおお、イイネ!

【Rust】Rustでトランザクションの受信

Post requestを受け取るにはactix-webを使う。
まず、受信のテストから。

use actix_web::{get, post, web, App, HttpResponse, HttpServer, Responder};

#[post("/handshake")]
async fn handshake(req_body: String)-> impl Responder {
    println!("{}", req_body);
    HttpResponse::Ok().body(req_body)

}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    HttpServer::new(||{
        App::new()
            .service(handshake)
    })
    .bind(("127.0.0.1", 8080))?
    .run()
    .await
}

postする
$ curl -X POST -d “{\”time\”:\”2024-12-25 22:53:36.824066840 UTC\”,\”sender\”:\”4bac6cb0f4ad6397752c3d73b88c5c86e3d88ac695118494a1732e2abd16c76acad3d6586c37c8db7e69c2f812f99275198936957d72c38d71981991123\”,\”receiver\”:\”4bac6cb0f4ad6397752c3d73b88c5c86e3d88ac695118494a1732e2abd16c76acad3d6586c37c8db7e69c2f812f99275198936957d72c38d71981991124\”,\”amount\”:10,\”signature\”:\”8000E340A55A517D0F27F3A63FBE39ED576BA491DFAC89B44654AB147EC66B206B054BAAF53E318EB2721DC892B4736630F400547989AE9F7C069034ECB4DF98\”}”

サーバ側
Finished `dev` profile [unoptimized + debuginfo] target(s) in 3.70s
Running `target/debug/hoge`
{“time”:”2024-12-25 22:53:36.824066840 UTC”,”sender”:”4bac6cb0f4ad6397752c3d73b88c5c86e3d88ac695118494a1732e2abd16c76acad3d6586c37c8db7e69c2f812f99275198936957d72c38d71981991123″,”receiver”:”4bac6cb0f4ad6397752c3d73b88c5c86e3d88ac695118494a1732e2abd16c76acad3d6586c37c8db7e69c2f812f99275198936957d72c38d71981991124″,”amount”:10,”signature”:”8000E340A55A517D0F27F3A63FBE39ED576BA491DFAC89B44654AB147EC66B206B054BAAF53E318EB2721DC892B4736630F400547989AE9F7C069034ECB4DF98″}

受信できてます。
ここで受け取ったデータからverifyすればOKですね。

use serde::{Serialize, Deserialize};

#[derive(Debug, Serialize, Deserialize)]
struct SignedTransaction {
    time: String,
    sender: String,
    receiver: String,
    amount: i32,
    signature: String,
}

#[post("/handshake")]
async fn handshake(req_body: String)-> impl Responder {
    let req : SignedTransaction = serde_json::from_str(&req_body).unwrap();;
    println!("{}", req.signature);
    HttpResponse::Ok().body(req_body)

}

Postされたデータはjsonにして、SignedTransactionの構造体で受け取ると、req.signatureというように、値を取り出すことができる。

【Rust】Rustでトランザクションを送信する

use serde::{Serialize, Deserialize};
use std::io::prelude::*;
use hex_literal::hex;
use k256::{ecdsa::{SigningKey, Signature, signature::Signer, signature::Verifier, VerifyingKey}};
use chrono::{Utc, Local, DateTime, Date};

#[derive(Serialize, Deserialize, Debug)]
struct UnsignedTransaction {
    time: String,
    sender: String,
    receiver: String,
    amount: i32,
}

#[derive(Serialize, Deserialize, Debug)]
struct SignedTransaction {
    time: String,
    sender: String,
    receiver: String,
    amount: i32,
    signature: String,
}

fn hex(bytes: &[u8]) -> String {
    bytes.iter().fold("".to_owned(), |s, b| format!("{}{:x}", s, b))
}

#[async_std::main]
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {

    let private_key: SigningKey = SigningKey::from_bytes(&hex!(
        "DCDFF4B7CA287CC7BD30ECAEF0622265DB4E14054E12954225457C3A6B84F135"
    ).into()).unwrap();
    let public_key: &VerifyingKey = private_key.verifying_key();
    let public_key_str = hex(&public_key.to_encoded_point(false).to_bytes());
    let public_key_b_str = "4bac6cb0f4ad6397752c3d73b88c5c86e3d88ac695118494a1732e2abd16c76acad3d6586c37c8db7e69c2f812f99275198936957d72c38d71981991124";

    let utc_datetime: DateTime<Utc> = Utc::now();
    let ut1 = UnsignedTransaction {time: utc_datetime.to_string(), sender: public_key_str.to_string(), receiver: public_key_b_str.to_string(), amount: 10};
    println!("{:?}", ut1);
    let serialized: String = serde_json::to_string(&ut1).unwrap();
    let sig1: Signature = private_key.sign(serialized.as_bytes());
    let signed_ut1 = SignedTransaction {time: utc_datetime.to_string(), sender: public_key_str.to_string(), receiver: public_key_b_str.to_string(), amount: 10, signature: sig1.to_string()};
 
    let uri = "https://httpbin.org/post";
    let mut res = surf::post(uri).body_json(&signed_ut1)?.await?;
    let body = res.body_string().await?;
    println!("{}", body);
    Ok(())
}

“files”: {},
“form”: {},
“headers”: {
“Accept”: “*/*”,
“Accept-Encoding”: “deflate, gzip”,
“Content-Length”: “471”,
“Content-Type”: “application/json”,
“Host”: “httpbin.org”,
“User-Agent”: “curl/8.11.0-DEV isahc/0.7.6”,
“X-Amzn-Trace-Id”: “Root=1-676c8cf1-39979cc169871725084b307e”
},
“json”: {
“amount”: 10,
“receiver”: “4bac6cb0f4ad6397752c3d73b88c5c86e3d88ac695118494a1732e2abd16c76acad3d6586c37c8db7e69c2f812f99275198936957d72c38d71981991124”,
“sender”: “4bac6cb0f4ad6397752c3d73b88c5c86e3d88ac695118494a1732e2abd16c76acad3d6586c37c8db7e69c2f812f99275198936957d72c38d71981991123”,
“signature”: “8000E340A55A517D0F27F3A63FBE39ED576BA491DFAC89B44654AB147EC66B206B054BAAF53E318EB2721DC892B4736630F400547989AE9F7C069034ECB4DF98”,
“time”: “2024-12-25 22:53:36.824066840 UTC”
},
“origin”: “hoge”,
“url”: “https://httpbin.org/post”
}

なるほど、送信側は相手のURL(IP)がわかっていれば、POSTするだけなので問題なく出来ますね。

【Rust】Actixの基礎

まずcargo newでプロジェクトを作成し、dependenciesにactixを追加します。

[dependencies]
actix-web = "4"
use actix_web::{get, post, web, App, HttpResponse, HttpServer, Responder};

#[get("/")]
async fn hello() -> impl Responder {
    HttpResponse::Ok().body("Hello world!")
}

#[post("/echo")]
async fn echo(req_body: String) -> impl Responder {
    HttpResponse::Ok().body(req_body)
}

async fn manual_hello() -> impl Responder {
    HttpResponse::Ok().body("Hey there!")
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    HttpServer::new(||{
        App::new()
            .service(hello)
            .service(echo)
            .route("/hey", web::get().to(manual_hello))
    })
    .bind(("127.0.0.1", 8080))?
    .run()
    .await
}

$ curl -X POST -d “age=30” 127.0.0.1:8080/echo
age=30

おおおおおおお、get, postまではできたな…

【Rust】surfでpostリクエストを処理したい(2)

use serde::{Deserialize, Serialize};

#[async_std::main]
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {

    #[derive(Deserialize, Serialize)]
    struct Ip {
        ip: String,
    }

    let uri = "https://httpbin.org/post";
    let data = &Ip {
        ip: "129.0.0.1".into(),
    };
    let mut res = surf::post(uri).body_json(data)?.await?;
    let body = res.body_string().await?;
    println!("{}", body);

    let uri = "https://api.ipify.org?format=json";
    let Ip { ip } = surf::get(uri).recv_json().await?;
    println!("{}", ip);
    assert!(ip.len() > 10);
    Ok(())
}

Postができる。actix-webでpostされたデータを受け取ることができるかは要確認。

【Rust】surfでpostリクエストを処理したい(1)

まずはGetリクエストから

use async_std::task;

fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
    task::block_on(async {
        let mut res = surf::get("https://httpbin.org/get").await?;
        dbg!(res.body_string().await?);
        Ok(())
    })
}
#[async_std::main]
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
    let mut res = surf::get("https://httpbin.org/get").await?;
    dbg!(res.body_string().await?);
    Ok(())
}

[src/main.rs:4:5] res.body_string().await? = “{\n \”args\”: {}, \n \”headers\”: {\n \”Accept\”: \”*/*\”, \n \”Accept-Encoding\”: \”deflate, gzip\”, \n \”Host\”: \”httpbin.org\”, \n \”User-Agent\”: \”curl/8.11.0-DEV isahc/0.7.6\”, \n \”X-Amzn-Trace-Id\”: \”Root=1-676a57b7-3de7e4ff65be3baf597f36f8\”\n }, \n \”origin\”: \”106.155.3.182\”, \n \”url\”: \”https://httpbin.org/get\”\n}\n”

【Rust】サーバのcrateを利用する

### actix-web
$ cargo new my_web_app
$ cd my_web_app

[dependencies]
actix-web = "4"

main.rs

use actix_web::{web, App, HttpResponse, HttpServer, Responder};

async fn greet() -> impl Responder {
    HttpResponse::Ok().body("Hello, world!")
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    HttpServer::new(||{
        App::new()
            .route("/", web::get().to(greet))
    })
    .bind("127.0.0.1:8080")?
    .run()
    .await
}

$ curl 127.0.0.1:8080
Hello, world!

ほう

### Rocket
$ cargo new rocket_web_app
$ cd rocket_web_app
$ rustup override set nightly

#[macro_use] extern crate rocket;

#[get("/")]
fn index() -> &'static str {
    "Hello, world!"
}

#[launch]
fn rocket() -> _ {
    rocket::build().mount("/", routes![index])
}

$ cargo run
Compiling rocket_web_app v0.1.0 (/home/vagrant/dev/rust/rocket_web_app)
error[E0463]: can’t find crate for `rocket`
–> src/main.rs:1:14
|
1 | #[macro_use] extern crate rocket;
| ^^^^^^^^^^^^^^^^^^^^ can’t find crate
….

rocketの方は色々エラーが出るので、少し触った感じではactix-webの方が使いやすそう..