init commit

This commit is contained in:
2026-03-17 09:56:00 +08:00
commit e2c8ae752d
6827 changed files with 1211784 additions and 0 deletions

View File

@@ -0,0 +1,372 @@
<?php
namespace AlibabaCloud\Dara;
use Adbar\Dot;
use AlibabaCloud\Dara\Exception\DaraException;
use AlibabaCloud\Dara\RetryPolicy\RetryOptions;
use AlibabaCloud\Dara\RetryPolicy\RetryPolicyContext;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\RequestOptions;
use GuzzleHttp\Middleware;
use GuzzleHttp\Promise\PromiseInterface;
use GuzzleHttp\TransferStats;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\UriInterface;
/**
* Class Dara.
*/
class Dara
{
/**
* @var array
*/
private static $config = [];
const MAX_DELAY_TIME = 120 * 1000;
const MIN_DELAY_TIME = 100;
public static function config(array $config)
{
self::$config = $config;
}
/**
* @throws GuzzleException
*
* @return Response
*/
public static function send(Request $request, array $config = [])
{
if (method_exists($request, 'getPsrRequest')) {
$request = $request->getPsrRequest();
}
$config = self::resolveConfig($config);
$res = self::client()->send(
$request,
$config
);
return new Response($res);
}
/**
* @return PromiseInterface
*/
public static function sendAsync(RequestInterface $request, array $config = [])
{
if (method_exists($request, 'getPsrRequest')) {
$request = $request->getPsrRequest();
}
$config = self::resolveConfig($config);
return self::client()->sendAsync(
$request,
$config
);
}
/**
* @return Client
*/
public static function client(array $config = [])
{
if (isset(self::$config['handler'])) {
$stack = self::$config['handler'];
} else {
$stack = HandlerStack::create();
$stack->push(Middleware::mapResponse(static function (ResponseInterface $response) {
return new Response($response);
}));
}
self::$config['handler'] = $stack;
if (!isset(self::$config['on_stats'])) {
self::$config['on_stats'] = function (TransferStats $stats) {
Response::$info = $stats->getHandlerStats();
};
}
$new_config = Helper::merge([self::$config, $config]);
return new Client($new_config);
}
/**
* @param string $method
* @param string|UriInterface $uri
* @param array $options
*
* @throws GuzzleException
*
* @return ResponseInterface
*/
public static function request($method, $uri, $options = [])
{
return self::client()->request($method, $uri, $options);
}
/**
* @param string $method
* @param string $uri
* @param array $options
*
* @throws GuzzleException
*
* @return string
*/
public static function string($method, $uri, $options = [])
{
return (string) self::client()->request($method, $uri, $options)
->getBody();
}
/**
* @param string $method
* @param string|UriInterface $uri
* @param array $options
*
* @return PromiseInterface
*/
public static function requestAsync($method, $uri, $options = [])
{
return self::client()->requestAsync($method, $uri, $options);
}
/**
* @param string|UriInterface $uri
* @param array $options
*
* @throws GuzzleException
*
* @return null|mixed
*/
public static function getHeaders($uri, $options = [])
{
return self::request('HEAD', $uri, $options)->getHeaders();
}
/**
* @param string|UriInterface $uri
* @param string $key
* @param null|mixed $default
*
* @throws GuzzleException
*
* @return null|mixed
*/
public static function getHeader($uri, $key, $default = null)
{
$headers = self::getHeaders($uri);
return isset($headers[$key][0]) ? $headers[$key][0] : $default;
}
/**
* @param int $retryTimes
* @param float $now
*
* @return bool
*/
public static function allowRetry(array $runtime, $retryTimes, $now)
{
unset($now);
if (!isset($retryTimes) || null === $retryTimes || !\is_numeric($retryTimes)) {
return false;
}
if ($retryTimes > 0 && (empty($runtime) || !isset($runtime['retryable']) || !$runtime['retryable'] || !isset($runtime['maxAttempts']))) {
return false;
}
$maxAttempts = $runtime['maxAttempts'];
$retry = empty($maxAttempts) ? 0 : (int) $maxAttempts;
return $retry >= $retryTimes;
}
/**
* @param int $retryTimes
*
* @return int
*/
public static function getBackoffTime(array $runtime, $retryTimes)
{
$backOffTime = 0;
$policy = isset($runtime['policy']) ? $runtime['policy'] : '';
if (empty($policy) || 'no' == $policy) {
return $backOffTime;
}
$period = isset($runtime['period']) ? $runtime['period'] : '';
if (null !== $period && '' !== $period) {
$backOffTime = (int) $period;
if ($backOffTime <= 0) {
return $retryTimes;
}
}
return $backOffTime;
}
public static function sleep($time)
{
sleep($time);
}
public static function isRetryable($retry, $retryTimes = 0)
{
if ($retry instanceof DaraException) {
return true;
}
if (\is_array($retry)) {
$max = isset($retry['maxAttempts']) ? (int) ($retry['maxAttempts']) : 3;
return $retryTimes <= $max;
}
return false;
}
/**
*
* @param RetryOptions $options
* @param RetryPolicyContext $optctxions
* @return bool
*/
public static function shouldRetry($options, $ctx) {
if($ctx->getRetryCount() === 0) {
return true;
}
if (!$options || !$options->getRetryable()) {
return false;
}
$retriesAttempted = $ctx->getRetryCount();
$ex = $ctx->getException();
$conditions = $options->getNoRetryCondition();
foreach ($conditions as $condition) {
if (in_array($ex->getName(), $condition->getException()) || in_array($ex->getErrCode(), $condition->getErrorCode())) {
return false;
}
}
$conditions = $options->getRetryCondition();
foreach ($conditions as $condition) {
if (!in_array($ex->getName(), $condition->getException()) && !in_array($ex->getErrCode(), $condition->getErrorCode())) {
continue;
}
if ($retriesAttempted >= $condition->getMaxAttempts()) {
return false;
}
return true;
}
return false;
}
/**
*
* @param RetryOptions $options
* @param RetryPolicyContext $optctxions
* @return int
*/
public static function getBackoffDelay($options, $ctx) {
$ex = $ctx->getException();
$fullClassName = get_class($ex);
$classNameParts = explode('\\', $fullClassName);
$className = end($classNameParts);
$conditions = $options->getRetryCondition();
foreach ($conditions as $condition) {
if (!in_array($className, $condition->getException()) && !in_array($ex->getErrCode(), $condition->getErrorCode())) {
continue;
}
$maxDelay = $condition->getMaxDelay() ?: self::MAX_DELAY_TIME;
$retryAfter = method_exists($ex, 'getRetryAfter') ? $ex->getRetryAfter() : null;
if ($retryAfter !== null) {
return min($retryAfter, $maxDelay);
}
$backoff = $condition->getBackoff();
if (!isset($backoff) || null === $backoff) {
return self::MIN_DELAY_TIME;
}
return min($backoff->getDelayTime($ctx), $maxDelay);
}
return self::MIN_DELAY_TIME;
}
/**
* @param mixed|Model[] ...$item
*
* @return mixed
*/
public static function merge(...$item)
{
$tmp = [];
$n = 0;
foreach ($item as $i) {
if (\is_object($i)) {
if ($i instanceof Model) {
$i = $i->toMap();
} else {
$i = json_decode(json_encode($i), true);
}
}
if (null === $i) {
continue;
}
if (\is_array($i)) {
$tmp[$n++] = $i;
}
}
if (\count($tmp)) {
return \call_user_func_array('array_merge', $tmp);
}
return [];
}
private static function resolveConfig(array $config = [])
{
$options = new Dot(['http_errors' => false]);
if (isset($config['httpProxy']) && !empty($config['httpProxy'])) {
$options->set('proxy.http', $config['httpProxy']);
}
if (isset($config['httpsProxy']) && !empty($config['httpsProxy'])) {
$options->set('proxy.https', $config['httpsProxy']);
}
if (isset($config['noProxy']) && !empty($config['noProxy'])) {
$options->set('proxy.no', $config['noProxy']);
}
if (isset($config['ignoreSSL']) && !empty($config['ignoreSSL'])) {
$options->set('verify',!((bool)$config['ignoreSSL']));
}
if (isset($config['stream']) && !empty($config['stream'])) {
$options->set(RequestOptions::STREAM, (bool)$config['stream']);
}
// readTimeout&connectTimeout unit is millisecond
$read_timeout = isset($config['readTimeout']) && !empty($config['readTimeout']) ? (int) $config['readTimeout'] : 3000;
$con_timeout = isset($config['connectTimeout']) && !empty($config['connectTimeout']) ? (int) $config['connectTimeout'] : 3000;
// timeout unit is second
$options->set('timeout', ($read_timeout + $con_timeout) / 1000);
return $options->all();
}
}

View File

@@ -0,0 +1,148 @@
<?php
namespace AlibabaCloud\Dara;
use DateTime;
use DateTimeZone;
use DateInterval;
use AlibabaCloud\Dara\Exception\DaraException;
class Date
{
private $date = null;
public function __construct($date = 'now') {
$pattern = '/(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}(?:\.\d+)?)(?: \+?(\d{4}))?/';
if (ctype_digit($date) || is_numeric($date)) {
$this->date = (new DateTime())->setTimestamp($date);
} elseif (preg_match($pattern, $date, $matches)) {
$timeStr = $matches[1];
$tzStr = isset($matches[2]) ? $matches[2] : null;
if ($tzStr) {
$timezone = new DateTimeZone($this->convertTzOffsetToTzString($tzStr));
$this->date = DateTime::createFromFormat('Y-m-d H:i:s.u', $timeStr, $timezone);
} else {
$this->date = new DateTime($timeStr);
}
} else {
$this->date = new DateTime($date);
}
if($this->date === false || is_null($this->date)) {
throw new DaraException([], $date . ' is not a valid time str.');
}
}
private function convertTzOffsetToTzString($offset) {
$sign = (intval($offset) >= 0) ? '+' : '-';
$hours = substr($offset, 0, 2);
$minutes = substr($offset, 2, 2);
return $sign . $hours . ':' . $minutes;
}
public function format($layout) {
$layout = strtr($layout, [
'yyyy' => 'Y', 'yy' => 'y',
'MM' => 'm', 'M' => 'n',
'DD' => 'd', 'D' => 'j',
'HH' => 'H', 'H' => 'G',
'hh' => 'h', 'h' => 'g',
'mm' => 'i', 'm' => 'i',
'ss' => 's', 's' => 's',
'A' => 'A', 'a' => 'a',
'E' => 'N', 'YYYY' => 'Y',
]);
return $this->date->format($layout);
}
public function UTC($time = null)
{
$utcDate = clone $this->date;
$utcDate->setTimezone(new DateTimeZone('UTC'));
return $utcDate->format('Y-m-d H:i:s.u O \\U\\T\\C');
}
public function unix() {
$date = $this->date;
return $date->getTimestamp();
}
public function sub($unit, $amount) {
$interval = new DateInterval('P' . strtoupper($amount) . strtoupper((string)$unit));
$this->date->sub($interval);
return $this;
}
public function add($unit, $amount) {
$interval = new DateInterval('P' . strtoupper($amount) . strtoupper((string)$unit));
$this->date->add($interval);
return $this;
}
public function diff($diffDate, $unit = null) {
$interval = $this->date->diff($diffDate->getDateObject());
switch ($unit) {
case 'year':
return $interval->y;
case 'month':
return $interval->m;
case 'day':
return $interval->d;
case 'hour':
return $interval->h;
case 'minute':
return $interval->i;
case 'second':
return $interval->s;
default:
return ($interval->days * 24 * 60 * 60) +
($interval->h * 60 * 60) +
($interval->i * 60) +
$interval->s;
}
}
public function hour() {
return (int)$this->date->format('H');
}
public function minute() {
return (int)$this->date->format('i');
}
public function second() {
return (int)$this->date->format('s');
}
public function month() {
return (int)$this->date->format('n');
}
public function year() {
return (int)$this->date->format('Y');
}
public function dayOfMonth() {
return (int)$this->date->format('j');
}
public function dayOfWeek() {
$weekday = (int)$this->date->format('w');
return $weekday === 0 ? 7 : $weekday;
}
public function weekOfYear() {
$week = (int)$this->date->format('W');
$weekday = (int)$this->date->format('w');
if ($weekday === 0 && $this->date->format('z') === (string)($this->date->format('L') ? '365' : '364')) {
return (int)$this->date->sub(new DateInterval('P1D'))->format('W');
}
return $week;
}
public function getDateObject() {
return clone $this->date;
}
}

View File

@@ -0,0 +1,67 @@
<?php
namespace AlibabaCloud\Dara\Exception;
use AlibabaCloud\Tea\Exception\TeaError;
/**
* Class DaraException.
*/
class DaraException extends TeaError
{
public $message = '';
public $errCode = '';
public $data;
public $name = '';
public $statusCode;
public $description;
public $accessDeniedDetail;
public $errorInfo;
/**
* DaraError DaraException.
*
* @param array $errorInfo
* @param string $message
* @param int $code
* @param null|\Throwable $previous
*/
public function __construct($errorInfo = [], $message = '', $code = '', $previous = null)
{
parent::__construct($errorInfo, $message, $code, $previous);
$this->errorInfo = $errorInfo;
$this->name = 'BaseError';
if (!empty($errorInfo)) {
$properties = ['name', 'message', 'errCode', 'data', 'description', 'accessDeniedDetail'];
foreach ($properties as $property) {
if (isset($errorInfo[$property])) {
$this->{$property} = $errorInfo[$property];
}
}
}
}
/**
* @return array
*/
public function getName()
{
return $this->name;
}
/**
* @return string
*/
public function getErrCode()
{
return $this->errCode;
}
/**
* @return array
*/
public function getErrorInfo()
{
return $this->errorInfo;
}
}

View File

@@ -0,0 +1,88 @@
<?php
namespace AlibabaCloud\Dara\Exception;
/**
* Class DaraRespException.
*/
class DaraRespException extends DaraException
{
public $statusCode;
protected $retryAfter;
public $data;
public $accessDeniedDetail;
public $description;
/**
* DaraRespException constructor.
*
* @param array $errorInfo
* @param string $message
* @param int $code
* @param null|\Throwable $previous
*/
public function __construct($errorInfo = [], $message = '', $code = 0, $previous = null)
{
parent::__construct($errorInfo, (string) $message, (int) $code, $previous);
$this->name = 'ResponseError';
if (!empty($errorInfo)) {
$properties = ['retryAfter', 'statusCode', 'data', 'description', 'accessDeniedDetail'];
foreach ($properties as $property) {
if (isset($errorInfo[$property])) {
$this->{$property} = $errorInfo[$property];
if ($property === 'data' && isset($errorInfo['data']['statusCode'])) {
$this->statusCode = $errorInfo['data']['statusCode'];
}
}
}
}
}
/**
* @return array
*/
public function getErrorInfo()
{
return $this->errorInfo;
}
/**
* @return int
*/
public function getStatusCode()
{
return $this->statusCode;
}
/**
* @return int
*/
public function getRetryAfter()
{
return $this->retryAfter;
}
/**
* @return array
*/
public function getAccessDeniedDetail()
{
return $this->accessDeniedDetail;
}
/**
* @return string
*/
public function getDescription()
{
return $this->description;
}
/**
* @return array
*/
public function getData()
{
return $this->data;
}
}

View File

@@ -0,0 +1,21 @@
<?php
namespace AlibabaCloud\Dara\Exception;
/**
* Class DaraRetryException
*/
class DaraRespException extends DaraException
{
/**
* DaraRetryException constructor.
*
* @param string $message
* @param int $code
* @param null|\Throwable $previous
*/
public function __construct($message = '', $code = 0, $previous = null)
{
parent::__construct([], $message, $code, $previous);
}
}

View File

@@ -0,0 +1,46 @@
<?php
namespace AlibabaCloud\Dara\Exception;
use AlibabaCloud\Dara\Request;
use AlibabaCloud\Dara\RetryPolicy\RetryPolicyContext;
/**
* Class DaraUnableRetryException.
*/
class DaraUnableRetryException extends DaraException
{
private $lastRequest;
private $lastException;
/**
* DaraUnableRetryException constructor.
*
* @param Request $lastRequest
* @param null|\Exception $lastException
*/
public function __construct($lastRequest, $lastException = null)
{
if($lastRequest instanceof RetryPolicyContext) {
$lastException = $lastRequest->getException();
$lastRequest = $lastRequest->getHttpRequest();
}
$error_info = [];
if (null !== $lastException && $lastException instanceof DaraException) {
$error_info = $lastException->getErrorInfo();
}
parent::__construct($error_info, $lastException->getMessage(), $lastException->getCode(), $lastException);
$this->lastRequest = $lastRequest;
$this->lastException = $lastException;
}
public function getLastRequest()
{
return $this->lastRequest;
}
public function getLastException()
{
return $this->lastException;
}
}

View File

@@ -0,0 +1,116 @@
<?php
namespace AlibabaCloud\Dara;
use AlibabaCloud\Dara\Date;
use GuzzleHttp\Psr7\Stream;
use GuzzleHttp\Psr7\Utils;
use AlibabaCloud\Dara\Exception\DaraException;
class File
{
private $_path;
private $_stat = null;
private $_fd = false;
private $_position = 0;
public function __construct($path) {
$this->_path = $path;
}
public function path() {
return $this->_path;
}
public function createTime() {
if (!$this->_stat) {
$this->_stat = stat($this->_path);
}
return new Date($this->_stat['ctime']);
}
public function modifyTime() {
if (!$this->_stat) {
$this->_stat = stat($this->_path);
}
return new Date($this->_stat['mtime']);
}
public function length() {
if (!$this->_stat) {
$this->_stat = stat($this->_path);
}
return $this->_stat['size'];
}
public function read($size) {
if (!$this->_fd) {
$this->_fd = fopen($this->_path, 'a+');
}
$position = ftell($this->_fd);
$position = ftell($this->_fd);
fseek($this->_fd, $this->_position);
$data = fread($this->_fd, $size);
$bytesRead = strlen($data);
if (!$bytesRead) {
return null;
}
$this->_position += $bytesRead;
return $data;
}
public function write($data) {
if (!$this->_fd) {
$this->_fd = fopen($this->_path, 'a+');
}
fwrite($this->_fd, $data);
fflush($this->_fd);
clearstatcache();
$this->_stat = stat($this->_path);
}
public function close() {
if ($this->_fd) {
fclose($this->_fd);
$this->_fd = false;
}
}
/**
*
* @param string $path
* @return bool
*/
public static function exists($path) {
return file_exists($path);
}
/**
*
* @param string $path
* @return Stream
*/
public static function createReadStream($path) {
try {
$stream = Utils::streamFor(fopen($path, 'r'));
return $stream;
} catch (Exception $e) {
throw new DaraException([], "Unable to open file for reading: " . $e->getMessage());
}
}
/**
*
* @param string $path
* @return Stream
*/
public static function createWriteStream($path) {
try {
$stream = Utils::streamFor(fopen($path, 'a+'));
return $stream;
} catch (Exception $e) {
throw new DaraException([], "Unable to open file for writing: " . $e->getMessage());
}
}
}

View File

@@ -0,0 +1,112 @@
<?php
namespace AlibabaCloud\Dara;
class Helper
{
/**
* @param string $content
* @param string $prefix
* @param string $end
* @param string[] $filter
*
* @return string|string[]
*/
public static function findFromString($content, $prefix, $end, $filter = ['"', ' '])
{
$len = mb_strlen($prefix);
$pos = mb_strpos($content, $prefix);
if (false === $pos) {
return '';
}
$pos_end = mb_strpos($content, $end, $pos);
$str = mb_substr($content, $pos + $len, $pos_end - $pos - $len);
return str_replace($filter, '', $str);
}
/**
* @param string $str
*
* @return bool
*/
public static function isJson($str)
{
json_decode($str);
return \JSON_ERROR_NONE == json_last_error();
}
/**
* @param mixed $value
*
* @return bool
*/
public static function isBytes($value)
{
if (!\is_array($value)) {
return false;
}
$i = 0;
foreach ($value as $k => $ord) {
if ($k !== $i) {
return false;
}
if (!\is_int($ord)) {
return false;
}
if ($ord < 0 || $ord > 255) {
return false;
}
++$i;
}
return true;
}
/**
* Convert a bytes to string(utf8).
*
* @param array $bytes
*
* @return string the return string
*/
public static function toString($bytes)
{
$str = '';
foreach ($bytes as $ch) {
$str .= \chr($ch);
}
return $str;
}
/**
* @return array
*/
public static function merge(array $arrays)
{
$result = [];
foreach ($arrays as $array) {
foreach ($array as $key => $value) {
if (\is_int($key)) {
$result[] = $value;
continue;
}
if (isset($result[$key]) && \is_array($result[$key])) {
$result[$key] = self::merge(
[$result[$key], $value]
);
continue;
}
$result[$key] = $value;
}
}
return $result;
}
}

View File

@@ -0,0 +1,138 @@
<?php
namespace AlibabaCloud\Dara;
class Model
{
protected $_name = [];
protected $_required = [];
public function __construct($config = [])
{
if (!empty($config)) {
foreach ($config as $k => $v) {
$this->{$k} = $v;
}
}
}
public function getName($name = null)
{
if (null === $name) {
return $this->_name;
}
return isset($this->_name[$name]) ? $this->_name[$name] : $name;
}
public function toMap()
{
$map = get_object_vars($this);
foreach ($map as $k => $m) {
if (0 === strpos($k, '_')) {
unset($map[$k]);
}
}
$res = [];
foreach ($map as $k => $v) {
$name = isset($this->_name[$k]) ? $this->_name[$k] : $k;
$res[$name] = $v;
}
return $res;
}
public function validate()
{
$vars = get_object_vars($this);
foreach ($vars as $k => $v) {
if (isset($this->_required[$k]) && $this->_required[$k] && empty($v)) {
throw new \InvalidArgumentException("{$k} is required.");
}
}
}
public function copyWithoutStream() {
$map = $this->toArray(true);
$calledClass = get_called_class();
if (method_exists($calledClass, 'fromMap')) {
return $calledClass::fromMap($map);
}
return null;
}
public static function validateRequired($fieldName, $field, $val = null)
{
if (true === $val && null === $field) {
throw new \InvalidArgumentException($fieldName . ' is required');
}
}
public static function validateMaxLength($fieldName, $field, $val = null)
{
if (null !== $field && \strlen($field) > (int) $val) {
throw new \InvalidArgumentException($fieldName . ' is exceed max-length: ' . $val);
}
}
public static function validateMinLength($fieldName, $field, $val = null)
{
if (null !== $field && \strlen($field) < (int) $val) {
throw new \InvalidArgumentException($fieldName . ' is less than min-length: ' . $val);
}
}
public static function validatePattern($fieldName, $field, $regex = '')
{
if (null !== $field && '' !== $field && !preg_match("/^{$regex}$/", $field)) {
throw new \InvalidArgumentException($fieldName . ' is not match ' . $regex);
}
}
public static function validateMaximum($fieldName, $field, $val)
{
if (null !== $field && $field > $val) {
throw new \InvalidArgumentException($fieldName . ' cannot be greater than ' . $val);
}
}
public static function validateMinimum($fieldName, $field, $val)
{
if (null !== $field && $field < $val) {
throw new \InvalidArgumentException($fieldName . ' cannot be less than ' . $val);
}
}
public static function validateArray($arr)
{
if (null === $arr) {
return;
}
foreach($arr as $item) {
if($item instanceof Model) {
$item->validate();
} else if(is_array($item)){
self::validateArray($item);
}
}
}
/**
* @param array $map
* @param Model $model
*
* @return mixed
*/
public static function toModel($map, $model)
{
$names = $model->getName();
$names = array_flip($names);
foreach ($map as $key => $value) {
$name = isset($names[$key]) ? $names[$key] : $key;
$model->{$name} = $value;
}
return $model;
}
}

View File

@@ -0,0 +1,39 @@
<?php
// This file is auto-generated, don't edit it. Thanks.
namespace AlibabaCloud\Dara\Models;
use AlibabaCloud\Dara\Model;
class ExtendsParameters extends Model {
public $headers;
public $queries;
public function validate() {}
public function toMap() {
$res = [];
if (null !== $this->headers) {
$res['headers'] = $this->headers;
}
if (null !== $this->queries) {
$res['queries'] = $this->queries;
}
return $res;
}
/**
* @param array $map
* @return ExtendsParameters
*/
public static function fromMap($map = []) {
$model = new self();
if(isset($map['headers'])){
$model->headers = $map['headers'];
}
if(isset($map['queries'])){
$model->queries = $map['queries'];
}
return $model;
}
}

View File

@@ -0,0 +1,22 @@
<?php
namespace AlibabaCloud\Dara\Models;
use AlibabaCloud\Dara\Model;
class FileField extends Model
{
public $filename;
public $contentType;
public $content;
public function __construct($config = [])
{
$this->_required = [
'filename' => true,
'contentType' => true,
'content' => true,
];
parent::__construct($config);
}
}

View File

@@ -0,0 +1,273 @@
<?php
// This file is auto-generated, don't edit it. Thanks.
namespace AlibabaCloud\Dara\Models;
use AlibabaCloud\Dara\Model;
/**
* The common runtime options model
*/
class RuntimeOptions extends Model {
protected $_name = [
'autoretry' => 'autoretry',
'ignoreSSL' => 'ignoreSSL',
'key' => 'key',
'cert' => 'cert',
'ca' => 'ca',
'maxAttempts' => 'max_attempts',
'backoffPolicy' => 'backoff_policy',
'backoffPeriod' => 'backoff_period',
'readTimeout' => 'readTimeout',
'connectTimeout' => 'connectTimeout',
'httpProxy' => 'httpProxy',
'httpsProxy' => 'httpsProxy',
'noProxy' => 'noProxy',
'maxIdleConns' => 'maxIdleConns',
'localAddr' => 'localAddr',
'socks5Proxy' => 'socks5Proxy',
'socks5NetWork' => 'socks5NetWork',
'keepAlive' => 'keepAlive',
];
public function validate() {}
public function toMap() {
$res = [];
if (null !== $this->autoretry) {
$res['autoretry'] = $this->autoretry;
}
if (null !== $this->ignoreSSL) {
$res['ignoreSSL'] = $this->ignoreSSL;
}
if (null !== $this->key) {
$res['key'] = $this->key;
}
if (null !== $this->cert) {
$res['cert'] = $this->cert;
}
if (null !== $this->ca) {
$res['ca'] = $this->ca;
}
if (null !== $this->maxAttempts) {
$res['max_attempts'] = $this->maxAttempts;
}
if (null !== $this->backoffPolicy) {
$res['backoff_policy'] = $this->backoffPolicy;
}
if (null !== $this->backoffPeriod) {
$res['backoff_period'] = $this->backoffPeriod;
}
if (null !== $this->readTimeout) {
$res['readTimeout'] = $this->readTimeout;
}
if (null !== $this->connectTimeout) {
$res['connectTimeout'] = $this->connectTimeout;
}
if (null !== $this->httpProxy) {
$res['httpProxy'] = $this->httpProxy;
}
if (null !== $this->httpsProxy) {
$res['httpsProxy'] = $this->httpsProxy;
}
if (null !== $this->noProxy) {
$res['noProxy'] = $this->noProxy;
}
if (null !== $this->maxIdleConns) {
$res['maxIdleConns'] = $this->maxIdleConns;
}
if (null !== $this->localAddr) {
$res['localAddr'] = $this->localAddr;
}
if (null !== $this->socks5Proxy) {
$res['socks5Proxy'] = $this->socks5Proxy;
}
if (null !== $this->socks5NetWork) {
$res['socks5NetWork'] = $this->socks5NetWork;
}
if (null !== $this->keepAlive) {
$res['keepAlive'] = $this->keepAlive;
}
if (null !== $this->extendsParameters) {
$res['extendsParameters'] = null !== $this->extendsParameters ? $this->extendsParameters->toMap() : null;
}
return $res;
}
/**
* @param array $map
* @return RuntimeOptions
*/
public static function fromMap($map = []) {
$model = new self();
if(isset($map['autoretry'])){
$model->autoretry = $map['autoretry'];
}
if(isset($map['ignoreSSL'])){
$model->ignoreSSL = $map['ignoreSSL'];
}
if(isset($map['key'])){
$model->key = $map['key'];
}
if(isset($map['cert'])){
$model->cert = $map['cert'];
}
if(isset($map['ca'])){
$model->ca = $map['ca'];
}
if(isset($map['max_attempts'])){
$model->maxAttempts = $map['max_attempts'];
}
if(isset($map['backoff_policy'])){
$model->backoffPolicy = $map['backoff_policy'];
}
if(isset($map['backoff_period'])){
$model->backoffPeriod = $map['backoff_period'];
}
if(isset($map['readTimeout'])){
$model->readTimeout = $map['readTimeout'];
}
if(isset($map['connectTimeout'])){
$model->connectTimeout = $map['connectTimeout'];
}
if(isset($map['httpProxy'])){
$model->httpProxy = $map['httpProxy'];
}
if(isset($map['httpsProxy'])){
$model->httpsProxy = $map['httpsProxy'];
}
if(isset($map['noProxy'])){
$model->noProxy = $map['noProxy'];
}
if(isset($map['maxIdleConns'])){
$model->maxIdleConns = $map['maxIdleConns'];
}
if(isset($map['localAddr'])){
$model->localAddr = $map['localAddr'];
}
if(isset($map['socks5Proxy'])){
$model->socks5Proxy = $map['socks5Proxy'];
}
if(isset($map['socks5NetWork'])){
$model->socks5NetWork = $map['socks5NetWork'];
}
if(isset($map['keepAlive'])){
$model->keepAlive = $map['keepAlive'];
}
if(isset($map['extendsParameters'])){
$model->extendsParameters = ExtendsParameters::fromMap($map['extendsParameters']);
}
return $model;
}
/**
* @description whether to try again
* @var bool
*/
public $autoretry;
/**
* @description ignore SSL validation
* @var bool
*/
public $ignoreSSL;
/**
* @description privite key for client certificate
* @var string
*/
public $key;
/**
* @description client certificate
* @var string
*/
public $cert;
/**
* @description server certificate
* @var string
*/
public $ca;
/**
* @description maximum number of retries
* @var int
*/
public $maxAttempts;
/**
* @description backoff policy
* @var string
*/
public $backoffPolicy;
/**
* @description backoff period
* @var int
*/
public $backoffPeriod;
/**
* @description read timeout
* @var int
*/
public $readTimeout;
/**
* @description connect timeout
* @var int
*/
public $connectTimeout;
/**
* @description http proxy url
* @var string
*/
public $httpProxy;
/**
* @description https Proxy url
* @var string
*/
public $httpsProxy;
/**
* @description agent blacklist
* @var string
*/
public $noProxy;
/**
* @description maximum number of connections
* @var int
*/
public $maxIdleConns;
/**
* @description local addr
* @var string
*/
public $localAddr;
/**
* @description SOCKS5 proxy
* @var string
*/
public $socks5Proxy;
/**
* @description SOCKS5 netWork
* @var string
*/
public $socks5NetWork;
/**
* @description whether to enable keep-alive
* @var bool
*/
public $keepAlive;
/**
* @description Extends Parameters
* @var ExtendsParameters
*/
public $extendsParameters;
}

View File

@@ -0,0 +1,76 @@
<?php
namespace AlibabaCloud\Dara\Models;
use AlibabaCloud\Dara\Model;
class SSEEvent extends Model {
public $data;
public $id;
public $event;
public $retry;
public function __construct($data = array()) {
$this->data = isset($data['data']) ? $data['data'] : null;
$this->id = isset($data['id']) ? $data['id'] : null;
$this->event = isset($data['event']) ? $data['event'] : null;
$this->retry = isset($data['retry']) ? $data['retry'] : null;
}
public function validate() { }
public function toArray()
{
$res = [];
if (null !== $this->data) {
$res['data'] = $this->data;
}
if (null !== $this->id) {
$res['id'] = $this->id;
}
if (null !== $this->event) {
$res['event'] = $this->event;
}
if (null !== $this->retry) {
$res['retry'] = $this->retry;
}
return $res;
}
public function toMap()
{
return $this->toArray();
}
public static function fromMap($map = [])
{
$model = new self();
if (isset($map['data'])) {
if(!empty($map['data'])){
$model->data = [];
foreach($map['data'] as $key => $value) {
$model->data[$key] = $value;
}
}
}
if (isset($map['id'])) {
$model->id = $map['id'];
}
if (isset($map['event'])) {
$model->event = $map['event'];
}
if (isset($map['retry'])) {
$model->retry = $map['retry'];
}
return $res;
}
}

View File

@@ -0,0 +1,50 @@
<?php
namespace AlibabaCloud\Dara;
use ArrayIterator;
use IteratorAggregate;
use ReflectionObject;
use Traversable;
/**
* Class Parameter.
*/
abstract class Parameter implements IteratorAggregate
{
/**
* @return ArrayIterator|Traversable
*/
#[\ReturnTypeWillChange]
public function getIterator()
{
return new ArrayIterator($this->toArray());
}
/**
* @return array
*/
public function getRealParameters()
{
$array = [];
$obj = new ReflectionObject($this);
$properties = $obj->getProperties();
foreach ($properties as $property) {
$docComment = $property->getDocComment();
$key = trim(Helper::findFromString($docComment, '@real', "\n"));
$value = $property->getValue($this);
$array[$key] = $value;
}
return $array;
}
/**
* @return array
*/
public function toArray()
{
return $this->getRealParameters();
}
}

View File

@@ -0,0 +1,123 @@
<?php
namespace AlibabaCloud\Dara;
use GuzzleHttp\Psr7\Request as PsrRequest;
use InvalidArgumentException;
use Psr\Http\Message\StreamInterface;
/**
* Class Request.
*/
class Request extends PsrRequest
{
/**
* @var string
*/
public $protocol = 'https';
/**
* @var string
*/
public $pathname = '/';
/**
* @var array
*/
public $headers = [];
/**
* @var array
*/
public $query = [];
/**
* @var string
*/
public $body;
/**
* @var int
*/
public $port;
public $method;
public function __construct($method = 'GET', $uri = '', array $headers = [], $body = null, $version = '1.1')
{
parent::__construct($method, $uri, $headers, $body, $version);
$this->method = $method;
}
/**
* These fields are compatible if you define other fields.
* Mainly for compatibility situations where the code generator cannot generate set properties.
*
* @return PsrRequest
*/
public function getPsrRequest()
{
$this->assertQuery($this->query);
$request = clone $this;
$uri = $request->getUri();
if ($this->query) {
$uri = $uri->withQuery(http_build_query($this->query));
}
if ($this->port) {
$uri = $uri->withPort($this->port);
}
if ($this->protocol) {
$uri = $uri->withScheme($this->protocol);
}
if ($this->pathname) {
$uri = $uri->withPath($this->pathname);
}
if (isset($this->headers['host'])) {
$uri = $uri->withHost($this->headers['host']);
}
$request = $request->withUri($uri);
$request = $request->withMethod($this->method);
if ('' !== $this->body && null !== $this->body) {
if ($this->body instanceof StreamInterface) {
$request = $request->withBody($this->body);
} else {
$body = $this->body;
if (Helper::isBytes($this->body)) {
$body = Helper::toString($this->body);
}
if (\function_exists('\GuzzleHttp\Psr7\stream_for')) {
// @deprecated stream_for will be removed in guzzlehttp/psr7:2.0
$request = $request->withBody(\GuzzleHttp\Psr7\stream_for($body));
} else {
$request = $request->withBody(\GuzzleHttp\Psr7\Utils::streamFor($body));
}
}
}
if ($this->headers) {
foreach ($this->headers as $key => $value) {
$request = $request->withHeader($key, $value);
}
}
return $request;
}
/**
* @param array $query
*/
private function assertQuery($query)
{
if (!\is_array($query) && $query !== null) {
throw new InvalidArgumentException('Query must be array.');
}
}
}

View File

@@ -0,0 +1,379 @@
<?php
namespace AlibabaCloud\Dara;
use Adbar\Dot;
use ArrayAccess;
use Countable;
use GuzzleHttp\Psr7\Response as PsrResponse;
use GuzzleHttp\TransferStats;
use IteratorAggregate;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\StreamInterface;
use AlibabaCloud\Dara\Util\StringUtil;
/**
* Class Response.
*/
class Response extends PsrResponse implements ArrayAccess, IteratorAggregate, Countable
{
public $headers = [];
public $statusCode;
public $statusMessage = '';
/**
* @var TransferStats
*/
public static $info;
/**
* @var StreamInterface
*/
public $body;
/**
* Instance of the Dot.
*
* @var Dot
*/
protected $dot;
/**
* Response constructor.
*/
public function __construct(ResponseInterface $response)
{
parent::__construct(
$response->getStatusCode(),
$response->getHeaders(),
$response->getBody(),
$response->getProtocolVersion(),
$response->getReasonPhrase()
);
$this->headers = $response->getHeaders();
$this->body = $response->getBody();
$this->statusCode = $response->getStatusCode();
if ($this->body->isSeekable()) {
$this->body->seek(0);
}
$contentType = $this->getHeaderLine('Content-Type');
if(StringUtil::hasPrefix($contentType, 'text/event-stream')) {
return;
}
if (Helper::isJson((string) $this->getBody())) {
$this->dot = new Dot($this->toArray());
} else {
$this->dot = new Dot();
}
}
/**
* @return string
*/
public function __toString()
{
return (string) $this->getBody();
}
/**
* @param string $name
*
* @return null|mixed
*/
public function __get($name)
{
$data = $this->dot->all();
if (!isset($data[$name])) {
return null;
}
return json_decode(json_encode($data))->{$name};
}
/**
* @param string $name
* @param mixed $value
*/
public function __set($name, $value)
{
$this->dot->set($name, $value);
}
/**
* @param string $name
*
* @return bool
*/
public function __isset($name)
{
return $this->dot->has($name);
}
/**
* @param $offset
*/
public function __unset($offset)
{
$this->dot->delete($offset);
}
/**
* @return array
*/
public function toArray()
{
return \GuzzleHttp\json_decode((string) $this->getBody(), true);
}
/**
* @param array|int|string $keys
* @param mixed $value
*/
public function add($keys, $value = null)
{
return $this->dot->add($keys, $value);
}
/**
* @return array
*/
public function all()
{
return $this->dot->all();
}
/**
* @param null|array|int|string $keys
*/
public function clear($keys = null)
{
return $this->dot->clear($keys);
}
/**
* @param array|int|string $keys
*/
public function delete($keys)
{
return $this->dot->delete($keys);
}
/**
* @param string $delimiter
* @param null|array $items
* @param string $prepend
*
* @return array
*/
public function flatten($delimiter = '.', $items = null, $prepend = '')
{
return $this->dot->flatten($delimiter, $items, $prepend);
}
/**
* @param null|int|string $key
* @param mixed $default
*
* @return mixed
*/
public function get($key = null, $default = null)
{
return $this->dot->get($key, $default);
}
/**
* @param array|int|string $keys
*
* @return bool
*/
public function has($keys)
{
return $this->dot->has($keys);
}
/**
* @param null|array|int|string $keys
*
* @return bool
*/
public function isEmpty($keys = null)
{
return $this->dot->isEmpty($keys);
}
/**
* @param array|self|string $key
* @param array|self $value
*/
public function merge($key, $value = [])
{
return $this->dot->merge($key, $value);
}
/**
* @param array|self|string $key
* @param array|self $value
*/
public function mergeRecursive($key, $value = [])
{
return $this->dot->mergeRecursive($key, $value);
}
/**
* @param array|self|string $key
* @param array|self $value
*/
public function mergeRecursiveDistinct($key, $value = [])
{
return $this->dot->mergeRecursiveDistinct($key, $value);
}
/**
* @param null|int|string $key
* @param mixed $default
*
* @return mixed
*/
public function pull($key = null, $default = null)
{
return $this->dot->pull($key, $default);
}
/**
* @param null|int|string $key
* @param mixed $value
*
* @return mixed
*/
public function push($key = null, $value = null)
{
return $this->dot->push($key, $value);
}
/**
* Replace all values or values within the given key
* with an array or Dot object.
*
* @param array|self|string $key
* @param array|self $value
*/
public function replace($key, $value = [])
{
return $this->dot->replace($key, $value);
}
/**
* Set a given key / value pair or pairs.
*
* @param array|int|string $keys
* @param mixed $value
*/
public function set($keys, $value = null)
{
return $this->dot->set($keys, $value);
}
/**
* Replace all items with a given array.
*
* @param mixed $items
*/
public function setArray($items)
{
return $this->dot->setArray($items);
}
/**
* Replace all items with a given array as a reference.
*/
public function setReference(array &$items)
{
return $this->dot->setReference($items);
}
/**
* Return the value of a given key or all the values as JSON.
*
* @param mixed $key
* @param int $options
*
* @return string
*/
public function toJson($key = null, $options = 0)
{
return $this->dot->toJson($key, $options);
}
/**
* Retrieve an external iterator.
*/
#[\ReturnTypeWillChange]
public function getIterator()
{
return $this->dot->getIterator();
}
/**
* Whether a offset exists.
*
* @param $offset
*
* @return bool
*/
#[\ReturnTypeWillChange]
public function offsetExists($offset)
{
return $this->dot->offsetExists($offset);
}
/**
* Offset to retrieve.
*
* @param $offset
*
* @return mixed
*/
#[\ReturnTypeWillChange]
public function offsetGet($offset)
{
return $this->dot->offsetGet($offset);
}
/**
* Offset to set.
*
* @param $offset
* @param $value
*/
#[\ReturnTypeWillChange]
public function offsetSet($offset, $value)
{
$this->dot->offsetSet($offset, $value);
}
/**
* Offset to unset.
*
* @param $offset
*/
#[\ReturnTypeWillChange]
public function offsetUnset($offset)
{
$this->dot->offsetUnset($offset);
}
/**
* Count elements of an object.
*
* @param null $key
*
* @return int
*/
#[\ReturnTypeWillChange]
public function count($key = null)
{
return $this->dot->count($key);
}
}

View File

@@ -0,0 +1,46 @@
<?php
namespace AlibabaCloud\Dara\RetryPolicy;
use AlibabaCloud\Dara\Exception\DaraException;
use AlibabaCloud\Dara\RetryPolicy\BackoffPolicy;
use AlibabaCloud\Dara\RetryPolicy\EqualJitterBackoffPolicy;
use AlibabaCloud\Dara\RetryPolicy\ExponentialBackoffPolicy;
use AlibabaCloud\Dara\RetryPolicy\FixedBackoffPolicy;
use AlibabaCloud\Dara\RetryPolicy\FullJitterBackoffPolicy;
use AlibabaCloud\Dara\RetryPolicy\RandomBackoffPolic;
interface BackoffPolicyInterface {
public function getDelayTime($ctx);
}
abstract class BackoffPolicy implements BackoffPolicyInterface {
protected $policy;
public function __construct($option) {
$this->policy = $option['policy'];
}
abstract public function getDelayTime($ctx);
public static function newBackoffPolicy($option) {
switch($option['policy']) {
case 'Fixed':
return new FixedBackoffPolicy($option);
case 'Random':
return new RandomBackoffPolicy($option);
case 'Exponential':
return new ExponentialBackoffPolicy($option);
case 'EqualJitter':
case 'ExponentialWithEqualJitter':
return new EqualJitterBackoffPolicy($option);
case 'FullJitter':
case 'ExponentialWithFullJitter':
return new FullJitterBackoffPolicy($option);
default:
throw new DaraException([], "Invalid backoff policy");
}
}
}

View File

@@ -0,0 +1,27 @@
<?php
namespace AlibabaCloud\Dara\RetryPolicy;
use AlibabaCloud\Dara\Exception\DaraException;
use AlibabaCloud\Dara\RetryPolicy\BackoffPolicy;
class EqualJitterBackoffPolicy extends BackoffPolicy {
private $period;
private $cap;
public function __construct(array $option) {
parent::__construct($option);
if (!isset($option['period'])) {
throw new InvalidArgumentException("Period must be specified.");
}
$this->period = $option['period'];
// 默认值: 3 天
$this->cap = isset($option['cap']) ? $option['cap'] : 3 * 24 * 60 * 60 * 1000;
}
public function getDelayTime($ctx) {
$ceil = min(pow(2, $ctx->getRetryCount() * $this->period), $this->cap);
return $ceil / 2 + mt_rand(0, $ceil / 2);
}
}

View File

@@ -0,0 +1,27 @@
<?php
namespace AlibabaCloud\Dara\RetryPolicy;
use AlibabaCloud\Dara\Exception\DaraException;
use AlibabaCloud\Dara\RetryPolicy\BackoffPolicy;
class ExponentialBackoffPolicy extends BackoffPolicy {
private $period;
private $cap;
public function __construct(array $option) {
parent::__construct($option);
if (!isset($option['period'])) {
throw new DaraException("Period must be specified.");
}
$this->period = $option['period'];
// 默认值: 3 天
$this->cap = isset($option['cap']) ? $option['cap'] : 3 * 24 * 60 * 60 * 1000;
}
public function getDelayTime($ctx) {
$randomTime = pow(2, $ctx->getRetryCount() * $this->period);
return ($randomTime > $this->cap) ? $this->cap : $randomTime;
}
}

View File

@@ -0,0 +1,24 @@
<?php
namespace AlibabaCloud\Dara\RetryPolicy;
use AlibabaCloud\Dara\Exception\DaraException;
use AlibabaCloud\Dara\RetryPolicy\BackoffPolicy;
class FixedBackoffPolicy extends BackoffPolicy {
private $period;
public function __construct(array $option) {
parent::__construct($option);
if (!isset($option['period'])) {
throw new DaraException([], "Period must be specified.");
}
$this->period = $option['period'];
}
public function getDelayTime($ctx) {
return $this->period;
}
}

View File

@@ -0,0 +1,27 @@
<?php
namespace AlibabaCloud\Dara\RetryPolicy;
use AlibabaCloud\Dara\Exception\DaraException;
use AlibabaCloud\Dara\RetryPolicy\BackoffPolicy;
class FullJitterBackoffPolicy extends BackoffPolicy {
private $period;
private $cap;
public function __construct(array $option) {
parent::__construct($option);
if (!isset($option['period'])) {
throw new DaraException("Period must be specified.");
}
$this->period = $option['period'];
// 默认值: 3 天
$this->cap = isset($option['cap']) ? $option['cap'] : 3 * 24 * 60 * 60 * 1000;
}
public function getDelayTime($ctx) {
$ceil = min(pow(2, $ctx->getRetryCount() * $this->period), $this->cap);
return mt_rand(0, $ceil);
}
}

View File

@@ -0,0 +1,26 @@
<?php
namespace AlibabaCloud\Dara\RetryPolicy;
use AlibabaCloud\Dara\Exception\DaraException;
use AlibabaCloud\Dara\RetryPolicy\BackoffPolicy;
class RandomBackoffPolicy extends BackoffPolicy {
private $period;
private $cap;
public function __construct(array $option) {
parent::__construct($option);
if (!isset($option['period'])) {
throw new DaraException([], "Period must be specified.");
}
$this->period = $option['period'];
$this->cap = isset($option['cap']) ? $option['cap'] : 20000;
}
public function getDelayTime($ctx) {
$randomTime = mt_rand(0, $ctx->getRetryCount() * $this->period);
return ($randomTime > $this->cap) ? $this->cap : $randomTime;
}
}

View File

@@ -0,0 +1,62 @@
<?php
namespace AlibabaCloud\Dara\RetryPolicy;
use AlibabaCloud\Dara\RetryPolicy\BackoffPolicy;
use AlibabaCloud\Dara\Exception\DaraException;
class RetryCondition {
private $maxAttempts;
private $backoff = null;
private $exception = [];
private $errorCode = [];
private $maxDelay;
public function __construct($condition) {
if(isset($condition['maxAttempts'])) {
$this->maxAttempts = $condition['maxAttempts'];
}
$this->backoff = isset($condition['backoff']) ? $condition['backoff'] : null;
$this->exception = isset($condition['exception']) ? $condition['exception'] : [];
$this->errorCode = isset($condition['errorCode']) ? $condition['errorCode'] : [];
$this->maxDelay = isset($condition['maxDelay']) ? $condition['maxDelay'] : [];
}
/**
* @return int
*/
public function getMaxAttempts() {
return $this->maxAttempts;
}
/**
* @return BackoffPolicy
*/
public function getBackoff() {
return $this->backoff;
}
/**
* @return string[]
*/
public function getException() {
return $this->exception;
}
/**
* @return string[]
*/
public function getErrorCode() {
return $this->errorCode;
}
/**
* @return int
*/
public function getMaxDelay() {
return $this->maxDelay;
}
}

View File

@@ -0,0 +1,50 @@
<?php
namespace AlibabaCloud\Dara\RetryPolicy;
use AlibabaCloud\Dara\RetryPolicy\BackoffPolicy;
use AlibabaCloud\Dara\RetryPolicy\RetryCondition;
class RetryOptions {
private $retryable;
private $retryCondition;
private $noRetryCondition;
public function __construct($options) {
$this->retryable = $options['retryable'];
$this->retryCondition = array_map(function ($condition) {
if($condition instanceof RetryCondition) {
return $condition;
}
return new RetryCondition($condition);
}, isset($options['retryCondition']) ? $options['retryCondition'] : []);
$this->noRetryCondition = array_map(function ($condition) {
if($condition instanceof RetryCondition) {
return $condition;
}
return new RetryCondition($condition);
}, isset($options['noRetryCondition']) ? $options['noRetryCondition'] : []);
}
/**
* @return bool
*/
public function getRetryable() {
return $this->retryable;
}
/**
* @return RetryCondition[]
*/
public function getRetryCondition() {
return $this->retryCondition;
}
/**
* @return RetryCondition[]
*/
public function getNoRetryCondition() {
return $this->noRetryCondition;
}
}

View File

@@ -0,0 +1,64 @@
<?php
namespace AlibabaCloud\Dara\RetryPolicy;
use AlibabaCloud\Dara\RetryPolicy\BackoffPolicy;
use AlibabaCloud\Dara\Request;
use AlibabaCloud\Dara\Response;
use AlibabaCloud\Dara\Exception\DaraException;
class RetryPolicyContext {
private $key;
private $retriesAttempted;
private $httpRequest;
private $httpResponse;
private $exception;
public function __construct($options) {
$this->key = isset($options['key']) ? $options['key'] : '';
$this->retriesAttempted = isset($options['retriesAttempted']) ? $options['retriesAttempted'] : 0;
$this->httpRequest = isset($options['httpRequest']) ? $options['httpRequest'] : null;
$this->httpResponse = isset($options['httpResponse']) ? $options['httpResponse'] : null;
$this->exception = isset($options['exception']) ? $options['exception'] : null;
}
/**
*
* @return int
*/
public function getRetryCount(){
return $this->retriesAttempted;
}
/**
*
* @return string
*/
public function getKey() {
return $this->key;
}
/**
*
* @return Request
*/
public function getHttpRequest() {
return $this->httpRequest;
}
/**
*
* @return Response
*/
public function getHttpResponse() {
return $this->httpResponse;
}
/**
*
* @return DaraException
*/
public function getException() {
return $this->exception;
}
}

View File

@@ -0,0 +1,152 @@
<?php
namespace AlibabaCloud\Dara;
class Url
{
private $url = '';
private $path = '';
private $pathname = '';
private $protocol = '';
private $hostname = '';
private $host = '';
private $port = '';
private $hash = '';
private $search = '';
private $auth = '';
public function __construct($str) {
$this->url = $str;
}
public function path() {
if(empty($this->path)) {
return ;
}
$pathname = $this->pathname();
$query = $this->search();
$this->path = $pathname . '?' . $query;
return $this->path;
}
public function pathname() {
if(empty($this->pathname)) {
return $this->pathname;
}
$this->pathname = parse_url($ref, PHP_URL_PATH);
return $this->pathname;
}
public function protocol() {
if(empty($this->protocol)) {
return $this->protocol;
}
$this->protocol = parse_url($ref, PHP_URL_SCHEME);
return $this->protocol;
}
public function hostname() {
if(empty($this->hostname)) {
return $this->hostname;
}
$this->hostname = parse_url($ref, PHP_URL_HOST);
return $this->hostname;
}
public function host() {
if(empty($this->host)) {
return ;
}
$hostname = $this->hostname();
$port = $this->port();
$this->host = $hostname . $port;
return $this->host;
}
public function port() {
if(empty($this->port)) {
return $this->port;
}
$this->port = parse_url($ref, PHP_URL_PORT);
return $this->port;
}
public function hash() {
if(empty($this->hash)) {
return $this->hash;
}
$this->hash = parse_url($ref, PHP_URL_FRAGMENT);
return $this->hash;
}
public function search() {
if(empty($this->search)) {
return $this->search;
}
$this->search = parse_url($ref, PHP_URL_QUERY);
return $this->search;
}
public function href() {
return $this->href;
}
public function auth() {
if(empty($this->auth)) {
return $this->auth;
}
$username = parse_url($ref, PHP_URL_USER);
$password = parse_url($ref, PHP_URL_PASS);
$this->auth = $username . ':' . $password;
return $this->auth;
}
public static function parse($url) {
return new self($url);
}
public static function urlEncode($url) {
if (empty($raw)) {
throw new \InvalidArgumentException('not a valid value for parameter');
}
$str = urlencode($raw);
$str = str_replace("%20", "+", $str);
$str = str_replace("%2A", "*", $str);
return $str;
}
public static function percentEncode($raw) {
if($raw === null) {
return null;
}
$encoded = urlencode($raw);
$encoded = str_replace('+', '%20', $encoded);
$encoded = str_replace('*', '%2A', $encoded);
$encoded = str_replace('%7E', '~', $encoded);
return $encoded;
}
public static function pathEncode($path) {
if (empty($raw) || $raw === '/') {
return $raw;
}
$arr = explode('/', $raw);
$ret = '';
foreach ($arr as $i => $path) {
$str = self::percentEncode($path);
$ret .= "$str/";
}
return substr($ret, 0, -1);
}
}

View File

@@ -0,0 +1,151 @@
<?php
namespace AlibabaCloud\Dara\Util;
use XmlWriter;
/**
* Based on: http://stackoverflow.com/questions/99350/passing-php-associative-arrays-to-and-from-xml.
*/
class ArrayToXml
{
private $version;
private $encoding;
/**
* Construct ArrayToXML object with selected version and encoding
* for available values check XmlWriter docs http://www.php.net/manual/en/function.xmlwriter-start-document.php.
*
* @param string $xmlVersion XML Version, default 1.0
* @param string $xmlEncoding XML Encoding, default UTF-8
*/
public function __construct($xmlVersion = '1.0', $xmlEncoding = 'utf-8')
{
$this->version = $xmlVersion;
$this->encoding = $xmlEncoding;
}
/**
* Build an XML Data Set.
*
* @param array $data Associative Array containing values to be parsed into an XML Data Set(s)
* @param string $startElement Root Opening Tag, default data
*
* @return string XML String containing values
* @return mixed Boolean false on failure, string XML result on success
*/
public function buildXML($data, $startElement = 'data')
{
if (!\is_array($data)) {
$err = 'Invalid variable type supplied, expected array not found on line ' . __LINE__ . ' in Class: ' . __CLASS__ . ' Method: ' . __METHOD__;
trigger_error($err);
return false; //return false error occurred
}
$xml = new XmlWriter();
$xml->openMemory();
$xml->startDocument($this->version, $this->encoding);
$xml->startElement($startElement);
$data = $this->writeAttr($xml, $data);
$this->writeEl($xml, $data);
$xml->endElement(); //write end element
//returns the XML results
return $xml->outputMemory(true);
}
/**
* Write keys in $data prefixed with @ as XML attributes, if $data is an array.
* When an @ prefixed key is found, a '%' key is expected to indicate the element itself,
* and '#' prefixed key indicates CDATA content.
*
* @param XMLWriter $xml object
* @param array $data with attributes filtered out
*
* @return array $data | $nonAttributes
*/
protected function writeAttr(XMLWriter $xml, $data)
{
if (\is_array($data)) {
$nonAttributes = [];
foreach ($data as $key => $val) {
//handle an attribute with elements
if ('@' == $key[0]) {
$xml->writeAttribute(substr($key, 1), $val);
} elseif ('%' == $key[0]) {
if (\is_array($val)) {
$nonAttributes = $val;
} else {
$xml->text($val);
}
} elseif ('#' == $key[0]) {
if (\is_array($val)) {
$nonAttributes = $val;
} else {
$xml->startElement(substr($key, 1));
$xml->writeCData($val);
$xml->endElement();
}
} elseif ('!' == $key[0]) {
if (\is_array($val)) {
$nonAttributes = $val;
} else {
$xml->writeCData($val);
}
} //ignore normal elements
else {
$nonAttributes[$key] = $val;
}
}
return $nonAttributes;
}
return $data;
}
/**
* Write XML as per Associative Array.
*
* @param XMLWriter $xml object
* @param array $data Associative Data Array
*/
protected function writeEl(XMLWriter $xml, $data)
{
foreach ($data as $key => $value) {
if (\is_array($value) && !$this->isAssoc($value)) { //numeric array
foreach ($value as $itemValue) {
if (\is_array($itemValue)) {
$xml->startElement($key);
$itemValue = $this->writeAttr($xml, $itemValue);
$this->writeEl($xml, $itemValue);
$xml->endElement();
} else {
$itemValue = $this->writeAttr($xml, $itemValue);
$xml->writeElement($key, "{$itemValue}");
}
}
} elseif (\is_array($value)) { //associative array
$xml->startElement($key);
$value = $this->writeAttr($xml, $value);
$this->writeEl($xml, $value);
$xml->endElement();
} else { //scalar
$value = $this->writeAttr($xml, $value);
$xml->writeElement($key, "{$value}");
}
}
}
/**
* Check if array is associative with string based keys
* FROM: http://stackoverflow.com/questions/173400/php-arrays-a-good-way-to-check-if-an-array-is-associative-or-sequential/4254008#4254008.
*
* @param array $array Array to check
*
* @return bool
*/
protected function isAssoc($array)
{
return (bool) \count(array_filter(array_keys($array), 'is_string'));
}
}

View File

@@ -0,0 +1,96 @@
<?php
namespace AlibabaCloud\Dara\Util;
use AlibabaCloud\Dara\Exception\DaraException;
class BytesUtil
{
private static function is_bytes($value)
{
if (!\is_array($value)) {
return false;
}
$i = 0;
foreach ($value as $k => $ord) {
if ($k !== $i) {
return false;
}
if (!\is_int($ord)) {
return false;
}
if ($ord < 0 || $ord > 255) {
return false;
}
++$i;
}
return true;
}
public static function from($input, $encoding = 'utf-8')
{
$buffer = '';
if (self::is_bytes($input)) {
return $input;
} elseif (is_string($input)) {
switch (strtolower($encoding)) {
case 'utf-8':
case 'utf8':
$buffer = $input;
break;
case 'base64':
$decoded = base64_decode($input);
if ($decoded === false) {
throw new DaraException([], 'Invalid base64 input.');
}
$buffer = $decoded;
break;
case 'hex':
$decoded = hex2bin($input);
if ($decoded === false) {
throw new DaraException([], 'Invalid hex input.');
}
$buffer = $decoded;
break;
default:
throw new DaraException([], 'Unsupported encoding type.');
}
} else {
throw new DaraException([], 'Input must be an bytes or a string.');
}
$result = [];
for ($i = 0, $len = strlen($buffer); $i < $len; $i++) {
$result[] = ord($buffer[$i]);
}
return $result;
}
/**
*
* @param int[] $bytes
* @return string
*/
public static function toString($bytes, $type = 'utf8')
{
if (\is_string($bytes)) {
return $bytes;
}
$str = '';
foreach ($bytes as $ch) {
$str .= \chr($ch);
}
if($type == 'hex') {
return bin2hex($str);
}
if($type == 'base64') {
return base64_encode($str);
}
return $str;
}
}

View File

@@ -0,0 +1,109 @@
<?php
namespace AlibabaCloud\Dara\Util;
use Monolog\Handler\AbstractProcessingHandler;
use Monolog\Handler\StreamHandler;
use Monolog\Logger;
/**
* This is a console module.
*/
class Console
{
/**
* @var Logger
*/
private static $loggerDriver;
/**
* Console val with log level into stdout.
*
* @param string $val the printing string
*
* @throws \Exception
*
* @example \[LOG\] tea console example
*/
public static function log($val)
{
self::logger()->log(200, $val);
}
/**
* Console val with info level into stdout.
*
* @param string $val the printing string
*
* @throws \Exception
*
* @example \[INFO\] tea console example
*/
public static function info($val)
{
self::logger()->info($val);
}
/**
* Console val with warning level into stdout.
*
* @param string $val the printing string
*
* @throws \Exception
*
* @example \[WARNING\] tea console example
*/
public static function warning($val)
{
self::logger()->warning($val);
}
/**
* Console val with debug level into stdout.
*
* @param string $val the printing string
*
* @throws \Exception
*
* @example \[DEBUG\] tea console example
*/
public static function debug($val)
{
self::logger()->debug($val);
}
/**
* Console val with error level into stderr.
*
* @param string $val the printing string
*
* @throws \Exception
*
* @example \[ERROR\] tea console example
*/
public static function error($val)
{
self::logger()->error($val);
}
/**
* @param AbstractProcessingHandler $handler
*/
public static function pushHandler($handler)
{
self::$loggerDriver->pushHandler($handler);
}
/**
* @return Logger
*/
public static function logger()
{
if (null === self::$loggerDriver) {
self::$loggerDriver = new Logger('tea-console-log');
self::$loggerDriver->pushHandler(new StreamHandler('php://stderr', 0));
}
return self::$loggerDriver;
}
}

View File

@@ -0,0 +1,330 @@
<?php
namespace AlibabaCloud\Dara\Util;
use AlibabaCloud\Dara\Models\FileField;
use GuzzleHttp\Psr7\Stream;
use Psr\Http\Message\StreamInterface;
/**
* @internal
* @coversNothing
*/
class FileFormStream implements StreamInterface
{
/**
* @var resource
*/
private $stream;
private $index = 0;
private $form = [];
private $boundary = '';
private $streaming = false;
private $keys = [];
/**
* @var Stream
*/
private $currStream;
private $size;
private $uri;
private $seekable;
private $readable = true;
private $writable = true;
public function __construct($map, $boundary)
{
$this->stream = fopen('php://memory', 'a+');
$this->form = $map;
$this->boundary = $boundary;
$this->keys = array_keys($map);
do {
$read = $this->readForm(1024);
} while (null !== $read);
$meta = stream_get_meta_data($this->stream);
$this->seekable = $meta['seekable'];
$this->uri = $this->getMetadata('uri');
$this->seek(0);
$this->seek(0);
}
/**
* Closes the stream when the destructed.
*/
public function __destruct()
{
$this->close();
}
/**
*
* @return string
*/
public function __toString()
{
try {
$this->seek(0);
return (string) stream_get_contents($this->stream);
} catch (\Exception $e) {
return '';
}
}
/**
* @param int $length
*
* @return false|int|string
*/
public function readForm($length)
{
if ($this->streaming) {
if (null !== $this->currStream) {
// @var string $content
$content = $this->currStream->read($length);
if (false !== $content && '' !== $content) {
fwrite($this->stream, $content);
return $content;
}
return $this->next("\r\n");
}
return $this->next();
}
$keysCount = \count($this->keys);
if ($this->index > $keysCount) {
return null;
}
if ($keysCount > 0) {
if ($this->index < $keysCount) {
$this->streaming = true;
$name = $this->keys[$this->index];
$field = $this->form[$name];
if (!empty($field) && $field instanceof FileField) {
if (!empty($field->content)) {
$this->currStream = $field->content;
$str = '--' . $this->boundary . "\r\n" .
'Content-Disposition: form-data; name="' . $name . '"; filename="' . $field->filename . "\"\r\n" .
'Content-Type: ' . $field->contentType . "\r\n\r\n";
$this->write($str);
return $str;
}
return $this->next();
}
$val = $field;
$str = '--' . $this->boundary . "\r\n" .
'Content-Disposition: form-data; name="' . $name . "\"\r\n\r\n" .
$val . "\r\n";
fwrite($this->stream, $str);
return $str;
}
if ($this->index == $keysCount) {
return $this->next('--' . $this->boundary . "--\r\n");
}
return null;
}
return null;
}
public function getContents()
{
if (!isset($this->stream)) {
throw new \RuntimeException('Stream is detached');
}
$contents = stream_get_contents($this->stream);
if (false === $contents) {
throw new \RuntimeException('Unable to read stream contents');
}
return $contents;
}
/**
*
*
* @return void
*/
public function close()
{
if (isset($this->stream)) {
if (\is_resource($this->stream)) {
fclose($this->stream);
}
$this->detach();
}
}
public function detach()
{
if (!isset($this->stream)) {
return null;
}
$result = $this->stream;
unset($this->stream);
$this->size = $this->uri = null;
return $result;
}
public function getSize()
{
if (null !== $this->size) {
return $this->size;
}
if (!isset($this->stream)) {
return null;
}
// Clear the stat cache if the stream has a URI
if ($this->uri) {
clearstatcache(true, $this->uri);
}
$stats = fstat($this->stream);
if (isset($stats['size'])) {
$this->size = $stats['size'];
return $this->size;
}
return null;
}
public function isReadable()
{
return $this->readable;
}
public function isWritable()
{
return $this->writable;
}
public function isSeekable()
{
return $this->seekable;
}
public function eof()
{
if (!isset($this->stream)) {
throw new \RuntimeException('Stream is detached');
}
return feof($this->stream);
}
public function tell()
{
if (!isset($this->stream)) {
throw new \RuntimeException('Stream is detached');
}
$result = ftell($this->stream);
if (false === $result) {
throw new \RuntimeException('Unable to determine stream position');
}
return $result;
}
public function rewind()
{
$this->seek(0);
}
public function seek($offset, $whence = SEEK_SET)
{
$whence = (int) $whence;
if (!isset($this->stream)) {
throw new \RuntimeException('Stream is detached');
}
if (!$this->seekable) {
throw new \RuntimeException('Stream is not seekable');
}
if (-1 === fseek($this->stream, $offset, $whence)) {
throw new \RuntimeException('Unable to seek to stream position ' . $offset . ' with whence ' . var_export($whence, true));
}
}
public function read($length)
{
if (!isset($this->stream)) {
throw new \RuntimeException('Stream is detached');
}
if (!$this->readable) {
throw new \RuntimeException('Cannot read from non-readable stream');
}
if ($length < 0) {
throw new \RuntimeException('Length parameter cannot be negative');
}
if (0 === $length) {
return '';
}
$string = fread($this->stream, $length);
if (false === $string) {
throw new \RuntimeException('Unable to read from stream');
}
return $string;
}
public function write($string)
{
if (!isset($this->stream)) {
throw new \RuntimeException('Stream is detached');
}
if (!$this->writable) {
throw new \RuntimeException('Cannot write to a non-writable stream');
}
// We can't know the size after writing anything
$this->size = null;
$result = fwrite($this->stream, $string);
if (false === $result) {
throw new \RuntimeException('Unable to write to stream');
}
return $result;
}
public function getMetadata($key = null)
{
if (!isset($this->stream)) {
return $key ? null : [];
}
$meta = stream_get_meta_data($this->stream);
return isset($meta[$key]) ? $meta[$key] : null;
}
private function next($endStr = '')
{
$this->streaming = false;
++$this->index;
$this->write($endStr);
$this->currStream = null;
return $endStr;
}
}

View File

@@ -0,0 +1,46 @@
<?php
namespace AlibabaCloud\Dara\Util;
use AlibabaCloud\Dara\Model;
class FormUtil
{
/**
*
* @param array $query
* @return string
*/
public static function toFormString($query)
{
if (null === $query) {
return '';
}
if ($query instanceof Model) {
$query = $query->toArray();
}
return str_replace('+', '%20', http_build_query($query));
}
/**
*
* @return string
*/
public static function getBoundary()
{
return (string) (mt_rand(10000000000000, 99999999999999));
}
/**
*
* @param array $map
* @param string $boundary
* @return string
*/
public static function toFileForm($map, $boundary)
{
return new FileFormStream($map, $boundary);
}
}

View File

@@ -0,0 +1,15 @@
<?php
namespace AlibabaCloud\Dara\Util;
class MathUtil
{
/**
*
* @return double
*/
public static function random()
{
return rand(0, getrandmax() - 1) / getrandmax();
}
}

View File

@@ -0,0 +1,153 @@
<?php
namespace AlibabaCloud\Dara\Util;
use GuzzleHttp\Psr7\Stream;
use AlibabaCloud\Dara\Util\StringUtil;
use AlibabaCloud\Dara\Models\SSEEvent;
class StreamUtil
{
/**
* @param Stream $stream
*
* @return int[]
*/
public static function readAsBytes($stream)
{
$str = self::readAsString($stream);
return StringUtil::toBytes($str);
}
/**
* @param Stream $stream
*
* @return array the parsed result
*/
public static function readAsJSON($stream)
{
$jsonString = self::readAsString($stream);
return json_decode($jsonString, true);
}
/**
* @param Stream $stream
*
* @return string
*/
public static function readAsString($stream)
{
if ($stream->isSeekable()) {
$stream->rewind();
}
return $stream->getContents();
}
private static function tryGetEvents($head, $chunk) {
$all = $head . $chunk;
if(empty($all)) {
return [];
}
$start = 0;
$events = [];
$lines = explode("\n", $all);
$event = new SSEEvent();
for ($i = 0; $i < strlen($all) - 1; $i++) {
$c = $all[$i];
$c2 = $all[$i + 1];
if ($c === "\n" && $c2 === "\n") {
$part = substr($all, $start, $i - $start);
$lines = explode("\n", $part);
$event = new SSEEvent();
foreach ($lines as $line) {
if ('' === trim($line)) {
continue;
} elseif (0 === strpos($line, 'data:')) {
$data = substr($line, 5);
$event->data .= trim($data);
} elseif (0 === strpos($line, 'event:')) {
$eventLine = substr($line, 6);
$event->event = trim($eventLine);
} elseif (0 === strpos($line, 'id:')) {
$id = substr($line, 3);
$event->id = trim($id);
} elseif (0 === strpos($line, 'retry:')) {
$retry = substr($line, 6);
$retry = trim($retry);
if (ctype_digit($retry)) {
$event->retry = intval($retry, 10);
}
} elseif (isset($line[0]) && $line[0] === ':') {
// Lines starting with ':' are comments and ignored.
}
}
array_push($events, $event);
$start = $i + 2;
}
}
$remain = substr($all, $start);
return ['events' => $events, 'remain' => $remain];
}
/**
* @param Stream $stream
*
* @return string
*/
public static function readAsSSE($stream)
{
$rest = '';
while (!$stream->eof()) {
$chunk = $stream->read(4096);
$result = self::tryGetEvents($rest, $chunk);
if(empty($result)) {
continue;
}
$events = $result['events'];
$rest = $result['remain'];
foreach ($events as $event) {
yield $event;
}
}
// If there is any remaining data that qualifies as an event, yield it as well
if ($rest !== '' && $rest !== false) {
$lastEvent = new SSEEvent();
$lastEvent->data = $rest;
yield $lastEvent;
}
}
/**
* @param mixin $str
*
* @return bool
*/
public static function streamFor($str)
{
if (!\is_array($value)) {
return false;
}
$i = 0;
foreach ($value as $k => $ord) {
if ($k !== $i) {
return false;
}
if (!\is_int($ord)) {
return false;
}
if ($ord < 0 || $ord > 255) {
return false;
}
++$i;
}
return true;
}
}

View File

@@ -0,0 +1,61 @@
<?php
namespace AlibabaCloud\Dara\Util;
use AlibabaCloud\Dara\Exception\DaraException;
use AlibabaCloud\Dara\Util\BytesUtil;
class StringUtil
{
/**
* @param string $string
* @param string $type
*
* @return int[]
*/
public static function toBytes($string, $type = 'utf8')
{
return BytesUtil::from($string, $type);
}
/**
* @param string $str
* @param string $prefix
*
* @return bool
*/
public static function hasPrefix($str, $prefix)
{
if(!is_string($prefix) || !is_string($str)) {
return false;
}
$length = strlen($prefix);
if ($length == 0) {
return true;
}
return substr($str, 0, $length) === $prefix;
}
/**
* @param string $str
* @param string $suffix
*
* @return bool
*/
public static function hasSuffix($str, $suffix)
{
if(!is_string($suffix) || !is_string($str)) {
return false;
}
$length = strlen($suffix);
if ($length == 0) {
return true;
}
return substr($str, -$length) === $suffix;
}
}

View File

@@ -0,0 +1,61 @@
<?php
namespace AlibabaCloud\Dara\Util;
use AlibabaCloud\Dara\Util\ArrayToXml;
class XML
{
public static function parseXml($xmlStr, $response)
{
$res = self::parse($xmlStr);
if ($response === null) {
return $res;
} else {
if (\is_string($response)) {
$response = new $response();
}
$prop = get_object_vars($response);
$target = [];
foreach ($res as $k => $v) {
if (isset($prop[$k])) {
$target[$k] = $v;
}
}
return $target;
}
}
public static function toXML($array)
{
$arrayToXml = new ArrayToXml();
if (\is_object($array)) {
$tmp = explode('\\', \get_class($array));
$rootName = $tmp[\count($tmp) - 1];
$data = json_decode(json_encode($array), true);
} else {
$tmp = $array;
reset($tmp);
$rootName = key($tmp);
$data = $array[$rootName];
}
ksort($data);
return $arrayToXml->buildXML($data, $rootName);
}
private static function parse($xml)
{
if (\PHP_VERSION_ID < 80000) {
libxml_disable_entity_loader(true);
}
return json_decode(
json_encode(
simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)
),
true
);
}
}