Ejemplo n.º 1
0
 /**
  * Copy steps from other AsyncSteps, useful for sub-step cloning
  *
  * @param \FutoIn\RI\AsyncSteps $other model AsyncSteps object for re-use
  * @return \FutoIn\AsyncSteps reference to $this
  */
 public function copyFrom(\FutoIn\AsyncSteps $other)
 {
     if (!$other instanceof \FutoIn\RI\AsyncSteps) {
         throw new \FutoIn\Error(\FutoIn\Error::InternalError);
     }
     // Copy steps
     $oq = $other->_getInnerQueue();
     $oq->rewind();
     $q = $this->queue;
     for (; $oq->valid(); $oq->next()) {
         $q->enqueue($oq->current());
     }
     // Copy state
     $s = $this->state;
     foreach ($other->state as $k => $v) {
         if (!isset($s->{$k})) {
             $s->{$k} = $v;
         }
     }
 }
Ejemplo n.º 2
0
 /** @see \FutoIn\AdvancedCCM */
 public function cacheInit(\FutoIn\AsyncSteps $as)
 {
     // TODO:
     $as->error(\FutoIn\Error::NotImplemented);
 }
Ejemplo n.º 3
0
 /** @see \FutoIn\SimpleCCM */
 public function register(\FutoIn\AsyncSteps $as, $name, $ifacever, $endpoint, $credentials = null, $options = null)
 {
     // Unregister First
     if (array_key_exists($name, $this->iface_info)) {
         $as->error(\FutoIn\Error::InvokerError, "Already registered");
     }
     // Check ifacever
     if (!preg_match('/^(([a-z][a-z0-9]*)(\\.[a-z][a-z0-9]*)+):(([0-9]+)\\.([0-9]+))$/', $ifacever, $m)) {
         $as->error(\FutoIn\Error::InvokerError, "Invalid ifacever");
     }
     $iface = $m[1];
     $mjrmnr = $m[4];
     $mjr = $m[5];
     $mnr = $m[6];
     if (!is_string($endpoint)) {
         $as->error(\FutoIn\Error::InvokerError, "Invalid endpoint");
     }
     $endpoint = preg_replace('/^secure\\+/', '', $endpoint, 1, $repcnt);
     $secure_channel = $repcnt > 0;
     // Silently map WebSockets to HTTP/HTTPS as per FTN7 spec, if not supported
     $endpoint = preg_replace('/^ws(s?):\\/\\//', 'http${1}://', $endpoint);
     if (!$secure_channel && preg_match('/^(https|wss|unix):/', $endpoint)) {
         $secure_channel = true;
     }
     $url = parse_url($endpoint);
     if ($url['scheme'] === 'self') {
         $impl = str_replace('.', '\\', $url['host']);
     } else {
         $impl = "\\FutoIn\\RI\\Invoker\\Details\\NativeInterface";
     }
     $options = array_merge((array) $options, $this->impl->options);
     $info = new Details\RegistrationInfo();
     $info->iface = $iface;
     $info->version = $mjrmnr;
     $info->mjrver = $mjr;
     $info->mnrver = $mnr;
     $info->endpoint = $endpoint;
     $info->creds = $credentials;
     $info->secure_channel = $secure_channel;
     $info->impl = $impl;
     $info->regname = $name;
     $info->options =& $options;
     $this->iface_info[$name] = $info;
     $this->impl->onRegister($as, $info);
     $as->add(function ($as) use($name, $ifacever, $info) {
         if (!$info->simple_req) {
             if (!isset($info->constraints['AllowAnonymous']) && !$info->creds) {
                 $as->error(\FutoIn\Error::SecurityError, "Requires authenticated user");
             }
             if (isset($info->constraints['SecureChannel']) && !$info->secure_channel) {
                 $as->error(\FutoIn\Error::SecurityError, "SecureChannel is required");
             }
             if (isset($info->constraints['MessageSignature']) && !$info->creds_master && !$info->creds_hmac) {
                 $as->error(\FutoIn\Error::SecurityError, "SecureChannel is required");
             }
             if (isset($info->constraints['BiDirectChannel']) && !false) {
                 $as->error(\FutoIn\Error::InvokerError, "BiDirectChannel is required");
             }
         }
         $this->emit('register', [$name, $ifacever, $info]);
     });
 }
Ejemplo n.º 4
0
 public function call(\FutoIn\AsyncSteps $as, $name, $params, $upload_data = null, $download_stream = null, $timeout = null)
 {
     $ctx = new \StdClass();
     $ctx->name = $name;
     $ctx->info = $this->raw_info;
     $ctx->upload_data = $upload_data;
     $ctx->download_stream = $download_stream;
     $params = (object) $params;
     // Create message
     //---
     $as->add(function ($as) use($ctx, $params) {
         $this->ccmimpl->createMessage($as, $ctx, $params);
     });
     // Perform request
     //---
     $as->add(function ($as, $req) use($ctx, $upload_data, $download_stream, $timeout) {
         $curl_opts = array(CURLOPT_FORBID_REUSE => FALSE, CURLOPT_FRESH_CONNECT => FALSE, CURLOPT_NETRC => FALSE, CURLOPT_SSLVERSION => 3, CURLOPT_SSL_VERIFYPEER => TRUE, CURLOPT_FOLLOWLOCATION => FALSE, CURLOPT_CONNECTTIMEOUT_MS => 3000, CURLOPT_TIMEOUT_MS => 30000, CURLOPT_BINARYTRANSFER => true, CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1) + $this->ccmimpl->curl_opts;
         $curl = curl_init();
         $headers = array("Accept: application/futoin+json, */*");
         $url = $this->raw_info->endpoint;
         if (substr($url, -1) !== '/') {
             $url .= '/';
         }
         if ($upload_data) {
             // Encode according to FTN5: HTTP integration
             //---
             // iface / ver / func
             $url .= str_replace(':', '/', $req->f);
             // /sec
             if (isset($req->sec)) {
                 $url .= '/' . $req->sec;
             }
             // Params as query
             if (isset($req->p)) {
                 $url .= '?' . http_build_query((array) $req->p);
             }
             //---
             if (is_resource($upload_data)) {
                 // Old C-style trick
                 fseek($upload_data, -1, SEEK_END);
                 $upload_size = ftell($upload_data) + 1;
                 fseek($upload_data, 0, SEEK_SET);
                 $curl_opts[CURLOPT_PUT] = true;
                 $curl_opts[CURLOPT_CUSTOMREQUEST] = "POST";
                 $curl_opts[CURLOPT_INFILE] = $upload_data;
                 $curl_opts[CURLOPT_INFILESIZE] = $upload_size;
                 # Disable cURL-specific 1 second delay (empty 'Expect' does not work)
                 $curl_opts[CURLOPT_HTTP_VERSION] = CURL_HTTP_VERSION_1_0;
             } else {
                 $upload_size = strlen($upload_data);
                 $curl_opts[CURLOPT_POST] = true;
                 $curl_opts[CURLOPT_POSTFIELDS] = $upload_data;
             }
             $headers[] = "Content-Type: application/octet-stream";
             $headers[] = 'Content-Length: ' . $upload_size;
         } else {
             $headers[] = "Content-Type: application/futoin+json";
             $req = json_encode($req, JSON_FORCE_OBJECT | JSON_UNESCAPED_UNICODE);
             $curl_opts[CURLOPT_POST] = true;
             $curl_opts[CURLOPT_POSTFIELDS] = $req;
         }
         if ($download_stream) {
             $curl_opts[CURLOPT_FILE] = $download_stream;
         } else {
             $curl_opts[CURLOPT_RETURNTRANSFER] = true;
             // Limit size for security reasons
             $curl_opts[CURLOPT_PROGRESSFUNCTION] = function ($curl, $full_dlsize, $dlsize) {
                 return $dlsize > self::MSG_MAXSIZE ? -1 : 0;
             };
         }
         $curl_opts[CURLOPT_HTTPHEADER] = $headers;
         $curl_opts[CURLOPT_URL] = $url;
         curl_setopt_array($curl, $curl_opts);
         // cURL multi
         //---
         if ($timeout === null) {
             $timeout = $curl_opts[CURLOPT_TIMEOUT_MS];
         }
         if ((int) $timeout > 0) {
             $as->setTimeout($timeout);
         }
         $as->add(function ($as) use($curl) {
             $this->ccmimpl->multiCurlAdd($as, $curl);
         });
         $as->add(function ($as, $curl, $info) use($ctx, $download_stream) {
             $http_code = curl_getinfo($curl, CURLINFO_HTTP_CODE);
             $content_type = curl_getinfo($curl, CURLINFO_CONTENT_TYPE);
             $error = curl_error($curl);
             curl_close($curl);
             //---
             if ($http_code !== 200) {
                 $as->error(\FutoIn\Error::CommError, "HTTP:{$http_code} CURL:{$error}");
             } elseif ($download_stream) {
                 if ($info['result'] === CURLE_OK) {
                     $as->success(true);
                 } else {
                     $as->error(\FutoIn\Error::CommError, "CURL:{$error}");
                 }
             } elseif ($content_type === 'application/futoin+json') {
                 $rsp = json_decode($as->_futoin_response);
                 if ($rsp) {
                     $this->ccmimpl->onMessageResponse($as, $ctx, $rsp);
                 } else {
                     $as->error(\FutoIn\Error::CommError, "JSON:" . json_last_error_msg());
                 }
             } else {
                 $this->ccmimpl->onDataResponse($as, $ctx);
             }
         });
     });
 }
Ejemplo n.º 5
0
 public function onDataResponse(\FutoIn\AsyncSteps $as, $ctx)
 {
     $as->success($as->_futoin_response);
 }
Ejemplo n.º 6
0
 public function onDataResponse(\FutoIn\AsyncSteps $as, $ctx)
 {
     if ($ctx->info->funcs[$ctx->name]->rawresult) {
         $as->success($as->_futoin_response);
     } else {
         $as->error(\FutoIn\Error::InternalError, "Raw result is not expected");
     }
 }
Ejemplo n.º 7
0
 public static function checkFutoInType(\FutoIn\AsyncSteps $as, $type, $var, $val)
 {
     $rtype = '';
     switch ($type) {
         case 'boolean':
         case 'integer':
         case 'string':
         case 'array':
             $rtype = $type;
             break;
         case 'map':
             $rtype = 'object';
             break;
         case 'number':
             $rtype = 'string';
             break;
     }
     if (gettype($val) !== $rtype) {
         $as->error(\FutoIn\Error::InvalidRequest, "Type mismatch for parameter");
     }
 }