Passed
Pull Request — master (#2331)
by Janko
11:37 queued 06:03
created

SpacecraftLoader::getWrapperByIdAndUser()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 15
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 8
nc 1
nop 4
dl 0
loc 15
ccs 8
cts 8
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Stu\Module\Spacecraft\Lib;
6
7
use RuntimeException;
8
use Stu\Component\Game\SemaphoreConstants;
0 ignored issues
show
Bug introduced by
The type Stu\Component\Game\SemaphoreConstants was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
9
use Stu\Component\Spacecraft\System\SpacecraftSystemTypeEnum;
10
use Stu\Exception\AccessViolationException;
11
use Stu\Exception\EntityLockedException;
12
use Stu\Exception\SpacecraftDoesNotExistException;
13
use Stu\Exception\UnallowedUplinkOperationException;
14
use Stu\Module\Control\SemaphoreUtilInterface;
15
use Stu\Module\Logging\LogTypeEnum;
16
use Stu\Module\Logging\StuLogger;
17
use Stu\Module\Spacecraft\Lib\SpacecraftWrapperFactoryInterface;
18
use Stu\Module\Spacecraft\Lib\SourceAndTargetWrappers;
19
use Stu\Module\Spacecraft\Lib\SourceAndTargetWrappersInterface;
20
use Stu\Module\Tick\Lock\LockManagerInterface;
21
use Stu\Module\Tick\Lock\LockTypeEnum;
22
use Stu\Orm\Entity\Spacecraft;
23
use Stu\Orm\Repository\CrewAssignmentRepositoryInterface;
24
use Stu\Orm\Repository\SpacecraftRepositoryInterface;
25
26
/**
27
 * @implements SpacecraftLoaderInterface<SpacecraftWrapperInterface>
28
 */
29
final class SpacecraftLoader implements SpacecraftLoaderInterface
30
{
31 11
    public function __construct(
32
        private readonly SpacecraftRepositoryInterface $spacecraftRepository,
33
        private readonly CrewAssignmentRepositoryInterface $crewAssignmentRepository,
34
        private readonly SemaphoreUtilInterface $semaphoreUtil,
35
        private readonly SpacecraftWrapperFactoryInterface $spacecraftWrapperFactory,
36
        private readonly LockManagerInterface $lockManager
37 11
    ) {}
38
39 51
    #[\Override]
40
    public function getByIdAndUser(
41
        int $spacecraftId,
42
        int $userId,
43
        bool $allowUplink = false,
44
        bool $checkForEntityLock = true
45
    ): Spacecraft {
46
47 51
        return $this->getByIdAndUserAndTargetIntern(
48 51
            $spacecraftId,
49 51
            $userId,
50 51
            null,
51 51
            $allowUplink,
52 51
            $checkForEntityLock
53 51
        )->getSource()->get();
54
    }
55
56 89
    #[\Override]
57
    public function getWrapperByIdAndUser(
58
        int $spacecraftId,
59
        int $userId,
60
        bool $allowUplink = false,
61
        bool $checkForEntityLock = true
62
    ): SpacecraftWrapperInterface {
63
64 89
        return $this->getByIdAndUserAndTargetIntern(
65 89
            $spacecraftId,
66 89
            $userId,
67 89
            null,
68 89
            $allowUplink,
69 89
            $checkForEntityLock
70 89
        )->getSource();
71
    }
72
73 21
    #[\Override]
74
    public function getWrappersBySourceAndUserAndTarget(
75
        int $spacecraftId,
76
        int $userId,
77
        int $targetId,
78
        bool $allowUplink = false,
79
        bool $checkForEntityLock = true
80
    ): SourceAndTargetWrappersInterface {
81
82 21
        return $this->getByIdAndUserAndTargetIntern(
83 21
            $spacecraftId,
84 21
            $userId,
85 21
            $targetId,
86 21
            $allowUplink,
87 21
            $checkForEntityLock
88 21
        );
89
    }
90
91
    /**
92
     * @return SourceAndTargetWrappersInterface<SpacecraftWrapperInterface>
93
     */
94 158
    private function getByIdAndUserAndTargetIntern(
95
        int $spacecraftId,
96
        int $userId,
97
        ?int $targetId,
98
        bool $allowUplink,
99
        bool $checkForEntityLock
100
    ): SourceAndTargetWrappersInterface {
101
102 158
        if ($checkForEntityLock) {
103 118
            $this->checkForEntityLock($spacecraftId);
104
        }
105
106 157
        $spacecraft = $this->spacecraftRepository->find($spacecraftId);
107 157
        if ($spacecraft === null) {
108 1
            throw new SpacecraftDoesNotExistException('Raumfahrzeug existiert nicht!');
109
        }
110 156
        $this->checkviolations($spacecraft, $userId, $allowUplink);
111
112 152
        return $this->acquireSemaphores($spacecraft, $targetId);
113
    }
114
115 120
    private function checkForEntityLock(int $spacecraftId): void
116
    {
117 120
        if ($this->lockManager->isLocked($spacecraftId, LockTypeEnum::SHIP_GROUP)) {
118 1
            throw new EntityLockedException('Tick läuft gerade, Zugriff auf Schiff ist daher blockiert');
119
        }
120
    }
121
122 156
    private function checkviolations(Spacecraft $spacecraft, int $userId, bool $allowUplink): void
123
    {
124 156
        if ($spacecraft->getUser()->getId() !== $userId) {
125 4
            if ($this->crewAssignmentRepository->hasCrewmanOfUser($spacecraft, $userId)) {
126 3
                if (!$allowUplink) {
127 1
                    throw new UnallowedUplinkOperationException(_('This Operation is not allowed via uplink!'));
128
                }
129 2
                if (!$spacecraft->getSystemState(SpacecraftSystemTypeEnum::UPLINK)) {
130 1
                    throw new UnallowedUplinkOperationException(_('Uplink is not activated!'));
131
                }
132 1
                if ($spacecraft->getUser()->isVacationRequestOldEnough()) {
133 1
                    throw new UnallowedUplinkOperationException(_('Owner is on vacation!'));
134
                }
135
            } else {
136 1
                throw new AccessViolationException(sprintf("Spacecraft owned by another user (%d)! Fool: %d", $spacecraft->getUser()->getId(), $userId));
137
            }
138
        }
139
    }
140
141 15
    #[\Override]
142
    public function find(int $spacecraftId, bool $checkForEntityLock = true): ?SpacecraftWrapperInterface
143
    {
144 15
        if ($checkForEntityLock) {
145 5
            $this->checkForEntityLock($spacecraftId);
146
        }
147
148 15
        $spacecraft = $this->spacecraftRepository->find($spacecraftId);
149 15
        if ($spacecraft === null) {
150 1
            return null;
151
        }
152
153 14
        return $this->acquireSemaphores($spacecraft, null)->getSource();
154
    }
155
156
    /**
157
     * @return SourceAndTargetWrappersInterface<SpacecraftWrapperInterface>
158
     */
159 155
    private function acquireSemaphores(Spacecraft $spacecraft, ?int $targetId): SourceAndTargetWrappersInterface
160
    {
161 155
        if ($targetId === null && $this->semaphoreUtil->isSemaphoreAlreadyAcquired($spacecraft->getUser()->getId())) {
162
            return new SourceAndTargetWrappers($this->spacecraftWrapperFactory->wrapSpacecraft($spacecraft));
163
        }
164
165
        //main spacecraft sema on
166 155
        StuLogger::log(sprintf(
167 155
            'Acquiring main semaphore for user %d and spacecraft %d%s',
168 155
            $spacecraft->getUser()->getId(),
169 155
            $spacecraft->getId(),
170 155
            $targetId !== null ? ', target ' . $targetId : ''
171 155
        ), LogTypeEnum::SEMAPHORE);
172
173 155
        $startTime = microtime(true);
174 155
        $mainSema = $this->semaphoreUtil->acquireSemaphore(SemaphoreConstants::MAIN_SHIP_SEMAPHORE_KEY);
175
176 155
        StuLogger::log(sprintf(
177 155
            'Main semaphore acquired for user %d, waited %F seconds',
178 155
            $spacecraft->getUser()->getId(),
179 155
            microtime(true) - $startTime
180 155
        ), LogTypeEnum::SEMAPHORE);
181
182 155
        StuLogger::log(sprintf(
183 155
            'Acquiring spacecraft semaphore for user %d and spacecraft %d',
184 155
            $spacecraft->getUser()->getId(),
185 155
            $spacecraft->getId()
186 155
        ), LogTypeEnum::SEMAPHORE);
187
188 155
        $startTime = microtime(true);
189 155
        $wrapper = $this->acquireSemaphoreForSpacecraft($spacecraft);
190 155
        if ($wrapper === null) {
191
            throw new RuntimeException('wrapper should not be null here');
192
        }
193
194 155
        StuLogger::log(sprintf(
195 155
            'Spacecraft semaphore acquired for user %d and spacecraft %d, waited %F seconds',
196 155
            $spacecraft->getUser()->getId(),
197 155
            $spacecraft->getId(),
198 155
            microtime(true) - $startTime
199 155
        ), LogTypeEnum::SEMAPHORE);
200
201 155
        $result = new SourceAndTargetWrappers($wrapper);
202
203 155
        if ($targetId !== null) {
204
205 21
            StuLogger::log(sprintf(
206 21
                'Acquiring target spacecraft semaphore for user %d and target %d',
207 21
                $spacecraft->getUser()->getId(),
208 21
                $targetId
209 21
            ), LogTypeEnum::SEMAPHORE);
210
211 21
            $startTime = microtime(true);
212 21
            $result->setTarget($this->acquireSemaphoreForSpacecraft($targetId));
213
214 21
            StuLogger::log(sprintf(
215 21
                'Target spacecraft semaphore acquired for user %d and target %d, waited %F seconds',
216 21
                $spacecraft->getUser()->getId(),
217 21
                $targetId,
218 21
                microtime(true) - $startTime
219 21
            ), LogTypeEnum::SEMAPHORE);
220
        }
221
222
        //main spacecraft sema off
223 155
        $this->semaphoreUtil->releaseSemaphore($mainSema);
224 155
        StuLogger::log(sprintf(
225 155
            'Main semaphore released for user %d',
226 155
            $spacecraft->getUser()->getId()
227 155
        ), LogTypeEnum::SEMAPHORE);
228
229 155
        return $result;
230
    }
231
232 155
    private function acquireSemaphoreForSpacecraft(Spacecraft|int $spacecraft): ?SpacecraftWrapperInterface
233
    {
234 155
        $spacecraft = $spacecraft instanceof Spacecraft
235 155
            ? $spacecraft
236 21
            : $this->spacecraftRepository->find($spacecraft);
237
238 155
        if ($spacecraft === null) {
239 2
            return null;
240
        }
241
242 155
        $key = $spacecraft->getUser()->getId();
243 155
        StuLogger::log(sprintf(
244 155
            'spacecraft %d with key %d',
245 155
            $spacecraft->getId(),
246 155
            $key
247 155
        ), LogTypeEnum::SEMAPHORE);
248 155
        $this->semaphoreUtil->acquireSemaphore($key);
249
250 155
        return $this->spacecraftWrapperFactory->wrapSpacecraft($spacecraft);
251
    }
252
}
253