madeon (madeon) wrote in changelog,
madeon
madeon
changelog

[livejournal] r21925: LJSUP-12148: JSON-RPC

Committer: sbelyaev
LJSUP-12148: JSON-RPC
U   trunk/bin/upgrading/proplists.dat
U   trunk/bin/upgrading/update-db-general.pl
A   trunk/cgi-bin/LJ/API/
A   trunk/cgi-bin/LJ/API/Error.pm
A   trunk/cgi-bin/LJ/API/Namespaces.pm
A   trunk/cgi-bin/LJ/API/Repost.pm
A   trunk/cgi-bin/LJ/Controller/
A   trunk/cgi-bin/LJ/Controller/API/
A   trunk/cgi-bin/LJ/Controller/API/JSON.pm
A   trunk/cgi-bin/LJ/Entry/
A   trunk/cgi-bin/LJ/Entry/Repost.pm
U   trunk/cgi-bin/LJ/Entry.pm
A   trunk/cgi-bin/LJ/JSON/
A   trunk/cgi-bin/LJ/JSON/RPC/
A   trunk/cgi-bin/LJ/JSON/RPC/Item.pm
A   trunk/cgi-bin/LJ/JSON/RPC.pm
A   trunk/cgi-bin/LJ/Router/
A   trunk/cgi-bin/LJ/Router/API.pm
U   trunk/cgi-bin/ljlib.pl
Modified: trunk/bin/upgrading/proplists.dat
===================================================================
--- trunk/bin/upgrading/proplists.dat	2012-05-12 09:03:36 UTC (rev 21924)
+++ trunk/bin/upgrading/proplists.dat	2012-05-12 09:05:55 UTC (rev 21925)
@@ -1836,3 +1836,9 @@
   prettyname: Crosspost to vkontakte
   sortorder: 114
 
+logproplist.repost_link:
+  datatype: char
+  des: repost link information
+  prettyname: Repost link informaton
+  sortorder: 114
+

Modified: trunk/bin/upgrading/update-db-general.pl
===================================================================
--- trunk/bin/upgrading/update-db-general.pl	2012-05-12 09:03:36 UTC (rev 21924)
+++ trunk/bin/upgrading/update-db-general.pl	2012-05-12 09:05:55 UTC (rev 21925)
@@ -3399,6 +3399,17 @@
 )
 EOC
 
+register_tablecreate('repost2', <<'EOC');
+CREATE TABLE `repost2` (
+    `journalid` int(10) NOT NULL,
+    `jitemid` int(11) NOT NULL,
+    `reposterid` int(10) NOT NULL,
+    `reposted_jitemid` int(11) NOT NULL,
+    PRIMARY KEY ( `journalid`, `reposterid`, `jitemid` ),
+    KEY `jitemid` ( `journalid`, `jitemid` )
+)
+EOC
+
 post_create("clients",
             "sqltry" => "INSERT INTO clients (client) SELECT DISTINCT client FROM logins",
             );

Added: trunk/cgi-bin/LJ/API/Error.pm
===================================================================
--- trunk/cgi-bin/LJ/API/Error.pm	                        (rev 0)
+++ trunk/cgi-bin/LJ/API/Error.pm	2012-05-12 09:05:55 UTC (rev 21925)
@@ -0,0 +1,41 @@
+package LJ::API::Error;
+
+use strict;
+use warnings;
+
+use LJ::Lang;
+
+my %errors = (
+    'unknown_error'        => {  'error_code' => -10000, 
+                                 'error_var'  => 'api.error.unknwon_error', },
+
+    'invalid_params'       => { 'error_code' => -32602,
+                                'error_text' => 'Invalid params', }, 
+
+    'invalid_data_format'  => { 'error_code' => -10001,
+                                'error_var'  => 'api.error.invalid_data_format', },
+
+    'invalid_method'       => { 'error_code' => -32601,
+                                'error_text'  => 'Method not found', },
+
+    'entry_not_found'      => { 'error_code' =>  -10002,
+                                'error_var'  => 'api.error.entry_not_found', },
+
+);
+
+# reserved: 10001 code for custom error
+sub get_error {
+    my ($class, $error_type, $options) = @_;
+    die "unknwon error" unless $error_type;
+
+    my $error = $errors{$error_type};
+    die "unknwon error" unless $error;
+
+    my $lang_var = $error->{'error_var'};
+    my $text = $lang_var ? LJ::Lang::ml($lang_var, $options) : $error->{'error_text'};
+    
+    return { 'error' => { 'error_code'    => $error->{'error_code'},
+                          'error_message' => $text, },
+           };
+}
+

Added: trunk/cgi-bin/LJ/API/Namespaces.pm
===================================================================
--- trunk/cgi-bin/LJ/API/Namespaces.pm	                        (rev 0)
+++ trunk/cgi-bin/LJ/API/Namespaces.pm	2012-05-12 09:05:55 UTC (rev 21925)
@@ -0,0 +1,59 @@
+package LJ::API::Namespaces;
+
+use strict;
+use warnings;
+use LJ::API::Error;
+use LJ::API::Repost;
+use attributes;
+
+my %namespace_map = (
+    'repost' => 'LJ::API::Repost',
+);
+
+sub __is_public {
+    my ($class, $function) = @_;
+
+    my @attrs = attributes::get($function);
+
+    foreach my $attr (@attrs) {
+        if ($attr eq 'method') {
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+sub call {
+    my ($class, $method, $data) = @_;
+
+    my ($namespace_name, $function) = split(/\./, $method);
+    my $namespace = $namespace_map{$namespace_name || ''};
+    
+    if (!$namespace || !$function) {
+        warn "error invalid_method";
+        return LJ::API::Error->get_error('invalid_method');
+    }
+
+    my $handler = $namespace->can($function);
+
+    if (!$handler || !$class->__is_public($handler)) {
+        return LJ::API::Error->get_error('invalid_method');
+    }
+
+    my $result = {};
+    
+    eval {
+        $result = $handler->($namespace, $data);
+    };
+    
+    if ($@) {
+        warn $@;
+        $result = LJ::API::Error->get_error('unknwon_error');
+    }
+        
+    return $result;
+
+}
+
+

Added: trunk/cgi-bin/LJ/API/Repost.pm
===================================================================
--- trunk/cgi-bin/LJ/API/Repost.pm	                        (rev 0)
+++ trunk/cgi-bin/LJ/API/Repost.pm	2012-05-12 09:05:55 UTC (rev 21925)
@@ -0,0 +1,84 @@
+package LJ::API::Repost;
+
+use strict;
+use warnings;
+
+use LJ::Entry;
+use LJ::API::Error;
+use LJ::Entry::Repost;
+
+sub create : method {
+    my ($self, $options) = @_;
+
+    return LJ::API::Error->get_error('invalid_params') unless
+        $options->{'url'};
+
+    my $u = LJ::get_remote();
+    if ($options->{'target'}) {
+        $u = LJ::load_user($options->{'target'});
+    }
+
+    return LJ::API::Error->get_error('invalid_params') unless $u;
+    return LJ::API::Error->get_error('invalid_params') unless $options->{'timezone'};
+
+    my $url   = $options->{'url'};
+    my $entry = LJ::Entry->new_from_url($url);
+
+    return LJ::API::Error->get_error('invalid_params') unless $entry;
+
+    my $timezone = $options->{'timezone'};
+
+    my $result = LJ::Entry::Repost->create(  $u, # destination journal
+                                             $entry, # entry to be reposted
+                                             $timezone ); # timezone for repost
+
+    return $result;    
+}
+
+sub delete : method {
+    my ($self, $options) = @_;
+
+    return LJ::API::Error->get_error('invalid_params') unless
+        $options->{'url'};
+
+    my $u = LJ::get_remote();
+    if ($options->{'target'}) {
+        $u = LJ::load_user($options->{'target'});
+    }
+
+    return LJ::API::Error->get_error('invalid_params') unless $u;
+
+    my $url   = $options->{'url'};
+    my $entry = LJ::Entry->new_from_url($url);
+
+    return LJ::API::Error->get_error('invalid_params') unless $entry;
+
+    my $result = LJ::Entry::Repost->delete(  $u, # destination journal
+                                             $entry,); # entry to be reposted
+    return $result;
+}
+
+sub get_status : method {
+    my ($self, $options) = @_;
+
+    return LJ::API::Error->get_error('invalid_params') unless
+        $options->{'url'};
+
+    my $u = LJ::get_remote();
+    if ($options->{'target'}) {
+        $u = LJ::load_user($options->{'target'});
+    }
+
+    return LJ::API::Error->get_error('invalid_params') unless $u;
+
+    my $url   = $options->{'url'};
+    my $entry = LJ::Entry->new_from_url($url);
+
+    return  LJ::API::Error->get_error('invalid_params') unless $entry;
+
+    my $result = LJ::Entry::Repost->get_status( $u, # destination journal
+                                                $entry,); # entry to be reposted
+    return $result;
+}
+
+1;

Added: trunk/cgi-bin/LJ/Controller/API/JSON.pm
===================================================================
--- trunk/cgi-bin/LJ/Controller/API/JSON.pm	                        (rev 0)
+++ trunk/cgi-bin/LJ/Controller/API/JSON.pm	2012-05-12 09:05:55 UTC (rev 21925)
@@ -0,0 +1,34 @@
+package LJ::Controller::API::JSON;
+use strict;
+use warnings;
+
+use LJ::Lang;
+use LJ::Response::CachedTemplate;
+use LJ::Response::Error;
+use LJ::Response::Redirect;
+use LJ::Request;
+use Data::Dumper;
+
+use base qw{ LJ::Controller };
+use LJ::API::Error;
+use LJ::API::Namespaces;
+use LJ::JSON::RPC; 
+
+sub process {
+    my ($self) = @_;
+ 
+    my $remote = LJ::get_remote();
+    my $raw_content = LJ::Request->raw_content;
+
+    my $rpc = LJ::JSON::RPC->new(LJ::Request->uri, $raw_content);
+    $rpc->call( sub {
+        return LJ::API::Namespaces->call(@_);
+    });
+
+    return $rpc->response;
+} # process
+
+sub need_res {
+}
+
+1;

Added: trunk/cgi-bin/LJ/Entry/Repost.pm
===================================================================
--- trunk/cgi-bin/LJ/Entry/Repost.pm	                        (rev 0)
+++ trunk/cgi-bin/LJ/Entry/Repost.pm	2012-05-12 09:05:55 UTC (rev 21925)
@@ -0,0 +1,290 @@
+package LJ::Entry::Repost;
+
+use strict;
+use warnings;
+
+require 'ljlib.pl';
+require 'ljprotocol.pl';
+use LJ::Lang;
+
+sub __get_count {
+    my ($u, $jitemid) = @_;
+    my $dbcr = LJ::get_cluster_master($u)
+        or die "get cluster for journal failed";
+
+    my ($count_jitemid) = $dbcr->selectrow_array( 'SELECT COUNT(reposted_jitemid) ' .
+                                                  'FROM repost2 ' .
+                                                  'WHERE journalid = ? AND jitemid = ?',
+                                                   undef,
+                                                   $u->userid,
+                                                   $jitemid, );
+    return $count_jitemid;
+
+}
+
+sub __get_repostid {
+    my ($u, $jitemid, $reposterid) = @_;
+    my $dbcr = LJ::get_cluster_master($u)
+        or die "get cluster for journal failed";
+
+    my ($repost_jitemid) = $dbcr->selectrow_array( 'SELECT reposted_jitemid ' .
+                                                   'FROM repost2 ' .
+                                                   'WHERE journalid = ? AND jitemid = ? AND reposterid = ?',
+                                                   undef,
+                                                   $u->userid,
+                                                   $jitemid,
+                                                   $reposterid, );
+    return $repost_jitemid;
+}
+
+sub __create_repost_record {
+    my ($u, $itemid, $repost_journalid, $repost_itemid) = @_;
+
+    $u->do('INSERT INTO repost2 VALUES(?,?,?,?)',
+            undef,
+            $u->userid,
+            $itemid,
+            $repost_journalid,
+            $repost_itemid, );
+}
+
+sub __delete_repost_record {
+    my ($u, $itemid, $reposterid) = @_;
+
+    $u->do('DELETE FROM repost2 WHERE journalid = ? AND jitemid = ? AND reposterid = ?',
+            undef,
+            $u->userid,
+            $itemid,
+            $reposterid,);
+}
+
+sub __create_post {
+    my ($u, $timezone, $url, $error) = @_;
+
+    my $err = 0;
+    my $flags = { 'noauth'             => 1,
+                  'use_custom_time'    => 0,
+                  'allow_dupsing_post' => 1,
+                  'u'                  => $u };
+
+    my %req = ( 'username'    => $u->user,
+                'event'       => LJ::Lang::ml('repost.text', { 'url' =>  $url}),
+                'subject'     => '',
+                'tz'          => $timezone,
+              );
+
+    # move to LJ::API
+    my $res = LJ::Protocol::do_request("postevent", \%req, \$err, $flags);
+
+    my $fail = !defined $res->{itemid} && $res->{message};
+    if ($fail) {
+         $$error = $res->{message};
+         return;
+    }
+
+    return LJ::Entry->new($u, jitemid => $res->{'itemid'} );
+}
+
+sub __create_repost {
+    my ($opts) = @_;
+
+    my $u         = $opts->{'u'};
+    my $entry_obj = $opts->{'entry_obj'}; 
+    my $timezone  = $opts->{'timezone'};
+    my $error     = $opts->{'error'};
+
+    if (!$entry_obj->visible_to($u)) {
+        $$error = LJ::Lang::ml('repost.access_denied');
+        return;
+    }
+
+    my $post_obj = __create_post($u, $timezone, $entry_obj->url);
+    if (!$post_obj) {
+        $$error = LJ::Lang::ml('repost.unknown_error');
+        return;
+    }
+
+    my $url = $entry_obj->url;
+    $post_obj->convert_to_repost($url);
+
+    # create record
+    my $repost_jitemid = $post_obj->jitemid;
+    
+    my $journalid = $entry_obj->journalid;
+    my $jitemid   = $entry_obj->jitemid;
+
+    __create_repost_record($entry_obj->journal,
+                           $jitemid,
+                           $u->userid,
+                           $repost_jitemid);
+
+    return $post_obj;
+}
+
+sub get_status {
+    my ($class, $u, $entry_obj) = @_;
+
+    my $reposted = __get_repostid( $entry_obj->journal, $entry_obj->jitemid, $u->userid );
+    return  { 'result' => { 
+                  'count'    =>  __get_count($entry_obj->journal, $entry_obj->jitemid), 
+                  'reposted' => !!$reposted, },
+            };
+}
+
+sub delete {
+    my ($class, $u, $entry_obj) = @_;
+    my $repost_itemid = __get_repostid( $entry_obj->journal, $entry_obj->jitemid, $u->userid );
+
+    if ($repost_itemid) {
+        LJ::delete_entry($u, $repost_itemid, undef, undef);
+        __delete_repost_record($entry_obj->journal, $entry_obj->jitemid, $u->userid);
+    
+        return  { 'result' => 'OK' };
+    }
+
+    return LJ::API::Error->get_error('entry_not_found');
+}
+
+sub create {
+    my ($class, $u, $entry_obj, $timezone) = @_;
+    my $result = {};
+   
+    if ($entry_obj->original_post) {
+        $entry_obj = $entry_obj->original_post;
+    }
+
+    my $journalid = $entry_obj->journalid;
+    my $jitemid   = $entry_obj->jitemid;
+
+    my $repost_itemid = __get_repostid( $entry_obj->journal, $jitemid, $u->userid );
+
+    my $error;
+
+    if ($repost_itemid) {
+        $error = LJ::Lang::ml('repost.already_exist');
+    } else {
+        my $reposted_obj = __create_repost( {'u'          => $u,
+                                             'entry_obj'  => $entry_obj,
+                                             'timezone'   => $timezone,
+                                             'error'      => \$error } );
+
+        if ($reposted_obj) {
+            my $count = __get_count($entry_obj->journal, $entry_obj->jitemid);
+            $result->{'result'} = { 'count' => $count };
+        } elsif (!$error) {
+            $error = LJ::Lang::ml('api.unknown');
+        }
+    }
+
+    if ($error) {
+        $result->{'error'}  = { 'error_code'    => -9000,
+                                'error_message' => $error };
+    }
+
+    return $result;
+}
+
+sub substitute_content {
+    my ($class, $entry_obj, $opts) = @_;
+
+    my $original_entry_obj = $entry_obj->original_post;
+    return unless $original_entry_obj;
+
+    if ($opts->{'anum'}) {
+        ${$opts->{'anum'}} = $original_entry_obj->anum;
+    }
+
+    if ($opts->{'cluster_id'}) {
+        ${$opts->{'cluster_id'}} = $original_entry_obj->journal->clusterid;
+    }
+    
+    if ($opts->{'original_post_obj'}) {
+        ${$opts->{'original_post_obj'}}= $original_entry_obj;
+    }
+
+    if ($opts->{'repost_obj'}) {
+        ${$opts->{'repost_obj'}} = $entry_obj;
+    }
+
+    if ($opts->{'ditemid'}) {
+        ${$opts->{'ditemid'}} = $original_entry_obj->ditemid;
+    }
+
+    if ($opts->{'itemid'}) {
+        ${$opts->{'itemid'}} = $original_entry_obj->jitemid;
+    }
+
+    if ($opts->{'journalid'}) {
+        ${$opts->{'journalid'}} = $original_entry_obj->journalid;
+    }
+
+    if ($opts->{'journalu'}) {
+        ${$opts->{'journalu'}} = $original_entry_obj->journal;
+    }
+
+    if ($opts->{'posterid'}) {
+        ${$opts->{'posterid'}} = $original_entry_obj->posterid;
+    }
+
+    if ($opts->{'allowmask'}) {
+        ${$opts->{'allowmask'}} = $original_entry_obj->allowmask;
+    }
+
+    if ($opts->{'security'}) {
+        ${$opts->{'security'}} = $original_entry_obj->security;
+    }
+
+    if ($opts->{'eventtime'}) {
+        ${$opts->{'eventtime'}} = $original_entry_obj->eventtime_mysql;
+    }
+
+    if ($opts->{'event'}) {
+        my $remote = LJ::get_remote();
+        my $text_var =  LJ::u_equals($remote, $entry_obj->poster) ? 'entry.reference.journal.owner' : 
+                                                                    'entry.reference.journal.guest';
+
+        my $event_text = $original_entry_obj->event_html;
+        my $event =  LJ::Lang::ml($text_var,  
+                                    { 'author'       => LJ::ljuser2($original_entry_obj->poster),
+                                      'reposter'     => LJ::ljuser2($entry_obj->poster),
+                                      'datetime'     => $entry_obj->eventtime_mysql,
+                                      'text'         => $event_text, });
+ 
+        ${$opts->{'event'}} = $event;
+    }
+
+    if ($opts->{'event_friend'}) {       
+        my $event_text = $original_entry_obj->event_html;
+        my $journal = $original_entry_obj->journal;
+        
+        my $text_var = $journal->is_community ? 'entry.reference.friends.community' :
+                                                'entry.reference.friends.journal';
+         
+        my $event = LJ::Lang::ml($text_var, 
+                                   { 'author'       => LJ::ljuser2($original_entry_obj->poster),
+                                     'community'    => LJ::ljuser2($original_entry_obj->journal->user),
+                                     'reposter'     => LJ::ljuser2($entry_obj->poster),
+                                     'text'         => $event_text, });
+
+        ${$opts->{'event_friend'}} = $event;
+    }
+
+    if ($opts->{'subject_repost'}) {
+        my $subject_text = $original_entry_obj->subject_html;
+        my $repost_text = LJ::Lang::ml('entry.reference.subject');
+        $subject_text .= " ( $repost_text )";
+        ${$opts->{'subject_repost'}} = $subject_text;
+    }
+
+    if ($opts->{'subject'}) {
+        ${$opts->{'subject'}}  = $original_entry_obj->subject_html;
+    }
+
+    if ($opts->{'reply_count'}) {    
+        ${$opts->{'reply_count'}} = $original_entry_obj->reply_count;
+    } 
+    
+    return 1;
+}
+
+1;

Modified: trunk/cgi-bin/LJ/Entry.pm
===================================================================
--- trunk/cgi-bin/LJ/Entry.pm	2012-05-12 09:03:36 UTC (rev 21924)
+++ trunk/cgi-bin/LJ/Entry.pm	2012-05-12 09:05:55 UTC (rev 21925)
@@ -121,6 +121,11 @@
     # save the singleton if it doesn't exist
     $singletons{$journalid}->{$jitemid} = $self;
 
+    my $url = $self->prop('repost_link');
+    if ($url && ($url ne $self->url) ) {
+        $self->{'original_post_obj'} = LJ::Entry->new_from_url($url);
+    }
+
     return $self;
 }
 
@@ -1490,6 +1495,17 @@
     return LJ::can_delete_journal_item(@_);
 }
 
+sub convert_to_repost {
+    my ($class, $url) = @_;
+    $class->set_prop( 'repost_link' =>  $url);
+} 
+
+sub original_post {
+    my ($class) = @_;
+
+    return $class->{'original_post_obj'};
+}
+
 package LJ;
 
 use Class::Autouse qw (

Added: trunk/cgi-bin/LJ/JSON/RPC/Item.pm
===================================================================
--- trunk/cgi-bin/LJ/JSON/RPC/Item.pm	                        (rev 0)
+++ trunk/cgi-bin/LJ/JSON/RPC/Item.pm	2012-05-12 09:05:55 UTC (rev 21925)
@@ -0,0 +1,179 @@
+package LJ::JSON::RPC::Item;
+
+use strict;
+use warnings;
+
+use LJ::API::Error;
+
+#
+# json request and response jpc 2.0
+#
+
+use LJ::JSON;
+
+sub new {
+    my ($class, $uri, $data) = @_;
+
+    my $self = bless {}, $class;
+
+    if ($data->{'fatal'}) {
+        $self->{'fatal'} = $data->{'fatal'};
+        return $self;
+    }
+
+    my $jsonrpc = $data->{'jsonrpc'};
+    my $method  = $data->{'method'};
+    my $params  = $data->{'params'};
+
+    $self->{'fatal'} = { 'error_code' => -32602, 'error_message' => 'Invalid params' } unless $params;
+    $self->{'fatal'} = { 'error_code' => -32602, 'error_message' => 'Invalid params' } if ref $params eq 'ARRAY';
+    if ($self->{'fatal'}) {
+        return $self;
+    }
+
+    my $remote  = LJ::get_remote;
+    my $auth    = delete $params->{'auth'};
+    if (!$auth) {
+        $self->{'fatal'} = { 'error_code' => -12600, 'error_message' => 'Auth is missed' };
+    } else {
+        if (!LJ::Auth->check_ajax_auth_token($remote, $uri, 'auth_token' => $auth)) {
+            $self->{'fatal'} = { 'error_code' => -12600, 'error_message' => 'Auth failed' };
+        }
+    }
+    if ($self->{'fatal'}) {
+        return $self;
+    }
+
+
+    $self->{'fatal'} = { 'error_code' => -32600, 'error_message' => 'Invalid Request' } unless $method;
+    $self->{'fatal'} = { 'error_code' => -32600, 'error_message' => 'Invalid Request' } if !$jsonrpc || $jsonrpc ne '2.0';
+
+    if ($self->{'fatal'}) {
+        return $self;
+    }
+
+
+    $self->{'uri'}    = $uri;
+    $self->{'method'} = $method;
+    $self->{'params'} = $params;
+    $self->{'id'}     = $data->{'id'};
+ 
+    return $self,
+}
+
+
+#
+# When a rpc call encounters an error, the Response Object MUST contain 
+# the error member with a value that is a Object with the following members:
+# - code 
+# - message
+# - data
+#
+sub __construct_error_object {
+    LJ::API::Error->get_error 
+}
+
+sub response {
+    my ($self, $options) = @_;
+
+    my $result = $options->{'result'};
+    my $error  = $options->{'error'};
+    my $fatal  = $self->{'fatal'};
+    return if ($self->is_notitification && !$fatal);
+    
+    my $resp = { 'jsonrpc' => '2.0' };
+            
+    if ($result && $error) {
+        # internal error
+        $fatal = { 'error_code' => -32603, 'error_message' => 'Internal error' };
+    }
+
+    ############################################################################
+    # result
+    ############################################################################
+    #
+    # This member is REQUIRED on success.
+    # This member MUST NOT exist if there was an error invoking the method.
+    # The value of this member is determined by the method invoked on the Server.
+    #
+    ############################################################################
+    if ($result) {
+        my $remote = LJ::get_remote;
+        my @params_vars = keys %{$self->{'params'}};
+        my $auth = LJ::Auth->ajax_auth_token($remote, $self->{'uri'}, \@params_vars);
+        $result->{'auth'} = $auth;
+        $resp->{'result'} = $result; 
+    }
+ 
+    ############################################################################
+    # error
+    ############################################################################
+    #
+    # When a rpc call encounters an error, the Response Object MUST contain
+    # the error member with a value that is a Object with the following members:
+    # - code
+    # - message
+    # - data
+    #
+    #############################################################################
+    if ($error || $fatal) {
+        $error = $fatal if ($fatal);
+        my $error_information;
+
+        my $error_data; 
+        if ($error->{'defined'}) {
+            my $error_type     = $error->{'error_type'};
+            my $error_options  = $error->{'error_options'};
+
+            $error = LJ::API::Error->get_error($error_type, $error_options)->{'error'};
+        } 
+
+        my $error_code = $error->{'error_code'};
+        my $error_msg  = $error->{'error_message'};
+
+        $error_data->{'code'}   = $error_code;
+        $error_data->{'message'}= $error_msg; 
+        
+        if ($error->{'data'}) {
+            $error_data->{'data'} = $error->{'data'};
+        }
+
+        $resp->{'error'} = $error_data;
+    }
+
+    ##############################################################################
+    # id
+    ##############################################################################
+    #
+    # This member is REQUIRED.
+    # It MUST be the same as the value of the id member in the Request Object.
+    # If there was an error in detecting the id in the Request object 
+    # (e.g. Parse error/Invalid Request), it MUST be Null.
+    #
+    ##############################################################################
+    $resp->{'id'} = $self->{'id'};
+
+    return $resp;
+}
+
+sub error {
+    my ($self) = @_;
+    return $self->{'fatal'};
+}
+
+sub method {
+    my ($self) = @_;
+    return $self->{'method'};
+}
+
+sub params {
+    my ($self) = @_;
+    return $self->{'params'};
+}
+
+sub is_notitification {
+    my ($self) = @_;
+    return !$self->{'id'};
+}
+
+1;

Added: trunk/cgi-bin/LJ/JSON/RPC.pm
===================================================================
--- trunk/cgi-bin/LJ/JSON/RPC.pm	                        (rev 0)
+++ trunk/cgi-bin/LJ/JSON/RPC.pm	2012-05-12 09:05:55 UTC (rev 21925)
@@ -0,0 +1,86 @@
+package LJ::JSON::RPC;
+
+use strict;
+use warnings;
+
+use LJ::JSON;
+use LJ::JSON::RPC::Item;
+use LJ::Response::JSON;
+
+sub new {
+    my ($class, $uri, $request) = @_;
+    my $self = bless {}, $class;
+
+    eval {
+        my $data = LJ::JSON->from_json($request);
+
+        if (ref $data eq 'ARRAY') {
+            foreach my $entry (@$data) {
+                push @{$self->{'items'}}, { 'item'  => LJ::JSON::RPC::Item->new($uri, $entry), };
+            }
+
+            unless (@$data) {
+                my $fatal = { 'error_code' => -32600, 'error_message' => 'Invalid Request' };
+                $self->{'items'} = { 'item' => LJ::JSON::RPC::Item->new({ 'fatal' =>  $fatal })};
+            }
+        } else {
+            $self->{'items'} = { 'item'   => LJ::JSON::RPC::Item->new($uri, $data),};
+        }
+    };
+
+    if ($@) {
+        warn $@;
+        my $fatal = { 'error_code' => -32700, 'error_message' => 'Parse error' };
+        $self->{'items'} = { 'item' => LJ::JSON::RPC::Item->new({ 'fatal' =>  $fatal })};
+    }
+
+    return $self;
+}
+
+sub call {
+    my ($self, $callback) = @_;
+    my $items = $self->{'items'};
+
+    if (ref $items eq 'ARRAY') {
+        foreach my $entry (@$items) {
+            my $item = $entry->{'item'};
+            next if $item->error;            
+
+            my $method = $item->method;
+            my $params = $item->params;
+
+            $entry->{'result'} = $callback->($method, $params);
+        }
+    } else {
+        my $item   = $items->{'item'};
+        return if $item->error;
+
+        my $method = $item->method;
+        my $params = $item->params;
+
+       $items->{'result'} = $callback->($method, $params);
+    }
+}
+
+sub response {
+    my ($self) = @_;
+    my $items = $self->{'items'};
+    my $resp_data;
+    
+    if (ref $items eq 'ARRAY') {
+        foreach my $entry (@$items) {
+            my $item   = $entry->{'item'};
+            my $response = $item->response($entry->{'result'});
+            push @{$resp_data}, $response if $response;
+        }
+    } else {
+        my $item = $items->{'item'};
+        $resp_data = $item->response($items->{'result'});
+    }
+
+    my $response = LJ::Response::JSON->new();
+    $response->data($resp_data);
+    return $response;
+}
+
+1;

Added: trunk/cgi-bin/LJ/Router/API.pm
===================================================================
--- trunk/cgi-bin/LJ/Router/API.pm	                        (rev 0)
+++ trunk/cgi-bin/LJ/Router/API.pm	2012-05-12 09:05:55 UTC (rev 21925)
@@ -0,0 +1,16 @@
+package LJ::Router::API;
+use strict;
+use warnings;
+
+use LJ::Controller::API::JSON;
+
+sub match_controller {
+    if ( LJ::Request->hostname eq $LJ::DOMAIN_WEB ) {
+        if ( LJ::Request->uri =~ m!^\/__api\/!ig and 'JSON_rpc' ) {
+            LJ::Request->notes( controller  => 'LJ::Controller::API::JSON' );
+            return;
+        }
+    }
+}
+
+1;

Modified: trunk/cgi-bin/ljlib.pl
===================================================================
--- trunk/cgi-bin/ljlib.pl	2012-05-12 09:03:36 UTC (rev 21924)
+++ trunk/cgi-bin/ljlib.pl	2012-05-12 09:05:55 UTC (rev 21925)
@@ -106,6 +106,7 @@
                     "comet_history", "pingrel",
                     "eventrates", "eventratescounters",
                     "friending_actions_q", "delayedlog2", "delayedblob2",
+                    "repost2",
                     );
 
 # keep track of what db locks we have out

Tags: dat, livejournal, madeon, pl, pm, sbelyaev
Subscribe
  • Post a new comment

    Error

    Anonymous comments are disabled in this journal

    default userpic

    Your reply will be screened

    Your IP address will be recorded 

  • 0 comments