LCOV - code coverage report
Current view: top level - muse/framework/rcommand/internal - commanddispatcher.cpp Coverage Total Hit
Test: filtered_coverage.info Lines: 28.8 % 80 23
Test Date: 2026-11-05 04:07:02

            Line data    Source code
       1              : /*
       2              :  * SPDX-License-Identifier: GPL-3.0-only
       3              :  * MuseScore/Audacity CLA applies
       4              :  *
       5              :  * Copyright (C) 2026 MuseScore/Audacity and others
       6              :  *
       7              :  * This program is free software: you can redistribute it and/or modify
       8              :  * it under the terms of the GNU General Public License version 3 as
       9              :  * published by the Free Software Foundation.
      10              :  *
      11              :  * This program is distributed in the hope that it will be useful,
      12              :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      13              :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14              :  * GNU General Public License for more details.
      15              :  *
      16              :  * You should have received a copy of the GNU General Public License
      17              :  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
      18              :  */
      19              : #include "commanddispatcher.h"
      20              : 
      21              : #include "async/promise.h"
      22              : 
      23              : #include "../commandable.h"
      24              : #include "../commandtypes.h"
      25              : 
      26              : #include "log.h"
      27              : 
      28              : using namespace muse;
      29              : using namespace muse::rcommand;
      30              : 
      31           32 : CommandDispatcher::~CommandDispatcher()
      32              : {
      33          544 :     for (auto it = m_clients.begin(); it != m_clients.end(); ++it) {
      34          512 :         Commandable* client = it->second.client;
      35          512 :         if (client) {
      36          512 :             client->setDispatcher(nullptr);
      37              :         }
      38              :     }
      39              : 
      40           32 :     m_clients.clear();
      41           32 : }
      42              : 
      43            0 : async::Promise<Response> CommandDispatcher::dispatch(const Request& request)
      44              : {
      45            0 :     if (request.command == NONE_COMMAND) {
      46            0 :         return async::make_promise<Response>([request](auto resolve) {
      47            0 :             return resolve(make_response(request, make_ret(Ret::Code::Ok)));
      48            0 :         });
      49              :     }
      50              : 
      51            0 :     auto it = m_clients.find(request.command);
      52            0 :     if (it == m_clients.end()) {
      53            0 :         LOGW() << "command not registered: " << request.command;
      54            0 :         return async::make_promise<Response>([request](auto resolve) {
      55            0 :             return resolve(make_response(request, make_ret(Ret::Code::UnknownError)));
      56            0 :         });
      57              :     }
      58              : 
      59            0 :     LOGI() << "try call command: " << request.command << ", params: " << request.params;
      60              : 
      61            0 :     Client client = it->second;
      62              : 
      63            0 :     return async::make_promise<Response>([this, request, client](auto resolve) {
      64            0 :         if (client.asyncCallback) {
      65            0 :             bool allowDispatch = true;
      66            0 :             m_preDispatch.send(request.command, &allowDispatch);
      67            0 :             if (!allowDispatch) {
      68            0 :                 return resolve(make_response(request, make_ret(Ret::Code::Cancel)));
      69              :             }
      70              : 
      71            0 :             client.asyncCallback(request, [this, request, resolve](const Response& response) {
      72            0 :                 (void)resolve(response);
      73            0 :                 m_postDispatch.send(request.command);
      74              :             });
      75              : 
      76            0 :             return async::Promise<Response>::dummy_result();
      77              :         }
      78              : 
      79            0 :         if (client.callback) {
      80            0 :             bool allowDispatch = true;
      81            0 :             m_preDispatch.send(request.command, &allowDispatch);
      82            0 :             if (!allowDispatch) {
      83            0 :                 return resolve(make_response(request, make_ret(Ret::Code::Cancel)));
      84              :             }
      85              : 
      86            0 :             auto res = resolve(client.callback(request));
      87            0 :             m_postDispatch.send(request.command);
      88            0 :             return res;
      89              :         }
      90              : 
      91            0 :         UNREACHABLE;
      92              :         return resolve(make_response(request, make_ret(Ret::Code::UnknownError)));
      93            0 :     });
      94            0 : }
      95              : 
      96           36 : Response CommandDispatcher::dispatch(const Command& command, const Params& params)
      97              : {
      98           36 :     Request request = make_request(command, params);
      99              : 
     100           36 :     auto it = m_clients.find(command);
     101           36 :     if (it == m_clients.end()) {
     102            0 :         LOGW() << "command not registered: " << command;
     103            0 :         return make_response(request, make_ret(Ret::Code::UnknownError));
     104              :     }
     105              : 
     106           36 :     LOGI() << "try call command: " << command << " with params: " << params;
     107              : 
     108           36 :     CallBack callback = it->second.callback;
     109              : 
     110           36 :     IF_ASSERT_FAILED(callback) {
     111            0 :         return make_response(request, make_ret(Ret::Code::NotSupported));
     112              :     }
     113              : 
     114           36 :     return callback(request);
     115           36 : }
     116              : 
     117            0 : Response CommandDispatcher::dispatch(const CommandQuery& query)
     118              : {
     119            0 :     return dispatch(query.uri(), query.params());
     120              : }
     121              : 
     122          512 : void CommandDispatcher::onRequest(Commandable* client, const Command& command, const CallBack& callback)
     123              : {
     124          512 :     reg(client, command, { client, callback, nullptr });
     125         1024 : }
     126              : 
     127            0 : void CommandDispatcher::onRequest(Commandable* client, const Command& command, const AsyncCallBack& callback)
     128              : {
     129            0 :     reg(client, command, { client, nullptr, callback });
     130            0 : }
     131              : 
     132          512 : void CommandDispatcher::reg(Commandable* client, const Command& command, const Client& c)
     133              : {
     134          512 :     if (m_clients.find(command) != m_clients.end()) {
     135            0 :         LOGW() << "command already registered: " << command;
     136            0 :         return;
     137              :     }
     138              : 
     139          512 :     m_clients[command] = c;
     140          512 :     client->setDispatcher(this);
     141              : }
     142              : 
     143            0 : void CommandDispatcher::unreg(Commandable* client)
     144              : {
     145            0 :     if (!client || !client->isDispatcher(this)) {
     146            0 :         return;
     147              :     }
     148              : 
     149            0 :     for (auto it = m_clients.begin(); it != m_clients.end();) {
     150            0 :         if (it->second.client == client) {
     151            0 :             it = m_clients.erase(it);
     152            0 :             continue;
     153              :         }
     154            0 :         ++it;
     155              :     }
     156              : 
     157            0 :     client->setDispatcher(nullptr);
     158              : }
     159              : 
     160            0 : async::Channel<Command, bool*> CommandDispatcher::preDispatch() const
     161              : {
     162            0 :     return m_preDispatch;
     163              : }
     164              : 
     165            0 : async::Channel<Command> CommandDispatcher::postDispatch() const
     166              : {
     167            0 :     return m_postDispatch;
     168              : }
        

Generated by: LCOV version 2.0-1