summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorgregor herrmann <gregoa@debian.org>2020-01-24 17:08:06 +0100
committergregor herrmann <gregoa@debian.org>2020-01-24 17:08:06 +0100
commitd20d2f668f1faf341a78af4ff1846fd3e56d281b (patch)
tree1d2791ff8fb35298c91f69726a2d2fb8efdc87b6
parente94e49c7dad19be389216f42fdc051cdb5009722 (diff)
parenta0ffee3b830a0e147851f4462e599fe8eb7a63ff (diff)
Update upstream source from tag 'upstream/0.25'
Update to upstream version '0.25' with Debian dir a71a64936bd7ea64a3672e2a16449fa127d58dbd
-rw-r--r--Build.PL1
-rw-r--r--Changes13
-rw-r--r--LICENSE6
-rw-r--r--MANIFEST2
-rw-r--r--META.json53
-rw-r--r--META.yml51
-rw-r--r--doc/Tangence.txt54
-rw-r--r--lib/Tangence.pm2
-rw-r--r--lib/Tangence/Class.pm16
-rw-r--r--lib/Tangence/Client.pm75
-rw-r--r--lib/Tangence/Compiler/Parser.pm38
-rw-r--r--lib/Tangence/Constants.pm2
-rw-r--r--lib/Tangence/Message.pm2
-rw-r--r--lib/Tangence/Meta/Argument.pm14
-rw-r--r--lib/Tangence/Meta/Class.pm68
-rw-r--r--lib/Tangence/Meta/Event.pm25
-rw-r--r--lib/Tangence/Meta/Field.pm16
-rw-r--r--lib/Tangence/Meta/Method.pm28
-rw-r--r--lib/Tangence/Meta/Property.pm32
-rw-r--r--lib/Tangence/Meta/Struct.pm24
-rw-r--r--lib/Tangence/Meta/Type.pm26
-rw-r--r--lib/Tangence/Object.pm82
-rw-r--r--lib/Tangence/ObjectProxy.pm10
-rw-r--r--lib/Tangence/Property.pm2
-rw-r--r--lib/Tangence/Registry.pm20
-rw-r--r--lib/Tangence/Server.pm307
-rw-r--r--lib/Tangence/Server/Context.pm4
-rw-r--r--lib/Tangence/Stream.pm42
-rw-r--r--lib/Tangence/Struct.pm2
-rw-r--r--lib/Tangence/Type.pm22
-rw-r--r--lib/Tangence/Types.pm2
-rw-r--r--t/21client.t3
-rw-r--r--t/30props-cbs.t2
-rw-r--r--t/33props-set.t53
-rw-r--r--t/40server-security.t82
-rw-r--r--t/Conversation.pm2
36 files changed, 770 insertions, 413 deletions
diff --git a/Build.PL b/Build.PL
index 5a6ca01..fb93230 100644
--- a/Build.PL
+++ b/Build.PL
@@ -13,6 +13,7 @@ my $build = Module::Build->new(
'perl' => 5.010,
'Parser::MGC' => '0.04',
'Struct::Dumb' => 0,
+ 'Sub::Util' => '1.40',
},
test_requires => {
'Struct::Dumb' => '0.09',
diff --git a/Changes b/Changes
index eeef3a9..7ec70f0 100644
--- a/Changes
+++ b/Changes
@@ -1,5 +1,18 @@
Revision history for Tangence
+0.25 2020-01-14
+ [CHANGES]
+ * Allow servers to disallow access to Registry
+ * Disallow clients from accessing objects that haven't already been
+ sent to them
+ * Customisable root object per connection
+ * Added $client->get_registry; discourage the ->registry method
+ * Use core's Sub::Util::set_subname()
+ * Removed support for protocol minor version 2
+
+ [BUGFIXES]
+ * Ensure MSG_SETPROP serialises correctly for non-scalar properties
+
0.24 2017-11-14 17:48:45
[BUGFIXES]
* Avoid harmless warning about wide characters during SvIV test
diff --git a/LICENSE b/LICENSE
index 8a8e8e5..139e99b 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,4 +1,4 @@
-This software is copyright (c) 2017 by Paul Evans <leonerd@leonerd.org.uk>.
+This software is copyright (c) 2020 by Paul Evans <leonerd@leonerd.org.uk>.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
@@ -12,7 +12,7 @@ b) the "Artistic License"
--- The GNU General Public License, Version 1, February 1989 ---
-This software is Copyright (c) 2017 by Paul Evans <leonerd@leonerd.org.uk>.
+This software is Copyright (c) 2020 by Paul Evans <leonerd@leonerd.org.uk>.
This is free software, licensed under:
@@ -272,7 +272,7 @@ That's all there is to it!
--- The Artistic License 1.0 ---
-This software is Copyright (c) 2017 by Paul Evans <leonerd@leonerd.org.uk>.
+This software is Copyright (c) 2020 by Paul Evans <leonerd@leonerd.org.uk>.
This is free software, licensed under:
diff --git a/MANIFEST b/MANIFEST
index b90d94e..d849d6d 100644
--- a/MANIFEST
+++ b/MANIFEST
@@ -47,6 +47,8 @@ t/23close.t
t/30props-cbs.t
t/31props-cache.t
t/32props-cursor.t
+t/33props-set.t
+t/40server-security.t
t/90close-leak.t
t/99pod.t
t/Ball.pm
diff --git a/META.json b/META.json
index ba9c7f9..f406afb 100644
--- a/META.json
+++ b/META.json
@@ -4,7 +4,7 @@
"Paul Evans <leonerd@leonerd.org.uk>"
],
"dynamic_config" : 1,
- "generated_by" : "Module::Build version 0.422",
+ "generated_by" : "Module::Build version 0.4224",
"license" : [
"perl_5"
],
@@ -27,6 +27,7 @@
"List::Util" : "1.29",
"Parser::MGC" : "0.04",
"Struct::Dumb" : "0",
+ "Sub::Util" : "1.40",
"perl" : "5.01"
}
},
@@ -45,91 +46,91 @@
"provides" : {
"Tangence" : {
"file" : "lib/Tangence.pm",
- "version" : "0.24"
+ "version" : "0.25"
},
"Tangence::Class" : {
"file" : "lib/Tangence/Class.pm",
- "version" : "0.24"
+ "version" : "0.25"
},
"Tangence::Client" : {
"file" : "lib/Tangence/Client.pm",
- "version" : "0.24"
+ "version" : "0.25"
},
"Tangence::Compiler::Parser" : {
"file" : "lib/Tangence/Compiler/Parser.pm",
- "version" : "0.24"
+ "version" : "0.25"
},
"Tangence::Constants" : {
"file" : "lib/Tangence/Constants.pm",
- "version" : "0.24"
+ "version" : "0.25"
},
"Tangence::Message" : {
"file" : "lib/Tangence/Message.pm",
- "version" : "0.24"
+ "version" : "0.25"
},
"Tangence::Meta::Argument" : {
"file" : "lib/Tangence/Meta/Argument.pm",
- "version" : "0.24"
+ "version" : "0.25"
},
"Tangence::Meta::Class" : {
"file" : "lib/Tangence/Meta/Class.pm",
- "version" : "0.24"
+ "version" : "0.25"
},
"Tangence::Meta::Event" : {
"file" : "lib/Tangence/Meta/Event.pm",
- "version" : "0.24"
+ "version" : "0.25"
},
"Tangence::Meta::Field" : {
"file" : "lib/Tangence/Meta/Field.pm",
- "version" : "0.24"
+ "version" : "0.25"
},
"Tangence::Meta::Method" : {
"file" : "lib/Tangence/Meta/Method.pm",
- "version" : "0.24"
+ "version" : "0.25"
},
"Tangence::Meta::Property" : {
"file" : "lib/Tangence/Meta/Property.pm",
- "version" : "0.24"
+ "version" : "0.25"
},
"Tangence::Meta::Struct" : {
"file" : "lib/Tangence/Meta/Struct.pm",
- "version" : "0.24"
+ "version" : "0.25"
},
"Tangence::Meta::Type" : {
"file" : "lib/Tangence/Meta/Type.pm",
- "version" : "0.24"
+ "version" : "0.25"
},
"Tangence::Object" : {
"file" : "lib/Tangence/Object.pm",
- "version" : "0.24"
+ "version" : "0.25"
},
"Tangence::ObjectProxy" : {
"file" : "lib/Tangence/ObjectProxy.pm",
- "version" : "0.24"
+ "version" : "0.25"
},
"Tangence::Property" : {
"file" : "lib/Tangence/Property.pm",
- "version" : "0.24"
+ "version" : "0.25"
},
"Tangence::Registry" : {
"file" : "lib/Tangence/Registry.pm",
- "version" : "0.24"
+ "version" : "0.25"
},
"Tangence::Server" : {
"file" : "lib/Tangence/Server.pm",
- "version" : "0.24"
+ "version" : "0.25"
},
"Tangence::Server::Context" : {
"file" : "lib/Tangence/Server/Context.pm",
- "version" : "0.24"
+ "version" : "0.25"
},
"Tangence::Stream" : {
"file" : "lib/Tangence/Stream.pm",
- "version" : "0.24"
+ "version" : "0.25"
},
"Tangence::Struct" : {
"file" : "lib/Tangence/Struct.pm",
- "version" : "0.24"
+ "version" : "0.25"
},
"Tangence::Type" : {
"file" : "lib/Tangence/Type.pm"
@@ -139,7 +140,7 @@
},
"Tangence::Types" : {
"file" : "lib/Tangence/Types.pm",
- "version" : "0.24"
+ "version" : "0.25"
}
},
"release_status" : "stable",
@@ -148,6 +149,6 @@
"http://dev.perl.org/licenses/"
]
},
- "version" : "0.24",
- "x_serialization_backend" : "JSON::PP version 2.94"
+ "version" : "0.25",
+ "x_serialization_backend" : "JSON::PP version 4.04"
}
diff --git a/META.yml b/META.yml
index 9c724ec..6a1c702 100644
--- a/META.yml
+++ b/META.yml
@@ -13,7 +13,7 @@ build_requires:
configure_requires:
Module::Build: '0.4004'
dynamic_config: 1
-generated_by: 'Module::Build version 0.422, CPAN::Meta::Converter version 2.150010'
+generated_by: 'Module::Build version 0.4224, CPAN::Meta::Converter version 2.150010'
license: perl
meta-spec:
url: http://module-build.sourceforge.net/META-spec-v1.4.html
@@ -22,77 +22,77 @@ name: Tangence
provides:
Tangence:
file: lib/Tangence.pm
- version: '0.24'
+ version: '0.25'
Tangence::Class:
file: lib/Tangence/Class.pm
- version: '0.24'
+ version: '0.25'
Tangence::Client:
file: lib/Tangence/Client.pm
- version: '0.24'
+ version: '0.25'
Tangence::Compiler::Parser:
file: lib/Tangence/Compiler/Parser.pm
- version: '0.24'
+ version: '0.25'
Tangence::Constants:
file: lib/Tangence/Constants.pm
- version: '0.24'
+ version: '0.25'
Tangence::Message:
file: lib/Tangence/Message.pm
- version: '0.24'
+ version: '0.25'
Tangence::Meta::Argument:
file: lib/Tangence/Meta/Argument.pm
- version: '0.24'
+ version: '0.25'
Tangence::Meta::Class:
file: lib/Tangence/Meta/Class.pm
- version: '0.24'
+ version: '0.25'
Tangence::Meta::Event:
file: lib/Tangence/Meta/Event.pm
- version: '0.24'
+ version: '0.25'
Tangence::Meta::Field:
file: lib/Tangence/Meta/Field.pm
- version: '0.24'
+ version: '0.25'
Tangence::Meta::Method:
file: lib/Tangence/Meta/Method.pm
- version: '0.24'
+ version: '0.25'
Tangence::Meta::Property:
file: lib/Tangence/Meta/Property.pm
- version: '0.24'
+ version: '0.25'
Tangence::Meta::Struct:
file: lib/Tangence/Meta/Struct.pm
- version: '0.24'
+ version: '0.25'
Tangence::Meta::Type:
file: lib/Tangence/Meta/Type.pm
- version: '0.24'
+ version: '0.25'
Tangence::Object:
file: lib/Tangence/Object.pm
- version: '0.24'
+ version: '0.25'
Tangence::ObjectProxy:
file: lib/Tangence/ObjectProxy.pm
- version: '0.24'
+ version: '0.25'
Tangence::Property:
file: lib/Tangence/Property.pm
- version: '0.24'
+ version: '0.25'
Tangence::Registry:
file: lib/Tangence/Registry.pm
- version: '0.24'
+ version: '0.25'
Tangence::Server:
file: lib/Tangence/Server.pm
- version: '0.24'
+ version: '0.25'
Tangence::Server::Context:
file: lib/Tangence/Server/Context.pm
- version: '0.24'
+ version: '0.25'
Tangence::Stream:
file: lib/Tangence/Stream.pm
- version: '0.24'
+ version: '0.25'
Tangence::Struct:
file: lib/Tangence/Struct.pm
- version: '0.24'
+ version: '0.25'
Tangence::Type:
file: lib/Tangence/Type.pm
Tangence::Type::Primitive:
file: lib/Tangence/Type/Primitive.pm
Tangence::Types:
file: lib/Tangence/Types.pm
- version: '0.24'
+ version: '0.25'
requires:
Encode: '0'
Exporter: '5.57'
@@ -100,8 +100,9 @@ requires:
List::Util: '1.29'
Parser::MGC: '0.04'
Struct::Dumb: '0'
+ Sub::Util: '1.40'
perl: '5.01'
resources:
license: http://dev.perl.org/licenses/
-version: '0.24'
+version: '0.25'
x_serialization_backend: 'CPAN::Meta::YAML version 0.018'
diff --git a/doc/Tangence.txt b/doc/Tangence.txt
index 62081d1..205744a 100644
--- a/doc/Tangence.txt
+++ b/doc/Tangence.txt
@@ -812,60 +812,6 @@ not need serialising by DATAMETA_STRUCT records.
type : str
smashed : bool
-
-5. Perl Distribution
---------------------
-
-The perl distribution is available from
-
- http://bazaar.leonerd.dyndns.org/perl/Tangence/
-
-At some stage when the details become more concrete this will start
-gaining inline documentation, but for now it just has some commenting.
-
-As a rough description of the modules:
-
-5.1. Shared by server and client
-
- + Tangence::Constants
- Defines various magic numbers used in the wire streaming protocol.
-
- + Tangence::Stream
- Implements most of the lower level wire streaming protocol, including
- the symmetric parts of data serialisation.
-
-5.2. Used by the client
-
- + Tangence::Connection
- The connection to the server. Handles the higher-level client-specific
- parts of the wire protocol.
-
- + Tangence::ObjectProxy
- Acts as a proxy to one particular object within the server. Used for
- invoking methods, subscribing to events, and interacting with
- properties.
-
-5.3. Used by the server
-
- + Tangence::Object
- A base class for implementing Tangence objects within the server.
-
- + Tangence::Registry
- The object registry; keeps a reference to every Tangence object in the
- server.
-
- + Tangence::Server
- A base class for implementing the entire server.
-
- + Tangence::Server::Connection
- Server end of a client connection. Handles most of the higher-level
- server-specific parts of the wire protocol.
-
- + Tangence::Server::Context
- An object class to represent the client calling context during the
- invocation of a server object method or property change.
-
-
--
Paul "LeoNerd" Evans
diff --git a/lib/Tangence.pm b/lib/Tangence.pm
index 984c3bb..2e020ef 100644
--- a/lib/Tangence.pm
+++ b/lib/Tangence.pm
@@ -12,7 +12,7 @@ use warnings;
# It is provided simply to keep CPAN happy:
# cpan -i Tangence
-our $VERSION = '0.24';
+our $VERSION = '0.25';
=head1 NAME
diff --git a/lib/Tangence/Class.pm b/lib/Tangence/Class.pm
index b7d0e55..460efae 100644
--- a/lib/Tangence/Class.pm
+++ b/lib/Tangence/Class.pm
@@ -1,7 +1,7 @@
# You may distribute under the terms of either the GNU General Public License
# or the Artistic License (the same terms as Perl itself)
#
-# (C) Paul Evans, 2010-2014 -- leonerd@leonerd.org.uk
+# (C) Paul Evans, 2010-2020 -- leonerd@leonerd.org.uk
package Tangence::Class;
@@ -19,17 +19,9 @@ use Tangence::Meta::Argument;
use Carp;
-BEGIN {
- if( eval { require Sub::Name } ) {
- Sub::Name->import(qw( subname ));
- }
- else {
- # Emulate it by just returning the CODEref and ignoring setting the name
- *subname = sub { $_[1] };
- }
-}
+use Sub::Util 1.40 qw( set_subname );
-our $VERSION = '0.24';
+our $VERSION = '0.25';
our %metas; # cache one per class, keyed by _Tangence_ class name
@@ -130,7 +122,7 @@ sub define
no strict 'refs';
foreach my $name ( keys %subs ) {
next if defined &{"${class}::${name}"};
- *{"${class}::${name}"} = subname "${class}::${name}" => $subs{$name};
+ *{"${class}::${name}"} = set_subname "${class}::${name}" => $subs{$name};
}
}
diff --git a/lib/Tangence/Client.pm b/lib/Tangence/Client.pm
index 7ca656e..fb1483e 100644
--- a/lib/Tangence/Client.pm
+++ b/lib/Tangence/Client.pm
@@ -1,7 +1,7 @@
# You may distribute under the terms of either the GNU General Public License
# or the Artistic License (the same terms as Perl itself)
#
-# (C) Paul Evans, 2010-2015 -- leonerd@leonerd.org.uk
+# (C) Paul Evans, 2010-2020 -- leonerd@leonerd.org.uk
package Tangence::Client;
@@ -10,7 +10,7 @@ use warnings;
use base qw( Tangence::Stream );
-our $VERSION = '0.24';
+our $VERSION = '0.25';
use Carp;
@@ -22,7 +22,7 @@ use Future;
use List::Util qw( max );
-use constant VERSION_MINOR_MIN => 2;
+use constant VERSION_MINOR_MIN => 3;
=head1 NAME
@@ -110,7 +110,13 @@ sub rootobj
$registry = $client->registry
-Returns a L<Tangence::ObjectProxy> to the server's object registry
+Returns a L<Tangence::ObjectProxy> to the server's object registry if one has
+been received, or C<undef> if not.
+
+This method is now deprecated in favour of L</get_registry>. Additionally note
+that currently the client will attempt to request the registry at connection
+time, but a later version of this module will stop doing that, so users who
+need access to it should call C<get_registry>.
=cut
@@ -121,6 +127,35 @@ sub registry
return $self->{registry};
}
+=head2 get_registry
+
+ $registry = $client->get_registry->get
+
+Returns a L<Future> that will yield a L<Tangence::ObjectProxy> to the server's
+registry object.
+
+Note that not all servers may permit access to the registry.
+
+=cut
+
+sub get_registry
+{
+ my $self = shift;
+
+ $self->request(
+ request => Tangence::Message->new( $self, MSG_GETREGISTRY ),
+ )->then( sub {
+ my ( $message ) = @_;
+ my $code = $message->code;
+
+ $code == MSG_RESULT or
+ return Future->fail( "Cannot get registry - code $code", tangence => $message );
+
+ $self->registry( TYPE_OBJ->unpack_value( $message ) );
+ return Future->done( $self->registry );
+ });
+}
+
sub on_error
{
my $self = shift;
@@ -159,6 +194,11 @@ be passed a L<Tangence::ObjectProxy> to the registry.
$on_registry->( $registry )
+Note that in the case that the server does not permit access to the registry
+or an error occurs while requesting it, this is invoked with an empty list.
+
+ $on_registry->()
+
=item version_minor_min => INT
Optional minimum minor version to negotiate with the server. This can be used
@@ -233,26 +273,15 @@ sub tangence_initialised
}
);
- $self->request(
- request => Tangence::Message->new( $self, MSG_GETREGISTRY ),
-
- on_response => sub {
- my ( $message ) = @_;
- my $code = $message->code;
-
- if( $code == MSG_RESULT ) {
- $self->registry( TYPE_OBJ->unpack_value( $message ) );
- $args{on_registry}->( $self->registry ) if $args{on_registry};
- }
- elsif( $code == MSG_ERROR ) {
- my $msg = $message->unpack_str();
- print STDERR "Cannot get registry - error $msg";
- }
- else {
- print STDERR "Cannot get registry - code $code\n";
- }
+ $self->get_registry->then(
+ sub {
+ my ( $registry ) = @_;
+ $args{on_registry}->( $registry ) if $args{on_registry};
+ },
+ sub {
+ $args{on_registry}->() if $args{on_registry};
}
- );
+ )->retain;
}
sub handle_request_EVENT
diff --git a/lib/Tangence/Compiler/Parser.pm b/lib/Tangence/Compiler/Parser.pm
index e6caad2..e4ce39a 100644
--- a/lib/Tangence/Compiler/Parser.pm
+++ b/lib/Tangence/Compiler/Parser.pm
@@ -1,7 +1,7 @@
# You may distribute under the terms of either the GNU General Public License
# or the Artistic License (the same terms as Perl itself)
#
-# (C) Paul Evans, 2011-2014 -- leonerd@leonerd.org.uk
+# (C) Paul Evans, 2011-2017 -- leonerd@leonerd.org.uk
package Tangence::Compiler::Parser;
@@ -12,7 +12,7 @@ use base qw( Parser::MGC );
use feature qw( switch ); # we like given/when
no if $] >= 5.017011, warnings => 'experimental::smartmatch';
-our $VERSION = '0.24';
+our $VERSION = '0.25';
use File::Basename qw( dirname );
@@ -391,7 +391,9 @@ in the syntax tree.
=cut
-=head2 $class = $parser->make_class( name => $name )
+=head2 make_class
+
+ $class = $parser->make_class( name => $name )
Return a new instance of L<Tangence::Meta::Class> to go in a package. The
parser will call C<define> on it.
@@ -405,7 +407,9 @@ sub make_class
return Tangence::Meta::Class->new( @_ );
}
-=head2 $struct = $parser->make_struct( name => $name )
+=head2 make_struct
+
+ $struct = $parser->make_struct( name => $name )
Return a new instance of L<Tangence::Meta::Struct> to go in a package. The
parser will call C<define> on it.
@@ -419,11 +423,17 @@ sub make_struct
return Tangence::Meta::Struct->new( @_ );
}
-=head2 $method = $parser->make_method( %args )
+=head2 make_method
+
+ $method = $parser->make_method( %args )
+
+=head2 make_event
-=head2 $event = $parser->make_event( %args )
+ $event = $parser->make_event( %args )
-=head2 $property = $parser->make_property( %args )
+=head2 make_property
+
+ $property = $parser->make_property( %args )
Return a new instance of L<Tangence::Meta::Method>, L<Tangence::Meta::Event>
or L<Tangence::Meta::Property> to go in a class.
@@ -451,7 +461,9 @@ sub make_property
return Tangence::Meta::Property->new( @_ );
}
-=head2 $argument = $parser->make_argument( %args )
+=head2 make_argument
+
+ $argument = $parser->make_argument( %args )
Return a new instance of L<Tangence::Meta::Argument> to use for a method
or event argument.
@@ -465,7 +477,9 @@ sub make_argument
return Tangence::Meta::Argument->new( @_ );
}
-=head2 $field = $parser->make_field( %args )
+=head2 make_field
+
+ $field = $parser->make_field( %args )
Return a new instance of L<Tangence::Meta::Field> to use for a structure type.
@@ -478,9 +492,11 @@ sub make_field
return Tangence::Meta::Field->new( @_ );
}
-=head2 $type = $parser->make_type( $primitive_name )
+=head2 make_type
+
+ $type = $parser->make_type( $primitive_name )
-=head2 $type = $parser->make_type( $aggregate_name => $member_type )
+ $type = $parser->make_type( $aggregate_name => $member_type )
Return an instance of L<Tangence::Meta::Type> representing the given
primitive or aggregate type name. An implementation is allowed to use
diff --git a/lib/Tangence/Constants.pm b/lib/Tangence/Constants.pm
index b0ef67c..26f65fe 100644
--- a/lib/Tangence/Constants.pm
+++ b/lib/Tangence/Constants.pm
@@ -8,7 +8,7 @@ package Tangence::Constants;
use strict;
use warnings;
-our $VERSION = '0.24';
+our $VERSION = '0.25';
use Exporter 'import';
our @EXPORT = qw(
diff --git a/lib/Tangence/Message.pm b/lib/Tangence/Message.pm
index 38a8465..a66ed9f 100644
--- a/lib/Tangence/Message.pm
+++ b/lib/Tangence/Message.pm
@@ -13,7 +13,7 @@ use warnings;
# restriction could be listed.
use 5.010; # pack endian formats
-our $VERSION = '0.24';
+our $VERSION = '0.25';
use Carp;
diff --git a/lib/Tangence/Meta/Argument.pm b/lib/Tangence/Meta/Argument.pm
index d810013..2d02af4 100644
--- a/lib/Tangence/Meta/Argument.pm
+++ b/lib/Tangence/Meta/Argument.pm
@@ -8,7 +8,7 @@ package Tangence::Meta::Argument;
use strict;
use warnings;
-our $VERSION = '0.24';
+our $VERSION = '0.25';
=head1 NAME
@@ -27,7 +27,9 @@ immutable.
=cut
-=head2 $argument = Tangence::Meta::Argument->new( %args )
+=head2 new
+
+ $argument = Tangence::Meta::Argument->new( %args )
Returns a new instance initialised by the given arguments.
@@ -56,7 +58,9 @@ sub new
=cut
-=head2 $name = $argument->name
+=head2 name
+
+ $name = $argument->name
Returns the name of the class
@@ -68,7 +72,9 @@ sub name
return $self->{name};
}
-=head2 $type = $argument->type
+=head2 type
+
+ $type = $argument->type
Return the type as a L<Tangence::Meta::Type> reference.
diff --git a/lib/Tangence/Meta/Class.pm b/lib/Tangence/Meta/Class.pm
index 369e262..677e5f7 100644
--- a/lib/Tangence/Meta/Class.pm
+++ b/lib/Tangence/Meta/Class.pm
@@ -1,7 +1,7 @@
# You may distribute under the terms of either the GNU General Public License
# or the Artistic License (the same terms as Perl itself)
#
-# (C) Paul Evans, 2011-2013 -- leonerd@leonerd.org.uk
+# (C) Paul Evans, 2011-2017 -- leonerd@leonerd.org.uk
package Tangence::Meta::Class;
@@ -10,7 +10,7 @@ use warnings;
use Carp;
-our $VERSION = '0.24';
+our $VERSION = '0.25';
=head1 NAME
@@ -27,7 +27,9 @@ Once constructed and defined, such objects are immutable.
=cut
-=head2 $class = Tangence::Meta::Class->new( name => $name )
+=head2 new
+
+ $class = Tangence::Meta::Class->new( name => $name )
Returns a new instance representing the given name.
@@ -41,7 +43,9 @@ sub new
return $self;
}
-=head2 $class->define( %args )
+=head2 define
+
+ $class->define( %args )
Provides a definition for the class.
@@ -84,7 +88,9 @@ sub define
=cut
-=head2 $defined = $class->defined
+=head2 defined
+
+ $defined = $class->defined
Returns true if a definintion for the class has been provided using C<define>.
@@ -96,7 +102,9 @@ sub defined
return exists $self->{superclasses};
}
-=head2 $name = $class->name
+=head2 name
+
+ $name = $class->name
Returns the name of the class
@@ -108,7 +116,9 @@ sub name
return $self->{name};
}
-=head2 $perlname = $class->perlname
+=head2 perlname
+
+ $perlname = $class->perlname
Returns the perl name of the class. This will be the Tangence name, with dots
replaced by double colons (C<::>).
@@ -122,7 +132,9 @@ sub perlname
return $perlname;
}
-=head2 @superclasses = $class->direct_superclasses
+=head2 direct_superclasses
+
+ @superclasses = $class->direct_superclasses
Return the direct superclasses in a list of C<Tangence::Meta::Class>
references.
@@ -136,7 +148,9 @@ sub direct_superclasses
return @{ $self->{superclasses} };
}
-=head2 $methods = $class->direct_methods
+=head2 direct_methods
+
+ $methods = $class->direct_methods
Return the methods that this class directly defines (rather than inheriting
from superclasses) as a HASH reference mapping names to
@@ -151,7 +165,9 @@ sub direct_methods
return $self->{methods};
}
-=head2 $events = $class->direct_events
+=head2 direct_events
+
+ $events = $class->direct_events
Return the events that this class directly defines (rather than inheriting
from superclasses) as a HASH reference mapping names to
@@ -166,7 +182,9 @@ sub direct_events
return $self->{events};
}
-=head2 $properties = $class->direct_properties
+=head2 direct_properties
+
+ $properties = $class->direct_properties
Return the properties that this class directly defines (rather than inheriting
from superclasses) as a HASH reference mapping names to
@@ -188,7 +206,9 @@ all its superclasses
=cut
-=head2 @superclasses = $class->superclasses
+=head2 superclasses
+
+ @superclasses = $class->superclasses
Return all the superclasses in a list of unique C<Tangence::Meta::Class>
references.
@@ -204,7 +224,9 @@ sub superclasses
return grep { !$seen{$_}++ } map { $_, $_->superclasses } $self->direct_superclasses;
}
-=head2 $methods = $class->methods
+=head2 methods
+
+ $methods = $class->methods
Return all the methods available to this class as a HASH reference mapping
names to L<Tangence::Meta::Method> instances.
@@ -222,7 +244,9 @@ sub methods
return \%methods;
}
-=head2 $method = $class->method( $name )
+=head2 method
+
+ $method = $class->method( $name )
Return the named method as a L<Tangence::Meta::Method> instance, or C<undef>
if no such method exists.
@@ -236,7 +260,9 @@ sub method
return $self->methods->{$name};
}
-=head2 $events = $class->events
+=head2 events
+
+ $events = $class->events
Return all the events available to this class as a HASH reference mapping
names to L<Tangence::Meta::Event> instances.
@@ -254,7 +280,9 @@ sub events
return \%events;
}
-=head2 $event = $class->event( $name )
+=head2 event
+
+ $event = $class->event( $name )
Return the named event as a L<Tangence::Meta::Event> instance, or C<undef> if
no such event exists.
@@ -268,7 +296,9 @@ sub event
return $self->events->{$name};
}
-=head2 $properties = $class->properties
+=head2 properties
+
+ $properties = $class->properties
Return all the properties available to this class as a HASH reference mapping
names to L<Tangence::Meta::Property> instances.
@@ -286,7 +316,9 @@ sub properties
return \%properties;
}
-=head2 $property = $class->property( $name )
+=head2 property
+
+ $property = $class->property( $name )
Return the named property as a L<Tangence::Meta::Property> instance, or
C<undef> if no such property exists.
diff --git a/lib/Tangence/Meta/Event.pm b/lib/Tangence/Meta/Event.pm
index f2de493..6f84c7c 100644
--- a/lib/Tangence/Meta/Event.pm
+++ b/lib/Tangence/Meta/Event.pm
@@ -1,14 +1,14 @@
# You may distribute under the terms of either the GNU General Public License
# or the Artistic License (the same terms as Perl itself)
#
-# (C) Paul Evans, 2011 -- leonerd@leonerd.org.uk
+# (C) Paul Evans, 2011-2017 -- leonerd@leonerd.org.uk
package Tangence::Meta::Event;
use strict;
use warnings;
-our $VERSION = '0.24';
+our $VERSION = '0.25';
use Scalar::Util qw( weaken );
@@ -27,7 +27,9 @@ event. Once constructed, such objects are immutable.
=cut
-=head2 $event = Tangence::Meta::Event->new( %args )
+=head2 new
+
+ $event = Tangence::Meta::Event->new( %args )
Returns a new instance initialised by the given arguments.
@@ -64,7 +66,9 @@ sub new
=cut
-=head2 $class = $event->class
+=head2 class
+
+ $class = $event->class
Returns the class the event is a member of
@@ -76,7 +80,9 @@ sub class
return $self->{class};
}
-=head2 $name = $event->name
+=head2 name
+
+ $name = $event->name
Returns the name of the class
@@ -88,7 +94,9 @@ sub name
return $self->{name};
}
-=head2 @arguments = $event->arguments
+=head2 arguments
+
+ @arguments = $event->arguments
Return the arguments in a list of L<Tangence::Meta::Argument> references.
@@ -100,7 +108,9 @@ sub arguments
return @{ $self->{arguments} };
}
-=head2 @argtypes = $event->argtypes
+=head2 argtypes
+
+ @argtypes = $event->argtypes
Return the argument types in a list of strings.
@@ -119,4 +129,3 @@ Paul Evans <leonerd@leonerd.org.uk>
=cut
0x55AA;
-
diff --git a/lib/Tangence/Meta/Field.pm b/lib/Tangence/Meta/Field.pm
index 4974e0e..2572c45 100644
--- a/lib/Tangence/Meta/Field.pm
+++ b/lib/Tangence/Meta/Field.pm
@@ -1,14 +1,14 @@
# You may distribute under the terms of either the GNU General Public License
# or the Artistic License (the same terms as Perl itself)
#
-# (C) Paul Evans, 2012 -- leonerd@leonerd.org.uk
+# (C) Paul Evans, 2012-2017 -- leonerd@leonerd.org.uk
package Tangence::Meta::Field;
use strict;
use warnings;
-our $VERSION = '0.24';
+our $VERSION = '0.25';
=head1 NAME
@@ -26,7 +26,9 @@ structure. Once constructed, such objects are immutable.
=cut
-=head2 $field = Tangence::Meta::Field->new( %args )
+=head2 new
+
+ $field = Tangence::Meta::Field->new( %args )
Returns a new instance initialised by the given fields.
@@ -55,7 +57,9 @@ sub new
=cut
-=head2 $name = $field->name
+=head2 name
+
+ $name = $field->name
Returns the name of the field
@@ -67,7 +71,9 @@ sub name
return $self->{name};
}
-=head2 $type = $field->type
+=head2 type
+
+ $type = $field->type
Return the type as a L<Tangence::Meta::Type> reference.
diff --git a/lib/Tangence/Meta/Method.pm b/lib/Tangence/Meta/Method.pm
index f845553..c0c13ff 100644
--- a/lib/Tangence/Meta/Method.pm
+++ b/lib/Tangence/Meta/Method.pm
@@ -1,14 +1,14 @@
# You may distribute under the terms of either the GNU General Public License
# or the Artistic License (the same terms as Perl itself)
#
-# (C) Paul Evans, 2011-2012 -- leonerd@leonerd.org.uk
+# (C) Paul Evans, 2011-2017 -- leonerd@leonerd.org.uk
package Tangence::Meta::Method;
use strict;
use warnings;
-our $VERSION = '0.24';
+our $VERSION = '0.25';
use Scalar::Util qw( weaken );
@@ -27,7 +27,9 @@ method. Once constructed, such objects are immutable.
=cut
-=head2 $method = Tangence::Meta::Method->new( %args )
+=head2 new
+
+ $method = Tangence::Meta::Method->new( %args )
Returns a new instance initialised by the given arguments.
@@ -69,7 +71,9 @@ sub new
=cut
-=head2 $class = $method->class
+=head2 class
+
+ $class = $method->class
Returns the class the method is a member of
@@ -81,7 +85,9 @@ sub class
return $self->{class};
}
-=head2 $name = $method->name
+=head2 name
+
+ $name = $method->name
Returns the name of the class
@@ -93,7 +99,9 @@ sub name
return $self->{name};
}
-=head2 @arguments = $method->arguments
+=head2 arguments
+
+ @arguments = $method->arguments
Return the arguments in a list of L<Tangence::Meta::Argument> references.
@@ -105,7 +113,9 @@ sub arguments
return @{ $self->{arguments} };
}
-=head2 @argtypes = $method->argtypes
+=head2 argtype
+
+ @argtypes = $method->argtypes
Return the argument types in a list of L<Tangence::Meta::Type> references.
@@ -117,7 +127,9 @@ sub argtypes
return map { $_->type } $self->arguments;
}
-=head2 $ret = $method->ret
+=head2 ret
+
+ $ret = $method->ret
Returns the return type as a L<Tangence::Meta::Type> reference or C<undef> if
the method does not return a value.
diff --git a/lib/Tangence/Meta/Property.pm b/lib/Tangence/Meta/Property.pm
index d6fdd83..da84691 100644
--- a/lib/Tangence/Meta/Property.pm
+++ b/lib/Tangence/Meta/Property.pm
@@ -1,14 +1,14 @@
# You may distribute under the terms of either the GNU General Public License
# or the Artistic License (the same terms as Perl itself)
#
-# (C) Paul Evans, 2011-2014 -- leonerd@leonerd.org.uk
+# (C) Paul Evans, 2011-2017 -- leonerd@leonerd.org.uk
package Tangence::Meta::Property;
use strict;
use warnings;
-our $VERSION = '0.24';
+our $VERSION = '0.25';
use Tangence::Constants;
@@ -29,7 +29,9 @@ property. Once constructed, such objects are immutable.
=cut
-=head2 $property = Tangence::Meta::Property->new( %args )
+=head2 new
+
+ $property = Tangence::Meta::Property->new( %args )
Returns a new instance initialised by the given arguments.
@@ -73,7 +75,9 @@ sub new
=cut
-=head2 $class = $property->class
+=head2 class
+
+ $class = $property->class
Returns the class the property is a member of
@@ -85,7 +89,9 @@ sub class
return $self->{class};
}
-=head2 $name = $property->name
+=head2 name
+
+ $name = $property->name
Returns the name of the class
@@ -97,7 +103,9 @@ sub name
return $self->{name};
}
-=head2 $dimension = $property->dimension
+=head2 dimension
+
+ $dimension = $property->dimension
Returns the dimension as one of the C<DIM_*> constants.
@@ -109,7 +117,9 @@ sub dimension
return $self->{dimension};
}
-=head2 $type = $property->type
+=head2 type
+
+ $type = $property->type
Returns the element type as a L<Tangence::Meta::Type> reference.
@@ -121,7 +131,9 @@ sub type
return $self->{type};
}
-=head2 $type = $property->overall_type
+=head2 overall_type
+
+ $type = $property->overall_type
Returns the type of the entire collection as a L<Tangence::Meta::Type>
reference. For scalar types this will be the element type. For dict types this
@@ -151,7 +163,9 @@ sub overall_type
}
}
-=head2 $smashed = $property->smashed
+=head2 smashed
+
+ $smashed = $property->smashed
Returns true if the property is smashed.
diff --git a/lib/Tangence/Meta/Struct.pm b/lib/Tangence/Meta/Struct.pm
index 1180c46..cc5e49a 100644
--- a/lib/Tangence/Meta/Struct.pm
+++ b/lib/Tangence/Meta/Struct.pm
@@ -1,7 +1,7 @@
# You may distribute under the terms of either the GNU General Public License
# or the Artistic License (the same terms as Perl itself)
#
-# (C) Paul Evans, 2012 -- leonerd@leonerd.org.uk
+# (C) Paul Evans, 2012-2017 -- leonerd@leonerd.org.uk
package Tangence::Meta::Struct;
@@ -10,7 +10,7 @@ use warnings;
use Carp;
-our $VERSION = '0.24';
+our $VERSION = '0.25';
=head1 NAME
@@ -28,7 +28,9 @@ Once constructed and defined, such objects are immutable.
=cut
-=head2 $struct = Tangence::Meta::Struct->new( name => $name )
+=head2 new
+
+ $struct = Tangence::Meta::Struct->new( name => $name )
Returns a new instance representing the given name.
@@ -42,7 +44,9 @@ sub new
return $self;
}
-=head2 $struct->define( %args )
+=head2 define
+
+ $struct->define( %args )
Provides a definition for the structure.
@@ -71,7 +75,9 @@ sub define
=cut
-=head2 $defined = $struct->defined
+=head2 defined
+
+ $defined = $struct->defined
Returns true if a definition of the structure has been provided using
C<define>.
@@ -84,7 +90,9 @@ sub defined
return exists $self->{fields};
}
-=head2 $name = $struct->name
+=head2 name
+
+ $name = $struct->name
Returns the name of the structure
@@ -96,7 +104,9 @@ sub name
return $self->{name};
}
-=head2 @fields = $struct->fields
+=head2 fields
+
+ @fields = $struct->fields
Returns a list of the fields defined on the structure, in their order of
definition.
diff --git a/lib/Tangence/Meta/Type.pm b/lib/Tangence/Meta/Type.pm
index 45fc233..084a4c4 100644
--- a/lib/Tangence/Meta/Type.pm
+++ b/lib/Tangence/Meta/Type.pm
@@ -1,7 +1,7 @@
# You may distribute under the terms of either the GNU General Public License
# or the Artistic License (the same terms as Perl itself)
#
-# (C) Paul Evans, 2012 -- leonerd@leonerd.org.uk
+# (C) Paul Evans, 2012-2017 -- leonerd@leonerd.org.uk
package Tangence::Meta::Type;
@@ -10,7 +10,7 @@ use warnings;
use Carp;
-our $VERSION = '0.24';
+our $VERSION = '0.25';
=head1 NAME
@@ -30,11 +30,13 @@ implemented as singletons.
=cut
-=head2 $type = Tangence::Meta::Type->new( $primitive )
+=head2 new
+
+ $type = Tangence::Meta::Type->new( $primitive )
Returns an instance to represent the given primitive type signature.
-=head2 $type = Tangence::Meta::Type->new( $aggregate => $member_type )
+ $type = Tangence::Meta::Type->new( $aggregate => $member_type )
Returns an instance to represent the given aggregation of the given type
instance.
@@ -65,7 +67,9 @@ sub new
die "TODO: @_";
}
-=head2 $type = Tangence::Meta::Type->new_from_sig( $sig )
+=head2 new_from_sig
+
+ $type = Tangence::Meta::Type->new_from_sig( $sig )
Parses the given full Tangence type signature and returns an instance to
represent it.
@@ -90,7 +94,9 @@ sub new_from_sig
=cut
-=head2 $agg = $type->aggregate
+=head2 aggregate
+
+ $agg = $type->aggregate
Returns C<"prim"> for primitive types, or the aggregation name for list and
dict aggregate types.
@@ -103,7 +109,9 @@ sub aggregate
return $self->[0];
}
-=head2 $member_type = $type->member_type
+=head2 member_type
+
+ $member_type = $type->member_type
Returns the member type for aggregation types. Throws an exception for
primitive types.
@@ -117,7 +125,9 @@ sub member_type
return $self->[1];
}
-=head2 $sig = $type->sig
+=head2 sig
+
+ $sig = $type->sig
Returns the Tangence type signature for the type.
diff --git a/lib/Tangence/Object.pm b/lib/Tangence/Object.pm
index 9c3e30d..055804e 100644
--- a/lib/Tangence/Object.pm
+++ b/lib/Tangence/Object.pm
@@ -1,14 +1,14 @@
# You may distribute under the terms of either the GNU General Public License
# or the Artistic License (the same terms as Perl itself)
#
-# (C) Paul Evans, 2010-2016 -- leonerd@leonerd.org.uk
+# (C) Paul Evans, 2010-2017 -- leonerd@leonerd.org.uk
package Tangence::Object;
use strict;
use warnings;
-our $VERSION = '0.24';
+our $VERSION = '0.25';
use Carp;
@@ -75,7 +75,9 @@ sub new
=cut
-=head2 $obj->destroy
+=head2 destroy
+
+ $obj->destroy
Requests that the object destroy itself, informing all clients that are aware
of it. Once they all report that they have dropped the object, the object is
@@ -123,7 +125,9 @@ sub _destroy_really
$self->{destroyed} = 1;
}
-=head2 $id = $obj->id
+=head2 id
+
+ $id = $obj->id
Returns the object's C<Tangence> ID number
@@ -135,7 +139,9 @@ sub id
return $self->{id};
}
-=head2 $description = $obj->describe
+=head2 describe
+
+ $description = $obj->describe
Returns a textual description of the object, for internal debugging purposes.
Subclasses are encouraged to override this method to return something more
@@ -149,7 +155,9 @@ sub describe
return ref $self;
}
-=head2 $registry = $obj->registry
+=head2 registry
+
+ $registry = $obj->registry
Returns the L<Tangence::Registry> that constructed this object.
@@ -182,7 +190,9 @@ sub smash
} @keys };
}
-=head2 $class = $obj->class
+=head2 class
+
+ $class = $obj->class
Returns the L<Tangence::Meta::Class> object representing the class of this
object.
@@ -195,7 +205,9 @@ sub class
return ref $self ? $self->{meta} : Tangence::Class->for_perlname( $self );
}
-=head2 $method = $obj->can_method( $name )
+=head2 can_method
+
+ $method = $obj->can_method( $name )
Returns the L<Tangence::Meta::Method> object representing the named method, or
C<undef> if no such method exists.
@@ -208,7 +220,9 @@ sub can_method
return $self->class->method( @_ );
}
-=head2 $event = $obj->can_event( $name )
+=head2 can_event
+
+ $event = $obj->can_event( $name )
Returns the L<Tangence::Meta::Event> object representing the named event, or
C<undef> if no such event exists.
@@ -221,7 +235,9 @@ sub can_event
return $self->class->event( @_ );
}
-=head2 $property = $obj->can_property( $name )
+=head2 can_property
+
+ $property = $obj->can_property( $name )
Returns the L<Tangence::Meta::Property> object representing the named
property, or C<undef> if no such property exists.
@@ -240,7 +256,9 @@ sub smashkeys
return $self->class->smashkeys;
}
-=head2 $obj->fire_event( $event, @args )
+=head2 fire_event
+
+ $obj->fire_event( $event, @args )
Fires the named event on the object. Each event subscription function will be
invoked with the given arguments.
@@ -263,7 +281,9 @@ sub fire_event
}
}
-=head2 $id = $obj->subscribe_event( $event, $callback )
+=head2 subscribe_event
+
+ $id = $obj->subscribe_event( $event, $callback )
Subscribes an event-handling callback CODE ref to the named event. When the
event is fired by C<fire_event> this callback will be invoked, being passed
@@ -291,7 +311,9 @@ sub subscribe_event
return $ref + 0; # force numeric context
}
-=head2 $obj->unsubscribe_event( $event, $id )
+=head2 unsubscribe_event
+
+ $obj->unsubscribe_event( $event, $id )
Removes an event-handling callback previously registered with
C<subscribe_event>.
@@ -313,7 +335,9 @@ sub unsubscribe_event
splice @$sublist, $index, 1, ();
}
-=head2 $id = $obj->watch_property( $prop, %callbacks )
+=head2 watch_property
+
+ $id = $obj->watch_property( $prop, %callbacks )
Watches a named property for changes, registering a set of callback functions
to be invoked when the property changes in certain ways. The set of callbacks
@@ -321,34 +345,34 @@ required depends on the dimension of the property being watched.
For all property types:
- $on_set->( $obj, $value )
+ $on_set->( $obj, $value )
For hash properties:
- $on_add->( $obj, $key, $value )
- $on_del->( $obj, $key )
+ $on_add->( $obj, $key, $value )
+ $on_del->( $obj, $key )
For queue properties:
- $on_push->( $obj, @values )
- $on_shift->( $obj, $count )
+ $on_push->( $obj, @values )
+ $on_shift->( $obj, $count )
For array properties:
- $on_push->( $obj, @values )
- $on_shift->( $obj, $count )
- $on_splice->( $obj, $index, $count, @values )
- $on_move->( $obj, $index, $delta )
+ $on_push->( $obj, @values )
+ $on_shift->( $obj, $count )
+ $on_splice->( $obj, $index, $count, @values )
+ $on_move->( $obj, $index, $delta )
For objset properties:
- $on_add->( $obj, $added_object )
- $on_del->( $obj, $deleted_object_id )
+ $on_add->( $obj, $added_object )
+ $on_del->( $obj, $deleted_object_id )
Alternatively, a single callback may be installed that is invoked after any
change of the property, being passed the new value entirely:
- $on_updated->( $obj, $value )
+ $on_updated->( $obj, $value )
Returns an opaque ID value that can be used to remove this watch by calling
C<unwatch_property>.
@@ -388,7 +412,9 @@ sub watch_property
return $ref + 0; # force numeric context
}
-=head2 $obj->unwatch_property( $prop, $id )
+=head2 unwatch_property
+
+ $obj->unwatch_property( $prop, $id )
Removes the set of callback functions previously registered with
C<watch_property>.
@@ -512,7 +538,7 @@ sub handle_request_SETPROP
my $pdef = $self->can_property( $prop ) or die "Object does not have property $prop\n";
- my $value = $pdef->type->unpack_value( $message );
+ my $value = $pdef->overall_type->unpack_value( $message );
my $m = "set_prop_$prop";
$self->can( $m ) or die "Object cannot set property $prop\n";
diff --git a/lib/Tangence/ObjectProxy.pm b/lib/Tangence/ObjectProxy.pm
index 0d3bb21..6a11d51 100644
--- a/lib/Tangence/ObjectProxy.pm
+++ b/lib/Tangence/ObjectProxy.pm
@@ -1,14 +1,14 @@
# You may distribute under the terms of either the GNU General Public License
# or the Artistic License (the same terms as Perl itself)
#
-# (C) Paul Evans, 2010-2016 -- leonerd@leonerd.org.uk
+# (C) Paul Evans, 2010-2020 -- leonerd@leonerd.org.uk
package Tangence::ObjectProxy;
use strict;
use warnings;
-our $VERSION = '0.24';
+our $VERSION = '0.25';
use Carp;
@@ -427,7 +427,6 @@ sub get_property_element
or croak "Class ".$self->classname." does not have a property $property";
my $client = $self->{client};
- $client->_ver_can_getpropelem or croak "Server is too old to support MSG_GETPROPELEM";
my $request = Tangence::Message->new( $client, MSG_GETPROPELEM )
->pack_int( $self->id )
@@ -504,7 +503,7 @@ sub set_property
my $request = Tangence::Message->new( $client, MSG_SETPROP )
->pack_int( $self->id )
->pack_str( $property );
- $pdef->type->pack_value( $request, $value ),
+ $pdef->overall_type->pack_value( $request, $value );
$client->request(
request => $request,
@@ -708,7 +707,7 @@ sub watch_property_with_cursor
my $smashed = $pdef->smashed;
if( my $cbs = $self->{props}->{$property}->{cbs} ) {
- die "TODO: need to synthesize a second cursor";
+ die "TODO: need to synthesize a second cursor for $self";
}
$self->{props}->{$property}->{cbs} = [ $callbacks ];
@@ -718,7 +717,6 @@ sub watch_property_with_cursor
}
my $client = $self->{client};
- $client->_ver_can_cursor or croak "Server is too old to support MSG_WATCH_CUSR";
$pdef->dimension == DIM_QUEUE or croak "Can only iterate on queue-dimension properties";
$client->request(
diff --git a/lib/Tangence/Property.pm b/lib/Tangence/Property.pm
index 436d28e..fbd8a3e 100644
--- a/lib/Tangence/Property.pm
+++ b/lib/Tangence/Property.pm
@@ -18,7 +18,7 @@ require Tangence::Type;
use Struct::Dumb;
struct Instance => [qw( value callbacks cursors )];
-our $VERSION = '0.24';
+our $VERSION = '0.25';
sub build_accessor
{
diff --git a/lib/Tangence/Registry.pm b/lib/Tangence/Registry.pm
index 4d0df92..e98e388 100644
--- a/lib/Tangence/Registry.pm
+++ b/lib/Tangence/Registry.pm
@@ -1,7 +1,7 @@
# You may distribute under the terms of either the GNU General Public License
# or the Artistic License (the same terms as Perl itself)
#
-# (C) Paul Evans, 2010-2014 -- leonerd@leonerd.org.uk
+# (C) Paul Evans, 2010-2017 -- leonerd@leonerd.org.uk
package Tangence::Registry;
@@ -9,7 +9,7 @@ use strict;
use warnings;
use base qw( Tangence::Object );
-our $VERSION = '0.24';
+our $VERSION = '0.25';
use Carp;
@@ -67,7 +67,9 @@ objects it creates, so it can dispatch incoming messages from clients to them.
=cut
-=head2 $registry = Tangence::Registry->new
+=head2 new
+
+ $registry = Tangence::Registry->new
Returns a new instance of a C<Tangence::Registry> object. An entire server
requires one registry object; it will be shared among all the client
@@ -108,7 +110,9 @@ sub new
=cut
-=head2 $obj = $registry->get_by_id( $id )
+=head2 get_by_id
+
+ $obj = $registry->get_by_id( $id )
Returns the object with the given object ID.
@@ -131,7 +135,9 @@ sub method_get_by_id
return $self->get_by_id( $id );
}
-=head2 $obj = $registry->construct( $type, @args )
+=head2 construct
+
+ $obj = $registry->construct( $type, @args )
Constructs a new exposed object of the given type, and returns it. Any
additional arguments are passed to the object's constructor.
@@ -181,7 +187,9 @@ sub destroy_object
push @{ $self->{freeids} }, $id; # Recycle the ID
}
-=head2 $registry->load_tanfile( $tanfile )
+=head2 load_tanfile
+
+ $registry->load_tanfile( $tanfile )
Loads additional Tangence class and struct definitions from the given F<.tan>
file.
diff --git a/lib/Tangence/Server.pm b/lib/Tangence/Server.pm
index 59970f9..f98556a 100644
--- a/lib/Tangence/Server.pm
+++ b/lib/Tangence/Server.pm
@@ -1,7 +1,7 @@
# You may distribute under the terms of either the GNU General Public License
# or the Artistic License (the same terms as Perl itself)
#
-# (C) Paul Evans, 2011-2016 -- leonerd@leonerd.org.uk
+# (C) Paul Evans, 2011-2020 -- leonerd@leonerd.org.uk
package Tangence::Server;
@@ -10,11 +10,12 @@ use warnings;
use base qw( Tangence::Stream );
-our $VERSION = '0.24';
+our $VERSION = '0.25';
use Carp;
use Scalar::Util qw( weaken );
+use Sub::Util 1.40 qw( set_subname );
use Tangence::Constants;
use Tangence::Types;
@@ -23,18 +24,8 @@ use Tangence::Server::Context;
use Struct::Dumb;
struct CursorObject => [qw( cursor obj )];
-# We will accept any version back to 2
-use constant VERSION_MINOR_MIN => 2;
-
-BEGIN {
- if( eval { require Sub::Name } ) {
- Sub::Name->import(qw( subname ));
- }
- else {
- # Emulate it by just returning the CODEref and ignoring setting the name
- *subname = sub { $_[1] };
- }
-}
+# We will accept any version back to 3
+use constant VERSION_MINOR_MIN => 3;
=head1 NAME
@@ -100,9 +91,11 @@ The following methods are provided by this mixin.
sub subscriptions { shift->{subscriptions} ||= [] }
sub watches { shift->{watches} ||= [] }
-=head2 $server->registry( $registry )
+=head2 registry
+
+ $server->registry( $registry )
-=head2 $registry = $server->registry
+ $registry = $server->registry
Accessor to set or obtain the L<Tangence::Registry> object for the server.
@@ -150,22 +143,31 @@ sub get_by_id
my $self = shift;
my ( $id ) = @_;
- return $self->registry->get_by_id( $id );
+ # Only permit the client to interact with objects they've already been
+ # sent, so they cannot gain access by inventing object IDs
+ $self->peer_hasobj->{$id} or
+ die "Access not allowed to object with id $id\n";
+
+ my $obj = $self->registry->get_by_id( $id ) or
+ die "No such object with id $id\n";
+
+ return $obj;
}
sub handle_request_CALL
{
my $self = shift;
my ( $token, $message ) = @_;
-
- my $objid = $message->unpack_int();
my $ctx = Tangence::Server::Context->new( $self, $token );
- my $object = $self->registry->get_by_id( $objid ) or
- return $ctx->responderr( "No such object with id $objid" );
+ my $response = eval {
+ my $objid = $message->unpack_int();
+
+ my $object = $self->get_by_id( $objid );
- my $response = eval { $object->handle_request_CALL( $ctx, $message ) };
+ $object->handle_request_CALL( $ctx, $message )
+ };
$@ and return $ctx->responderr( $@ );
$ctx->respond( $response );
@@ -175,76 +177,85 @@ sub handle_request_SUBSCRIBE
{
my $self = shift;
my ( $token, $message ) = @_;
-
- my $objid = $message->unpack_int();
- my $event = $message->unpack_str();
my $ctx = Tangence::Server::Context->new( $self, $token );
- my $object = $self->registry->get_by_id( $objid ) or
- return $ctx->responderr( "No such object with id $objid" );
+ my $response = eval {
+ my $objid = $message->unpack_int();
+ my $event = $message->unpack_str();
- weaken( my $weakself = $self );
+ my $object = $self->get_by_id( $objid );
- my $id = $object->subscribe_event( $event,
- subname "__SUBSCRIBE($event)__" => sub {
- $weakself or return;
- my $object = shift;
+ weaken( my $weakself = $self );
- my $message = $object->generate_message_EVENT( $weakself, $event, @_ );
- $weakself->request(
- request => $message,
- on_response => sub { "IGNORE" },
- );
- }
- );
+ my $id = $object->subscribe_event( $event,
+ set_subname "__SUBSCRIBE($event)__" => sub {
+ $weakself or return;
+ my $object = shift;
+
+ my $message = $object->generate_message_EVENT( $weakself, $event, @_ );
+ $weakself->request(
+ request => $message,
+ on_response => sub { "IGNORE" },
+ );
+ }
+ );
- push @{ $self->subscriptions }, [ $object, $event, $id ];
+ push @{ $self->subscriptions }, [ $object, $event, $id ];
- $ctx->respond( Tangence::Message->new( $self, MSG_SUBSCRIBED ) );
+ Tangence::Message->new( $self, MSG_SUBSCRIBED )
+ };
+ $@ and return $ctx->responderr( $@ );
+
+ $ctx->respond( $response );
}
sub handle_request_UNSUBSCRIBE
{
my $self = shift;
my ( $token, $message ) = @_;
-
- my $objid = $message->unpack_int();
- my $event = $message->unpack_str();
my $ctx = Tangence::Server::Context->new( $self, $token );
- my $object = $self->registry->get_by_id( $objid ) or
- return $ctx->responderr( "No such object with id $objid" );
+ my $response = eval {
+ my $objid = $message->unpack_int();
+ my $event = $message->unpack_str();
- my $edef = $object->can_event( $event ) or
- return $ctx->responderr( "Object cannot respond to event $event" );
+ my $object = $self->get_by_id( $objid );
- # Delete from subscriptions and obtain id
- my $id;
- @{ $self->subscriptions } = grep { $_->[0] == $object and $_->[1] eq $event and ( $id = $_->[2], 0 ) or 1 }
- @{ $self->subscriptions };
- defined $id or
- return $ctx->responderr( "Not subscribed to $event" );
+ my $edef = $object->can_event( $event ) or
+ die "Object cannot respond to event $event\n";
- $object->unsubscribe_event( $event, $id );
+ # Delete from subscriptions and obtain id
+ my $id;
+ @{ $self->subscriptions } = grep { $_->[0] == $object and $_->[1] eq $event and ( $id = $_->[2], 0 ) or 1 }
+ @{ $self->subscriptions };
+ defined $id or
+ die "Not subscribed to $event\n";
- $ctx->respond( Tangence::Message->new( $self, MSG_OK ) );
+ $object->unsubscribe_event( $event, $id );
+
+ Tangence::Message->new( $self, MSG_OK )
+ };
+ $@ and return $ctx->responderr( $@ );
+
+ $ctx->respond( $response );
}
sub handle_request_GETPROP
{
my $self = shift;
my ( $token, $message ) = @_;
-
- my $objid = $message->unpack_int();
my $ctx = Tangence::Server::Context->new( $self, $token );
- my $object = $self->registry->get_by_id( $objid ) or
- return $ctx->responderr( "No such object with id $objid" );
+ my $response = eval {
+ my $objid = $message->unpack_int();
- my $response = eval { $object->handle_request_GETPROP( $ctx, $message ) };
+ my $object = $self->get_by_id( $objid );
+
+ $object->handle_request_GETPROP( $ctx, $message )
+ };
$@ and return $ctx->responderr( $@ );
$ctx->respond( $response );
@@ -255,14 +266,15 @@ sub handle_request_GETPROPELEM
my $self = shift;
my ( $token, $message ) = @_;
- my $objid = $message->unpack_int();
-
my $ctx = Tangence::Server::Context->new( $self, $token );
- my $object = $self->registry->get_by_id( $objid ) or
- return $ctx->responderr( "No such object with id $objid" );
+ my $response = eval {
+ my $objid = $message->unpack_int();
+
+ my $object = $self->get_by_id( $objid );
- my $response = eval { $object->handle_request_GETPROPELEM( $ctx, $message ) };
+ $object->handle_request_GETPROPELEM( $ctx, $message )
+ };
$@ and return $ctx->responderr( $@ );
$ctx->respond( $response );
@@ -272,15 +284,16 @@ sub handle_request_SETPROP
{
my $self = shift;
my ( $token, $message ) = @_;
-
- my $objid = $message->unpack_int();
my $ctx = Tangence::Server::Context->new( $self, $token );
- my $object = $self->registry->get_by_id( $objid ) or
- return $ctx->responderr( "No such object with id $objid" );
+ my $response = eval {
+ my $objid = $message->unpack_int();
- my $response = eval { $object->handle_request_SETPROP( $ctx, $message ) };
+ my $object = $self->get_by_id( $objid );
+
+ $object->handle_request_SETPROP( $ctx, $message )
+ };
$@ and return $ctx->responderr( $@ );
$ctx->respond( $response );
@@ -292,43 +305,46 @@ sub _handle_request_WATCHany
{
my $self = shift;
my ( $token, $message ) = @_;
-
- my $objid = $message->unpack_int();
- my $prop = $message->unpack_str();
- my $want_initial;
- my $from;
- if( $message->code == MSG_WATCH ) {
- $want_initial = $message->unpack_bool();
- }
- elsif( $message->code == MSG_WATCH_CUSR ) {
- $from = $message->unpack_int();
- }
my $ctx = Tangence::Server::Context->new( $self, $token );
- my $object = $self->registry->get_by_id( $objid ) or
- return $ctx->responderr( "No such object with id $objid" );
+ my ( $want_initial, $object, $prop );
- my $pdef = $object->can_property( $prop ) or
- return $ctx->responderr( "Object does not have property $prop" );
+ my $response = eval {
+ my $objid = $message->unpack_int();
+ $prop = $message->unpack_str();
- $self->_install_watch( $object, $prop );
+ $object = $self->get_by_id( $objid );
- if( $message->code == MSG_WATCH ) {
- $ctx->respond( Tangence::Message->new( $self, MSG_WATCHING ) );
- $self->_send_initial( $object, $prop ) if $want_initial;
- }
- elsif( $message->code == MSG_WATCH_CUSR ) {
- my $m = "cursor_prop_$prop";
- my $cursor = $object->$m( $from );
- my $id = $self->message_state->{next_cursorid}++;
- $self->peer_hascursor->{$id} = CursorObject( $cursor, $object );
- $ctx->respond( Tangence::Message->new( $self, MSG_WATCHING_CUSR )
- ->pack_int( $id )
- ->pack_int( 0 ) # first index
- ->pack_int( $#{ $object->${\"get_prop_$prop"} } ) # last index
- );
- }
+ my $pdef = $object->can_property( $prop ) or
+ die "Object does not have property $prop\n";
+
+ $self->_install_watch( $object, $prop );
+
+ if( $message->code == MSG_WATCH ) {
+ $want_initial = $message->unpack_bool();
+
+ Tangence::Message->new( $self, MSG_WATCHING )
+ }
+ elsif( $message->code == MSG_WATCH_CUSR ) {
+ my $from = $message->unpack_int();
+
+ my $m = "cursor_prop_$prop";
+ my $cursor = $object->$m( $from );
+ my $id = $self->message_state->{next_cursorid}++;
+
+ $self->peer_hascursor->{$id} = CursorObject( $cursor, $object );
+ Tangence::Message->new( $self, MSG_WATCHING_CUSR )
+ ->pack_int( $id )
+ ->pack_int( 0 ) # first index
+ ->pack_int( $#{ $object->${\"get_prop_$prop"} } ) # last index
+ }
+ };
+ $@ and return $ctx->responderr( $@ );
+
+ $ctx->respond( $response );
+
+ $self->_send_initial( $object, $prop ) if $want_initial;
}
sub _send_initial
@@ -354,28 +370,32 @@ sub handle_request_UNWATCH
{
my $self = shift;
my ( $token, $message ) = @_;
-
- my $objid = $message->unpack_int();
- my $prop = $message->unpack_str();
my $ctx = Tangence::Server::Context->new( $self, $token );
- my $object = $self->registry->get_by_id( $objid ) or
- return $ctx->responderr( "No such object with id $objid" );
+ my $response = eval {
+ my $objid = $message->unpack_int();
+ my $prop = $message->unpack_str();
- my $pdef = $object->can_property( $prop ) or
- return $ctx->responderr( "Object does not have property $prop" );
+ my $object = $self->get_by_id( $objid );
- # Delete from watches and obtain id
- my $id;
- @{ $self->watches } = grep { $_->[0] == $object and $_->[1] eq $prop and ( $id = $_->[2], 0 ) or 1 }
- @{ $self->watches };
- defined $id or
- return $ctx->responderr( "Not watching $prop" );
+ my $pdef = $object->can_property( $prop ) or
+ die "Object does not have property $prop\n";
- $object->unwatch_property( $prop, $id );
+ # Delete from watches and obtain id
+ my $id;
+ @{ $self->watches } = grep { $_->[0] == $object and $_->[1] eq $prop and ( $id = $_->[2], 0 ) or 1 }
+ @{ $self->watches };
+ defined $id or
+ die "Not watching $prop\n";
- $ctx->respond( Tangence::Message->new( $self, MSG_OK ) );
+ $object->unwatch_property( $prop, $id );
+
+ Tangence::Message->new( $self, MSG_OK );
+ };
+ $@ and return $ctx->responderr( $@ );
+
+ $ctx->respond( $response );
}
sub handle_request_CUSR_NEXT
@@ -461,10 +481,10 @@ sub handle_request_GETROOT
my $ctx = Tangence::Server::Context->new( $self, $token );
- my $root = $self->registry->get_by_id( 1 );
-
$self->identity( $identity );
+ my $root = $self->rootobj( $identity );
+
my $response = Tangence::Message->new( $self, MSG_RESULT );
TYPE_OBJ->pack_value( $response, $root );
@@ -478,6 +498,9 @@ sub handle_request_GETREGISTRY
my $ctx = Tangence::Server::Context->new( $self, $token );
+ $self->permit_registry or
+ return $ctx->responderr( "This client is not permitted access to the registry" );
+
my $response = Tangence::Message->new( $self, MSG_RESULT );
TYPE_OBJ->pack_value( $response, $self->registry );
@@ -507,7 +530,7 @@ sub _install_watch
my %callbacks;
foreach my $name ( @{ CHANGETYPES->{$dim} } ) {
my $how = $change_values{$name};
- $callbacks{$name} = subname "__WATCH($prop:$name)__" => sub {
+ $callbacks{$name} = set_subname "__WATCH($prop:$name)__" => sub {
$weakself or return;
my $object = shift;
@@ -562,6 +585,50 @@ sub object_destroyed
$self->SUPER::object_destroyed( @_ );
}
+=head1 OVERRIDEABLE METHODS
+
+The following methods are provided but intended to be overridden if the
+implementing class wishes to provide different behaviour from the default.
+
+=cut
+
+=head2 rootobj
+
+ $rootobj = $server->rootobj( $identity )
+
+Invoked when a C<GETROOT> message is received from the client, this method
+should return a L<Tangence::Object> as root object for the connection.
+
+The default implementation will return the object with ID 1; i.e. the first
+object created in the registry.
+
+=cut
+
+sub rootobj
+{
+ my $self = shift;
+
+ return $self->registry->get_by_id( 1 );
+}
+
+=head2 permit_registry
+
+ $allow = $server->permit_registry
+
+Invoked when a C<GETREGISTRY> message is received from the client, this method
+should return a boolean to indicate whether the client is allowed to access
+the object registry.
+
+The default implementation always permits this, but an overridden method may
+decide to disallow it in some situations. When disabled, a client will not be
+able to gain access to any serverside objects other than the root object, and
+(recursively) any other objects returned by methods, events or properties on
+objects already known. This can be used as a security mechanism.
+
+=cut
+
+sub permit_registry { 1; }
+
=head1 AUTHOR
Paul Evans <leonerd@leonerd.org.uk>
diff --git a/lib/Tangence/Server/Context.pm b/lib/Tangence/Server/Context.pm
index ed7c417..c4a6f7c 100644
--- a/lib/Tangence/Server/Context.pm
+++ b/lib/Tangence/Server/Context.pm
@@ -8,7 +8,7 @@ package Tangence::Server::Context;
use strict;
use warnings;
-our $VERSION = '0.24';
+our $VERSION = '0.25';
use Carp;
@@ -56,6 +56,8 @@ sub responderr
my $self = shift;
my ( $msg ) = @_;
+ chomp $msg; # In case of simple ->responderr( $@ );
+
$self->respond( Tangence::Message->new( $self->stream, MSG_ERROR )
->pack_str( $msg )
);
diff --git a/lib/Tangence/Stream.pm b/lib/Tangence/Stream.pm
index e54194f..2f49590 100644
--- a/lib/Tangence/Stream.pm
+++ b/lib/Tangence/Stream.pm
@@ -1,7 +1,7 @@
# You may distribute under the terms of either the GNU General Public License
# or the Artistic License (the same terms as Perl itself)
#
-# (C) Paul Evans, 2011-2016 -- leonerd@leonerd.org.uk
+# (C) Paul Evans, 2011-2020 -- leonerd@leonerd.org.uk
package Tangence::Stream;
@@ -9,7 +9,7 @@ use strict;
use warnings;
use 5.010; # //
-our $VERSION = '0.24';
+our $VERSION = '0.25';
use Carp;
@@ -68,14 +68,18 @@ mixin.
=cut
-=head2 $stream->tangence_write( $data )
+=head2 tangence_write
+
+ $stream->tangence_write( $data )
Write bytes of data to the connected peer. C<$data> will be a plain perl
string.
=cut
-=head2 $stream->handle_request_$CODE( $token, $message )
+=head2 handle_request_$CODE
+
+ $stream->handle_request_$CODE( $token, $message )
Invoked on receipt of a given message code. C<$token> will be some opaque perl
scalar value, and C<$message> will be an instance of L<Tangence::Message>.
@@ -117,7 +121,9 @@ sub identity
return $self->{identity};
}
-=head2 $stream->tangence_closed
+=head2 tangence_closed
+
+ $stream->tangence_closed
Informs the object that the underlying connection has now been closed, and any
attachments to C<Tangence::Object> or C<Tangence::ObjectProxy> instances
@@ -135,7 +141,9 @@ sub tangence_closed
}
}
-=head2 $stream->tangence_readfrom( $buffer )
+=head2 tangence_readfrom
+
+ $stream->tangence_readfrom( $buffer )
Informs the object that more data has been read from the underlying connection
stream. Whole messages will be removed from the beginning of the C<$buffer>,
@@ -213,7 +221,9 @@ sub object_destroyed
);
}
-=head2 $stream->request( %args )
+=head2 request
+
+ $stream->request( %args )
Serialises a message object to pass to the C<tangence_write> method, then
enqueues a response handler to be invoked when a reply arrives. Takes the
@@ -234,7 +244,9 @@ received. It will be passed the response message:
=back
-=head2 $response = $stream->request( request => $request )->get
+=head2 request (non-void)
+
+ $response = $stream->request( request => $request )->get
When called in non-void context, this method returns a L<Future> that will
yield the response instead. In this case it should not be given an
@@ -280,7 +292,9 @@ sub request
return $f;
}
-=head2 $stream->respond( $token, $message )
+=head2 respond
+
+ $stream->respond( $token, $message )
Serialises a message object to be sent to the C<tangence_write> method. The
C<$token> value that was passed to the C<handle_request_> method ensures that
@@ -313,7 +327,9 @@ sub respondERROR
);
}
-=head2 $ver = $stream->minor_version
+=head2 minor_version
+
+ $ver = $stream->minor_version
Returns the minor version negotiated by the C<MSG_INIT> / C<MSG_INITED>
initial message handshake.
@@ -329,12 +345,6 @@ sub minor_version
# Some (internal) methods that control new protocol features
-# wire protocol supports MSG_GETPROPELEM
-sub _ver_can_getpropelem { shift->minor_version >= 3 }
-
-# wire protocol supports MSG_WATCH_CUSR and cursors
-sub _ver_can_cursor { shift->minor_version >= 3 }
-
# wire protocol uses typed smash data
sub _ver_can_typed_smash { shift->minor_version >= 4 }
diff --git a/lib/Tangence/Struct.pm b/lib/Tangence/Struct.pm
index fcf3026..49d62b8 100644
--- a/lib/Tangence/Struct.pm
+++ b/lib/Tangence/Struct.pm
@@ -4,7 +4,7 @@ use strict;
use warnings;
use base qw( Tangence::Meta::Struct );
-our $VERSION = '0.24';
+our $VERSION = '0.25';
use Carp;
diff --git a/lib/Tangence/Type.pm b/lib/Tangence/Type.pm
index 2bb7a63..efc3444 100644
--- a/lib/Tangence/Type.pm
+++ b/lib/Tangence/Type.pm
@@ -1,7 +1,7 @@
# You may distribute under the terms of either the GNU General Public License
# or the Artistic License (the same terms as Perl itself)
#
-# (C) Paul Evans, 2013-2014 -- leonerd@leonerd.org.uk
+# (C) Paul Evans, 2013-2017 -- leonerd@leonerd.org.uk
package Tangence::Type;
@@ -27,13 +27,15 @@ implementations.
=head1 CONSTRUCTOR
-=head2 $type = Tangence::Type->new( $primitive_sig )
+=head2 new
+
+ $type = Tangence::Type->new( $primitive_sig )
Returns an instance to represent a primitive type of the given signature.
-=head2 $type = Tangence::Type->new( list => $member_type )
+ $type = Tangence::Type->new( list => $member_type )
-=head2 $type = Tangence::Type->new( dict => $member_type )
+ $type = Tangence::Type->new( dict => $member_type )
Returns an instance to represent a list or dict aggregation containing members
of the given type.
@@ -69,15 +71,21 @@ sub new
=head1 METHODS
-=head2 $value = $type->default_value
+=head2 default_value
+
+ $value = $type->default_value
Returns a value suitable to use as an initial value for object properties.
-=head2 $type->pack_value( $message, $value )
+=head2 pack_value
+
+ $type->pack_value( $message, $value )
Appends a value of this type to the end of a L<Tangence::Message>.
-=head2 $value = $type->unpack_value( $message )
+=head2 unpack_value
+
+ $value = $type->unpack_value( $message )
Removes a value of this type from the start of a L<Tangence::Message>.
diff --git a/lib/Tangence/Types.pm b/lib/Tangence/Types.pm
index a56219f..ec4ba42 100644
--- a/lib/Tangence/Types.pm
+++ b/lib/Tangence/Types.pm
@@ -8,7 +8,7 @@ package Tangence::Types;
use strict;
use warnings;
-our $VERSION = '0.24';
+our $VERSION = '0.25';
use Exporter 'import';
our @EXPORT = qw(
diff --git a/t/21client.t b/t/21client.t
index 91751dd..bdd92b6 100644
--- a/t/21client.t
+++ b/t/21client.t
@@ -29,6 +29,9 @@ my $client = TestClient->new();
$client->send_message( $S2C{GETROOT} );
$client->send_message( $S2C{GETREGISTRY} );
+
+ ok( defined $client->rootobj, 'client has rootobj' );
+ ok( defined $client->registry, 'client has registry' );
}
my $objproxy = $client->rootobj;
diff --git a/t/30props-cbs.t b/t/30props-cbs.t
index afb9ca6..e9f8757 100644
--- a/t/30props-cbs.t
+++ b/t/30props-cbs.t
@@ -3,7 +3,7 @@
use strict;
use warnings;
-use Test::More tests => 24;
+use Test::More;
use Test::Memory::Cycle;
use Tangence::Constants;
diff --git a/t/33props-set.t b/t/33props-set.t
new file mode 100644
index 0000000..c9e32a9
--- /dev/null
+++ b/t/33props-set.t
@@ -0,0 +1,53 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use Test::More;
+
+use Tangence::Registry;
+
+use lib ".";
+use t::TestObj;
+use t::TestServerClient;
+
+my $registry = Tangence::Registry->new(
+ tanfile => "t/TestObj.tan",
+);
+my $obj = $registry->construct(
+ "t::TestObj",
+);
+
+my ( $server, $client ) = make_serverclient( $registry );
+
+my $proxy = $client->rootobj;
+
+# scalar
+{
+ $proxy->set_property( "scalar", 456 )->get;
+
+ is( $obj->get_prop_scalar, 456, 'set_property on scalar' );
+}
+
+# array
+{
+ $proxy->set_property( "array", [ 4, 5, 6 ] )->get;
+
+ is_deeply( $obj->get_prop_array, [ 4, 5, 6 ], 'set_property on array' );
+}
+
+# queue
+{
+ $proxy->set_property( "queue", [ 4, 5, 6 ] )->get;
+
+ is_deeply( $obj->get_prop_queue, [ 4, 5, 6 ], 'set_property on queue' );
+}
+
+# hash
+{
+ $proxy->set_property( "hash", { four => 4, five => 5 } )->get;
+
+ is_deeply( $obj->get_prop_hash, { four => 4, five => 5 }, 'set_property on hash' );
+}
+
+done_testing;
diff --git a/t/40server-security.t b/t/40server-security.t
new file mode 100644
index 0000000..7d338bd
--- /dev/null
+++ b/t/40server-security.t
@@ -0,0 +1,82 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use Test::More;
+
+use Tangence::Constants;
+use Tangence::Registry;
+
+use lib ".";
+use t::TestObj;
+use t::TestServerClient;
+
+my $registry = Tangence::Registry->new(
+ tanfile => "t/TestObj.tan",
+);
+my $obj = $registry->construct(
+ "t::TestObj",
+);
+# generate a second object that exists but we don't tell the client about
+my $obj2 = $registry->construct(
+ "t::TestObj",
+);
+
+my ( $server, $client ) = make_serverclient( $registry );
+
+my $proxy = $client->rootobj;
+
+# gutwrench into the objectproxy to make a new one with a different ID
+$proxy->{id} == $obj->id or die "ARGH failed to have correct object ID in proxy";
+
+my $proxy2 = { %$proxy, id => $obj2->id };
+bless $proxy2, ref $proxy;
+
+# $proxy2 should now not work for anything
+
+# methods
+{
+ my $f = $proxy2->call_method( "method", 0, "" );
+
+ like( $f->failure, qr/^Access not allowed to object with id 2/,
+ 'unseen objects inaccessible by method' );
+}
+
+# events
+{
+ my $f = $proxy2->subscribe_event( "event", on_fire => sub {} );
+
+ like( $f->failure, qr/^Access not allowed to object with id 2/,
+ 'unseen objects inaccessible by event' );
+}
+
+# properties
+{
+ my $f = $proxy2->get_property( "scalar" );
+
+ like( $f->failure, qr/^Access not allowed to object with id 2/,
+ 'unseen objects inaccessible by property get' );
+
+ $f = $proxy2->set_property( "scalar", 123 );
+
+ like( $f->failure, qr/^Access not allowed to object with id 2/,
+ 'unseen objects inaccessible by property set' );
+
+ $f = $proxy2->watch_property( "scalar", on_set => sub {} );
+
+ like( $f->failure, qr/^Access not allowed to object with id 2/,
+ 'unseen objects inaccessible by property watch' );
+}
+
+# as argument to otherwise-allowed object
+{
+ $proxy->set_property( "objset", [ $proxy ] )->get; # is allowed
+
+ my $f = $proxy->set_property( "objset", [ $proxy2 ] );
+
+ like( $f->failure, qr/^Access not allowed to object with id 2/,
+ 'unseen objects not allowed by value' );
+}
+
+done_testing;
diff --git a/t/Conversation.pm b/t/Conversation.pm
index 27e5d16..97ca600 100644
--- a/t/Conversation.pm
+++ b/t/Conversation.pm
@@ -29,7 +29,7 @@ $C2S{INIT} =
"\x7f" . "\0\0\0\6" .
"\x02" . "\0" .
"\x02" . "\4" .
- "\x02" . "\2";
+ "\x02" . "\3";
# MSG_INITED
$S2C{INITED} =