oddsmatrix/sepc-connector

此软件包最新版本(dev-master)没有提供许可证信息。

PHP的SEPC连接器实现

dev-master 2022-03-14 00:14 UTC

This package is auto-updated.

Last update: 2024-09-14 05:47:00 UTC


README

体育引擎发布组件(SEPC)是客户端连接以获取体育引擎数据的组件。

我们提供了一个基于PHP的连接器,它知道如何连接并与SEPC进行通信。

当前版本:0.1.29-dev

安装

该连接器可以在公开的Packagist存储库中找到,名称为oddsmatrix/sepc-connector。要安装,只需在基于Composer的项目根目录中运行composer require oddsmatrix/sepc-connector

注意

在发布之前,为了能够运行composer require命令,必须遵循以下步骤

  • 克隆sepc-connector-php存储库
  • 如果尚未添加,请在项目的根目录中的composer.json文件中添加repositories条目。对于SEPC库条目
    • 将存储库类型设置为vcs
    • 将存储库的URL设置为本地sepc-connector-php克隆的路径
  • composer.json文件中添加minimum-stability条目并将其设置为dev
{
    "type": "project",
    "license": "proprietary",
    "repositories": [{
        "type": "vcs",
        "url": "/<path_to_your_project>/sepc-connector-php"
    }],
    "minimum-stability": "dev",
    "require": {
        "php": "^7.2.5",
        "ext-ctype": "*",
        "ext-iconv": "*",
        "oddsmatrix/sepc-connector": "dev-master",
...

运行composer require oddsmatrix/sepc-connector

现在应该在您的composer.json文件中显示"oddsmatrix/sepc-connector": "dev-master",行。

使用方法

SEPC连接器可以使用3种模式

  • PUSH - 直接套接字连接到体育引擎。此配置提供最快的更新,因为体育引擎不断推送更新。
  • PULL - 使用HTTP协议检索数据。更适合网络连接不稳定的情况,更新频率为1/30秒。
  • 保留状态PULL - 与PULL相同,但允许在请求之间保存状态(身份验证/完成状态)。这在您想从supervisor无服务器函数轮询SE时很有用。

PUSH

1. 创建SEPCCredentials

参考通用部分。

2. 实例化SEPCPushConnector

use OM\OddsMatrix\SEPC\Connector\SEPCPushConnector;

$connector = new SEPCPushConnector(
            $credentials,
            $logger
        );

3. 连接

对于套接字连接使用端口7000。

$connector->connect("sept.oddsmatrix.com", 7000);

4. 轮询更新

/** @var SDQLResponse|null $response */
$response = $connector->getNextData();

保留状态PUSH

1. 创建SEPCCredentials

参考通用部分。

2. 获取持久化状态文件

我们将使用相同的SDQLSerializer进行序列化和反序列化持久化状态。

$stateFilePath = ...;
$serializer = SDQLSerializerProvider::getSerializer();
$state = null;

try {
    $stateFileContent = file_get_contents($stateFilePath);
    if (false !== $stateFileContent) {
        $state = $serializer->deserialize($stateFileContent, PersistableConnectionState::class, 'xml');
    }
} catch (\Exception $e) {
    ...
}

如果没有要读取的状态,我们将创建一个新的空状态。

if (is_null($state)) {
    $state = new PersistableConnectionState();
}

3. 创建连接器

对于套接字连接使用端口7000。

$connector = new SEPCPushConnector(
            $credentials,
            $this->_logger,
            $state
        );

4. 连接

$connector->autoconnect("sept.oddsmatrix.com", 7000);

5. 轮询连接器以获取数据

/** @var SDQLResponse|null $response */
$response = $connector->getNextData();

6. 在每次轮询之后持久化更新后的状态

file_put_contents($stateFilePath, $serializer->serialize($connector->getConnectionState(), 'xml'));

(可选) 使用supervisor保持进程活动状态

设置supervisor目录参数非常重要。(设置CWD)以下是一个用于Symfony应用的示例supervisor配置。Supervisor配置文件应位于/etc/supervisor.d/并具有.ini扩展名。注意,只有当日志接口打印到控制台时,stderrstdout转发才有意义。

[program:push-persisted-state]
directory=$HOME/sepc-connector-test
command=$HOME/sepc-connector-test/bin/console sepc:push -vv --state-file-path=$HOME/sepc-state.xml
autostart=true
startsecs=60
startretries=5
autorestart=true
stopsignal=KILL
stdout_logfile=/var/log/sepc/push_stdout.log
stderr_logfile=/var/log/sepc/push_stderr.log
stdout_logfile_maxbytes=1GB
stderr_logfile_maxbytes=1GB

PULL

1. 创建SEPCCredentials

参考通用部分。

2. 实例化SEPCPullConnector

$connector = new SEPCPullConnector(
            $credentials,
            $this->_logger
        );

3. 连接

对于HTTP连接使用端口8081。

$connector->connect("http://sept.oddsmatrix.com", 8081);

4. 轮询更新

/** @var SDQLResponse|null $response */
$response = $connector->getNextData();

保留状态PULL

1. 创建SEPCCredentials

参考通用部分。

2. 实现可持久化的SEPCConnectionStateInterface

以下是一个可持久化的连接状态接口的示例,可以使用JMS Serializer进行序列化和反序列化。

在这个例子中,我们将使用这个可持久化的连接状态,以便在后续调用之间在文件系统上保存状态。

请注意,我们还在此持久连接状态中添加了一个请求计数器。这不是必需的,只是为了记录目的。

<?php


namespace App\Entity;


/**
 * Class PersistableConnectionState
 *
 * @Serializer\XmlRoot(name="PersistableConnection")
 */
class PersistableConnectionState implements SEPCConnectionStateInterface
{

    /**
     * @var string
     *
     * @Serializer\Type("string")
     * @Serializer\SerializedName("subscriptionId")
     * @Serializer\XmlAttribute()
     */
    private $_subscriptionId;

    /**
     * @var string
     *
     * @Serializer\Type("string")
     * @Serializer\SerializedName("subscriptionSpecificationName")
     * @Serializer\XmlAttribute()
     */
    private $_subscriptionSpecificationName;

    /**
     * @var int
     *
     * @Serializer\Type("int")
     * @Serializer\SerializedName("port")
     * @Serializer\XmlAttribute()
     */
    private $_port;

    /**
     * @var string
     *
     * @Serializer\Type("string")
     * @Serializer\SerializedName("host")
     * @Serializer\XmlAttribute()
     */
    private $_host;

    /**
     * @var bool
     *
     * @Serializer\Type("bool")
     * @Serializer\SerializedName("initialDataDumpComplete")
     * @Serializer\XmlAttribute()
     */
    private $_initialDataDumpComplete = false;

    /**
     * @var int
     *
     * @Serializer\Type("int")
     * @Serializer\SerializedName("count")
     * @Serializer\XmlAttribute()
     */
    private $_count = 0;

    /**
     * @var string|null
     *
     * @Serializer\Type("string")
     * @Serializer\SerializedName("lastBatchUuid")
     * @Serializer\XmlAttribute()
     */
    private $_lastBatchUuid;

    /**
     * @var string|null
     *
     * @Serializer\Type("string")
     * @Serializer\SerializedName("subscriptionChecksum")
     * @Serializer\XmlAttribute()
     */
    private $_subscriptionChecksum;

    /**
     * @var bool
     *
     * @Serializer\Type("bool")
     * @Serializer\SerializedName("resumable")
     * @Serializer\XmlAttribute()
     */
    private $_resumable = false;

    /**
     * @return string
     */
    public function getSubscriptionId(): string
    {
        return $this->_subscriptionId;
    }

    /**
     * @param string $subscriptionId
     * @return PersistableConnectionState
     */
    public function setSubscriptionId(string $subscriptionId): PersistableConnectionState
    {
        $this->_subscriptionId = $subscriptionId;
        return $this;
    }

    /**
     * @return string
     */
    public function getSubscriptionSpecificationName(): string
    {
        return $this->_subscriptionSpecificationName;
    }

    /**
     * @param string $subscriptionSpecificationName
     * @return PersistableConnectionState
     */
    public function setSubscriptionSpecificationName(string $subscriptionSpecificationName): PersistableConnectionState
    {
        $this->_subscriptionSpecificationName = $subscriptionSpecificationName;
        return $this;
    }

    /**
     * @return int
     */
    public function getPort(): int
    {
        return $this->_port;
    }

    /**
     * @param int $port
     * @return PersistableConnectionState
     */
    public function setPort(int $port): PersistableConnectionState
    {
        $this->_port = $port;
        return $this;
    }

    /**
     * @return string
     */
    public function getHost(): string
    {
        return $this->_host;
    }

    /**
     * @param string $host
     * @return PersistableConnectionState
     */
    public function setHost(string $host): PersistableConnectionState
    {
        $this->_host = $host;
        return $this;
    }

    /**
     * @return bool
     */
    public function isInitialDataDumpComplete(): bool
    {
        return $this->_initialDataDumpComplete;
    }

    /**
     * @param bool $initialDataDumpComplete
     * @return PersistableConnectionState
     */
    public function setInitialDataDumpComplete(bool $initialDataDumpComplete): PersistableConnectionState
    {
        $this->_initialDataDumpComplete = $initialDataDumpComplete;
        return $this;
    }

    /**
     * @return int
     */
    public function getCount(): int
    {
        return $this->_count;
    }

    /**
     * @param int $count
     * @return PersistableConnectionState
     */
    public function setCount(int $count): PersistableConnectionState
    {
        $this->_count = $count;
        return $this;
    }

    /**
     * @return string|null
     */
    public function getLastBatchUuid(): ?string
    {
        return $this->_lastBatchUuid;
    }

    /**
     * @param string|null $lastBatchUuid
     * @return PersistableConnectionState
     */
    public function setLastBatchUuid(?string $lastBatchUuid): PersistableConnectionState
    {
        $this->_lastBatchUuid = $lastBatchUuid;
        return $this;
    }

    /**
     * @return string|null
     */
    public function getSubscriptionChecksum(): ?string
    {
        return $this->_subscriptionChecksum;
    }

    /**
     * @param string|null $subscriptionChecksum
     * @return PersistableConnectionState
     */
    public function setSubscriptionChecksum(?string $subscriptionChecksum): PersistableConnectionState
    {
        $this->_subscriptionChecksum = $subscriptionChecksum;
        return $this;
    }

    /**
     * @return bool
     */
    public function isResumable(): bool
    {
        return $this->_resumable;
    }

    /**
     * @param bool $resumable
     * @return PersistableConnection
     */
    public function setResumable(bool $resumable): PersistableConnection
    {
        $this->_resumable = $resumable;
        return $this;
    }
}

3. 连接

只有当连接从未建立或已过期时,此阶段才是必需的。请记住,30分钟内不轮询连接会导致令牌过期。

在此示例中,我们将使用处理XML格式请求序列化的相同序列化器。

$serializer = \OM\OddsMatrix\SEPC\Connector\Util\SDQLSerializerProvider::getSerializer();

找到包含连接状态数据的文件或找不到文件将决定我们是否创建新的连接。

 /** @var PersistableConnectionState $connectionState */
$connectionState = null;
try {
    $connectionStateData = file_get_contents(self::connectionStatePath);
    $connectionState = $serializer->deserialize($connectionStateData, PersistableConnectionState::class, 'xml');
} catch (\Exception $e) {
    $this->_logger->warning("$e");
}

只有在连接状态不存在时才需要调用 connect()。否则,它将覆盖当前状态。

if (null == $connectionState) {
    $connector = new SEPCPullConnector($credentials, $this->_logger, new PersistableConnectionState());
    $connector->connect("http://sept.oddsmatrix.com", 8081);
    $connectionState = $connector->getConnectionState();
} else {
    $connector = new SEPCPullConnector($credentials, $this->_logger, $connectionState);
}

4. 使用可持久化的 SEPCConnectionStateInterface 实现轮询更新

一旦有了有效的连接状态并且已实例化连接器对象,我们可以运行一次 getNextData() 方法。

/** @var SDQLResponse|null $response */
$response = $connector->getNextData();

在此之后,持久化更新的状态很重要。

file_put_contents(self::connectionStatePath, $serializer->serialize($connectionState, 'xml'));

通用部分

创建 SEPCCredentials

use OM\OddsMatrix\SEPC\Connector\SEPCCredentials;

$credentials = new SEPCCredentials("<subscription_specification_name>");

使用 getNextData() 响应

SDQLResponse 类是围绕从SE接收的任何响应的包装器。来自拉连接器的任何HTTP请求或通过推送连接接收的任何消息都将反序列化为此类的一个对象。

如果消息包含初始数据转储的一批数据,则单个实体可以在以下位置找到:

/** var \OM\OddsMatrix\SEPC\Connector\SDQL\Response\SDQLResponse $sdqlResponse */
$entities = $sdqlResponse->getInitialData()->getEntities();

如果消息包含更新批,则单个实体更新可以在以下位置找到:

/** var \OM\OddsMatrix\SEPC\Connector\SDQL\Response\SDQLResponse $sdqlResponse */
$entities = $sdqlResponse->getDataUpdates();

$entities 对象将包含针对每个 SportsModel 实体的特定对象列表。

停止会话

调用任何连接器的 disconnect() 方法将向SE发送退订请求。

/** @var SDQLResponse|null $response */
$response = $connector->disconnect();

在退订时也重要地使持久连接状态无效。

日志记录

可以通过在任何SEPC连接器构造函数中传递可选的第二个参数来启用日志记录。第二个参数必须实现 Psr\Log\LoggerInterface。将第二个参数传递为 null 是有效的。

额外配置

连接器的额外配置可通过环境变量获得。

性能信息

将此环境变量 SEPC_CONNECTOR_PROFILING_LOGS 设置为字符串 true 将导致连接器打印额外的性能信息。

附加日志如下所示

Receive data time: 0.00014305114746094
GZDecode time: 0.0008389949798584
Deserialize time: 0.012924909591675

接收数据时间:从套接字读取所花费的时间。GZDecode时间:因为数据是接收到的gzipped,这是解压缩数据所花费的时间。反序列化时间:映射字符串数据到实际PHP对象所花费的时间。