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 :
20 : #include "tcptransport.h"
21 :
22 : #include <QTcpServer>
23 : #include <QTcpSocket>
24 :
25 : #include "global/serialization/json.h"
26 :
27 : #include "log.h"
28 :
29 : static const int DEFAULT_PORT = 2212;
30 :
31 : using namespace muse::rcontrol::mcp;
32 :
33 0 : TcpConnection::TcpConnection(QTcpSocket* socket, const ITransport::RequestHandler& onRequest, QObject* parent)
34 0 : : QObject(parent), m_socket(socket), m_onRequest(onRequest)
35 : {
36 0 : m_socket->setParent(this);
37 0 : connect(m_socket, &QTcpSocket::readyRead, this, &TcpConnection::onReadyRead);
38 0 : connect(m_socket, &QTcpSocket::disconnected, this, &QObject::deleteLater);
39 0 : }
40 :
41 0 : void TcpConnection::onReadyRead()
42 : {
43 0 : m_buffer += m_socket->readAll();
44 :
45 0 : int idx = -1;
46 0 : while ((idx = m_buffer.indexOf('\n')) != -1) {
47 0 : const QByteArray message = m_buffer.left(idx);
48 0 : m_buffer.remove(0, idx + 1);
49 0 : processMessage(message);
50 0 : }
51 0 : }
52 :
53 0 : void TcpConnection::processMessage(const QByteArray& request)
54 : {
55 0 : LOGD() << "request: " << request;
56 :
57 0 : if (m_onRequest) {
58 0 : ByteArray req = ByteArray::fromQByteArrayNoCopy(request);
59 0 : m_onRequest(req, [this](const ByteArray& response) {
60 0 : QByteArray resp = response.toQByteArrayNoCopy();
61 0 : LOGD() << "response: " << resp;
62 0 : m_socket->write(resp);
63 0 : m_socket->write("\n");
64 0 : m_socket->flush();
65 0 : });
66 0 : } else {
67 0 : LOGE() << "No onResponse handler";
68 0 : m_socket->write("\n");
69 0 : m_socket->flush();
70 : }
71 0 : }
72 :
73 0 : TcpTransport::~TcpTransport()
74 : {
75 0 : stop();
76 0 : }
77 :
78 0 : bool TcpTransport::start()
79 : {
80 0 : if (!m_server) {
81 0 : m_server = new QTcpServer();
82 0 : QObject::connect(m_server, &QTcpServer::newConnection, [this]() {
83 0 : if (m_connection) {
84 0 : LOGE() << "Already connected";
85 0 : return;
86 : }
87 :
88 0 : QTcpSocket* socket = m_server->nextPendingConnection();
89 0 : m_connection = new TcpConnection(socket, m_onRequest);
90 : });
91 : }
92 :
93 0 : if (!m_server->listen(QHostAddress::Any, DEFAULT_PORT)) {
94 0 : return false;
95 : }
96 :
97 0 : LOGI() << "TcpTransport started on port " << DEFAULT_PORT;
98 :
99 0 : return true;
100 : }
101 :
102 0 : void TcpTransport::stop()
103 : {
104 0 : if (m_server) {
105 0 : delete m_connection;
106 0 : m_connection = nullptr;
107 :
108 0 : m_server->close();
109 0 : delete m_server;
110 0 : m_server = nullptr;
111 : }
112 0 : }
113 :
114 0 : void TcpTransport::onRequest(const RequestHandler& onRequest)
115 : {
116 0 : m_onRequest = onRequest;
117 0 : }
|