Util.pm 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. package Playwright::Util;
  2. use strict;
  3. use warnings;
  4. use v5.28;
  5. use JSON::MaybeXS();
  6. use Carp qw{confess};
  7. use Sereal::Encoder;
  8. use Sereal::Decoder;
  9. use File::Temp;
  10. use POSIX();
  11. #ABSTRACT: Common utility functions for the Playwright module
  12. no warnings 'experimental';
  13. use feature qw{signatures};
  14. use constant IS_WIN => $^O eq 'MSWin32';
  15. =head2 request(STRING method, STRING url, STRING host, INTEGER port, LWP::UserAgent ua, HASH args) = HASH
  16. De-duplicates request logic in the Playwright Modules.
  17. =cut
  18. sub request ( $method,$url, $host, $port, $ua, %args ) {
  19. my $fullurl = "http://$host:$port/$url";
  20. # Handle passing Playwright elements as arguments
  21. if (ref $args{args} eq 'ARRAY') {
  22. @{$args{args}} = map {
  23. my $transformed = $_;
  24. if (ref($_) eq 'Playwright::ElementHandle' ) {
  25. $transformed = { uuid => $_->{guid} }
  26. }
  27. $transformed;
  28. } @{$args{args}};
  29. }
  30. my $request = HTTP::Request->new( $method, $fullurl );
  31. $request->header( 'Content-type' => 'application/json' );
  32. $request->content( JSON::MaybeXS::encode_json( \%args ) );
  33. my $response = $ua->request($request);
  34. my $content = $response->decoded_content();
  35. # If we get this kind of response the server failed to come up :(
  36. die "playwright server failed to spawn!" if $content =~ m/^Can't connect to/;
  37. my $decoded = JSON::MaybeXS::decode_json($content);
  38. my $msg = $decoded->{message};
  39. confess($msg) if $decoded->{error};
  40. return $msg;
  41. }
  42. sub arr2hash ($array,$primary_key,$callback='') {
  43. my $inside_out = {};
  44. @$inside_out{map { $callback ? $callback->($_->{$primary_key}) : $_->{$primary_key} } @$array} = @$array;
  45. return $inside_out;
  46. }
  47. # Serialize a subprocess because NOTHING ON CPAN DOES THIS GRRRRR
  48. sub async ($subroutine) {
  49. # The fork would result in the tmpdir getting whacked when it terminates.
  50. my $fh = File::Temp->new();
  51. my $pid = fork() // die "Could not fork";
  52. _child($fh->filename, $subroutine) unless $pid;
  53. return { pid => $pid, file => $fh };
  54. }
  55. sub _child ($filename,$subroutine) {
  56. Sereal::Encoder->encode_to_file($filename,$subroutine->());
  57. # Prevent destructors from firing due to exiting instantly...unless we are on windows, where they won't.
  58. POSIX::_exit(0) unless IS_WIN;
  59. exit 0;
  60. }
  61. sub await ($to_wait) {
  62. waitpid($to_wait->{pid},0);
  63. confess("Timed out while waiting for event.") unless -f $to_wait->{file}->filename && -s _;
  64. return Sereal::Decoder->decode_from_file($to_wait->{file}->filename);
  65. }
  66. 1;