• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

CPS-IT / monitoring / 12368095125

17 Dec 2024 07:09AM UTC coverage: 97.619%. First build
12368095125

push

github

eliashaeussler
Initial commit

164 of 168 new or added lines in 8 files covered. (97.62%)

164 of 168 relevant lines covered (97.62%)

2.35 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

97.73
/src/Middleware/MonitoringMiddleware.php
1
<?php
2

3
declare(strict_types=1);
4

5
/*
6
 * This file is part of the Composer package "cpsit/monitoring".
7
 *
8
 * Copyright (C) 2021 Elias Häußler <e.haeussler@familie-redlich.de>
9
 *
10
 * This program is free software: you can redistribute it and/or modify
11
 * it under the terms of the GNU General Public License as published by
12
 * the Free Software Foundation, either version 3 of the License, or
13
 * (at your option) any later version.
14
 *
15
 * This program is distributed in the hope that it will be useful,
16
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
 * GNU General Public License for more details.
19
 *
20
 * You should have received a copy of the GNU General Public License
21
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
22
 */
23

24
namespace CPSIT\Monitoring\Middleware;
25

26
use CPSIT\Monitoring\Authorization\Authorizer;
27
use CPSIT\Monitoring\Monitoring;
28
use CPSIT\Monitoring\Provider\MonitoringProvider;
29
use CPSIT\Monitoring\Result\MonitoringResult;
30
use CPSIT\Monitoring\Validation\Validator;
31
use GuzzleHttp\Psr7\Response;
32
use JsonException;
33
use Psr\Http\Message\ResponseInterface;
34
use Psr\Http\Message\ServerRequestInterface;
35
use Psr\Http\Server\MiddlewareInterface;
36
use Psr\Http\Server\RequestHandlerInterface;
37

38
/**
39
 * MonitoringMiddleware.
40
 *
41
 * @author Elias Häußler <e.haeussler@familie-redlich.de>
42
 * @license GPL-3.0-or-later
43
 */
44
final class MonitoringMiddleware implements MiddlewareInterface
45
{
46
    /**
47
     * @var Authorizer[]
48
     */
49
    private readonly array $authorizers;
50

51
    /**
52
     * @param MonitoringProvider[]    $monitoringProviders
53
     * @param Authorizer|Authorizer[] $authorizers
54
     */
55
    public function __construct(
6✔
56
        private readonly Validator $validator,
57
        private readonly Monitoring $monitoring,
58
        private readonly array $monitoringProviders,
59
        Authorizer|array $authorizers = [],
60
    ) {
61
        if (!is_array($authorizers)) {
6✔
62
            $authorizers = [$authorizers];
6✔
63
        }
64

65
        $this->authorizers = $this->sortAuthorizers($authorizers);
6✔
66
    }
67

68
    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
5✔
69
    {
70
        // Continue request process if middleware cannot handle current request
71
        if (!$this->validator->isValidRequest($request)) {
5✔
72
            return $handler->handle($request);
1✔
73
        }
74

75
        // Check if current request is authorized using available authorizers
76
        if (!$this->isAuthorizedRequest($request)) {
4✔
77
            return $this->buildUnauthorizedResponse();
1✔
78
        }
79

80
        // Perform monitoring health check and send monitoring result as response
81
        $monitoringResult = $this->monitoring->checkHealth($this->monitoringProviders);
3✔
82

83
        return $this->buildResponseFromResult($monitoringResult);
3✔
84
    }
85

86
    /**
87
     * Check whether current request is correctly authorized.
88
     *
89
     * @param ServerRequestInterface $request Current request
90
     *
91
     * @return bool `true` if current request is correctly authorized, `false` otherwise
92
     */
93
    private function isAuthorizedRequest(ServerRequestInterface $request): bool
4✔
94
    {
95
        foreach ($this->authorizers as $authorizer) {
4✔
96
            if ($authorizer->isAuthorized($request)) {
4✔
97
                return true;
3✔
98
            }
99
        }
100

101
        return false;
1✔
102
    }
103

104
    /**
105
     * Sort given authorizers by their priority (from higher to lower priority).
106
     *
107
     * @param Authorizer[] $authorizers Unsorted list of authorizers
108
     *
109
     * @return Authorizer[] List of authorizers, sorted from higher to lower priority
110
     */
111
    private function sortAuthorizers(array $authorizers): array
6✔
112
    {
113
        usort(
6✔
114
            $authorizers,
6✔
115
            static fn (Authorizer $a, Authorizer $b) => ($a->getPriority() <=> $b->getPriority()) * -1,
6✔
116
        );
6✔
117

118
        return $authorizers;
6✔
119
    }
120

121
    /**
122
     * Return JSON response for monitoring result.
123
     *
124
     * @param MonitoringResult $result Monitoring result
125
     *
126
     * @return ResponseInterface JSON response for the given monitoring result
127
     */
128
    private function buildResponseFromResult(MonitoringResult $result): ResponseInterface
3✔
129
    {
130
        try {
131
            $data = json_encode($result, JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_NUMERIC_CHECK);
3✔
132
        } catch (JsonException $exception) {
1✔
133
            // Handle errors during json_encode
134
            return $this->buildServerErrorResponse($exception->getMessage());
1✔
135
        }
136

137
        // Handle unhealthy monitoring result
138
        if (!$result->isHealthy()) {
2✔
139
            return $this->buildJsonResponse($data, 424);
1✔
140
        }
141

142
        return $this->buildJsonResponse($data);
1✔
143
    }
144

145
    private function buildUnauthorizedResponse(): ResponseInterface
1✔
146
    {
147
        $json = json_encode(['error' => 'Unauthorized']);
1✔
148

149
        // Handle errors during json_encode
150
        if (!is_string($json)) {
1✔
NEW
151
            return $this->buildServerErrorResponse(json_last_error_msg());
×
152
        }
153

154
        return $this->buildJsonResponse($json, 401);
1✔
155
    }
156

157
    private function buildServerErrorResponse(string $message): ResponseInterface
1✔
158
    {
159
        return $this->buildJsonResponse(sprintf('{"error":"%s"}', $message), 500);
1✔
160
    }
161

162
    private function buildJsonResponse(string $json, int $status = 200): ResponseInterface
4✔
163
    {
164
        $response = new Response($status, [
4✔
165
            'Content-Type' => 'application/json; charset=utf-8',
4✔
166
            'Cache-Control' => 'private, no-store',
4✔
167
        ]);
4✔
168

169
        $response->getBody()->write($json);
4✔
170
        $response->getBody()->rewind();
4✔
171

172
        return $response;
4✔
173
    }
174
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc