REQ に対しての処理の外側
実際に求められたデータを流す部分はバックグラウンドで実行する。何故ならばある REQ リクエストが求められている間にも他のリクエストが来て、それを処理しなくてはならなくなることもあるからだ。これを in.sh として別に作るが、取り敢えずは out.sh を書き続ける。
bash in.sh "$second_element" "third_element" &
inner=$!
と "&" を付ければバックグラウンド(別プロセス)で同時進行できる。しかしそのプロセスのID(PID)を保持しておかないと CLOSE が来ても kill できない。なので $! でそれを取得して変数 inner に入れている。それを REQ の次の要素、セッションID と結びつけて保つことにする。これには連想配列を使う。なので while の上で
declare -A req_rec=()
と連想配列を宣言しておく。req_rec は REQ のレコードくらいの意味でつけた。この配列に
session_id=$(tr -d '"' <<< $second_element) # REQ のセッションID
req_rec[$session_id]=$inner # 連想配列にセッションIDをキーにPIDを収める
と、REQ に応じる in.sh のプロセスIDをセッションIDとセットで追加する。
in.sh の内容は後で記す。取り敢えず REQ に対する out.sh の処理は
elif [ "$first_element" = '"REQ"' ]; then
bash in.sh "$second_element" "$third_element" &
inner=$! # in.sh のプロセスID を inner に保持
session_id=$(tr -d '"' <<< $second_element) # REQ のセッションID
req_rec[$session_id]=$inner # 連想配列にセッションIDをキーにPIDを収める
とする。
CLOSE に対する処理
CLOSE が来たらセッションIDとセットになっているプロセスIDを kill し、req_rec 配列から削除すればよい。
elif [ "$first_element" = '"CLOSE"' ]; then
session_id=$(tr -d '"' <<< $second_element) # CLOSE するのセッションID
kill $( echo ${req_rec[$session_id]} ) # プロセスIDを kill し
unset req_rec[$session_id] # req_rec から削除
out.sh の全文を以下に記すが、最初に trap 'kill $(jobs -p)' EXIT と書いておく。kill 漏れがあった場合でも out.sh を止めたとき全てのプロセスを kill するためだ。
#!/bin/bash
trap 'kill $(jobs -p)' EXIT
declare -A req_rec=()
while read -r line; do
first_element=$(echo $line | jq -c .[0])
second_element=$(echo $line | jq -c .[1])
third_element=$(echo $line | jq -c .[2:][])
if [ "$first_element" = '"EVENT"' ]; then
## 記録・保存
id=$(echo $second_element | jq '.id' | tr -d '"')
pubkey=$(echo $second_element | jq '.pubkey' | tr -d '"')
kind=$(echo $second_element | jq '.kind')
created_at=$(echo $second_element | jq '.created_at')
tags=( $(echo $second_element | jq -c .tags[][1] | tr -d '"' |
while read -r tag; do
echo "$tag"
done) ) # 配列化
tag1=${tags[0]}
tag2=${tags[1]}
tag3=${tags[2]}
tag4=${tags[3]}
sqlite3 test.db "insert into forRelay (created_at, id, author, kind, tag1, tag2, tag3, tag4) values ('$created_at', '$id', '$pubkey', '$kind', '$tag1', '$tag2','$tag3','$tag4');" # シングルクォート大事
echo $second_element > ./jsons/$created_at
echo "[\"OK\",\"$id\",true,\"\"]"
## 記録・保存 ここまで
elif [ "$first_element" = '"REQ"' ]; then
bash in.sh "$second_element" "$third_element" &
inner=$! # in.sh のプロセスID を inner に保持
session_id=$(tr -d '"' <<< $second_element) # REQ のセッションID
req_rec[$session_id]=$inner # 連想配列にセッションIDをキーにPIDを収める
elif [ "$first_element" = '"CLOSE"' ]; then
session_id=$(tr -d '"' <<< $second_element) # CLOSE するのセッションID
kill $( echo ${req_rec[$session_id]} ) # プロセスIDを kill し
unset req_rec[$session_id] # req_rec から削除
else echo "[NOTICE]" # これで誤魔化す
fi
done