فهرست منبع

I have event waiters working ok. But I need a better async solution

George S. Baugh 5 سال پیش
والد
کامیت
119e0af722
4فایلهای تغییر یافته به همراه82 افزوده شده و 37 حذف شده
  1. 13 0
      bin/playwright.js
  2. 17 0
      example.pl
  3. 45 4
      lib/Playwright.pm
  4. 7 33
      lib/Playwright/Base.pm

+ 13 - 0
bin/playwright.js

@@ -35,6 +35,9 @@ const port = argv.port || 6969;
 var objects = {};
 var browsers = { 'firefox' : firefox, 'chrome' : chromium, 'webkit' : webkit };
 
+//Stash for users to put data in
+var userdata = {};
+
 app.use(express.json())
 
 app.post('/session', async (req, res) => {
@@ -116,6 +119,16 @@ app.post('/command', async (req, res) => {
         } catch (e) {
             result = { error : true, message : e.message };
         }
+    // Allow creation of event listeners if we can actually wait for them
+    } else if (command == 'on' && subject && spec[type].members.waitForEvent ) {
+        try {
+            var evt = args.shift();
+            const cb  = new Function (args.shift());
+            subject.on(evt,cb);
+            result = { error : false, message : "Listener set up" };
+        } catch (e) {
+            result = { error : true, message : e.message };
+        }
     } else {
         result = { error : true, message : "No such object, or " + command + " is not a globally recognized command for puppeteer" };
     }

+ 17 - 0
example.pl

@@ -3,6 +3,8 @@ use warnings;
 
 use Data::Dumper;
 use JSON::PP;
+use Async;
+
 use Playwright;
 
 use Try::Tiny;
@@ -47,6 +49,21 @@ my $fun = "
 my $result = $page->evaluate($fun, 'zippy');
 print Dumper($result);
 
+# Read the console
+$page->on('console',"return [...arguments]");
+
+#XXX this is unfortunately stringifying this object
+my $proc = Async->new( sub {
+    return $page->waitForEvent('console');
+});
+$page->evaluate("console.log('hug')");
+my $console_log = $proc->result(1);
+
+use Data::Dumper;
+print Dumper($console_log);
+
+#print "Logged to console: '".$console_log->text()."'\n";
+
 # Use a selector to find which input is visible and type into it
 # Ideally you'd use a better selector to solve this problem, but this is just showing off
 my $inputs = $page->selectMulti('input');

+ 45 - 4
lib/Playwright.pm

@@ -93,7 +93,7 @@ Creates a new browser and returns a handle to interact with it.
 
 =cut
 
-our ($spec, $server_bin, %mapper);
+our ($spec, $server_bin, %mapper, %methods_to_rename);
 
 BEGIN {
     my $path2here = File::Basename::dirname(Cwd::abs_path($INC{'Playwright.pm'}));
@@ -104,6 +104,16 @@ BEGIN {
     my $decoder = JSON::MaybeXS->new();
     $spec = $decoder->decode($spec_raw);
 
+    $mapper{mouse}    = sub { my ($self, $res) = @_; return Playwright::Mouse->new( handle => $self, id => $res->{_guid}, type => 'Mouse' ) };
+    $mapper{keyboard} = sub { my ($self, $res) = @_; return Playwright::Keyboard->new( handle => $self, id => $res->{_guid}, type => 'Keyboard' ) };
+
+    %methods_to_rename = (
+        '$'      => 'select',
+        '$$'     => 'selectMulti',
+        '$eval'  => 'eval',
+        '$$eval' => 'evalMulti',
+    );
+
     foreach my $class (keys(%$spec)) {
         $mapper{$class} = sub {
             my ($self, $res) = @_;
@@ -121,10 +131,37 @@ BEGIN {
             as   => 'new',
             into => "Playwright::$class",
         });
-    }
 
-    $mapper{mouse}    = sub { my ($self, $res) = @_; return Playwright::Mouse->new( handle => $self, id => $res->{_guid}, type => 'Mouse' ) };
-    $mapper{keyboard} = sub { my ($self, $res) = @_; return Playwright::Keyboard->new( handle => $self, id => $res->{_guid}, type => 'Keyboard' ) };
+        # Hack in mouse and keyboard objects for the Page class
+        if ($class eq 'Page') {
+            foreach my $hid (qw{keyboard mouse}) {
+                Sub::Install::install_sub({
+                    code => sub {
+                        my $self = shift;
+                        $Playwright::mapper{$hid}->($self, { _type => $self->{type}, _guid => $self->{guid} }) if exists $Playwright::mapper{$hid};
+                    },
+                    as   => $hid,
+                    into => "Playwright::$class",
+                });
+            }
+        }
+
+        # Install the subroutines if they aren't already
+        foreach my $method ((keys(%{$spec->{$class}{members}}), 'on')) {
+            next if grep { $_ eq $method } qw{keyboard mouse};
+            my $renamed = exists $methods_to_rename{$method} ? $methods_to_rename{$method} : $method;
+
+            print "Installing sub $renamed into Playwright::$class\n";
+            Sub::Install::install_sub({
+                code => sub {
+                    my $self = shift;
+                    Playwright::Base::_request($self, args => [@_], command => $method, object => $self->{guid}, type => $self->{type} );
+                },
+                as   => $renamed,
+                into => "Playwright::$class",
+            });
+        }
+    }
 
     # Make sure it's possible to start the server
     $server_bin = "$path2here/../bin/playwright.js";
@@ -140,6 +177,7 @@ sub new ($class, %options) {
         port    => $port,
         debug   => $options{debug},
         pid     => _start_server( $port, $options{debug}),
+        parent  => $$,
     }, $class);
 
     return $self;
@@ -172,6 +210,9 @@ Automatically called when the Playwright object goes out of scope.
 =cut
 
 sub quit ($self) {
+    #Prevent destructor from firing in child processes so we can do things like async()
+    return unless $$ == $self->{parent};
+
     Playwright::Util::request ('GET', 'shutdown', $self->{port}, $self->{ua} ); 
     return waitpid($self->{pid},0);
 }

+ 7 - 33
lib/Playwright/Base.pm

@@ -37,12 +37,13 @@ Creates a new page and returns a handle to interact with it.
 
 =cut
 
-our %methods_to_rename = (
-    '$'      => 'select',
-    '$$'     => 'selectMulti',
-    '$eval'  => 'eval',
-    '$$eval' => 'evalMulti',
-);
+sub AUTOLOAD {
+    our $AUTOLOAD;
+    my $method = $AUTOLOAD;
+    my ($self,@args) = @_;
+
+    return Playwright::Base::_request($self, args => [@args], command => $method, object => $self->{guid}, type => $self->{type} );
+}
 
 sub new ($class, %options) {
 
@@ -54,33 +55,6 @@ sub new ($class, %options) {
         port    => $options{handle}{port},
     }, $class);
 
-    # Hack in mouse and keyboard objects for the Page class
-    if ($self->{type} eq 'Page') {
-        foreach my $hid (qw{keyboard mouse}) {
-            Sub::Install::install_sub({
-                code => sub {
-                    my $self = shift;
-                    $Playwright::mapper{$hid}->($self, { _type => 'Page', _guid => $self->{guid} }) if exists $Playwright::mapper{$hid};
-                },
-                as   => $hid,
-                into => $class,
-            }) unless $self->can($hid);
-        }
-    }
-
-    # Install the subroutines if they aren't already
-    foreach my $method (keys(%{$self->{spec}})) {
-        my $renamed = exists $methods_to_rename{$method} ? $methods_to_rename{$method} : $method;
-        Sub::Install::install_sub({
-            code => sub {
-                my $self = shift;
-                Playwright::Base::_request($self, args => [@_], command => $method, object => $self->{guid}, type => $self->{type} );
-            },
-            as   => $renamed,
-            into => $class,
-        }) unless $self->can($renamed);
-    }
-
     return ($self);
 }