Acme-RPC

 view release on metacpan or  search on metacpan

lib/Acme/RPC.pm  view on Meta::CPAN

package Acme::RPC;

Devel::Trace::trace('off') if exists $INC{'Devel/Trace.pm'};

use strict;
use warnings;

our $VERSION = '0.01';

use B;
use B::Deparse;
use Continuity;
use IO::Handle;
# use Devel::Pointer;
use JSON;
use Data::Dumper;
use Devel::Caller 'caller_cv';
use PadWalker 'peek_sub';
use Scalar::Util 'blessed';

my $comment = <<'EOF';

Todo:

* Accept JSON as input too, for the parameters!

* When taking apart CODE, do closes_over() too, not just peek_my().

* Weaken references held in %registry.

* Bug:  Second hit with an oid= finds the server not accepting.

* Optionally require a password... use Acme::RPC password => whatever;

* entersubs=1, enterpackages=1, etc args to control how far the recurse goes in building $tree.

* Maybe don't recurse into blessed objects, but dump them nicely upon request.
  Or maybe do recurse into them and dump their instance data.
  If $oid is passed then recurse into arrays, hashes, and object instance data.

* We don't dump references found inside CODE in the main view.
  But if they request a dump for that object, dump it.
  Likewise, we're not dumping arrays and hashes, but if they request a dump on it, dump it.

* JSON output on the default tree view too.
  We'd have to sanitize our tree...

* Document that people need to use Event::loop or something; an Acme module to insert calls to cede would be awesome for this

* Package names like foo:: should be hyperlinked too; should be able call ?oid=whatever&action=new&args=whatever on them

* The whole tree() recurse thing if it gets any more complicated is going to need a %seen list to avoid infinite recursion.

Think About:

* ?ref is for plain references (array, hash, scalar, code);  ?obj is for objects...?

* ?action parameter:  dump, call, set, new
  new is like call but it accepts a bare package name rather than an oid.

Done:

* The tree structure where each only leafs contain "hits" (references to things that get ?oid links made from them)
  is causing confusion and grief.
  Need a structure where for any given $node, $node->{chr(0)} is the (possible) object representing that node,
  and $node->{everything else} is the stuff under it.
  Then given a code ref, $node->{chr(0)} would be the code ref itself, and $node->{everything else} would be lexicals vars.
  Given a stash like "foo::", $node->{chr(0)} would actually be \%{'foo::'} and $node->{everything else} would be stuff in that package.

* Rather than only taking oids to dump/call, also take a path in the tree.

* lazy=1 parameter where the last $tree is re-used rather than re-computed.

* Should switch to our own recurse logic from Data::Dumper to support these other things.

* action=dump on anything; in the case of a coderef, find its source on disc or else deparse it

* action=call on coderefs and blessed objects, with an args parameter, or arg1, arg2, arg3, etc, and a method parameter for blessed objs.

* json will croak if a reference contains objects in side it somewhere.  Should handle this gracefully.

* Offer JSON output!  Not just Data::Dumper.  Do this for action=dump, action=call, and the default tree view.

* If Devel::Leak won't give us refs... have to do an Acme::State style crawl from main::, 
  but crawling into each sub and looking at its lexicals with PadWalker.
  Could make for a nice tree view.
  Would also make it easy to filter out the variables that hold refs.

* Maybe this should be called Acme::RPC.

* Actually crawl into code refs when recursing the output!

* Devel pointer is too much work also.  Maybe we should just cache $tree and then
  walk it again when passed an oid.  *sigh*  Magic isn't working for me today.
  Bleah.


EOF

# our $lt;
our $continuity;  # don't lose this reference
our @keepalive;   # stuff instances of objects created over RPC in there so they don't get garbage collected before the other end can use them
our $tree;        # cached tree
our %registry;    # oid=>objectrefs


sub import {

    Devel::Trace::trace('off') if exists $INC{'Devel/Trace.pm'};

    $continuity = Continuity->new(port => 7777, callback => sub {

        my $request = shift;
        while(1) {

            $SIG{PIPE} = 'IGNORE';

            my $action = $request->param('action') || 'dump';
            my $output = $request->param('output');
            my $ob;

            $tree = tree('main::') unless $tree and $request->param('lazy');

            #
            # if they're referencing a specific object, find it
            #

            if($request->param('oid')) {
                my $oid = $request->param('oid');
                $ob = $registry{$oid};
                $ob or do { $request->print("no object with that oid"); next; };
            } elsif($request->param('path')) {
                my @path = split m{/}, $request->param('path');
                my $node = $tree;
                while(@path) {
                    my $step = shift @path;
                    $node = $node->{$step} or do {
                        $step =~ s{[^a-z0-9:_-]}{}g;
                        $request->print("step ``$step'' not found in path");
                        $node = undef;
                        last;
                    };

 view all matches for this distribution
 view release on metacpan -  search on metacpan

( run in 0.710 second using v1.00-cache-2.02-grep-82fe00e-cpan-2c419f77a38b )