package Dakkar::Misskey; use v5.36; use Moo; use JSON::MaybeXS; use LWP::UserAgent; use Types::Standard qw(Str); use Types::URI qw(Uri); use List::Util qw(maxstr); use URI; use namespace::clean; has _json => ( is => 'lazy', builder => sub { JSON::MaybeXS->new(utf8=>1,relaxed=>1, pretty=>0) } ); has ua => ( is => 'lazy', builder => sub { LWP::UserAgent->new(agent=>'Dakkar::Misskey') } ); has token => ( is => 'ro', required => 1 ); has base_url => ( is => 'ro', required => 1, isa => Uri, coerce => 1 ); sub _request($self, $endpoint, $payload) { my $payload_json = $self->_json->encode({ $payload->%*, i => $self->token, }); my $uri = URI->new($endpoint)->abs($self->base_url); my $response = $self->ua->post( $uri, 'Content-type' => 'application/json', Content => $payload_json, ); if ($response->is_success) { return $self->_json->decode( $response->decoded_content(charset=>'none') ); } die $response->status_line; } sub _paged_request($self, $endpoint, $payload, $cb) { my @all_results; # misskey paged endpoints return results ordered differently # depending on the presence of `sinceId`, `untilId`, `sinceDate`, # `untilDate` # # sinceId untilId sinceDate untilDate order by # x x ? ? id DESC # x ? ? id ASC # x ? ? id DESC # x x createdAt DESC # x createdAt ASC # x createdAt DESC # id DESC # # for simplicity, here we assume we'll never get `untilId`, # `sinceDate`, or `untilDate`, and we page with `sinceId` in # ASCending `id` order my $page_payload = { limit => 100, sinceId => '0', $payload->%*, }; while (1) { my $result = $self->_request($endpoint, $page_payload); last unless $result->@*; if ($cb) { $cb->($result); } else { push @all_results, $result->@*; } $page_payload->{sinceId} = maxstr(map { $_->{id} } $result->@* ); } return \@all_results; } sub timeline($self,$options,$cb=undef) { return $self->_paged_request( 'api/notes/timeline', $options, $cb, ); } sub followers($self,$user_id,$cb=undef) { return $self->_paged_request( 'api/users/followers', { userId => $user_id }, $cb, ); } sub following($self,$user_id,$cb=undef) { return $self->_paged_request( 'api/users/following', { userId => $user_id }, $cb, ); } 1;