From 657430422797f015d8499c5a4abe1ee95bb775e9 Mon Sep 17 00:00:00 2001 From: "Robin E. R. Davies" Date: Sat, 16 May 2026 06:26:53 -0400 Subject: [PATCH] NAM Performance profiling (sync) --- .github/workflows/cmake.yml | 13 +- .vscode/launch.json | 2 +- CMakeLists.txt | 3 + PiPedalCommon/src/include/HtmlHelper.hpp | 2 + PiPedalCommon/src/include/json.hpp | 11 + docs/BuildPrerequisites.md | 2 +- src/AesDigest.cpp | 40 + src/AesDigest.hpp | 25 + src/CMakeLists.txt | 21 +- src/PiPedalSocket.cpp | 25 +- src/Tone3000Downloader.cpp | 116 +++ src/Tone3000Downloader.hpp | 17 +- vite/public/html/t3k_response.html | 1 + vite/public/var/config.json | 2 +- vite/src/pipedal/AppThemed.tsx | 2 +- vite/src/pipedal/JackStatusView.tsx | 10 +- vite/src/pipedal/PiPedalModel.tsx | 19 + vite/src/pipedal/Tone3000Downloader.tsx | 59 +- vite/src/pipedal/t3k/config.ts | 15 +- vite/src/pipedal/t3k/tone3000-client.ts | 950 ++++++++++++----------- 20 files changed, 841 insertions(+), 494 deletions(-) create mode 100644 src/AesDigest.cpp create mode 100644 src/AesDigest.hpp diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index 5d38427..e0e489b 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -28,12 +28,13 @@ jobs: npm view npm get version of @babel/plugin-proposal-private-property-in-object version command sudo apt-get update sudo apt install gcc-12 g++-12 libnm-dev - sudo apt-get install liblilv-dev libboost-dev libjack-jackd2-dev libnl-3-dev libnl-genl-3-dev libsystemd-dev catch - sudo apt install libasound2-dev - sudo apt install libwebsocketpp-dev authbind - sudo apt install libsdbus-c++-dev libsdbus-c++-bin - sudo apt install libavahi-client-dev libzip-dev libicu-dev apt - sudo apt install libpipewire-0.3-dev + sudo apt-get install -y liblilv-dev libboost-dev libjack-jackd2-dev libnl-3-dev libnl-genl-3-dev libsystemd-dev catch + sudo apt install -y libasound2-dev + sudo apt install -y libwebsocketpp-dev authbind + sudo apt install -y libsdbus-c++-dev libsdbus-c++-bin + sudo apt install -y libavahi-client-dev libzip-dev libicu-dev apt + sudo apt install -y libpipewire-0.3-dev + sudo apt install -y libssl-dev sudo apt install -y librsvg2-dev git submodule update --init --recursive diff --git a/.vscode/launch.json b/.vscode/launch.json index ccadb2a..c696ea3 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -337,7 +337,7 @@ "program": "${command:cmake.launchTargetPath}", "args": [ "--no-profile", - "--preset-file", "/home/robin/Downloads/NAM Profiling.piPreset", + "--preset-file", "/home/robin/Downloads/A1 Profiling.piPreset", "--seconds", "100", "-w" ], diff --git a/CMakeLists.txt b/CMakeLists.txt index f426427..26caa26 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,6 +11,9 @@ set (DISPLAY_VERSION "PiPedal v2.0.101-Alpha") set (PACKAGE_ARCHITECTURE ${DEBIAN_ARCHITECTURE}) set (CMAKE_INSTALL_PREFIX "/usr/") +set(PIPEDAL_T3K_PUBLISHABLE_KEY "t3k_pub_bHrH8btdwXXTtxz5ryEU8sNLF-2TGRT9") + + set (LIBZIP_DO_INSTALL OFF CACHE BOOL "Disable libzip install" FORCE) set (SQLITECPP_INSTALL OFF CACHE BOOL "Disable SQLiteCpp install" FORCE) diff --git a/PiPedalCommon/src/include/HtmlHelper.hpp b/PiPedalCommon/src/include/HtmlHelper.hpp index b3be4cf..c362427 100644 --- a/PiPedalCommon/src/include/HtmlHelper.hpp +++ b/PiPedalCommon/src/include/HtmlHelper.hpp @@ -20,9 +20,11 @@ #pragma once #include +#include #include #include #include +#include namespace pipedal { diff --git a/PiPedalCommon/src/include/json.hpp b/PiPedalCommon/src/include/json.hpp index 27d65a5..51f5087 100644 --- a/PiPedalCommon/src/include/json.hpp +++ b/PiPedalCommon/src/include/json.hpp @@ -38,6 +38,7 @@ #include #include +#ifndef __INTELLISENSE__ #define DECLARE_JSON_MAP(CLASSNAME) \ static pipedal::json_map::storage_type jmap @@ -56,7 +57,17 @@ } \ } \ ; +#else +#define DECLARE_JSON_MAP(CLASSNAME) +#define JSON_MAP_BEGIN(CLASSNAME) + +#define JSON_MAP_REFERENCE(class, name) + +#define JSON_MAP_END() ; + ; + +#endif #define JSON_GETTER_SETTER_REF(name) \ const decltype(name##_) &name() const { return name##_; } \ diff --git a/docs/BuildPrerequisites.md b/docs/BuildPrerequisites.md index 3f1a9b6..7ab9402 100644 --- a/docs/BuildPrerequisites.md +++ b/docs/BuildPrerequisites.md @@ -27,7 +27,7 @@ Run the following commands to install dependent libraries required by the PiPeda authbind libavahi-client-dev libnm-dev libicu-dev \ libsdbus-c++-dev libzip-dev google-perftools \ libgoogle-perftools-dev \ - libpipewire-0.3-dev libbz2-dev + libpipewire-0.3-dev libbz2-dev libssl-dev ### Installing Sources diff --git a/src/AesDigest.cpp b/src/AesDigest.cpp new file mode 100644 index 0000000..825f1e0 --- /dev/null +++ b/src/AesDigest.cpp @@ -0,0 +1,40 @@ +#include "AesDigest.hpp" + +#include +#include +#include + +using namespace pipedal; + + +std::string pipedal::AesDigest(const std::string &text) +{ + std::array digest{}; + size_t digestLength = 0; + + if (EVP_Q_digest( + nullptr, + "SHA256", + nullptr, + reinterpret_cast(text.data()), + text.size(), + digest.data(), + &digestLength) + != 1) + { + throw std::runtime_error("EVP_Q_digest(SHA256) failed."); + } + + static constexpr char hexDigits[] = "0123456789abcdef"; + std::string result(digestLength * 2, '\0'); + for (size_t i = 0; i < digestLength; ++i) + { + unsigned char value = digest[i]; + result[2 * i] = hexDigits[(value >> 4) & 0x0F]; + result[2 * i + 1] = hexDigits[value & 0x0F]; + } + return result; +} + + + diff --git a/src/AesDigest.hpp b/src/AesDigest.hpp new file mode 100644 index 0000000..8d122b2 --- /dev/null +++ b/src/AesDigest.hpp @@ -0,0 +1,25 @@ +// Copyright (c) 2026 Robin E. R. Davies +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#pragma once + +#include +namespace pipedal { + std::string AesDigest(const std::string &text); +} \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d042d1e..7707dd3 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,6 +1,13 @@ set(VERBOSE true) cmake_minimum_required(VERSION 3.16.0) +configure_file(config.hpp.in config.hpp) +file(GENERATE + OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/T3kConfig.h" + CONTENT "#define PIPEDAL_T3K_PUBLISHABLE_KEY \"${PIPEDAL_T3K_PUBLISHABLE_KEY}\"\n") + + + set (CMAKE_INSTALL_PREFIX "/usr/") set (USE_PCH 1) @@ -10,19 +17,13 @@ set (ENABLE_BACKTRACE 0) set (USE_SANITIZE OFF) # seems to be broken on Ubuntu 24.10 + set(CXX_STANDARD 20) find_package(PkgConfig REQUIRED) pkg_check_modules(PipeWire REQUIRED libpipewire-0.3) - -message(STATUS "PipeWire_INCLUDE_DIRS: ${PipeWire_INCLUDE_DIRS}" - "PipeWire_LIBRARIES: ${PipeWire_LIBRARIES}" - "PipeWire_CFLAGS: ${PipeWire_CFLAGS}" - "PipeWire_DEFINES: ${PipeWire_DEFINES}" - "PipeWire_VERSION: ${PipeWire_VERSION}") - include(FetchContent) # FOR FTXUI @@ -58,6 +59,8 @@ include(FindPkgConfig) +find_package(OpenSSL REQUIRED) + find_package(ICU REQUIRED COMPONENTS uc i18n) message(STATUS "ICU_LIBRARIES: ${ICU_LIBRARIES}") @@ -204,6 +207,7 @@ else() endif() set (PIPEDAL_SOURCES + AesDigest.cpp AesDigest.hpp ChannelRouterSettings.cpp ChannelRouterSettings.hpp Curl.cpp Curl.hpp Tone3000DownloadType.cpp Tone3000DownloadType.hpp @@ -324,7 +328,7 @@ set (PIPEDAL_SOURCES ) -configure_file(config.hpp.in config.hpp) + include_directories( ${pipedald_SOURCE_DIR}/. ../build/src @@ -364,6 +368,7 @@ target_link_libraries(libpipedald PiPedalCommon PRIVATE SQLiteCpp + OpenSSL::Crypto ${PipeWire_LIBRARIES} ) diff --git a/src/PiPedalSocket.cpp b/src/PiPedalSocket.cpp index 6bf91c4..71abf71 100644 --- a/src/PiPedalSocket.cpp +++ b/src/PiPedalSocket.cpp @@ -456,7 +456,7 @@ public: JSON_MAP_BEGIN(RenameBankBody) JSON_MAP_REFERENCE(RenameBankBody, bankId) JSON_MAP_REFERENCE(RenameBankBody, newName) -JSON_MAP_END() +JSON_MAP_END(); class RenamePresetBody { @@ -1181,6 +1181,29 @@ public: } REGISTER_MESSAGE_HANDLER(setControl) + + void handle_makeTone3000Pkce(int replyTo, json_reader *pReader) + { + std::string redirectUrl; + pReader->read(&redirectUrl); + + Tone3000PkceParams result {redirectUrl}; + this->Reply(replyTo, "makeTone3000Pkce", result); + + } + REGISTER_MESSAGE_HANDLER(makeTone3000Pkce); + + void handle_sha256Base64url(int replyTo, json_reader *pReader) + { + std::string input; + pReader->read(&input); + + std::string result = Sha256Base64Url(input); + this->Reply(replyTo, "sha256Base64url", result); + + } + REGISTER_MESSAGE_HANDLER(sha256Base64url); + void handle_previewControl(int replyTo, json_reader *pReader) { ControlChangedBody message; diff --git a/src/Tone3000Downloader.cpp b/src/Tone3000Downloader.cpp index cb15224..30cf42f 100644 --- a/src/Tone3000Downloader.cpp +++ b/src/Tone3000Downloader.cpp @@ -28,9 +28,12 @@ #include #include "HtmlHelper.hpp" #include "Curl.hpp" +#include +#include #include #include #include +#include #include #include #include "TemporaryFile.hpp" @@ -39,6 +42,102 @@ using namespace pipedal; namespace fs = std::filesystem; + +// Pulls in the define for T3kConfig.h + +#define PIPEDAL_T3K_PUBLISHABLE_KEY "t3k_pub_bHrH8btdwXXTtxz5ryEU8sNLF-2TGRT9" + + + +namespace { + std::string Base64UrlEncode(const unsigned char* data, size_t size) + { + static constexpr char base64Table[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + std::string result; + result.reserve(((size + 2) / 3) * 4); + + for (size_t i = 0; i + 3 <= size; i += 3) + { + uint32_t value = (static_cast(data[i]) << 16) + | (static_cast(data[i + 1]) << 8) + | static_cast(data[i + 2]); + result.push_back(base64Table[(value >> 18) & 0x3F]); + result.push_back(base64Table[(value >> 12) & 0x3F]); + result.push_back(base64Table[(value >> 6) & 0x3F]); + result.push_back(base64Table[value & 0x3F]); + } + + size_t remainder = size % 3; + if (remainder == 1) + { + uint32_t value = static_cast(data[size - 1]) << 16; + result.push_back(base64Table[(value >> 18) & 0x3F]); + result.push_back(base64Table[(value >> 12) & 0x3F]); + result.push_back('='); + result.push_back('='); + } + else if (remainder == 2) + { + uint32_t value = (static_cast(data[size - 2]) << 16) + | (static_cast(data[size - 1]) << 8); + result.push_back(base64Table[(value >> 18) & 0x3F]); + result.push_back(base64Table[(value >> 12) & 0x3F]); + result.push_back(base64Table[(value >> 6) & 0x3F]); + result.push_back('='); + } + + for (char &ch : result) + { + if (ch == '+') + { + ch = '-'; + } + else if (ch == '/') + { + ch = '_'; + } + } + while (!result.empty() && result.back() == '=') + { + result.pop_back(); + } + return result; + } + + std::string RandomBase64Url(size_t size) + { + std::string bytes(size, '\0'); + if (RAND_bytes(reinterpret_cast(bytes.data()), static_cast(bytes.size())) != 1) + { + throw std::runtime_error("RAND_bytes failed."); + } + return Base64UrlEncode(reinterpret_cast(bytes.data()), bytes.size()); + } + +} + + +std::string pipedal::Sha256Base64Url(const std::string &text) +{ + std::array digest{}; + size_t digestLength = 0; + if (EVP_Q_digest( + nullptr, + "SHA256", + nullptr, + reinterpret_cast(text.data()), + text.size(), + digest.data(), + &digestLength) + != 1) + { + throw std::runtime_error("EVP_Q_digest(SHA256) failed."); + } + return Base64UrlEncode(digest.data(), digestLength); +} + static const std::filesystem::path WEB_TEMP_DIR{"/var/pipedal/web_temp"}; static const std::filesystem::path TONE3000_THUMBNAIL_PATH{"/var/pipedal/tone3000_thumbnails"}; @@ -1168,6 +1267,23 @@ std::shared_ptr Tone3000DownloaderImpl::GetTone3000Tone( return tone; } +Tone3000PkceParams::Tone3000PkceParams( + const std::string &redirectUrl) +{ + + this->publishableKey_ = PIPEDAL_T3K_PUBLISHABLE_KEY; + this->redirectUrl_ = redirectUrl; + this->codeVerifier_ = RandomBase64Url(32); + this->codeChallenge_ = Sha256Base64Url(this->codeVerifier_); + this->state_ = RandomBase64Url(16); +} + + + + + + + ////////////////////////////////////////////////////////////////////////////////// JSON_MAP_BEGIN(Tone3000PkceParams) diff --git a/src/Tone3000Downloader.hpp b/src/Tone3000Downloader.hpp index 6690469..8d05cb8 100644 --- a/src/Tone3000Downloader.hpp +++ b/src/Tone3000Downloader.hpp @@ -33,14 +33,19 @@ namespace pipedal { - class Tone3000PkceParams { + class Tone3000PkceParams + { private: std::string publishableKey_; std::string redirectUrl_; std::string codeVerifier_; std::string codeChallenge_; std::string state_; + public: + Tone3000PkceParams() = default; + Tone3000PkceParams(const std::string &redirectUrl); + JSON_GETTER_SETTER_REF(publishableKey); JSON_GETTER_SETTER_REF(redirectUrl); JSON_GETTER_SETTER_REF(codeVerifier); @@ -62,6 +67,8 @@ namespace pipedal DECLARE_JSON_MAP(Tone3000ModelInfo); }; + std::string Sha256Base64Url(const std::string&input); + // class Tone3000DownloadRequest // { // private: @@ -108,7 +115,6 @@ namespace pipedal // JSON_GETTER_SETTER_REF(license); // JSON_GETTER_SETTER_REF(links); - // DECLARE_JSON_MAP(Tone3000DownloadRequest); // }; @@ -144,10 +150,8 @@ namespace pipedal using self = Tone3000Downloader; static std::shared_ptr Create(); - virtual void SetListener(Listener *listener) = 0; - virtual void CancelDownload( handle_t handle) = 0; @@ -155,12 +159,9 @@ namespace pipedal const uri &uri, const Tone3000PkceParams &pkceParams, const std::string &downloadPath, - Tone3000DownloadType downloadType) - = 0; + Tone3000DownloadType downloadType) = 0; virtual void Close() = 0; virtual Tone3000DownloadProgress GetDownloadStatus() = 0; - - }; } \ No newline at end of file diff --git a/vite/public/html/t3k_response.html b/vite/public/html/t3k_response.html index 6143065..78ef2e1 100644 --- a/vite/public/html/t3k_response.html +++ b/vite/public/html/t3k_response.html @@ -3,6 +3,7 @@ T3K Response