Remote Procedure Call (RPC) Plugin

RPC plugin is an easy way to implement a Remote Procedure Call API. Plugin use JSON-RPC protocol version 2. You can read the specification by the link.

Install

RPC Plugin is dependent on Jimbo.

  1. Check the Jimbo plugin has been installed
  2. Add the plugin:
    git submodule add [email protected]:FestiPlugins/php_festi_plugin_rpc.git plugins/Rpc
  3. Run dump from install folder
  4. Add area and rule
    INSERT INTO festi_url_areas (ident) VALUES ('rpc');
    INSERT INTO festi_url_rules (plugin, pattern, method) VALUES ('Rpc', '~^/rpc/(.*)$~', 'onJsonCallMethod');
    And add this rule to festi_url_rules2areas for area rpc
  5. Call RPC method syncRpcMethods
  6. Configure permission section
  7. Add column access_token to users table
  8. Configure index.php and .htaccess. Example you could found into install/rpc/
  9. Add composer package festi-team/festi-framework-serialization

Authentication

Access toke should be stored into the users table on the access_token column. You have two way for authentication:

  1. Put token to GET param token:
    https://RPC_HOST/?token=XXX
  2. Put to X-Authorization header

Request

You can send parameters use array or object:

{"jsonrpc":"2.0", "method":"getScraperActions", "params":["linkedin"], "id":1}
{"jsonrpc":"2.0", "method":"getScraperActions", "params":{"ident":"linkedin"}, "id":1}

if you use an object please double-check that the key is an equal name in RPC method param annotation.

RPC Plugin support batch request:

[
  {"jsonrpc":"2.0","method":"getScraperActions","params":["linkedin"],"id":1},
  {"jsonrpc":"2.0","method":"getScraperActions","params":{"ident":"google"},"id":2}
]

For easy debug you could use GET param rawRequest:

https://RPC_HOST/?rawRequest={"jsonrpc":"2.0","method":"syncRpcMethods}

RPC Method Implementation

Use @rpc annotation to define RPC method:

class ScraperPlugin extends DisplayPlugin
{
    /**
     * @rpc getScraperActions
     * @param string $ident
     * @section scraper
     * @return array
     */
    public function getActionsByIdent(string $ident): array
    {
        ...
    }
}

if @rpc doesn't have a name will be use real method name:

/**
 * @rpc
 * @param bool $idUser
 * @return mixed
 * @throws PermissionsException
 */
public function getMentors($idUser = false)
{
    ...
}

You can use on* methods and methods with DGS as well:

/**
 * @rpc getProjects
 * @urlRule ~^/projects/$~
 * @area backend
 * @param Response $response
 * @return bool
 * @throws SystemException
 * @section manage_projects
 */
public function onDisplayList(Response &$response)
{
    $store = $this->createStoreInstance("projects");

    $store->onRequest($response);

    return true;
}

Parameters for result wil be getting from Response

Update RPC methods

All RPC methods stored into rpc_methods. For update you can call RPC method syncRpcMethods or call the method from code:

Core::getInstance()->getPluginInstance('Rpc')->syncRpcMethods();
or
https://RPC_HOST/?rawRequest={"jsonrpc":"2.0","method":"syncRpcMethods"}

Client

  • jQuery - https://github.com/Textalk/jquery.jsonrpcclient.js
let rpc = new jQuery.JsonRpcClient({ ajaxUrl: 'https://RPC_HOST/' });

rpc.call(
    'getScraperActions', ['linkedin'],
    function (response) {
        console.log("RUSULT:", result);
    },
    function (error) {
        console.error(error);
    }
);

rpc.batch(
    function (batch) {
        batch.call('getScraperActions', ['linkedin'], function (response) {
            console.log("1", response);
        }, function (error) {
            console.error(error);
        });
        batch.call('getScraperActions', { "ident": "linkedin" }, function (response) {
            console.log("2", response);
        }, function (error) {
            console.error(error);
        });
    },
    function (all_result_array) { alert('All done.'); },
    function (error_data) { alert('Error in batch response.'); }
);

Override authorization logic

init.php:

assert($this instanceof Core);

$this->addEventListener(Core::EVENT_ON_AFTER_INIT, function () {
    $this->addEventListener(IRpc::EVENT_ON_TOKEN_LOGIN, function (FestiEvent &$event) {
        Core::getInstance()->getPluginInstance('YourNewPlugin')->onInterceptLoginByToken($event);
    });
});

public function onInterceptLoginByToken(FestiEvent &$event): void
{
    $isAuth = &$event->getTargetValueByKey('is_auth');
    $token = &$event->getTargetValueByKey('token');

    if (mb_strlen($token) == 32) { // system access token
        $isAuth = $this->core->getSystemPlugin()->signinByToken($token);
    } else {
        $isAuth = $this->_signInByGoogleTokenID($token);
    }

     if (!$isAuth) {
         throw new PermissionsException("Undefined access token.");
     }
}

RPC API

getDataGridStoreModel

Returns DGS model.

  • Based on: RpcPlugin::onJsonDataGridStore
  • Paramaters:
    • pluginName or [0]
    • storeName or [1]

syncRpcMethods

Scan project and update RPC methods.

  • Based on: RpcPlugin::syncRpcMethods

getStructureMenu

Scan project and update RPC methods.

  • Based on: Jimbo::getStructureMenu
  • Paramaters:
    • area or [0]

getSchemeByUrl

Returns all schemes by url

  • Paramaters:
    • url or [0]
    • area or [1]

execUrl

Execute request

  • Paramaters:
    • url or [0]
    • area or [1]