A bash exchange example
A Linkspace Exchange Tutorial
Available in the pkg or in repository/linkspace/examples/
Available in the repo/linkspace/examples/
See repo/dev/exchange.md for some open design issues/notes.
This is a rather dumb client & host. It simply forwards requests. It does no pruning before sending or receiving.
- anyhost client
#!/bin/bash set -euo pipefail export SERVER=${SERVER:-${1:-"127.0.0.1:5020"}} export LK_GROUP=${LK_GROUP:-[#:test]} socat /dev/null tcp:$SERVER export LK_PASS=$(lk key --no-pubkey --no-enckey --display-pass) echo Connecting $LK_GROUP $SERVER socat tcp:$SERVER,keepalive exec:"anyhost.handshake.sh connect anyhost.client-io.sh",fdout=4 #websocat -E --binary ws://$SERVER sh-c:"handshake.sh connect client_io.sh"
#!/bin/bash # parent should set out to fd4. otherwise add a exec 4>&1 1>&2 set -euo pipefail function fin (){ kill -9 -- -$$ $(jobs -p) 2>/dev/null || true echo Disconnected - $THEIR_KEY } trap "fin" EXIT cd $SESSION # ensure we have a fixed [b:...] repr (lns [#:name] could update between proc calls) LK_GROUP=$(lk eval "$LK_GROUP" | lk encode b:32) THEIR_KEY=$(lk eval "$THEIR_KEY" | lk encode b:32) echo SESSION=$SESSION echo THEIR_KEY=$THEIR_KEY echo LK_GROUP=$LK_GROUP lk link --create [u64:0] ":[#:0]:/rxlog/$THEIR_KEY" --write db lk link --create [u64:0] ":[#:0]:/txlog/$THEIR_KEY" --write db LAST_RX=$(lk --private watch --max 1 ":[#:0]:/rxlog/$THEIR_KEY" | lk pktf [create:str]) LAST_TX=$(lk --private watch --max 1 ":[#:0]:/txlog/$THEIR_KEY" | lk pktf [create:str]) lk eval "last rx [u64:$LAST_RX/us:str]\nlast tx [u64:$LAST_TX/us:str]\n" lk status set exchange $LK_GROUP process anyhost-client --data-str "$(lk e "OK\nPID:$$\nSESSION:$SESSION")" --data-repeat & export LK_SKIP_HASH=true # save reads from stdin, ie. the server LK_SKIP_HASH=false lk save --new db --new stdout \ | lk pktf --inspect "RX [domain:str] [spacename:str] [hash:str]" \ | lk --private collect ":[#:0]:/rxlog/$THEIR_KEY" \ --min-interval 1m \ --forward null \ --write db & # read the pull request made by other apps and place them into the group lk --private watch --new-only "[f:exchange]:[#:0]:/pull/$LK_GROUP:**" \ | lk --private rewrite \ --group $LK_GROUP \ --write db --write stdout sign-all \ | lk p ">>>>new request [hash:str]\n[data]\n<<<<" & # The exchange logic is to have every piece of data created locally send to a server lk watch --bare --mode log-asc -- "group:=:$LK_GROUP" "hop:=:[u32:0]" "recv:>:[u64:$LAST_TX]" \ | lk get-links skip \ | lk dedup \ | lk pktf --inspect "[now:str] SENDING [hash:str]" \ | tee --output-error=exit >( cat >&4 ) \ | lk --private collect ":[#:0]:/txlog/$THEIR_KEY" \ --min-interval 1m \ --forward null \ --write db & echo PIDS $(jobs -p) wait -n
- handshake
#!/bin/bash set -euo pipefail if [[ ${SOCAT_PEERADDR+x} ]] then export THEIR_ADDR=$SOCAT_PEERADDR:$SOCAT_PEERPORT else # websocat export THEIR_ADDR=${WEBSOCAT_CLIENT:-$SERVER} fi export SESSION=$(mktemp -dt $THEIR_ADDR.XXXXX) MODE=${1:-serve} lk handshake --max-diff-secs 6000 \ --write stdout --write file:$SESSION/handshake.out \ --forward file:$SESSION/handshake.in \ $MODE >&4 export THEIR_KEY=$(cat $SESSION/handshake.in | lk filter --bare --signed --max-new 1 | lk pktf "[pubkey/?:b]") echo Connected $THEIR_ADDR - Their Key : $THEIR_KEY 1>&2 exec ${@:2}
- anyhost server
#!/bin/bash set -euo pipefail export PORT=${PORT:-"5020"} echo My Key $(lk key) echo Serving $LK_GROUP $PORT export LK_PASS=$(lk key --no-pubkey --no-enckey --display-pass) function fin (){ kill -9 -- -$$ kill -9 -- $(jobs -p) 2>/dev/null || true echo Disconnected - $LK_GROUP $PORT } trap "fin" EXIT lk status set exchange $LK_GROUP process anyhost-client --data-str "$(lk e "OK\nPID:$$\nwe're hosting")" --data-repeat & socat tcp-listen:$PORT,fork exec:"anyhost.handshake.sh serve anyhost.serve-io.sh",fdout=4 & PIDS=$(jobs -p) echo PIDS $PIDS wait -- $PIDS #websocat -e -E --binary --ping-timeout 15 --ping-interval 10 \ # ws-l:0.0.0.0:5020 sh-c:"strace -e 'trace=!all' handshake.sh serve serve_io.sh"
#!/bin/bash # parent should set out to fd4. otherwise add a exec 4>&1 1>&2 set -euo pipefail PID=$$ function fin (){ kill -9 -- -$$ $(jobs -p) 2>/dev/null || true echo $PID Disconnected - $THEIR_KEY } trap "fin" EXIT cd $SESSION # ensure we have a fixed [b:...] repr (lns [#:name] could update between proc calls) LK_GROUP=$(lk eval "$LK_GROUP" | lk encode b:32) THEIR_KEY=$(lk eval "$THEIR_KEY" | lk encode b:32) echo SESSION=$SESSION echo THEIR_KEY=$THEIR_KEY echo LK_GROUP=$LK_GROUP echo PID=$PID lk link --create [u64:0] ":[#:0]:/rxlog/$THEIR_KEY" --write db lk link --create [u64:0] ":[#:0]:/txlog/$THEIR_KEY" --write db LAST_RX=$(lk --private watch --max 1 ":[#:0]:/rxlog/$THEIR_KEY" | lk pktf [create:str]) LAST_TX=$(lk --private watch --max 1 ":[#:0]:/txlog/$THEIR_KEY" | lk pktf [create:str]) lk eval "last rx [u64:$LAST_RX/us:str]\nlast tx [u64:$LAST_TX/us:str]\n" export LK_SKIP_HASH=true # save reads from std. i.e. what the client is sending LK_SKIP_HASH=false lk save --new db --new stdout \ --old file:>( lk pktf "$PID Ignored [hash:str] (old)" >&2 ) \ | lk pktf --inspect "$PID RX [domain:str] [spacename:str] [hash:str]" \ | lk --private collect ":[#:0]:/rxlog/$THEIR_KEY" \ --min-interval 1m \ --forward null \ --write db > /dev/null & # Read new request keypoints and return their content lk watch --new-only "[f:exchange]:$LK_GROUP:/pull/$LK_GROUP:**" -- "pubkey:=:$THEIR_KEY" \ | lk pktf --inspect ">>>>Pull req [hash:str]\n[data]\n<<<<$PID " \ | lk multi-watch \ | lk dedup \ | lk pktf --inspect "$PID Tx [hash:str]" >&4 echo PIDS $(jobs -p) wait -n