Line data Source code
1 : /*
2 : * If not stated otherwise in this file or this component's LICENSE file the
3 : * following copyright and licenses apply:
4 : *
5 : * Copyright 2022 Sky UK
6 : *
7 : * Licensed under the Apache License, Version 2.0 (the "License");
8 : * you may not use this file except in compliance with the License.
9 : * You may obtain a copy of the License at
10 : *
11 : * http://www.apache.org/licenses/LICENSE-2.0
12 : *
13 : * Unless required by applicable law or agreed to in writing, software
14 : * distributed under the License is distributed on an "AS IS" BASIS,
15 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 : * See the License for the specific language governing permissions and
17 : * limitations under the License.
18 : */
19 :
20 : #include "SessionServerAppManager.h"
21 : #include "RialtoServerManagerLogging.h"
22 : #include "Utils.h"
23 : #include <algorithm>
24 : #include <future>
25 : #include <utility>
26 :
27 : namespace rialto::servermanager::common
28 : {
29 44 : SessionServerAppManager::SessionServerAppManager(
30 : std::unique_ptr<ipc::IController> &ipcController, const std::shared_ptr<service::IStateObserver> &stateObserver,
31 : std::unique_ptr<ISessionServerAppFactory> &&sessionServerAppFactory,
32 : std::unique_ptr<IHealthcheckServiceFactory> &&healthcheckServiceFactory,
33 : const std::shared_ptr<firebolt::rialto::common::IEventThreadFactory> &eventThreadFactory,
34 : const firebolt::rialto::ipc::INamedSocketFactory &namedSocketFactory,
35 44 : std::shared_ptr<firebolt::rialto::wrappers::IYamlCppWrapper> yamlCppWrapper)
36 44 : : m_ipcController{ipcController},
37 88 : m_eventThread{eventThreadFactory->createEventThread("rialtoservermanager-appmanager")},
38 44 : m_sessionServerAppFactory{std::move(sessionServerAppFactory)}, m_stateObserver{stateObserver},
39 44 : m_healthcheckService{healthcheckServiceFactory->createHealthcheckService(*this)},
40 132 : m_namedSocketFactory{namedSocketFactory}, m_isShuttingDown{false}
41 : {
42 : // Cache audio/video capabilities once - avoids re-reading the YAML file on every server configuration
43 44 : if (yamlCppWrapper)
44 : {
45 0 : firebolt::rialto::common::AudioDecoderCapabilities audioCaps;
46 0 : if (yamlCppWrapper->getAudioDecoderCapabilities(audioCaps) ==
47 : firebolt::rialto::common::DecoderCapabilitiesStatus::OK)
48 : {
49 0 : m_cachedAudioCapabilities = audioCaps;
50 : }
51 0 : firebolt::rialto::common::VideoDecoderCapabilities videoCaps;
52 0 : if (yamlCppWrapper->getVideoDecoderCapabilities(videoCaps) ==
53 : firebolt::rialto::common::DecoderCapabilitiesStatus::OK)
54 : {
55 0 : m_cachedVideoCapabilities = videoCaps;
56 : }
57 : }
58 44 : }
59 :
60 88 : SessionServerAppManager::~SessionServerAppManager()
61 : {
62 44 : m_eventThread->add(&SessionServerAppManager::shutdownAllSessionServers, this);
63 44 : m_eventThread->flush();
64 44 : m_eventThread.reset();
65 88 : }
66 :
67 46 : void SessionServerAppManager::setShuttingDown()
68 : {
69 46 : m_isShuttingDown = true;
70 : }
71 :
72 8 : void SessionServerAppManager::preloadSessionServers(unsigned numOfPreloadedServers)
73 : {
74 8 : m_eventThread->add(
75 8 : [this, numOfPreloadedServers]()
76 : {
77 16 : for (unsigned i = 0; i < numOfPreloadedServers; ++i)
78 : {
79 8 : connectSessionServer(preloadSessionServer());
80 : }
81 8 : });
82 : }
83 :
84 38 : bool SessionServerAppManager::initiateApplication(const std::string &appName,
85 : const firebolt::rialto::common::SessionServerState &state,
86 : const firebolt::rialto::common::AppConfig &appConfig)
87 : {
88 38 : std::promise<bool> p;
89 38 : std::future<bool> f{p.get_future()};
90 76 : m_eventThread->add([&]() { return p.set_value(handleInitiateApplication(appName, state, appConfig)); });
91 76 : return f.get();
92 38 : }
93 :
94 38 : bool SessionServerAppManager::handleInitiateApplication(const std::string &appName,
95 : const firebolt::rialto::common::SessionServerState &state,
96 : const firebolt::rialto::common::AppConfig &appConfig)
97 : {
98 38 : RIALTO_SERVER_MANAGER_LOG_INFO("RialtoServerManager requests to launch %s with initial state: %s", appName.c_str(),
99 : toString(state));
100 113 : if (state != firebolt::rialto::common::SessionServerState::NOT_RUNNING &&
101 38 : state != firebolt::rialto::common::SessionServerState::SUSPENDED && !getServerByAppName(appName))
102 : {
103 36 : auto preloadedServer{getPreloadedServer()};
104 36 : if (preloadedServer)
105 : {
106 5 : return configurePreloadedSessionServer(preloadedServer, appName, state, appConfig,
107 10 : m_namedSocketFactory.createNamedSocket());
108 : }
109 31 : return connectSessionServer(launchSessionServer(appName, state, appConfig));
110 36 : }
111 2 : else if (state == firebolt::rialto::common::SessionServerState::NOT_RUNNING ||
112 1 : state == firebolt::rialto::common::SessionServerState::SUSPENDED)
113 : {
114 1 : RIALTO_SERVER_MANAGER_LOG_ERROR("Initialization of %s failed - wrong state", appName.c_str());
115 : }
116 : else
117 : {
118 1 : RIALTO_SERVER_MANAGER_LOG_ERROR("Initialization of %s failed. App is already launched", appName.c_str());
119 : }
120 2 : return false;
121 : }
122 :
123 14 : bool SessionServerAppManager::setSessionServerState(const std::string &appName,
124 : const firebolt::rialto::common::SessionServerState &newState)
125 : {
126 14 : std::promise<bool> p;
127 14 : std::future<bool> f{p.get_future()};
128 28 : m_eventThread->add([&]() { return p.set_value(changeSessionServerState(appName, newState)); });
129 28 : return f.get();
130 14 : }
131 :
132 30 : void SessionServerAppManager::onSessionServerStateChanged(int serverId,
133 : const firebolt::rialto::common::SessionServerState &newState)
134 : {
135 30 : RIALTO_SERVER_MANAGER_LOG_DEBUG("Queue state change of serverId: %d to %s", serverId, toString(newState));
136 : // Event loop needed here, as function caller may be deleted as a result of this call
137 30 : m_eventThread->add(&SessionServerAppManager::handleSessionServerStateChange, this, serverId, newState);
138 : }
139 :
140 3 : void SessionServerAppManager::sendPingEvents(int pingId)
141 : {
142 3 : RIALTO_SERVER_MANAGER_LOG_DEBUG("Queue ping procedure with id: %d", pingId);
143 3 : m_eventThread->add(
144 3 : [this, pingId]()
145 : {
146 3 : if (m_healthcheckService)
147 : {
148 6 : for (const auto &sessionServer : m_sessionServerApps)
149 : {
150 3 : const auto kSessionServerState{sessionServer->getExpectedState()};
151 3 : if (firebolt::rialto::common::SessionServerState::SUSPENDED == kSessionServerState ||
152 2 : firebolt::rialto::common::SessionServerState::NOT_RUNNING == kSessionServerState)
153 : {
154 1 : RIALTO_SERVER_MANAGER_LOG_DEBUG("Ping with id: %d skipped for server: %d as it is in state: %s",
155 : pingId, sessionServer->getServerId(),
156 : toString(kSessionServerState));
157 2 : continue;
158 : }
159 2 : auto serverId{sessionServer->getServerId()};
160 2 : if (!m_ipcController->performPing(serverId, pingId))
161 : {
162 1 : RIALTO_SERVER_MANAGER_LOG_ERROR("Ping with id: %d failed for server: %d", pingId, serverId);
163 1 : m_healthcheckService->onPingFailed(serverId, pingId);
164 1 : continue;
165 : }
166 1 : m_healthcheckService->onPingSent(serverId, pingId);
167 : }
168 : }
169 3 : });
170 : }
171 :
172 2 : void SessionServerAppManager::onAck(int serverId, int pingId, bool success)
173 : {
174 2 : RIALTO_SERVER_MANAGER_LOG_DEBUG("Queue ack handling for serverId: %d ping id: %d", serverId, pingId);
175 2 : m_eventThread->add(&SessionServerAppManager::handleAck, this, serverId, pingId, success);
176 : }
177 :
178 7 : std::string SessionServerAppManager::getAppConnectionInfo(const std::string &appName) const
179 : {
180 7 : std::promise<std::string> p;
181 7 : std::future<std::string> f{p.get_future()};
182 7 : m_eventThread->add(
183 7 : [&]()
184 : {
185 7 : auto sessionServer{getServerByAppName(appName)};
186 7 : if (sessionServer)
187 : {
188 1 : return p.set_value(sessionServer->getSessionManagementSocketName());
189 : }
190 6 : RIALTO_SERVER_MANAGER_LOG_ERROR("App: %s could not be found", appName.c_str());
191 18 : return p.set_value("");
192 7 : });
193 14 : return f.get();
194 7 : }
195 :
196 2 : bool SessionServerAppManager::setLogLevels(const service::LoggingLevels &logLevels) const
197 : {
198 2 : std::promise<bool> p;
199 2 : std::future<bool> f{p.get_future()};
200 2 : m_eventThread->add(
201 2 : [&]()
202 : {
203 2 : setLocalLogLevels(logLevels);
204 2 : if (!m_ipcController->setLogLevels(logLevels))
205 : {
206 1 : RIALTO_SERVER_MANAGER_LOG_WARN("Change log levels failed.");
207 1 : return p.set_value(false);
208 : }
209 1 : RIALTO_SERVER_MANAGER_LOG_INFO("Change log levels succeeded.");
210 1 : return p.set_value(true);
211 : });
212 4 : return f.get();
213 2 : }
214 :
215 4 : void SessionServerAppManager::restartServer(int serverId)
216 : {
217 4 : RIALTO_SERVER_MANAGER_LOG_DEBUG("Queue restart server handling for serverId: %d", serverId);
218 4 : m_eventThread->add(&SessionServerAppManager::handleRestartServer, this, serverId);
219 : }
220 :
221 4 : void SessionServerAppManager::handleRestartServer(int serverId)
222 : {
223 4 : if (m_isShuttingDown)
224 : {
225 1 : RIALTO_SERVER_MANAGER_LOG_DEBUG("Not restarting serverId: %d as server manager is shutting down", serverId);
226 3 : return;
227 : }
228 3 : auto sessionServer{getServerById(serverId)};
229 3 : if (!sessionServer)
230 : {
231 0 : RIALTO_SERVER_MANAGER_LOG_WARN("Unable to restart server, serverId: %d", serverId);
232 0 : return;
233 : }
234 3 : if (m_healthcheckService)
235 : {
236 3 : m_healthcheckService->onServerRemoved(sessionServer->getServerId());
237 : }
238 : // First, get all needed information from current app
239 3 : const std::string kAppName{sessionServer->getAppName()};
240 3 : const firebolt::rialto::common::SessionServerState kState{sessionServer->getExpectedState()};
241 3 : const firebolt::rialto::common::AppConfig kAppConfig{sessionServer->getSessionManagementSocketName(),
242 3 : sessionServer->getClientDisplayName()};
243 3 : std::unique_ptr<firebolt::rialto::ipc::INamedSocket> namedSocket{std::move(sessionServer->releaseNamedSocket())};
244 3 : if (firebolt::rialto::common::SessionServerState::INACTIVE != kState &&
245 2 : firebolt::rialto::common::SessionServerState::ACTIVE != kState)
246 : {
247 2 : RIALTO_SERVER_MANAGER_LOG_DEBUG("Restart server to %s not needed for serverId: %d", toString(kState), serverId);
248 2 : return;
249 : }
250 1 : RIALTO_SERVER_MANAGER_LOG_DEBUG("Restarting server with id: %d", serverId);
251 : // Then kill the app
252 1 : sessionServer->kill();
253 1 : handleSessionServerStateChange(serverId, firebolt::rialto::common::SessionServerState::NOT_RUNNING);
254 1 : sessionServer.reset();
255 :
256 : // Finally, spawn the new app with old settings and set named socket if present
257 1 : auto app = m_sessionServerAppFactory->create(kAppName, kState, kAppConfig, *this, std::move(namedSocket));
258 1 : if (app->launch())
259 : {
260 1 : auto result = m_sessionServerApps.emplace(std::move(app));
261 1 : if (result.second)
262 : {
263 1 : connectSessionServer(*result.first);
264 : }
265 : }
266 : else
267 : {
268 0 : RIALTO_SERVER_MANAGER_LOG_ERROR("Failed to restart server");
269 : }
270 9 : }
271 :
272 3 : bool SessionServerAppManager::resurrectSuspendedServer(const std::shared_ptr<ISessionServerApp> &kSessionServer,
273 : const firebolt::rialto::common::SessionServerState &state)
274 : {
275 3 : const std::string kAppName{kSessionServer->getAppName()};
276 3 : const firebolt::rialto::common::AppConfig kAppConfig{kSessionServer->getSessionManagementSocketName(),
277 3 : kSessionServer->getClientDisplayName()};
278 3 : std::unique_ptr<firebolt::rialto::ipc::INamedSocket> namedSocket{std::move(kSessionServer->releaseNamedSocket())};
279 3 : m_sessionServerApps.erase(kSessionServer);
280 :
281 3 : RIALTO_SERVER_MANAGER_LOG_INFO("Resurrecting server for app: %s", kAppName.c_str());
282 3 : auto app{getPreloadedServer()};
283 3 : if (app)
284 : {
285 1 : configurePreloadedSessionServer(app, kAppName, state, kAppConfig, std::move(namedSocket));
286 1 : m_sessionServerApps.emplace(std::move(app));
287 1 : return true;
288 : }
289 2 : app = m_sessionServerAppFactory->create(kAppName, state, kAppConfig, *this, std::move(namedSocket));
290 2 : if (app->launch())
291 : {
292 1 : auto result = m_sessionServerApps.emplace(std::move(app));
293 1 : if (result.second)
294 : {
295 1 : return connectSessionServer(*result.first);
296 : }
297 : }
298 : else
299 : {
300 1 : RIALTO_SERVER_MANAGER_LOG_ERROR("Failed to resurrect suspended server for %s", kAppName.c_str());
301 : }
302 1 : return false;
303 3 : }
304 :
305 48 : bool SessionServerAppManager::connectSessionServer(const std::shared_ptr<ISessionServerApp> &kSessionServer)
306 : {
307 48 : if (!kSessionServer)
308 : {
309 7 : RIALTO_SERVER_MANAGER_LOG_ERROR("Unable to connect Session Server - pointer is null!");
310 7 : return false;
311 : }
312 41 : if (!m_ipcController->createClient(kSessionServer->getServerId(), kSessionServer->getAppManagementSocketName()))
313 : {
314 2 : RIALTO_SERVER_MANAGER_LOG_ERROR("Failed to establish RialtoServerManager - RialtoSessionServer connection for "
315 : "session server with id: %d",
316 : kSessionServer->getServerId());
317 2 : kSessionServer->kill();
318 2 : if (m_healthcheckService)
319 : {
320 2 : m_healthcheckService->onServerRemoved(kSessionServer->getServerId());
321 : }
322 2 : m_sessionServerApps.erase(kSessionServer);
323 2 : return false;
324 : }
325 39 : RIALTO_SERVER_MANAGER_LOG_INFO("RialtoServerManager with id %d successfully connected",
326 : kSessionServer->getServerId());
327 39 : return true;
328 : }
329 :
330 14 : bool SessionServerAppManager::configureSessionServer(const std::shared_ptr<ISessionServerApp> &kSessionServer)
331 : {
332 14 : if (!kSessionServer)
333 : {
334 0 : RIALTO_SERVER_MANAGER_LOG_ERROR("Unable to configure Session Server - pointer is null!");
335 0 : return false;
336 : }
337 14 : if (kSessionServer->isNamedSocketInitialized())
338 : {
339 3 : return configureSessionServerWithSocketFd(kSessionServer);
340 : }
341 11 : return configureSessionServerWithSocketName(kSessionServer);
342 : }
343 :
344 6 : bool SessionServerAppManager::configurePreloadedSessionServer(
345 : const std::shared_ptr<ISessionServerApp> &kSessionServer, const std::string &appName,
346 : const firebolt::rialto::common::SessionServerState &state, const firebolt::rialto::common::AppConfig &appConfig,
347 : std::unique_ptr<firebolt::rialto::ipc::INamedSocket> &&namedSocket)
348 : {
349 6 : RIALTO_SERVER_MANAGER_LOG_INFO("Configuration of preloaded session server with id: %d for %s app",
350 : kSessionServer->getServerId(), appName.c_str());
351 11 : if (kSessionServer->configure(appName, state, appConfig, std::move(namedSocket)) &&
352 5 : configureSessionServer(kSessionServer))
353 : {
354 : // Schedule adding new preloaded session server (as we've just used one) and return immediately
355 8 : m_eventThread->add([this]() { connectSessionServer(preloadSessionServer()); });
356 4 : return true;
357 : }
358 : // Configuration failed, kill server and return error
359 2 : handleSessionServerStateChange(kSessionServer->getServerId(), firebolt::rialto::common::SessionServerState::ERROR);
360 2 : kSessionServer->kill();
361 2 : handleSessionServerStateChange(kSessionServer->getServerId(),
362 : firebolt::rialto::common::SessionServerState::NOT_RUNNING);
363 : // Schedule adding new preloaded session server
364 4 : m_eventThread->add([this]() { connectSessionServer(preloadSessionServer()); });
365 2 : return false;
366 : }
367 :
368 14 : bool SessionServerAppManager::changeSessionServerState(const std::string &appName,
369 : const firebolt::rialto::common::SessionServerState &newState)
370 : {
371 14 : RIALTO_SERVER_MANAGER_LOG_MIL("RialtoServerManager requests to change state of %s to %s", appName.c_str(),
372 : toString(newState));
373 14 : auto sessionServer{getServerByAppName(appName)};
374 14 : if (!sessionServer)
375 : {
376 2 : RIALTO_SERVER_MANAGER_LOG_ERROR("Change state of %s to %s failed - session server not found.", appName.c_str(),
377 : toString(newState));
378 2 : return false;
379 : }
380 12 : const firebolt::rialto::common::SessionServerState kCurrentState{sessionServer->getExpectedState()};
381 12 : sessionServer->setExpectedState(newState);
382 12 : if (kCurrentState == firebolt::rialto::common::SessionServerState::SUSPENDED &&
383 4 : (firebolt::rialto::common::SessionServerState::ACTIVE == newState ||
384 1 : firebolt::rialto::common::SessionServerState::INACTIVE == newState))
385 : {
386 3 : return resurrectSuspendedServer(sessionServer, newState);
387 : }
388 9 : else if (kCurrentState == firebolt::rialto::common::SessionServerState::SUSPENDED &&
389 1 : firebolt::rialto::common::SessionServerState::NOT_RUNNING == newState)
390 : {
391 : // Send the notification and do the cleanup only
392 1 : handleSessionServerStateChange(sessionServer->getServerId(), newState);
393 1 : return true;
394 : }
395 15 : else if (m_healthcheckService && (firebolt::rialto::common::SessionServerState::NOT_RUNNING == newState ||
396 15 : firebolt::rialto::common::SessionServerState::SUSPENDED == newState))
397 : {
398 6 : m_healthcheckService->onServerRemoved(sessionServer->getServerId());
399 : }
400 8 : if (!m_ipcController->performSetState(sessionServer->getServerId(), newState))
401 : {
402 2 : RIALTO_SERVER_MANAGER_LOG_ERROR("Change state of %s to %s failed.", appName.c_str(), toString(newState));
403 2 : handleStateChangeFailure(sessionServer, newState);
404 2 : return false;
405 : }
406 6 : RIALTO_SERVER_MANAGER_LOG_INFO("Change state of %s to %s succeeded.", appName.c_str(), toString(newState));
407 6 : return true;
408 14 : }
409 :
410 44 : void SessionServerAppManager::handleSessionServerStateChange(int serverId,
411 : firebolt::rialto::common::SessionServerState newState)
412 : {
413 44 : RIALTO_SERVER_MANAGER_LOG_INFO("SessionServer with id: %d changed state to %s", serverId, toString(newState));
414 44 : if (m_isShuttingDown)
415 : {
416 1 : RIALTO_SERVER_MANAGER_LOG_WARN("Not handling state change of serverId: %d as server manager is shutting down",
417 : serverId);
418 1 : return;
419 : }
420 43 : auto sessionServer{getServerById(serverId)};
421 43 : if (!sessionServer)
422 : {
423 0 : RIALTO_SERVER_MANAGER_LOG_WARN("SessionServer with id: %d not found", serverId);
424 0 : return;
425 : }
426 43 : std::string appName{sessionServer->getAppName()};
427 43 : if (!appName.empty() && m_stateObserver) // empty app name is when SessionServer is preloaded
428 : {
429 33 : m_stateObserver->stateChanged(appName, newState);
430 : }
431 43 : if (firebolt::rialto::common::SessionServerState::UNINITIALIZED == newState)
432 : {
433 15 : sessionServer->cancelStartupTimer();
434 15 : if (!sessionServer->isPreloaded() && !configureSessionServer(sessionServer))
435 : {
436 2 : handleSessionServerStateChange(serverId, firebolt::rialto::common::SessionServerState::ERROR);
437 2 : sessionServer->kill();
438 2 : handleSessionServerStateChange(serverId, firebolt::rialto::common::SessionServerState::NOT_RUNNING);
439 : }
440 : }
441 28 : else if (newState == firebolt::rialto::common::SessionServerState::ERROR && sessionServer->isPreloaded())
442 : {
443 1 : m_ipcController->removeClient(serverId);
444 1 : sessionServer->kill();
445 1 : if (m_healthcheckService)
446 : {
447 1 : m_healthcheckService->onServerRemoved(sessionServer->getServerId());
448 : }
449 1 : m_sessionServerApps.erase(sessionServer);
450 1 : if (!m_isShuttingDown)
451 : {
452 1 : connectSessionServer(preloadSessionServer());
453 : }
454 : }
455 27 : else if (newState == firebolt::rialto::common::SessionServerState::NOT_RUNNING)
456 : {
457 9 : m_ipcController->removeClient(serverId);
458 9 : if (m_healthcheckService)
459 : {
460 9 : m_healthcheckService->onServerRemoved(sessionServer->getServerId());
461 : }
462 9 : m_sessionServerApps.erase(sessionServer);
463 : }
464 18 : else if (newState == firebolt::rialto::common::SessionServerState::SUSPENDED)
465 : {
466 5 : m_ipcController->removeClient(sessionServer->getServerId());
467 5 : sessionServer->cleanup();
468 : }
469 43 : }
470 :
471 2 : void SessionServerAppManager::handleAck(int serverId, int pingId, bool success)
472 : {
473 2 : if (success)
474 : {
475 1 : RIALTO_SERVER_MANAGER_LOG_DEBUG("Ping with id: %d succeeded for server: %d", pingId, serverId);
476 : }
477 : else
478 : {
479 1 : RIALTO_SERVER_MANAGER_LOG_ERROR("Ping with id: %d failed for server: %d", pingId, serverId);
480 : }
481 2 : if (m_healthcheckService)
482 : {
483 2 : m_healthcheckService->onAckReceived(serverId, pingId, success);
484 : }
485 : }
486 :
487 44 : void SessionServerAppManager::shutdownAllSessionServers()
488 : {
489 44 : setShuttingDown();
490 44 : m_healthcheckService.reset();
491 70 : for (const auto &kSessionServer : m_sessionServerApps)
492 : {
493 26 : kSessionServer->kill();
494 : }
495 44 : m_sessionServerApps.clear();
496 : }
497 :
498 : std::shared_ptr<ISessionServerApp>
499 31 : SessionServerAppManager::launchSessionServer(const std::string &appName,
500 : const firebolt::rialto::common::SessionServerState &kInitialState,
501 : const firebolt::rialto::common::AppConfig &appConfig)
502 : {
503 31 : RIALTO_SERVER_MANAGER_LOG_INFO("Launching Rialto Session Server for %s", appName.c_str());
504 31 : auto app = m_sessionServerAppFactory->create(appName, kInitialState, appConfig, *this,
505 31 : m_namedSocketFactory.createNamedSocket());
506 31 : if (app->launch())
507 : {
508 30 : if (m_sessionServerApps.emplace(app).second)
509 : {
510 30 : return app;
511 : }
512 : }
513 1 : return nullptr;
514 31 : }
515 :
516 15 : std::shared_ptr<ISessionServerApp> SessionServerAppManager::preloadSessionServer()
517 : {
518 15 : RIALTO_SERVER_MANAGER_LOG_INFO("Preloading new Rialto Session Server");
519 15 : auto app = m_sessionServerAppFactory->create(*this);
520 15 : if (app->launch())
521 : {
522 9 : if (m_sessionServerApps.emplace(app).second)
523 : {
524 9 : return app;
525 : }
526 : }
527 6 : return nullptr;
528 15 : }
529 :
530 39 : std::shared_ptr<ISessionServerApp> SessionServerAppManager::getPreloadedServer() const
531 : {
532 39 : auto iter = std::find_if(m_sessionServerApps.begin(), m_sessionServerApps.end(),
533 6 : [](const auto &srv) { return srv->isPreloaded() && srv->isConnected(); });
534 39 : if (m_sessionServerApps.end() != iter)
535 : {
536 6 : return *iter;
537 : }
538 33 : return nullptr;
539 : }
540 :
541 58 : std::shared_ptr<ISessionServerApp> SessionServerAppManager::getServerByAppName(const std::string &appName) const
542 : {
543 58 : auto iter{std::find_if(m_sessionServerApps.begin(), m_sessionServerApps.end(),
544 19 : [&](const auto &srv) { return srv->getAppName() == appName; })};
545 58 : if (m_sessionServerApps.end() != iter)
546 : {
547 14 : return *iter;
548 : }
549 44 : return nullptr;
550 : }
551 :
552 48 : std::shared_ptr<ISessionServerApp> SessionServerAppManager::getServerById(int serverId) const
553 : {
554 48 : auto iter{std::find_if(m_sessionServerApps.begin(), m_sessionServerApps.end(),
555 47 : [&](const auto &srv) { return srv->getServerId() == serverId; })};
556 48 : if (m_sessionServerApps.end() != iter)
557 : {
558 47 : return *iter;
559 : }
560 1 : return nullptr;
561 : }
562 :
563 2 : void SessionServerAppManager::handleStateChangeFailure(const std::shared_ptr<ISessionServerApp> &kSessionServer,
564 : const firebolt::rialto::common::SessionServerState &state)
565 : {
566 2 : if (state == firebolt::rialto::common::SessionServerState::NOT_RUNNING ||
567 1 : state == firebolt::rialto::common::SessionServerState::SUSPENDED)
568 : {
569 1 : RIALTO_SERVER_MANAGER_LOG_WARN("Force change of %s to NotRunning.", kSessionServer->getAppName().c_str());
570 1 : kSessionServer->kill();
571 1 : handleSessionServerStateChange(kSessionServer->getServerId(), state);
572 : }
573 : else
574 : {
575 1 : handleSessionServerStateChange(kSessionServer->getServerId(),
576 : firebolt::rialto::common::SessionServerState::ERROR);
577 : }
578 2 : }
579 :
580 11 : bool SessionServerAppManager::configureSessionServerWithSocketName(const std::shared_ptr<ISessionServerApp> &kSessionServer)
581 : {
582 11 : RIALTO_SERVER_MANAGER_LOG_DEBUG("Configuring Session Server using socket name");
583 11 : const auto kInitialState{kSessionServer->getInitialState()};
584 11 : const auto kSocketName{kSessionServer->getSessionManagementSocketName()};
585 11 : const auto kClientDisplayName{kSessionServer->getClientDisplayName()};
586 11 : const auto kSocketPermissions{kSessionServer->getSessionManagementSocketPermissions()};
587 11 : const auto kSocketOwner{kSessionServer->getSessionManagementSocketOwner()};
588 11 : const auto kSocketGroup{kSessionServer->getSessionManagementSocketGroup()};
589 11 : const auto &kAppName{kSessionServer->getAppName()};
590 :
591 11 : const firebolt::rialto::common::MaxResourceCapabilitites kMaxResource{kSessionServer->getMaxPlaybackSessions(),
592 11 : kSessionServer->getMaxWebAudioPlayers()};
593 :
594 22 : if (!m_ipcController->performSetConfiguration(kSessionServer->getServerId(), kInitialState, kSocketName,
595 : kClientDisplayName, kMaxResource, kSocketPermissions, kSocketOwner,
596 11 : kSocketGroup, kAppName, m_cachedAudioCapabilities,
597 11 : m_cachedVideoCapabilities))
598 : {
599 2 : RIALTO_SERVER_MANAGER_LOG_ERROR("Configuration of server with id %d failed - ipc error.",
600 : kSessionServer->getServerId());
601 2 : return false;
602 : }
603 9 : RIALTO_SERVER_MANAGER_LOG_INFO("Configuration of server with id %d succeeded.", kSessionServer->getServerId());
604 9 : return true;
605 11 : }
606 :
607 3 : bool SessionServerAppManager::configureSessionServerWithSocketFd(const std::shared_ptr<ISessionServerApp> &kSessionServer)
608 : {
609 3 : RIALTO_SERVER_MANAGER_LOG_DEBUG("Configuring Session Server using socket fd");
610 3 : const auto kInitialState{kSessionServer->getInitialState()};
611 3 : const auto kSocketFd{kSessionServer->getSessionManagementSocketFd()};
612 3 : const auto kClientDisplayName{kSessionServer->getClientDisplayName()};
613 3 : const auto &kAppName{kSessionServer->getAppName()};
614 :
615 3 : const firebolt::rialto::common::MaxResourceCapabilitites kMaxResource{kSessionServer->getMaxPlaybackSessions(),
616 3 : kSessionServer->getMaxWebAudioPlayers()};
617 :
618 6 : if (!m_ipcController->performSetConfiguration(kSessionServer->getServerId(), kInitialState, kSocketFd,
619 3 : kClientDisplayName, kMaxResource, kAppName, m_cachedAudioCapabilities,
620 3 : m_cachedVideoCapabilities))
621 : {
622 1 : RIALTO_SERVER_MANAGER_LOG_ERROR("Configuration of server with id %d failed - ipc error.",
623 : kSessionServer->getServerId());
624 1 : return false;
625 : }
626 2 : RIALTO_SERVER_MANAGER_LOG_INFO("Configuration of server with id %d succeeded.", kSessionServer->getServerId());
627 2 : return true;
628 3 : }
629 :
630 2 : void SessionServerAppManager::onServerStartupTimeout(int serverId)
631 : {
632 2 : m_eventThread->add(&SessionServerAppManager::handleServerStartupTimeout, this, serverId);
633 : }
634 :
635 2 : void SessionServerAppManager::handleServerStartupTimeout(int serverId)
636 : {
637 2 : auto sessionServer{getServerById(serverId)};
638 2 : if (!sessionServer)
639 : {
640 1 : RIALTO_SERVER_MANAGER_LOG_WARN("Unable to handle startup timeout for serverId: %d", serverId);
641 1 : return;
642 : }
643 1 : const bool isPreloaded{sessionServer->isPreloaded()};
644 1 : RIALTO_SERVER_MANAGER_LOG_WARN("Killing: %d", serverId);
645 1 : handleSessionServerStateChange(serverId, firebolt::rialto::common::SessionServerState::ERROR);
646 :
647 1 : if (!isPreloaded)
648 : {
649 1 : if (m_healthcheckService)
650 : {
651 1 : m_healthcheckService->onServerRemoved(sessionServer->getServerId());
652 : }
653 1 : sessionServer->kill();
654 1 : handleSessionServerStateChange(serverId, firebolt::rialto::common::SessionServerState::NOT_RUNNING);
655 : }
656 2 : }
657 : } // namespace rialto::servermanager::common
|