enabled = $enabled; $this->on_chunk = $on_chunk; $this->on_tick = $on_tick; $this->deadline = microtime( true ) + max( 1, $timeout ); } /** * Hooks in (no-op when not streaming). */ public function attach(): void { if ( ! $this->enabled ) { return; } $this->armed = true; add_action( 'requests-requests.before_request', array( $this, 'before_request' ), 10, 5 ); add_action( 'requests-request.progress', array( $this, 'progress' ), 10, 1 ); } /** * Unhooks. */ public function detach(): void { if ( ! $this->enabled ) { return; } remove_action( 'requests-requests.before_request', array( $this, 'before_request' ), 10 ); remove_action( 'requests-request.progress', array( $this, 'progress' ), 10 ); $this->armed = false; } /** * Requests options of OUR request: fsockopen (when available) and HTTP/1.0. * * @param mixed $url URL (by reference, unchanged). * @param mixed $headers Headers (by reference, unchanged). * @param mixed $data Body (by reference, unchanged). * @param mixed $type Method (by reference, unchanged). * @param mixed $options Requests options (by reference). */ public function before_request( &$url, &$headers, &$data, &$type, &$options ): void { if ( ! $this->armed || ! is_array( $options ) ) { return; } $this->armed = false; $ssl = is_string( $url ) && 0 === stripos( $url, 'https://' ); if ( \WpOrg\Requests\Transport\Fsockopen::test( array( 'ssl' => $ssl ) ) ) { $options['transport'] = \WpOrg\Requests\Transport\Fsockopen::class; } // HTTP/1.0: the server cannot answer with chunked framing, so the hook sees the plain SSE bytes. $options['protocol_version'] = 1.0; } /** * One body chunk. * * @param mixed $data Chunk. * @throws \WpOrg\Requests\Exception To stop the transfer (Stop / total timeout). */ public function progress( $data ): void { if ( $this->busy || ! is_string( $data ) ) { return; } $this->busy = true; try { $this->body .= $data; if ( null === $this->sse && '' !== ltrim( $this->body ) ) { $this->sse = (bool) preg_match( '/^(event:|data:|id:|retry:|:)/', ltrim( $this->body ) ); } $continue = true; if ( $this->sse && $this->on_chunk && '' !== $data ) { $this->delivered = true; $continue = false !== call_user_func( $this->on_chunk, $data, 200, 'text/event-stream' ); } if ( $continue && $this->on_tick ) { $continue = false !== call_user_func( $this->on_tick ); } if ( ! $continue ) { $this->aborted = true; throw new \WpOrg\Requests\Exception( 'Stopped.', 'addsynapse_assistant_abort' ); } if ( microtime( true ) > $this->deadline ) { $this->timed_out = true; throw new \WpOrg\Requests\Exception( 'Timed out.', 'addsynapse_assistant_timeout' ); } } finally { $this->busy = false; }//end try } }