]> git.corax.cc Git - toolbox/commitdiff
utils: Implement hooks in ipc-tap and ipc-inject
authorMatthias Kruk <m@m10k.eu>
Sat, 1 Oct 2022 12:47:33 +0000 (21:47 +0900)
committerMatthias Kruk <m@m10k.eu>
Sat, 1 Oct 2022 12:47:33 +0000 (21:47 +0900)
To correctly forward foundry messages using ipc-tap and ipc-inject,
it is necessary to move data that is usually not transferred over
IPC messages. In order to transfer this data over ipc-tap and
ipc-inject, hooks are necessary that allow user-data to be generated
on the ipc-tap side and consumed on the ipc-inject side.

This commit implements a simple mechanism that allows the user to
specify hooks that are called by ipc-tap whenever a message on a
user-defined topic is encountered. The hook can then inject
messages into ipc-tap's data stream. On the ipc-inject side, the
user may define hooks that are called when a user-message with a
application-defined tag is encountered, allowing the injected
message to be handled on the ipc-inject side.

utils/ipc-inject.sh
utils/ipc-tap.sh

index b0f418da4a3a806bc4a01b492fd8b657b11049b5..bb0000a1b2e5d45171eed9e3e4d0734950af4e46 100755 (executable)
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <https://www.gnu.org/licenses/>.
 
+add_hook() {
+       # local name="$1" # not used
+       local value="$2"
+
+       local tag
+       local handler
+
+       tag="${value%%:*}"
+       handler="${value#*:}"
+
+       hooks["$tag"]="$handler"
+       return 0
+}
+
 signal_handler() {
        signal_received=1
 }
 
+handle_hook_data() {
+       local endpoint="$1"
+       local hook_data="$2"
+
+       local tag
+       local data
+       local handler
+
+       if ! tag=$(json_object_get "$hook_data" "tag"); then
+               log_warn "Dropping message without tag"
+               return 1
+       fi
+
+       handler="${hooks[$tag]}"
+
+       if [[ -z "$handler" ]]; then
+               log_warn "No handler for tag $tag"
+               return 0
+       fi
+
+       if ! data=$(json_object_get "$hook_data" "data"); then
+               log_warn "Dropping message without data"
+               return 1
+       fi
+
+       if ! "$handler" <<< "$data"; then
+               return 1
+       fi
+
+       return 0
+}
+
+handle_ipc_message() {
+       local endpoint="$1"
+       local data="$2"
+
+       local topic
+
+       if ! topic=$(ipc_msg_get_topic "$data"); then
+               log_warn "Dropping message without topic"
+               return 1
+       fi
+
+       if ! ipc_endpoint_publish "$endpoint" "$topic" "$data"; then
+               log_error "Could not publish message for $topic on $endpoint"
+               return 1
+       fi
+
+       return 0
+}
+
+handle_message() {
+       local endpoint="$1"
+       local message="$2"
+
+       local decoded
+       local type
+       local data
+       local handler
+
+       if ! decoded=$(base64 -d <<< "$message"); then
+               log_warn "Could not decode message"
+               return 1
+       fi
+
+       if ! type=$(json_object_get "$decoded" "type") ||
+          ! data=$(json_object_get "$decoded" "data"); then
+               log_warn "Could not parse message"
+               return 1
+       fi
+
+       handler="${message_handler[$type]}"
+
+       if [[ -n "$handler" ]]; then
+               "$handler" "$endpoint" "$data"
+       fi
+
+       return 0
+}
+
 main() {
        local endpoint
        local message
+       declare -gA hooks
        declare -gi signal_received
+       declare -gA message_handler
+
+       message_handler["HookData"]=handle_hook_data
+       message_handler["IPCMessage"]=handle_ipc_message
 
        signal_received=0
 
+       opt_add_arg "k" "hook" "v" ""                \
+                   "Command for handling hook data" \
+                   '^[^:]+:.*$'                     \
+                   add_hook
+
        if ! opt_parse "$@"; then
                return 1
        fi
@@ -39,16 +143,7 @@ main() {
        trap signal_handler INT TERM ABRT ALRM USR1 USR2
 
        while (( signal_received == 0 )) && read -r message; do
-               local topic
-
-               if ! topic=$(ipc_msg_get_topic "$message"); then
-                       log_warn "Dropping message without topic"
-                       continue
-               fi
-
-               if ! ipc_endpoint_publish "$endpoint" "$topic" "$message"; then
-                       log_error "Could not publish message for $topic on $endpoint"
-               fi
+               handle_message "$endpoint" "$message"
        done
 
        log_info "Closing endpoint $endpoint"
index 45279b0d9ec09e8f7a4f3ad69dbd50de484e05b1..df49a1364077181a2dde921eab85e3cab9c1f2c6 100755 (executable)
@@ -25,10 +25,57 @@ add_topic() {
        return 0
 }
 
+add_hook() {
+       # local name="$1" # not needed
+       local value="$2"
+
+       local topic
+       local hook
+
+       topic="${value%%:*}"
+       hook="${value#*:}"
+
+       # hooks is inherited from main() via opt_parse()
+       hooks["$topic"]="$hook"
+}
+
 signal_handler() {
        signal_received=1
 }
 
+output_message() {
+       local type="$1"
+       local data="$2"
+
+       local message
+
+       if ! message=$(json_object "type" "$type" \
+                                  "data" "$data"); then
+               return 1
+       fi
+
+       if ! base64 -w 0 <<< "$message"; then
+               return 1
+       fi
+
+       printf '\n'
+       return 0
+}
+
+invoke_hooks() {
+       local topic="$1"
+       local message="$2"
+
+       local data
+
+       if data=$("${hooks[$topic]}" <<< "$message") &&
+          [[ -n "$data" ]]; then
+               output_message "HookData" "$data"
+       fi
+
+       return 0
+}
+
 tap_topics() {
        local topics=("$@")
 
@@ -62,10 +109,19 @@ tap_topics() {
 
                while (( signal_received == 0 )); do
                        local message
+                       local topic
 
-                       if message=$(ipc_endpoint_recv "$endpoint" 5); then
-                               printf '%s\n' "$message"
+                       if message=$(ipc_endpoint_recv "$endpoint" 5); then
+                               continue
                        fi
+
+                       if ! topic=$(ipc_msg_get_topic "$message"); then
+                               log_warn "Dropping message without topic"
+                               continue
+                       fi
+
+                       invoke_hooks "$topic" "$message"
+                       output_message "IPCMessage" "$message"
                done
        fi
 
@@ -77,10 +133,18 @@ tap_topics() {
 
 main() {
        local topics
+       declare -gA hooks
 
        topics=()
 
-       opt_add_arg "t" "topic" "rv" "" "A topic to tap into" "" add_topic
+       opt_add_arg "t" "topic" "rv" ""            \
+                   "A topic to tap into"          \
+                   ''                             \
+                   add_topic
+       opt_add_arg "k" "hook"  "v"  ""            \
+                   "Hook to execute upon receipt" \
+                   '^[^:]+:.+$'                   \
+                   add_hook
 
        if ! opt_parse "$@"; then
                return 1
@@ -98,7 +162,7 @@ main() {
                exit 1
        fi
 
-       if ! include "log" "opt" "ipc"; then
+       if ! include "log" "opt" "ipc" "json"; then
                exit 1
        fi