config = array_merge([ 'schemaLoaderPrefix' => '', 'schemaLoaderDirs' => [], // 'schemaCacheDir' => __DIR__.\DIRECTORY_SEPARATOR.'schema-store'.\DIRECTORY_SEPARATOR, 'schemaCacheDir' => sys_get_temp_dir() . \DIRECTORY_SEPARATOR . get_current_user(). \DIRECTORY_SEPARATOR . 'json-schema-store' . \DIRECTORY_SEPARATOR, 'discovery' => $discovery, 'meta' => [ 'openrpc' => '1.0.0-rc1', "info" => [ "title" => "JSON-RPC Server", "description" =>"This the RPC-part of an Frdlweb API Server definition https://look-up.webfan3.de/?goto=oid%3A1.3.6.1.4.1.37553.8.1.8.1.13878", "version" => "1.0.0", ], 'servers' => [ [ 'name' => 'Webfan Homepagesystem RPC API', 'summary' => 'Webfan Homepagesystem RPC API methods description', 'description' => 'This is the RPC part of an implementation of the Frdlweb API Specification (1.3.6.1.4.1.37553.8.1.8.1.13878)', // 'url' => 'https://'.$_SERVER['SERVER_NAME'].'/software-center/modules-api/rpc/0.0.2/', 'url' => 'https://'.$_SERVER['SERVER_NAME'].$_SERVER['REQUEST_URI'], ] ], 'methods' => [], 'components' => [ 'links' => [], 'contentDescriptors' => [], 'schemas' => [], 'examples' => [], ], ], ], $config); /* parent::__construct($container, $batchLimit); */ $this->container = $container; $this->batchLimit = $batchLimit; $this->methods = []; $this->middlewares = []; if(true === $this->config['discovery']){ /* $this->setDiscovery(DiscoverMethod::class, [$this, 'discoveryFactory']); */ $callable = [$this, 'discoveryFactory']; $this->setDiscovery(DiscoverMethod::class,static function(ContainerInterface $c) use($callable){ return call_user_func_array($callable, func_get_args()); }); } } public function discoveryFactory(ContainerInterface $c) : MethodDiscoverableInterface{ $DiscoverMethod = new DiscoverMethod($this); $DiscoverMethod->config(null, $this->config['meta']); return $DiscoverMethod; } public function setDiscovery($serviceId, callable $factory){ if(!$this->getContainer()->has( $serviceId)){ if( $this->container instanceof \Di\CompiledContainer || 'CompiledContainer' === basename(get_class($this->container)) ) { $this->getContainer()->set( $serviceId, call_user_func_array($factory, [$this->container])); }elseif($factory instanceof \closure || 'ContainerBuilder' === basename(get_class($this->container)) ){ $this->getContainer()->set( $serviceId, $factory); }else{ //$this->getContainer()->set( $serviceId, $factory); $this->getContainer()->set( $serviceId, call_user_func_array($factory, [$this->container])); } } $this->set('rpc.discover', $serviceId); /**/ return $this; } public function getMethodDefinitions(){ return $this->methods; } public function getContainer():ContainerInterface{ return $this->container; } public function getConfig(){ return $this->config; } public static function event($name, Request $request = null, Response $response = null, EventableServer $server = null) : Event { $event = new Event($name); if(null!==$request)$event->setArgument('request', $request); if(null!==$response)$event->setArgument('response', $response); if(null!==$server)$event->setArgument('server', $server); return $event; } public function set(string $method, string $serviceId): EventableServer { if (!$this->container->has($serviceId)) { throw new LogicException("Cannot find service '$serviceId' in the container"); } $this->methods[$method] = $serviceId; return $this; } public function attach(string $serviceId): EventableServer { if (!$this->container->has($serviceId)) { throw new LogicException("Cannot find service '$serviceId' in the container"); } $this->middlewares[$serviceId] = null; return $this; } /** * @throws TypeError */ public function run(string $raw): ?string { $input = Input::fromString($raw); if (!$input->parsable()) { return self::end(Error::parsing()); } $Event = self::event('run.before', null, null, $this); $Event->setArgument('input', $input); $this->emit($Event->getName(), $Event); if ($input->isArray()) { if ($this->tooManyBatchRequests($input)) { return self::end(Error::tooManyBatchRequests($this->batchLimit)); } return $this->batch($input); } return $this->single($input); } protected function batch(Input $input): ?string { \assert($input->isArray()); $Event = self::event('batch.before', null, null, $this); $Event->setArgument('input', $input); $this->emit($Event->getName(), $Event); $responses = []; foreach ($input->data() as $request) { $pseudoInput = Input::fromSafeData($request); if (null !== $response = $this->single($pseudoInput)) { $responses[] = $response; } } $Event = self::event('batch.after', null, null, $this); $Event->setArgument('input', $input); $Event->setResult('responses', $responses); $this->emit($Event->getName(), $Event); return empty($responses) ? null : \sprintf('[%s]', \implode(',', $responses)); } /** * @throws TypeError */ protected function single(Input $input): ?string { if (!$input->isRpcRequest()) { return self::end(Error::invalidRequest()); } $request = new Request($input); if (!\array_key_exists($request->method(), $this->methods)) { return self::end(Error::unknownMethod($request->id()), $request); } try { $procedure = Assert::isProcedure( $this->container->get($this->methods[$request->method()]) ); } catch (ContainerExceptionInterface | NotFoundExceptionInterface $e) { return self::end(Error::internal($request->id()), $request); } if (!Validator::validate($procedure->getSpec(), $request->params())) { return self::end(Error::invalidParams($request->id()), $request, $procedure, $Server); } $stack = MiddlewareStack::compose( $procedure, ...\array_map(function(string $serviceId) { return $this->container->get($serviceId); }, \array_keys($this->middlewares)) ); $Event = self::event('method', $request, $stack($request), $this); $Event->setArgument('procedure', $procedure); $this->emit($Event->getName(), $Event); return self::end($Event->getArgument('response'), $Event->getArgument('request'), $Event->getArgument('procedure'), $Event->getArgument('server')); } protected function tooManyBatchRequests(Input $input): bool { \assert($input->isArray()); return \is_int($this->batchLimit) && $this->batchLimit < \count($input->data()); } protected static function end(Response $response, Request $request = null, Procedure $procedure = null, EventableServer $Server = null): ?string { if($response instanceof Error){ $Event = self::event('error', $request, $response, $Server); $Event->setArgument('procedure', $procedure); $Event->setResult($response); $Server->emit($Event->getName(), $Event); } if( $procedure && true !== $response instanceof Error && $procedure instanceof MethodDiscoverableInterface){ $spec = $procedure->getResultSpec(); $result = json_decode(json_encode($response)); if (!self::validateResponse($validation, $spec, $result->result, $Server)) { $ea=$validation->getFirstError()->errorArgs(); return self::end(new Error($request->id(), 'Invalid result '.print_r($ea,true), $result->result), $request, $procedure, $Server); } } $Event = self::event('end', $request, $response, $Server); $Event->setArgument('procedure', $procedure); $Event->setArgument('response', $response); // $Event->setResult($response); $Server->emit($Event->getName(), $Event); $r = ($Event->getResult()) ? $Event->getResult() : $Event->getArgument('response'); return $request instanceof Request && null === $request->id() ? null : \json_encode($r); } public static function validateResponse(&$validation = null, \stdClass $schema, $data, EventableServer $Server = null): bool { $Event = self::event('validate.before', null, null, $Server); $Event->setArgument('payload', $data); $Server->emit($Event->getName(), $Event); \assert(false !== \json_encode($Event->getArgument('payload'))); if(null!==$Server){ $config = $Server->getConfig(); }else{ $config = [ 'schemaLoaderPrefix' => 'https://json-schema.org', 'schemaLoaderDirs' => [], 'schemaCacheDir' =>sys_get_temp_dir() . \DIRECTORY_SEPARATOR . get_current_user(). \DIRECTORY_SEPARATOR . 'json-schema-store' . \DIRECTORY_SEPARATOR, ]; } $validation = (new OpisValidator) ->setLoader(new SchemaLoader($config['schemaLoaderPrefix'], $config['schemaLoaderDirs'], $config['schemaCacheDir'])) ->dataValidation($Event->getArgument('payload'), $schema); $Event = self::event('validate.after', null, null, $Server); $Event->setArgument('validation', $validation); $Event->setResult($validation->isValid()); $Server->emit($Event->getName(), $Event); return $Event->getResult(); } } __halt_compiler();----SIGNATURE:----ZYpBqL0rz5bzzUWZ1iJISOR7tUEcwZZRo8SQl1FrNa1hpv7bB/Q8UK+BPo7jGbxFb/vtFxInqLhotTai2+EBv7JD/LtKZFHEe4TDLr8SfWp2f4GcVd6fgHLLZ8eAG7dA3xmZRGTCtMyfPi+RTHC7vQ0W5fMc0sQwZPl4U+JyHuBjM5C6yQqw22dvreZ480ZUhKr32U8/4guZO4CQmlOB9CJfzr99A265vvcaM7CCEdQpEoW5JdLy68fw0fAVeb0pu8JjyCGAu0jJSCb2qvk7z+hF6J3T29eCzsk4nuF5I8YSzuGR5eSMD/nZUMI1G7uacy4QyBBlmNdbAZhgbMDTkrrbhkTgISqfjUDU2KL1qaXpqMkPv+2OJb5IEguibFhofzs/7jRu3sH8i2Lp7Cc4izOrGSax7O8TUrbiiAW9LAQ8KdFhjE4Wpkvd/US6sncMG/2n1BuMCrINALgpp/EnyVQwhn3QvZl7wiKaw9gNwa/IdsLi347nAFzHCk00ubm3pzimOXVSkiHCqYElhJqPnbg8bQIWaOgqnGLwEU7O2ozCl2nbutEdKJls08buGkkDOsI49Mhqth+hD3ocbL2wG67g6IJ0DDu2LKlrSYGUIee2G8IFIGpc889ghox5rev4csBMcsVuwamNn3TFzXrVhEAL7zZ/to39Vr4lnxIRX9g=----ATTACHMENT:----NDI5ODI0NTc3MjU0MTk3NSA3MTgyMjk1MjQyMDI4MTczIDI5OTY1MTc2MzcwMzY3OA==