public function multiCurlPoll() { $curl_mh = $this->curl_mh; do { $mrc = curl_multi_exec($curl_mh, $still_running); if ($mrc == CURLM_OK) { $info = curl_multi_info_read($curl_mh); if ($info && isset($this->curl_cb[(int) $info['handle']])) { $as = $this->curl_cb[(int) $info['handle']]; $curl = $info['handle']; unset($this->curl_cb[(int) $curl]); $as->_futoin_response = curl_multi_getcontent($curl); $as->success($curl, $info); curl_multi_remove_handle($this->curl_mh, $curl); } } } while ($mrc === CURLM_CALL_MULTI_PERFORM); if ($this->curl_event !== null) { \FutoIn\RI\AsyncTool::cancelCall($this->curl_event); $this->curl_event = null; } if ($this->curl_cb) { $this->curl_event = \FutoIn\RI\AsyncTool::callLater([$this, "multiCurlSelect"]); } }
/** * Execute loop until *as.break()* is called * @param callable $func loop body callable( as ) * @param string $label optional label to use for *as.break()* and *as.continue()* in inner loops */ public function loop(callable $func, $label = null) { $this->_sanityCheck(); $loop_state = new \StdClass(); $loop_state->model_as = new \FutoIn\RI\AsyncSteps(); $loop_state->inner_as = null; $loop_state->outer_as = null; $loop_state->func = $func; $loop_state->label = $label; $this->add(function ($outer_as) use($loop_state) { $loop_state->outer_as = $outer_as; $create_iteration = function () use($outer_as, $loop_state) { $inner_as = new \FutoIn\RI\AsyncSteps($outer_as->state()); $inner_as->copyFrom($loop_state->model_as); $loop_state->inner_as = $inner_as; $inner_as->execute(); }; $loop_state->model_as->add(function ($as) use($loop_state) { $func = $loop_state->func; $func($as); }, function ($as, $err) use($loop_state) { if ($err === \FutoIn\Error::LoopCont) { $label = $loop_state->label; $term_label = $as->state()->_loop_term_label; if ($term_label && $term_label !== $label) { // Unroll loops continue \FutoIn\RI\AsyncTool::callLater(function () use($loop_state, $term_label) { try { $loop_state->outer_as->continueLoop($term_label); } catch (\Exception $e) { } }); } else { $as->success(); return; } } elseif ($err === \FutoIn\Error::LoopBreak) { $label = $loop_state->label; $term_label = $as->state()->_loop_term_label; if ($term_label && $term_label !== $label) { // Unroll loops and break \FutoIn\RI\AsyncTool::callLater(function () use($loop_state, $term_label) { try { $loop_state->outer_as->breakLoop($term_label); } catch (\Exception $e) { } }); } else { // Continue linear execution \FutoIn\RI\AsyncTool::callLater(function () use($loop_state, $term_label) { try { $loop_state->outer_as->success(); } catch (\Exception $e) { } }); } } else { \FutoIn\RI\AsyncTool::callLater(function () use($loop_state, $err) { try { $loop_state->outer_as->error($err); } catch (\Exception $e) { } }); } $loop_state->model_as->cancel(); $loop_state->model_as = null; $loop_state->func = null; })->add(function ($as) use($create_iteration) { \FutoIn\RI\AsyncTool::callLater($create_iteration); }); $outer_as->setCancel(function ($as) use($loop_state) { $loop_state->inner_as->cancel(); $loop_state->inner_as = null; if ($loop_state->model_as) { $loop_state->model_as->cancel(); $loop_state->model_as = null; } $loop_state->func = null; }); $create_iteration(); }); return $this; }
use FutoIn\RI\AsyncTool; function dummy_service_read($success, $error) { // We expect it calles success when data is available // and error, if error occurs // Returns some request handle return null; } function dummy_service_cancel($reqhandle) { // We assume it cancels previously scheduled reqhandle } $root_as = new ScopedSteps(); $root_as->add(function ($as) { AsyncTool::callLater(function () use($as) { $as->success('async success()'); }); $as->setTimeout(10); // ms })->add(function ($as, $arg) { echo $arg . PHP_EOL; $reqhandle = dummy_service_read(function ($data) use($as) { $as->success($data); }, function ($err) use($as) { if ($err !== 'SomeSpecificCancelCode') { $as->error($err); } }); $as->setCancel(function ($as) use($reqhandle) { dummy_service_cancel($reqhandle); });
public function testAsyncSuccess() { $as = $this->as; $as->executed = false; $as->add(function ($as) { $as->setCancel(function () { }); AsyncTool::callLater(function () use($as) { try { $as->error('MyError'); } catch (\Exception $e) { } }); }, function ($as, $err) { $as->executed = $err === 'MyError'; }); $as->execute(); AsyncToolTest::run(); $this->assertTrue($as->executed); }