From ec2092ba1b97f67fafe034eaef11b76c7af6e861 Mon Sep 17 00:00:00 2001 From: Juerd Waalboer Date: Wed, 19 Jan 2022 17:37:37 +0100 Subject: [PATCH] Add json plugin for machine parseable output --- plugins/help | 3 +- plugins/json | 88 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 plugins/json diff --git a/plugins/help b/plugins/help index 38e0d45..f3abed2 100644 --- a/plugins/help +++ b/plugins/help @@ -20,6 +20,7 @@ sub command :Tab(help,wtf,omgwtfbbq) ($self, $cart, $command, @) { # On the other hand, busybox(1) has a "more" applet that gives the user # clear instructions and seems mostly harmless too. my $pipe; + my $oldhandle = select; if (open $pipe, "|-", "busybox", "more") { select $pipe; } @@ -49,7 +50,7 @@ ${bold}Advanced usage:${off} pass space separated arguments to parameters Complete each transaction with ${underline}account${off} (i.e. enter your name). END - select STDOUT; + select $oldhandle; close $pipe; return ACCEPT; diff --git a/plugins/json b/plugins/json new file mode 100644 index 0000000..2f3ad5e --- /dev/null +++ b/plugins/json @@ -0,0 +1,88 @@ +#!perl + +=head1 CAVEATS + +This module requires the Perl module "JSON" to be installed. + +Note that cent amounts are emitted as strings, not floats. This is on purpose. +They are, however, in a format that is easy to parse and convert (e.g. +JavaScript "parseFloat"). + +Note that things may be happening that don't have any JSON output. + +Note that if plugins explicitly print to STDOUT, that will break the JSON +output. Regular print (without specified filehandle) will be suppressed. + +Note that one command line may result in several separate transactions. + +Note that this plugin will always be highly experimental; re-evaluate your +assumptions when upgrading. :) + +This plugin is intended to be used together with "revbank -c 'command line'", +but you could try to use it interactively; if you do, please let me know about +your use case. + +Set the environment variable REVBANK_JSON to either "array" or "lines" (see +jsonlines.org). + +=cut + +use JSON; +my $json = JSON->new->utf8->convert_blessed->canonical; + +BEGIN { + if ($ENV{REVBANK_JSON} and $ENV{REVBANK_JSON} =~ /^(?:array|lines)$/) { + my $array = $ENV{REVBANK_JSON} eq "array"; + + # Suppress normal print output + open my $null, ">", "/dev/null"; + select $null; + + print STDOUT "[\n" if $array; + + my $count = 0; + *_log = sub($hash) { + # JSON does not allow trailing commas, argh + print STDOUT ",\n" if $array and $count++; + print STDOUT $json->encode($hash); + print STDOUT "\n" if not $array; + }; + + END { print STDOUT "\n]\n" if $array } + + # Monkey patch + *RevBank::Amount::TO_JSON = sub($self, @) { + $self->string("+"); + }; + } else { + *_log = sub { }; + } +} + + +sub hook_abort(@) { + _log({ _ => "ABORT" }); +} + +sub hook_reject($class, $plugin, $reason, $abort, @) { + _log({ _ => "REJECT", plugin => $plugin, reason => $reason, abort => $abort }); +} + +sub hook_retry($class, $plugin, $reason, $abort, @) { + _log({ _ => "RETRY", plugin => $plugin, reason => $reason, abort => $abort }); +} + +sub hook_user_created($class, $username, @) { + _log({ _ => "NEWUSER", account => $username }); +} + +# NB: stringify transaction_id because future ids might not be numeric. + +sub hook_user_balance($class, $user, $old, $delta, $new, $transaction_id, @) { + _log({ _ => "BALANCE", account => $user, old => $old, delta => $delta, new => $new, transaction_id => "$transaction_id" }); +} + +sub hook_checkout($class, $cart, $username, $transaction_id, @) { + _log({ _ => "CHECKOUT", account => $username, transaction_id => "$transaction_id" }); +} +