App-cpanel
view release on metacpan or search on metacpan
lib/App/cpanel.pm view on Meta::CPAN
use strict;
use warnings;
use Mojo::URL;
use Mojo::UserAgent;
use Mojo::File qw(path);
use Mojo::Util qw(dumper encode);
my %cmd2func = (
uapi => [ \&uapi_p, 1 ],
download => [ \&download_p, 0 ],
upload => [ \&upload_p, 1 ],
api2 => [ \&api2_p, 1 ],
mirror => [ \&mirror_p, 1 ],
);
my $token_file = "$ENV{HOME}/.cpanel-token";
my $domain_file = "$ENV{HOME}/.cpanel-domain";
my %localfs_map = (
ls => \&localfs_ls,
mkdir => \&localfs_mkdir,
read => \&localfs_read,
write => \&localfs_write,
chmod => \&localfs_chmod,
);
my %cpanel_map = (
ls => \&cpanel_ls,
mkdir => \&cpanel_mkdir,
read => \&cpanel_read,
write => \&cpanel_write,
chmod => \&cpanel_chmod,
);
our %MAP2HASH = (
localfs => \%localfs_map,
cpanel => \%cpanel_map,
);
sub dispatch_cmd_print {
my $cmd = shift;
die "No command\n" unless $cmd;
die "Unknown command '$cmd'\n" unless my $info = $cmd2func{$cmd};
my $p = dispatch_cmd_raw_p($cmd, @_);
$p = $p->then(\&dumper) if $info->[1];
$p->then(sub { print @_ }, sub { warn encode 'UTF-8', join '', @_ })->wait;
}
sub dispatch_cmd_raw_p {
my $cmd = shift;
die "No command\n" unless $cmd;
die "Unknown command '$cmd'\n" unless my $info = $cmd2func{$cmd};
goto &{$info->[0]};
}
sub api_request {
my ($method, $domain, $token, $parts, $args, @extra_args) = @_;
my ($url_token, $cookie_token) = split /\s+/, $token;
my $url = Mojo::URL->new("https://$domain:2083");
$url->path(join '/', '', "cpsess$url_token", @$parts);
$url->query(%$args) if $args;
CORE::state $ua = Mojo::UserAgent->new; # state as needs to live long enough to complete request
$ua->$method(
$url->to_abs . "",
{ Cookie => "cpsession=$cookie_token" },
@extra_args,
);
}
sub read_file {
my ($file) = @_;
die "$file: $!\n" unless -f $file;
die "$file: too readable\n" if (stat $file)[2] & 0044;
local $/;
open my $fh, $file or die "$file: $!\n";
my $content = <$fh>;
die "No content in '$file'\n" unless $content;
$content =~ s/^\s*(.*?)\s*$/$1/g;
$content;
}
sub read_token { read_file($token_file) }
sub read_domain { read_file($domain_file) }
sub _error_or_json {
my $res = $_[0]->res;
die $res->code . ": " . $res->message . "\n" if $res->code != 200;
$res->json;
}
sub _uapi_error_or_json {
my $json = $_[0];
if (!$json->{status}) {
die join '', "Failed:\n",
map "$_\n", map @{ $json->{$_} || [] }, qw(errors warnings);
}
$json;
}
sub uapi_p {
my ($module, $function, @args) = @_;
die "No module\n" unless $module;
die "No function\n" unless $function;
my ($token, $domain) = (read_token(), read_domain());
my $args_hash = ref($args[0]) eq 'HASH'
? $args[0]
: { map split('=', $_, 2), @args }
if @args;
my $tx_p = api_request 'get_p', $domain, $token,
[ 'execute', $module, $function ],
$args_hash;
$tx_p->then(\&_error_or_json)->then(\&_uapi_error_or_json);
}
sub download_p {
my ($file) = @_;
die "No file\n" unless $file;
my ($token, $domain) = (read_token(), read_domain());
my $tx_p = api_request 'get_p', $domain, $token,
[ 'download' ],
{ skipencode => 1, file => $file };
$tx_p->then(sub {
my $res = $_[0]->res;
die $res->code . ": " . $res->message . "\n" if $res->code != 200;
$res->body;
( run in 1.731 second using v1.01-cache-2.11-cpan-acf6aa7dc9e )