2017-12-14 13:12:04 +03:00
package PVE::APIClient::Exception ;
# a way to add more information to exceptions (see man perlfunc (die))
# use PVE::APIClient::Exception qw(raise);
# raise ("my error message", code => 400, errors => { param1 => "err1", ...} );
use strict ;
use warnings ;
2018-06-14 10:59:17 +03:00
use vars qw( @ISA @EXPORT_OK ) ;
require Exporter ;
use Storable qw( dclone ) ;
2017-12-14 13:12:04 +03:00
use HTTP::Status qw( :constants ) ;
2018-06-14 10:59:17 +03:00
@ ISA = qw( Exporter ) ;
2017-12-14 13:12:04 +03:00
use overload '""' = > sub { local $@ ; shift - > stringify } ;
use overload 'cmp' = > sub {
my ( $ a , $ b ) = @ _ ;
2018-06-14 10:59:17 +03:00
local $@ ;
2017-12-14 13:12:04 +03:00
return "$a" cmp "$b" ; # compare as string
} ;
2018-06-14 10:59:17 +03:00
@ EXPORT_OK = qw( raise raise_param_exc raise_perm_exc ) ;
2017-12-14 13:12:04 +03:00
sub new {
my ( $ class , $ msg , % param ) = @ _ ;
$ class = ref ( $ class ) || $ class ;
my $ self = {
msg = > $ msg ,
} ;
foreach my $ p ( keys % param ) {
2018-06-14 10:59:17 +03:00
next if defined ( $ self - > { $ p } ) ;
2017-12-14 13:12:04 +03:00
my $ v = $ param { $ p } ;
$ self - > { $ p } = ref ( $ v ) ? dclone ( $ v ) : $ v ;
}
return bless $ self ;
}
sub raise {
my $ exc = PVE::APIClient::Exception - > new ( @ _ ) ;
2018-06-14 10:59:17 +03:00
my ( $ pkg , $ filename , $ line ) = caller ;
$ exc - > { filename } = $ filename ;
$ exc - > { line } = $ line ;
die $ exc ;
}
sub raise_perm_exc {
my ( $ what ) = @ _ ;
my $ param = { code = > HTTP_FORBIDDEN } ;
2017-12-14 13:12:04 +03:00
2018-06-14 10:59:17 +03:00
my $ msg = "Permission check failed" ;
$ msg . = " ($what)" if $ what ;
my $ exc = PVE::APIClient::Exception - > new ( "$msg\n" , %$ param ) ;
my ( $ pkg , $ filename , $ line ) = caller ;
$ exc - > { filename } = $ filename ;
$ exc - > { line } = $ line ;
die $ exc ;
}
sub is_param_exc {
my ( $ self ) = @ _ ;
return $ self - > { code } && $ self - > { code } eq HTTP_BAD_REQUEST ;
}
sub raise_param_exc {
my ( $ errors , $ usage ) = @ _ ;
my $ param = {
code = > HTTP_BAD_REQUEST ,
errors = > $ errors ,
} ;
$ param - > { usage } = $ usage if $ usage ;
my $ exc = PVE::APIClient::Exception - > new ( "Parameter verification failed.\n" , %$ param ) ;
2017-12-14 13:12:04 +03:00
my ( $ pkg , $ filename , $ line ) = caller ;
$ exc - > { filename } = $ filename ;
$ exc - > { line } = $ line ;
die $ exc ;
}
sub stringify {
my $ self = shift ;
2020-12-03 17:55:53 +03:00
my $ msg = $ self - > { msg } ;
if ( my $ code = $ self - > { code } ) {
if ( $ msg !~ /^\s*\Q$code\E[\s:,]/ ) { # avoid duplicating the error code heuristically
$ msg = "$code $msg" ;
}
}
2017-12-14 13:12:04 +03:00
if ( $ msg !~ m/\n$/ ) {
2018-06-14 10:59:17 +03:00
2017-12-14 13:12:04 +03:00
if ( $ self - > { filename } && $ self - > { line } ) {
$ msg . = " at $self->{filename} line $self->{line}" ;
}
2018-06-14 10:59:17 +03:00
2017-12-14 13:12:04 +03:00
$ msg . = "\n" ;
}
if ( $ self - > { errors } ) {
foreach my $ e ( keys % { $ self - > { errors } } ) {
$ msg . = "$e: $self->{errors}->{$e}\n" ;
}
}
if ( $ self - > { propagate } ) {
foreach my $ pi ( @ { $ self - > { propagate } } ) {
$ msg . = "\t...propagated at $pi->[0] line $pi->[1]\n" ;
}
}
if ( $ self - > { usage } ) {
$ msg . = $ self - > { usage } ;
$ msg . = "\n" if $ msg !~ m/\n$/ ;
}
return $ msg ;
}
sub PROPAGATE {
my ( $ self , $ file , $ line ) = @ _ ;
2018-06-14 10:59:17 +03:00
push @ { $ self - > { propagate } } , [ $ file , $ line ] ;
2017-12-14 13:12:04 +03:00
return $ self ;
}
1 ;