Access remote actors, publish services, subscribe to messages and state updates etc., via the Syndicate network protocol from bash (and perhaps other shells).
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

166 lines
4.2 KiB

#!/bin/bash
set -euo pipefail
ds_handle=0
ds_buf=""
declare -A ds_handles
declare -A ds_handle_oids
declare -A ds_object_map
declare -A ds_retraction_handlers
ds_project() {
# cargo install preserves-tools
local input="$1"
local selector="$2"
shift 2
echo "$input" | preserves-tool convert --indent=no --select "$selector" "$@"
}
ds_connect_stdio() {
eval "$1"
exec 5<&0 6>&1
ds_flush
ds_mainloop
}
ds_connect() {
local addr=$1
case $(ds_project "$addr" ".^") in
tcp) nc_args="$(ds_project "$addr" ". 0" --output-format=unquoted) $(ds_project "$addr" ". 1")";;
unix) nc_args="-U $(ds_project "$addr" ". 0" --output-format=unquoted)";;
stdio) ds_connect_stdio "$2"; return;;
*) echo "ds_connect: address '$addr' not supported"; return 1;;
esac
local f=$(mktemp -u /tmp/ds.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX)
mkfifo $f
trap "rm -f $f" 2 EXIT RETURN
{
eval "$2"
ds_flush
ds_mainloop
} 5< <(nc $nc_args <$f) 6>$f
}
ds_send() {
echo "$@" >&6
# echo "SENDING: $@"
}
ds_mainloop() {
while read ds_packet
do
# echo "RECEIVING: $ds_packet"
while read ds_turnevent
do
ds_dispatch "$(ds_project "$ds_turnevent" '. 0')" "$(ds_project "$ds_turnevent" '. 1')"
done < <(ds_project "$ds_packet" 'seq /')
ds_flush
done <&5
}
ds_dispatch() {
ds_event="$2"
eval "${ds_object_map[$1]}"
}
ds_action() {
case $(ds_project "$1" '.embedded . 0') in
0) ds_dispatch "$(ds_project "$1" '.embedded . 1')" "$2" ;;
1) ds_buf="${ds_buf}[$(ds_project "$1" '.embedded . 1') $2]" ;;
esac
}
ds_flush() {
if [ -n "$ds_buf" ]
then
ds_send "[$ds_buf]"
ds_buf=""
fi
}
ds_assert() {
local h="$ds_handle"
ds_handle=$(($ds_handle + 1))
ds_action "$1" "<assert $2 $h>"
if [ -n "${3:-}" ]
then
ds_handle_oids[$3]="$1"
ds_handles[$3]="$h"
fi
}
ds_retract() {
ds_action "${ds_handle_oids[$1]}" "<retract ${ds_handles[$1]}>"
}
ds_message() {
ds_action "$1" "<message $2>"
}
ds_object() {
local oid="$ds_handle"
ds_handle=$(($ds_handle + 1))
ds_object_map[$oid]="$2"
printf -v $1 '%s' "#![0,$oid]"
}
demo() {
demo_ds_resolved() {
local oid="$(ds_project "$ds_event" '^ assert . 0 .embedded . 1')"
if [ -n "$oid" ]
then
ds_ref="#![1 $oid]"
echo "Dataspace: $ds_ref"
username="user$$"
declare -A demo_user_presence
demo_presence() {
case $(ds_project "$ds_event" .^) in
assert)
local h="$(ds_project "$ds_event" '. 1')"
local who="$(ds_project "$ds_event" '. 0 . 0')"
demo_user_presence[$h]="$who"
echo "JOIN: $who"
;;
retract)
local h="$(ds_project "$ds_event" '. 0')"
local who="${demo_user_presence[$h]}"
echo "PART: $who"
unset 'demo_user_presence[$h]'
;;
esac
}
ds_object presence demo_presence
ds_assert "$ds_ref" "<Observe <compound <rec Present 1> {0: <bind <_>>}> $presence>"
ds_assert "$ds_ref" "<Present \"$username\">"
demo_utterance() {
ds_project "$ds_event" '^ message . 0'
}
ds_object utterance demo_utterance
ds_assert "$ds_ref" "<Observe <compound <rec Says 2> {0: <bind <_>> 1: <bind <_>>}> $utterance>"
ds_flush
ds_mainloop </dev/null &
mainloop_pid=$!
while read line
do
ds_message "$ds_ref" "<Says \"$username\" \"$line\">"
ds_flush
done </dev/tty
kill $mainloop_pid
exit 0
fi
}
ds_object bootk demo_ds_resolved
ds_connect \
'<unix "./sock">' \
'ds_assert "#![1 0]" "<resolve <ref \"syndicate\" [] #x\"a6480df5306611ddd0d3882b546e1977\"> $bootk>"'
}
demo