Proyectos de Subversion Moodle

Rev

Rev 1 | | Comparar con el anterior | Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
<?php
2
 
3
namespace Aws\Api\Parser;
4
 
5
use \Iterator;
6
use Aws\Exception\EventStreamDataException;
7
use Aws\Api\Parser\Exception\ParserException;
8
use Aws\Api\StructureShape;
9
use Psr\Http\Message\StreamInterface;
10
 
11
/**
12
 * @internal Implements a decoder for a binary encoded event stream that will
13
 * decode, validate, and provide individual events from the stream.
14
 */
15
class EventParsingIterator implements Iterator
16
{
17
    /** @var StreamInterface */
18
    private $decodingIterator;
19
 
20
    /** @var StructureShape */
21
    private $shape;
22
 
23
    /** @var AbstractParser */
24
    private $parser;
25
 
26
    public function __construct(
27
        StreamInterface $stream,
28
        StructureShape $shape,
29
        AbstractParser $parser
30
    ) {
1441 ariadna 31
        $this->decodingIterator = $this->chooseDecodingIterator($stream);
1 efrain 32
        $this->shape = $shape;
33
        $this->parser = $parser;
34
    }
35
 
1441 ariadna 36
    /**
37
     * This method choose a decoding iterator implementation based on if the stream
38
     * is seekable or not.
39
     *
40
     * @param $stream
41
     *
42
     * @return Iterator
43
     */
44
    private function chooseDecodingIterator($stream)
45
    {
46
        if ($stream->isSeekable()) {
47
            return new DecodingEventStreamIterator($stream);
48
        } else {
49
            return new NonSeekableStreamDecodingEventStreamIterator($stream);
50
        }
51
    }
52
 
53
    /**
54
     * @return mixed
55
     */
1 efrain 56
    #[\ReturnTypeWillChange]
57
    public function current()
58
    {
59
        return $this->parseEvent($this->decodingIterator->current());
60
    }
61
 
1441 ariadna 62
    /**
63
     * @return mixed
64
     */
1 efrain 65
    #[\ReturnTypeWillChange]
66
    public function key()
67
    {
68
        return $this->decodingIterator->key();
69
    }
70
 
1441 ariadna 71
    /**
72
     * @return void
73
     */
1 efrain 74
    #[\ReturnTypeWillChange]
75
    public function next()
76
    {
77
        $this->decodingIterator->next();
78
    }
79
 
1441 ariadna 80
    /**
81
     * @return void
82
     */
1 efrain 83
    #[\ReturnTypeWillChange]
84
    public function rewind()
85
    {
86
        $this->decodingIterator->rewind();
87
    }
88
 
1441 ariadna 89
    /**
90
     * @return bool
91
     */
1 efrain 92
    #[\ReturnTypeWillChange]
93
    public function valid()
94
    {
95
        return $this->decodingIterator->valid();
96
    }
97
 
98
    private function parseEvent(array $event)
99
    {
100
        if (!empty($event['headers'][':message-type'])) {
101
            if ($event['headers'][':message-type'] === 'error') {
102
                return $this->parseError($event);
103
            }
1441 ariadna 104
 
1 efrain 105
            if ($event['headers'][':message-type'] !== 'event') {
106
                throw new ParserException('Failed to parse unknown message type.');
107
            }
108
        }
109
 
1441 ariadna 110
        $eventType = $event['headers'][':event-type'] ?? null;
111
        if (empty($eventType)) {
1 efrain 112
            throw new ParserException('Failed to parse without event type.');
113
        }
114
 
1441 ariadna 115
        $eventPayload = $event['payload'];
116
        if ($eventType === 'initial-response') {
117
            return $this->parseInitialResponseEvent($eventPayload);
118
        }
119
 
120
        $eventShape = $this->shape->getMember($eventType);
121
 
122
        return [
123
            $eventType => array_merge(
124
                $this->parseEventHeaders($event['headers'], $eventShape),
125
                $this->parseEventPayload($eventPayload, $eventShape)
126
            )
127
        ];
128
    }
129
 
130
    /**
131
     * @param $headers
132
     * @param $eventShape
133
     *
134
     * @return array
135
     */
136
    private function parseEventHeaders($headers, $eventShape): array
137
    {
138
        $parsedHeaders = [];
139
        foreach ($eventShape->getMembers() as $memberName => $memberProps) {
140
            if (isset($memberProps['eventheader'])) {
141
                $parsedHeaders[$memberName] = $headers[$memberName];
142
            }
143
        }
144
 
145
        return $parsedHeaders;
146
    }
147
 
148
    /**
149
     * @param $payload
150
     * @param $eventShape
151
     *
152
     * @return array
153
     */
154
    private function parseEventPayload($payload, $eventShape): array
155
    {
156
        $parsedPayload = [];
157
        foreach ($eventShape->getMembers() as $memberName => $memberProps) {
158
            $memberShape = $eventShape->getMember($memberName);
159
            if (isset($memberProps['eventpayload'])) {
160
                if ($memberShape->getType() === 'blob') {
161
                    $parsedPayload[$memberName] = $payload;
1 efrain 162
                } else {
1441 ariadna 163
                    $parsedPayload[$memberName] = $this->parser->parseMemberFromStream(
164
                        $payload,
165
                        $memberShape,
1 efrain 166
                        null
167
                    );
168
                }
1441 ariadna 169
 
170
                break;
1 efrain 171
            }
172
        }
173
 
1441 ariadna 174
        if (empty($parsedPayload) && !empty($payload->getContents())) {
175
            /**
176
             * If we did not find a member with an eventpayload trait, then we should deserialize the payload
177
             * using the event's shape.
178
             */
179
            $parsedPayload = $this->parser->parseMemberFromStream($payload, $eventShape, null);
180
        }
181
 
182
        return $parsedPayload;
1 efrain 183
    }
184
 
185
    private function parseError(array $event)
186
    {
187
        throw new EventStreamDataException(
188
            $event['headers'][':error-code'],
189
            $event['headers'][':error-message']
190
        );
191
    }
1441 ariadna 192
 
193
    private function parseInitialResponseEvent($payload): array
194
    {
195
        return ['initial-response' => json_decode($payload, true)];
196
    }
197
}