object proxying system
Matt S Trout [Sun, 30 Oct 2011 06:10:16 +0000 (06:10 +0000)]
lib/Tak/ObjectClient.pm [new file with mode: 0644]
lib/Tak/ObjectProxy.pm [new file with mode: 0644]
lib/Tak/ObjectService.pm [new file with mode: 0644]

diff --git a/lib/Tak/ObjectClient.pm b/lib/Tak/ObjectClient.pm
new file mode 100644 (file)
index 0000000..2761cc6
--- /dev/null
@@ -0,0 +1,63 @@
+package Tak::ObjectClient;
+
+use Tak::ObjectProxy;
+use Moo;
+
+with 'Tak::Role::ObjectMangling';
+
+has world => (is => 'ro', required => 1);
+
+has remote => (is => 'lazy');
+
+sub _build_remote {
+  my ($self) = @_;
+  my $world = $self->world;
+  $world->remote_for('meta')->blocking_request(
+    register => object_service => 'Tak::ObjectService'
+  );
+  $world->remote_for('object_service')
+}
+
+sub proxy_method_call {
+  my ($self, @call) = @_;
+  my $ready = $self->encode_objects(\@call);
+  my $context = wantarray;
+  my @res = $self->remote->blocking_request(call_method => $context => $ready);
+  if ($res[0] eq 'RESULT') {
+    my $unpacked = $self->decode_objects($res[1]);
+    if ($context) {
+      return @$unpacked;
+    } elsif (defined $context) {
+      return $unpacked->[0];
+    } else {
+      return;
+    }
+  } else {
+    die $res[1];
+  }
+}
+
+sub proxy_death {
+  my ($self, $proxy) = @_;
+  $self->remote->blocking_request(remove_object => $proxy->{tag});
+}
+
+sub inflate {
+  my ($self, $tag) = @_;
+  bless({ client => $self, tag => $tag }, 'Tak::ObjectProxy');
+}
+
+sub deflate {
+  my ($self, $obj) = @_;
+  unless (ref($obj) eq 'Tak::ObjectProxy') {
+    die "Can't deflate non-proxied object ${obj}";
+  }
+  return +{ __proxied_object__ => $obj->{tag} };
+}
+
+sub new_object {
+  my ($self, $class, @args) = @_;
+  $self->proxy_method_call($class, 'new', @args);
+}
+
+1;
diff --git a/lib/Tak/ObjectProxy.pm b/lib/Tak/ObjectProxy.pm
new file mode 100644 (file)
index 0000000..827e0bd
--- /dev/null
@@ -0,0 +1,16 @@
+package Tak::ObjectProxy;
+
+use strictures 1;
+
+sub AUTOLOAD {
+  my $self = shift;
+  (my $method) = (our $AUTOLOAD =~ /([^:]+)$/);
+  $self->{client}->proxy_method_call($self, $method => @_);
+}
+
+sub DESTROY {
+  my $self = shift;
+  $self->{client}->proxy_death($self);
+}
+
+1;
diff --git a/lib/Tak/ObjectService.pm b/lib/Tak/ObjectService.pm
new file mode 100644 (file)
index 0000000..94f1248
--- /dev/null
@@ -0,0 +1,49 @@
+package Tak::ObjectService;
+
+use overload ();
+use Moo;
+
+with 'Tak::Role::ObjectMangling';
+
+has proxied => (is => 'ro', init_arg => undef, default => sub { {} });
+
+sub inflate {
+  my ($self, $tag) = @_;
+  $self->proxied->{$tag};
+}
+
+sub deflate {
+  my ($self, $obj) = @_;
+  my $tag = overload::StrVal($obj);
+  $self->proxied->{$tag} = $obj;
+  return +{ __proxied_object__ => $tag };
+}
+
+sub handle_call_method {
+  my ($self, $context, $call) = @_;
+  my ($invocant, $method, @args) = @{$self->decode_objects($call)};
+  my @res;
+  eval {
+    if (!ref($invocant)) {
+      (my $file = $invocant) =~ s/::/\//g;
+      require "${file}.pm";
+    }
+    if ($context) {
+      @res = $invocant->$method(@args);
+    } elsif (defined $context) {
+      $res[0] = $invocant->$method(@args);
+    } else {
+      $invocant->$method(@args);
+    }
+    1;
+  } or return FAILURE => "$@";
+  return RESULT => $self->encode_objects(\@res);
+}
+
+sub handle_remove_object {
+  my ($self, $tag) = @_;
+  my $had = !!delete $self->proxied->{$tag};
+  return RESULT => $had;
+}
+
+1;