Skip to content

Instantly share code, notes, and snippets.

Created January 20, 2018 01:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save anonymous/13d3c6eecbfddc7715435d020d7e149a to your computer and use it in GitHub Desktop.
Save anonymous/13d3c6eecbfddc7715435d020d7e149a to your computer and use it in GitHub Desktop.
<?php
namespace Kirby\Registry {
use Kirby;
use Kirby\Registry;
class Rpc extends Entry {
public function set($name, $callback) {
$this->kirby->rpc->add($name, $callback);
}
}
}
namespace RpcPlugin {
class RpcDispatcher {
const JSON_RPC_VERSION = '2.0';
const JSON_PARSE_ERROR = -32700;
const INVALID_REQUEST = -32600;
const METHOD_NOT_FOUND = -32601;
const INVALID_PARAMS = -32602;
const INTERNAL_ERROR = -32603;
private $methods = [];
public function __construct(\Kirby $kirby) {
$this->methods = [];
$kirby->set('route', [
'pattern' => 'jsonrpc',
'method' => 'POST',
'action' => [$this, 'onMessage']
]);
}
private static function error($code, $message) {
if (!is_int($code)) throw new \Exception('code must be int');
$args = array_slice(func_get_args(), 1);
return new \Response([
'error' => [
'message' => call_user_func_array('sprintf', $args),
'code' => $code
]
], 'json', 504);
}
public function onMessage() {
$payloadRaw = file_get_contents('php://input');
$payload = json_decode($payloadRaw, true);
if (is_null($payload)) {
return self::error(self::JSON_PARSE_ERROR, 'unable to parse json');
}
if (!array_key_exists('id', $payload)) {
return self::error(0, 'missing id');
}
$id = $payload['id'];
$version = $payload['jsonrpc'];
if ($version !== self::JSON_RPC_VERSION) {
return self::error(0, 'jsonrpc must be %s, was %s', self::JSON_RPC_VERSION, $version);
}
$method = $payload['method'];
if (!array_key_exists($method, $this->methods)) {
return self::error(self::METHOD_NOT_FOUND, 'method %s is missing', $method);
}
$cb = $this->methods[$method];
$info = new \ReflectionFunction($cb);
$nargs = $info->getNumberOfRequiredParameters();
if (!array_key_exists('params', $payload)) {
return self::error(0, 'missing params');
}
$params = $payload['params'];
if (!is_array($params) || $nargs !== count($params)) {
return self::error(self::INVALID_PARAMS, 'Method expects %d params, but got %d', $nargs, count($params));
}
try {
$r = call_user_func_array($cb, $params);
return new \Response([
'result' => $r,
'jsonrpc' => self::JSON_RPC_VERSION,
'id' => $id
], 'json');
}
catch (Exception $e) {
return self::error(self::INTERNAL_ERROR, 'error :(');
}
}
public function add($name, callable $callback) {
if (array_key_exists($name, $this->methods)) {
throw new \Exception("method name $name already taken");
}
$this->methods[$name] = $callback;
}
}
$kirby->rpc = new RpcDispatcher(kirby());
}
namespace MyPlugin {
kirby()->set('rpc', 'add', function ($a, $b) {
return $a + $b;
});
kirby()->set('rpc', 'get_users', function () {
return kirby()->site()->users()->toArray();
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment