1<?php
2/**
3 * This file is part of the FreeDSx Socket package.
4 *
5 * (c) Chad Sikorra <Chad.Sikorra@gmail.com>
6 *
7 * For the full copyright and license information, please view the LICENSE
8 * file that was distributed with this source code.
9 */
10
11namespace FreeDSx\Socket\Queue;
12
13use FreeDSx\Asn1\Encoder\EncoderInterface;
14use FreeDSx\Asn1\Exception\PartialPduException;
15use FreeDSx\Socket\Exception\PartialMessageException;
16use FreeDSx\Socket\PduInterface;
17use FreeDSx\Socket\Socket;
18
19/**
20 * Represents an ASN.1 based message queue using the FreeDSx ASN.1 library.
21 *
22 * @author Chad Sikorra <Chad.Sikorra@gmail.com>
23 */
24class Asn1MessageQueue extends MessageQueue
25{
26    /**
27     * @var null|string
28     */
29    protected $pduClass;
30
31    /**
32     * @var EncoderInterface
33     */
34    protected $encoder;
35
36    /**
37     * @param Socket $socket
38     * @param EncoderInterface $encoder
39     * @param null|string $pduClass
40     */
41    public function __construct(Socket $socket, EncoderInterface $encoder, ?string $pduClass = null)
42    {
43        if ($pduClass !== null && !\is_subclass_of($pduClass, PduInterface::class)) {
44            throw new \RuntimeException(sprintf(
45                'The class "%s" must implement "%s", but it does not.',
46                $pduClass,
47                PduInterface::class
48            ));
49        }
50        $this->encoder = $encoder;
51        $this->pduClass = $pduClass;
52        parent::__construct($socket);
53    }
54
55    /**
56     * {@inheritdoc}
57     */
58    protected function decode($bytes): Message
59    {
60        try {
61            $asn1 = $this->encoder->decode($bytes);
62            $message = new Message($asn1, $this->encoder->getLastPosition());
63        } catch (PartialPduException $exception) {
64            throw new PartialMessageException($exception->getMessage(), $exception->getCode(), $exception);
65        }
66
67        return $message;
68    }
69
70    /**
71     * {@inheritdoc}
72     */
73    protected function constructMessage(Message $message, ?int $id = null)
74    {
75        if ($this->pduClass === null) {
76            throw new \RuntimeException('You must either define a PDU class or override getPdu().');
77        }
78        $callable = [$this->pduClass, 'fromAsn1'];
79        if (!\is_callable($callable)) {
80            throw new \RuntimeException(sprintf('The class %s is not callable.', $this->pduClass));
81        }
82
83        return \call_user_func($callable, $message->getMessage());
84    }
85}
86