NAM Performance profiling (sync)
This commit is contained in:
@@ -28,12 +28,13 @@ jobs:
|
|||||||
npm view npm get version of @babel/plugin-proposal-private-property-in-object version command
|
npm view npm get version of @babel/plugin-proposal-private-property-in-object version command
|
||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt install gcc-12 g++-12 libnm-dev
|
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-get install -y 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 -y libasound2-dev
|
||||||
sudo apt install libwebsocketpp-dev authbind
|
sudo apt install -y libwebsocketpp-dev authbind
|
||||||
sudo apt install libsdbus-c++-dev libsdbus-c++-bin
|
sudo apt install -y libsdbus-c++-dev libsdbus-c++-bin
|
||||||
sudo apt install libavahi-client-dev libzip-dev libicu-dev apt
|
sudo apt install -y libavahi-client-dev libzip-dev libicu-dev apt
|
||||||
sudo apt install libpipewire-0.3-dev
|
sudo apt install -y libpipewire-0.3-dev
|
||||||
|
sudo apt install -y libssl-dev
|
||||||
|
|
||||||
sudo apt install -y librsvg2-dev
|
sudo apt install -y librsvg2-dev
|
||||||
git submodule update --init --recursive
|
git submodule update --init --recursive
|
||||||
|
|||||||
Vendored
+1
-1
@@ -337,7 +337,7 @@
|
|||||||
"program": "${command:cmake.launchTargetPath}",
|
"program": "${command:cmake.launchTargetPath}",
|
||||||
"args": [
|
"args": [
|
||||||
"--no-profile",
|
"--no-profile",
|
||||||
"--preset-file", "/home/robin/Downloads/NAM Profiling.piPreset",
|
"--preset-file", "/home/robin/Downloads/A1 Profiling.piPreset",
|
||||||
"--seconds", "100",
|
"--seconds", "100",
|
||||||
"-w"
|
"-w"
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -11,6 +11,9 @@ set (DISPLAY_VERSION "PiPedal v2.0.101-Alpha")
|
|||||||
set (PACKAGE_ARCHITECTURE ${DEBIAN_ARCHITECTURE})
|
set (PACKAGE_ARCHITECTURE ${DEBIAN_ARCHITECTURE})
|
||||||
set (CMAKE_INSTALL_PREFIX "/usr/")
|
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 (LIBZIP_DO_INSTALL OFF CACHE BOOL "Disable libzip install" FORCE)
|
||||||
set (SQLITECPP_INSTALL OFF CACHE BOOL "Disable SQLiteCpp install" FORCE)
|
set (SQLITECPP_INSTALL OFF CACHE BOOL "Disable SQLiteCpp install" FORCE)
|
||||||
|
|
||||||
|
|||||||
@@ -20,9 +20,11 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
namespace pipedal
|
namespace pipedal
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -38,6 +38,7 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
#ifndef __INTELLISENSE__
|
||||||
#define DECLARE_JSON_MAP(CLASSNAME) \
|
#define DECLARE_JSON_MAP(CLASSNAME) \
|
||||||
static pipedal::json_map::storage_type<CLASSNAME> jmap
|
static pipedal::json_map::storage_type<CLASSNAME> 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) \
|
#define JSON_GETTER_SETTER_REF(name) \
|
||||||
const decltype(name##_) &name() const { return name##_; } \
|
const decltype(name##_) &name() const { return name##_; } \
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ Run the following commands to install dependent libraries required by the PiPeda
|
|||||||
authbind libavahi-client-dev libnm-dev libicu-dev \
|
authbind libavahi-client-dev libnm-dev libicu-dev \
|
||||||
libsdbus-c++-dev libzip-dev google-perftools \
|
libsdbus-c++-dev libzip-dev google-perftools \
|
||||||
libgoogle-perftools-dev \
|
libgoogle-perftools-dev \
|
||||||
libpipewire-0.3-dev libbz2-dev
|
libpipewire-0.3-dev libbz2-dev libssl-dev
|
||||||
|
|
||||||
|
|
||||||
### Installing Sources
|
### Installing Sources
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
#include "AesDigest.hpp"
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <openssl/evp.h>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
using namespace pipedal;
|
||||||
|
|
||||||
|
|
||||||
|
std::string pipedal::AesDigest(const std::string &text)
|
||||||
|
{
|
||||||
|
std::array<unsigned char, EVP_MAX_MD_SIZE> digest{};
|
||||||
|
size_t digestLength = 0;
|
||||||
|
|
||||||
|
if (EVP_Q_digest(
|
||||||
|
nullptr,
|
||||||
|
"SHA256",
|
||||||
|
nullptr,
|
||||||
|
reinterpret_cast<const unsigned char *>(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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -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 <string>
|
||||||
|
namespace pipedal {
|
||||||
|
std::string AesDigest(const std::string &text);
|
||||||
|
}
|
||||||
+13
-8
@@ -1,6 +1,13 @@
|
|||||||
set(VERBOSE true)
|
set(VERBOSE true)
|
||||||
cmake_minimum_required(VERSION 3.16.0)
|
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 (CMAKE_INSTALL_PREFIX "/usr/")
|
||||||
|
|
||||||
set (USE_PCH 1)
|
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 (USE_SANITIZE OFF) # seems to be broken on Ubuntu 24.10
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
set(CXX_STANDARD 20)
|
set(CXX_STANDARD 20)
|
||||||
|
|
||||||
find_package(PkgConfig REQUIRED)
|
find_package(PkgConfig REQUIRED)
|
||||||
|
|
||||||
pkg_check_modules(PipeWire REQUIRED libpipewire-0.3)
|
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)
|
include(FetchContent)
|
||||||
|
|
||||||
# FOR FTXUI
|
# FOR FTXUI
|
||||||
@@ -58,6 +59,8 @@ include(FindPkgConfig)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
find_package(OpenSSL REQUIRED)
|
||||||
|
|
||||||
find_package(ICU REQUIRED COMPONENTS uc i18n)
|
find_package(ICU REQUIRED COMPONENTS uc i18n)
|
||||||
message(STATUS "ICU_LIBRARIES: ${ICU_LIBRARIES}")
|
message(STATUS "ICU_LIBRARIES: ${ICU_LIBRARIES}")
|
||||||
|
|
||||||
@@ -204,6 +207,7 @@ else()
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
set (PIPEDAL_SOURCES
|
set (PIPEDAL_SOURCES
|
||||||
|
AesDigest.cpp AesDigest.hpp
|
||||||
ChannelRouterSettings.cpp ChannelRouterSettings.hpp
|
ChannelRouterSettings.cpp ChannelRouterSettings.hpp
|
||||||
Curl.cpp Curl.hpp
|
Curl.cpp Curl.hpp
|
||||||
Tone3000DownloadType.cpp Tone3000DownloadType.hpp
|
Tone3000DownloadType.cpp Tone3000DownloadType.hpp
|
||||||
@@ -324,7 +328,7 @@ set (PIPEDAL_SOURCES
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
configure_file(config.hpp.in config.hpp)
|
|
||||||
include_directories(
|
include_directories(
|
||||||
${pipedald_SOURCE_DIR}/.
|
${pipedald_SOURCE_DIR}/.
|
||||||
../build/src
|
../build/src
|
||||||
@@ -364,6 +368,7 @@ target_link_libraries(libpipedald
|
|||||||
PiPedalCommon
|
PiPedalCommon
|
||||||
PRIVATE
|
PRIVATE
|
||||||
SQLiteCpp
|
SQLiteCpp
|
||||||
|
OpenSSL::Crypto
|
||||||
${PipeWire_LIBRARIES}
|
${PipeWire_LIBRARIES}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
+24
-1
@@ -456,7 +456,7 @@ public:
|
|||||||
JSON_MAP_BEGIN(RenameBankBody)
|
JSON_MAP_BEGIN(RenameBankBody)
|
||||||
JSON_MAP_REFERENCE(RenameBankBody, bankId)
|
JSON_MAP_REFERENCE(RenameBankBody, bankId)
|
||||||
JSON_MAP_REFERENCE(RenameBankBody, newName)
|
JSON_MAP_REFERENCE(RenameBankBody, newName)
|
||||||
JSON_MAP_END()
|
JSON_MAP_END();
|
||||||
|
|
||||||
class RenamePresetBody
|
class RenamePresetBody
|
||||||
{
|
{
|
||||||
@@ -1181,6 +1181,29 @@ public:
|
|||||||
}
|
}
|
||||||
REGISTER_MESSAGE_HANDLER(setControl)
|
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)
|
void handle_previewControl(int replyTo, json_reader *pReader)
|
||||||
{
|
{
|
||||||
ControlChangedBody message;
|
ControlChangedBody message;
|
||||||
|
|||||||
@@ -28,9 +28,12 @@
|
|||||||
#include <functional>
|
#include <functional>
|
||||||
#include "HtmlHelper.hpp"
|
#include "HtmlHelper.hpp"
|
||||||
#include "Curl.hpp"
|
#include "Curl.hpp"
|
||||||
|
#include <openssl/evp.h>
|
||||||
|
#include <openssl/rand.h>
|
||||||
#include <charconv>
|
#include <charconv>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
#include <array>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include "TemporaryFile.hpp"
|
#include "TemporaryFile.hpp"
|
||||||
@@ -39,6 +42,102 @@
|
|||||||
using namespace pipedal;
|
using namespace pipedal;
|
||||||
namespace fs = std::filesystem;
|
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<uint32_t>(data[i]) << 16)
|
||||||
|
| (static_cast<uint32_t>(data[i + 1]) << 8)
|
||||||
|
| static_cast<uint32_t>(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<uint32_t>(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<uint32_t>(data[size - 2]) << 16)
|
||||||
|
| (static_cast<uint32_t>(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<unsigned char*>(bytes.data()), static_cast<int>(bytes.size())) != 1)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("RAND_bytes failed.");
|
||||||
|
}
|
||||||
|
return Base64UrlEncode(reinterpret_cast<const unsigned char*>(bytes.data()), bytes.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::string pipedal::Sha256Base64Url(const std::string &text)
|
||||||
|
{
|
||||||
|
std::array<unsigned char, EVP_MAX_MD_SIZE> digest{};
|
||||||
|
size_t digestLength = 0;
|
||||||
|
if (EVP_Q_digest(
|
||||||
|
nullptr,
|
||||||
|
"SHA256",
|
||||||
|
nullptr,
|
||||||
|
reinterpret_cast<const unsigned char *>(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 WEB_TEMP_DIR{"/var/pipedal/web_temp"};
|
||||||
static const std::filesystem::path TONE3000_THUMBNAIL_PATH{"/var/pipedal/tone3000_thumbnails"};
|
static const std::filesystem::path TONE3000_THUMBNAIL_PATH{"/var/pipedal/tone3000_thumbnails"};
|
||||||
|
|
||||||
@@ -1168,6 +1267,23 @@ std::shared_ptr<Tone3000Download> Tone3000DownloaderImpl::GetTone3000Tone(
|
|||||||
return tone;
|
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)
|
JSON_MAP_BEGIN(Tone3000PkceParams)
|
||||||
|
|||||||
@@ -33,14 +33,19 @@
|
|||||||
namespace pipedal
|
namespace pipedal
|
||||||
{
|
{
|
||||||
|
|
||||||
class Tone3000PkceParams {
|
class Tone3000PkceParams
|
||||||
|
{
|
||||||
private:
|
private:
|
||||||
std::string publishableKey_;
|
std::string publishableKey_;
|
||||||
std::string redirectUrl_;
|
std::string redirectUrl_;
|
||||||
std::string codeVerifier_;
|
std::string codeVerifier_;
|
||||||
std::string codeChallenge_;
|
std::string codeChallenge_;
|
||||||
std::string state_;
|
std::string state_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
Tone3000PkceParams() = default;
|
||||||
|
Tone3000PkceParams(const std::string &redirectUrl);
|
||||||
|
|
||||||
JSON_GETTER_SETTER_REF(publishableKey);
|
JSON_GETTER_SETTER_REF(publishableKey);
|
||||||
JSON_GETTER_SETTER_REF(redirectUrl);
|
JSON_GETTER_SETTER_REF(redirectUrl);
|
||||||
JSON_GETTER_SETTER_REF(codeVerifier);
|
JSON_GETTER_SETTER_REF(codeVerifier);
|
||||||
@@ -62,6 +67,8 @@ namespace pipedal
|
|||||||
DECLARE_JSON_MAP(Tone3000ModelInfo);
|
DECLARE_JSON_MAP(Tone3000ModelInfo);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
std::string Sha256Base64Url(const std::string&input);
|
||||||
|
|
||||||
// class Tone3000DownloadRequest
|
// class Tone3000DownloadRequest
|
||||||
// {
|
// {
|
||||||
// private:
|
// private:
|
||||||
@@ -108,7 +115,6 @@ namespace pipedal
|
|||||||
// JSON_GETTER_SETTER_REF(license);
|
// JSON_GETTER_SETTER_REF(license);
|
||||||
// JSON_GETTER_SETTER_REF(links);
|
// JSON_GETTER_SETTER_REF(links);
|
||||||
|
|
||||||
|
|
||||||
// DECLARE_JSON_MAP(Tone3000DownloadRequest);
|
// DECLARE_JSON_MAP(Tone3000DownloadRequest);
|
||||||
// };
|
// };
|
||||||
|
|
||||||
@@ -144,10 +150,8 @@ namespace pipedal
|
|||||||
using self = Tone3000Downloader;
|
using self = Tone3000Downloader;
|
||||||
static std::shared_ptr<self> Create();
|
static std::shared_ptr<self> Create();
|
||||||
|
|
||||||
|
|
||||||
virtual void SetListener(Listener *listener) = 0;
|
virtual void SetListener(Listener *listener) = 0;
|
||||||
|
|
||||||
|
|
||||||
virtual void CancelDownload(
|
virtual void CancelDownload(
|
||||||
handle_t handle) = 0;
|
handle_t handle) = 0;
|
||||||
|
|
||||||
@@ -155,12 +159,9 @@ namespace pipedal
|
|||||||
const uri &uri,
|
const uri &uri,
|
||||||
const Tone3000PkceParams &pkceParams,
|
const Tone3000PkceParams &pkceParams,
|
||||||
const std::string &downloadPath,
|
const std::string &downloadPath,
|
||||||
Tone3000DownloadType downloadType)
|
Tone3000DownloadType downloadType) = 0;
|
||||||
= 0;
|
|
||||||
|
|
||||||
virtual void Close() = 0;
|
virtual void Close() = 0;
|
||||||
virtual Tone3000DownloadProgress GetDownloadStatus() = 0;
|
virtual Tone3000DownloadProgress GetDownloadStatus() = 0;
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -3,6 +3,7 @@
|
|||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>T3K Response</title>
|
<title>T3K Response</title>
|
||||||
<script>
|
<script>
|
||||||
|
debugger;
|
||||||
window.opener.postMessage(
|
window.opener.postMessage(
|
||||||
{
|
{
|
||||||
type: "t3k_response",
|
type: "t3k_response",
|
||||||
|
|||||||
@@ -7,6 +7,6 @@
|
|||||||
"ui_plugins": [],
|
"ui_plugins": [],
|
||||||
"enable_auto_update": true,
|
"enable_auto_update": true,
|
||||||
"has_wifi_device": false,
|
"has_wifi_device": false,
|
||||||
"tone3000_A2_models": true,
|
"tone3000_A2_models": false,
|
||||||
"end": true
|
"end": true
|
||||||
}
|
}
|
||||||
@@ -587,6 +587,7 @@ export
|
|||||||
}
|
}
|
||||||
|
|
||||||
private beforeUnloadListener(e: Event) {
|
private beforeUnloadListener(e: Event) {
|
||||||
|
alert("BeforeUnload");
|
||||||
this.model_.close();
|
this.model_.close();
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
@@ -601,7 +602,6 @@ export
|
|||||||
|
|
||||||
super.componentDidMount();
|
super.componentDidMount();
|
||||||
window.addEventListener("beforeunload", this.beforeUnloadListener);
|
window.addEventListener("beforeunload", this.beforeUnloadListener);
|
||||||
window.addEventListener("unload", this.unloadListener);
|
|
||||||
|
|
||||||
this.model_.errorMessage.addOnChangedHandler(this.errorChangeHandler_);
|
this.model_.errorMessage.addOnChangedHandler(this.errorChangeHandler_);
|
||||||
this.model_.state.addOnChangedHandler(this.stateChangeHandler_);
|
this.model_.state.addOnChangedHandler(this.stateChangeHandler_);
|
||||||
|
|||||||
@@ -46,13 +46,21 @@ export default class JackStatusView extends React.Component<JackStatusViewProps,
|
|||||||
this.tick = this.tick.bind(this);
|
this.tick = this.tick.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private waitingForTick: boolean = false;
|
||||||
tick() {
|
tick() {
|
||||||
if (this.model.state.get() === State.Ready) {
|
if (this.model.state.get() === State.Ready) {
|
||||||
|
if (this.waitingForTick) return;
|
||||||
|
this.waitingForTick = true;
|
||||||
this.model.getJackStatus()
|
this.model.getJackStatus()
|
||||||
.then(jackStatus => {
|
.then(jackStatus => {
|
||||||
|
this.waitingForTick = false;
|
||||||
this.setState({jackStatus: jackStatus});
|
this.setState({jackStatus: jackStatus});
|
||||||
})
|
})
|
||||||
.catch(error => { /* ignore*/ });
|
.catch(error => {
|
||||||
|
this.waitingForTick = false;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.waitingForTick = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -707,6 +707,25 @@ export class PiPedalModel //implements PiPedalModel
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async makeTone3000Pkce(redirectUrl: string) : Promise<Tone3000PkceParams>
|
||||||
|
{
|
||||||
|
if (this.webSocket === undefined)
|
||||||
|
{
|
||||||
|
throw new Error("Server disconnected.");
|
||||||
|
}
|
||||||
|
return await this.webSocket.request<Tone3000PkceParams>(
|
||||||
|
"makeTone3000Pkce", redirectUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
async sha256Base64url(intput: string) : Promise<string> {
|
||||||
|
if (this.webSocket === undefined)
|
||||||
|
{
|
||||||
|
throw new Error("Server disconnected.");
|
||||||
|
}
|
||||||
|
return this.webSocket.request<string>(
|
||||||
|
"sha256Base64url", intput);
|
||||||
|
|
||||||
|
}
|
||||||
async pingTone3000Server(): Promise<boolean> {
|
async pingTone3000Server(): Promise<boolean> {
|
||||||
if (this.webSocket === undefined) {
|
if (this.webSocket === undefined) {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import { PiPedalModel, getErrorMessage, Tone3000PkceParams } from "./PiPedalModel";
|
import { PiPedalModel, getErrorMessage, Tone3000PkceParams } from "./PiPedalModel";
|
||||||
import Tone3000DownloadType from "./Tone3000DownloadType";
|
import Tone3000DownloadType from "./Tone3000DownloadType";
|
||||||
import { PkceParams, buildPkceParams, handleOAuthCallback } from "./t3k/tone3000-client.ts";
|
import { T3K_DEBUG, PkceParams, setServerPkceParams, handleOAuthCallback } from "./t3k/tone3000-client.ts";
|
||||||
|
|
||||||
import { Model, PaginatedResponse, Platform, Tone } from "./t3k/types.ts";
|
import { Model, PaginatedResponse, Platform, Tone } from "./t3k/types.ts";
|
||||||
import { PUBLISHABLE_KEY } from './t3k/config.ts';
|
import { PUBLISHABLE_KEY } from './t3k/config.ts';
|
||||||
|
|
||||||
|
|
||||||
import { startSelectFlowPopup, T3KClient } from "./t3k/tone3000-client.ts";
|
import { startSelectFlowPopup, buildPkceParams,T3KClient } from "./t3k/tone3000-client.ts";
|
||||||
import Tone3000DownloadProgress from './Tone3000DownloadProgress';
|
import Tone3000DownloadProgress from './Tone3000DownloadProgress';
|
||||||
import { safeFilenameEncode } from "./SafeFilename";
|
import { safeFilenameEncode } from "./SafeFilename";
|
||||||
|
|
||||||
@@ -20,6 +20,8 @@ async function asyncSleep(ms: number): Promise<void> {
|
|||||||
return new Promise(resolve => setTimeout(resolve, ms));
|
return new Promise(resolve => setTimeout(resolve, ms));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const USE_SERVER_PCKE=true;
|
||||||
|
|
||||||
|
|
||||||
const RUN_THROTTLER_TEST = true;
|
const RUN_THROTTLER_TEST = true;
|
||||||
const ALLOWED_DOWNLOADS_PER_MINUTE = 25;
|
const ALLOWED_DOWNLOADS_PER_MINUTE = 25;
|
||||||
@@ -119,6 +121,7 @@ export class Tone3000DownloadHandler {
|
|||||||
let uri = event.data.uri;
|
let uri = event.data.uri;
|
||||||
this.handleTone3000DownloadComplete();
|
this.handleTone3000DownloadComplete();
|
||||||
if (uri) {
|
if (uri) {
|
||||||
|
|
||||||
this_.handleT3kSelectResponse(uri, event.data.storedState, event.data.codeVerifier)
|
this_.handleT3kSelectResponse(uri, event.data.storedState, event.data.codeVerifier)
|
||||||
.then(() => { })
|
.then(() => { })
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
@@ -171,17 +174,18 @@ export class Tone3000DownloadHandler {
|
|||||||
|
|
||||||
private progress: Tone3000DownloadProgress = new Tone3000DownloadProgress();
|
private progress: Tone3000DownloadProgress = new Tone3000DownloadProgress();
|
||||||
|
|
||||||
private async throttleRequests(): Promise<void> {
|
private async throttleRequests(): Promise<boolean> {
|
||||||
let now = Date.now();
|
let now = Date.now();
|
||||||
let delay = this.throttler.getThrottleDelay(now);
|
let delay = this.throttler.getThrottleDelay(now);
|
||||||
while (delay > 0) {
|
while (delay > 0) {
|
||||||
await asyncSleep(250);
|
await asyncSleep(250);
|
||||||
if (this.checkForCancel())
|
if (this.checkForCancel())
|
||||||
{
|
{
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
delay -= 250;
|
delay -= 250;
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private onTone3000DownloadStarted() {
|
private onTone3000DownloadStarted() {
|
||||||
@@ -214,6 +218,10 @@ export class Tone3000DownloadHandler {
|
|||||||
downloadType: Tone3000DownloadType
|
downloadType: Tone3000DownloadType
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
try {
|
try {
|
||||||
|
|
||||||
|
if (T3K_DEBUG) {
|
||||||
|
console.debug("PiPedal responseUri: " + responseUri);
|
||||||
|
}
|
||||||
this.onTone3000DownloadStarted();
|
this.onTone3000DownloadStarted();
|
||||||
this.progress.title = "Authenticating..."
|
this.progress.title = "Authenticating..."
|
||||||
this.onTone3000DownloadProgress(this.progress);
|
this.onTone3000DownloadProgress(this.progress);
|
||||||
@@ -221,13 +229,13 @@ export class Tone3000DownloadHandler {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.throttleRequests();
|
if (!await this.throttleRequests()) return;
|
||||||
let tokenResponse = await handleOAuthCallback(
|
let tokenResponse = await handleOAuthCallback(
|
||||||
PUBLISHABLE_KEY,
|
PUBLISHABLE_KEY,
|
||||||
this.redirectUrl(),
|
this.redirectUrl(),
|
||||||
responseUri);
|
responseUri);
|
||||||
|
|
||||||
if (!tokenResponse.ok) {
|
if (!tokenResponse.ok) {
|
||||||
;
|
|
||||||
throw new Error(tokenResponse.error);
|
throw new Error(tokenResponse.error);
|
||||||
}
|
}
|
||||||
if (this.checkForCancel()) {
|
if (this.checkForCancel()) {
|
||||||
@@ -245,7 +253,7 @@ export class Tone3000DownloadHandler {
|
|||||||
this.onTone3000DownloadProgress(this.progress);
|
this.onTone3000DownloadProgress(this.progress);
|
||||||
|
|
||||||
|
|
||||||
await this.throttleRequests();
|
if (!await this.throttleRequests()) return;
|
||||||
let tone: Tone = await this.t3kClient.getTone(tokenResponse.toneId);
|
let tone: Tone = await this.t3kClient.getTone(tokenResponse.toneId);
|
||||||
|
|
||||||
if (this.checkForCancel()) {
|
if (this.checkForCancel()) {
|
||||||
@@ -264,7 +272,7 @@ export class Tone3000DownloadHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
await this.throttleRequests();
|
if (!await this.throttleRequests()) return;
|
||||||
if (this.checkForCancel()) {
|
if (this.checkForCancel()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -308,7 +316,7 @@ export class Tone3000DownloadHandler {
|
|||||||
lastUpdateTime = Date.now();
|
lastUpdateTime = Date.now();
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.throttleRequests();
|
if (!await this.throttleRequests()) return;
|
||||||
|
|
||||||
if (!model.model_url) {
|
if (!model.model_url) {
|
||||||
throw new Error("Model " + model.name + " does not have a model URL.");
|
throw new Error("Model " + model.name + " does not have a model URL.");
|
||||||
@@ -463,18 +471,45 @@ export class Tone3000DownloadHandler {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
let pkceParams = await buildPkceParams();
|
let t3kPceParams: Tone3000PkceParams;
|
||||||
|
let pkceParams: PkceParams;
|
||||||
|
if (USE_SERVER_PCKE) {
|
||||||
|
t3kPceParams = await this.model.makeTone3000Pkce(this.redirectUrl());
|
||||||
|
pkceParams = {
|
||||||
|
codeChallenge: t3kPceParams.codeChallenge,
|
||||||
|
codeVerifier: t3kPceParams.codeVerifier,
|
||||||
|
state: t3kPceParams.state
|
||||||
|
}
|
||||||
|
setServerPkceParams(pkceParams)
|
||||||
|
|
||||||
|
} else {
|
||||||
|
pkceParams = await buildPkceParams();
|
||||||
|
t3kPceParams = {
|
||||||
|
codeChallenge: pkceParams.codeChallenge,
|
||||||
|
codeVerifier: pkceParams.codeVerifier,
|
||||||
|
state: pkceParams.state,
|
||||||
|
publishableKey: PUBLISHABLE_KEY,
|
||||||
|
redirectUrl: this.redirectUrl()
|
||||||
|
};
|
||||||
|
// verify that the server matches.
|
||||||
|
let testcodeChallenge = await this.model.sha256Base64url(pkceParams.codeVerifier);
|
||||||
|
if (testcodeChallenge !== pkceParams.codeChallenge) {
|
||||||
|
throw new Error("model.sha256Base64url produces incorrect results. ");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
this.pkceParams = pkceParams;
|
this.pkceParams = pkceParams;
|
||||||
this.popupWindow = await startSelectFlowPopup(
|
this.popupWindow = await startSelectFlowPopup(
|
||||||
pkceParams,
|
pkceParams,
|
||||||
PUBLISHABLE_KEY,
|
PUBLISHABLE_KEY,
|
||||||
this.redirectUrl(),
|
this.redirectUrl(),
|
||||||
{
|
{
|
||||||
architecture: downloadType === Tone3000DownloadType.CabIr ? undefined : 2,
|
architecture: (downloadType === Tone3000DownloadType.Nam && this.model.tone3000_A2_models) ? 2: undefined,
|
||||||
platform: downloadType === Tone3000DownloadType.CabIr ? Platform.Ir : Platform.Nam,
|
platform: downloadType === Tone3000DownloadType.CabIr ? Platform.Ir : Platform.Nam,
|
||||||
menubar: true,
|
menubar: true,
|
||||||
width: popupWidth,
|
width: popupWidth,
|
||||||
height: popupHeight
|
height: popupHeight,
|
||||||
},
|
},
|
||||||
|
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -3,18 +3,13 @@
|
|||||||
// Trailing slashes are stripped so `${T3K_API}/api/...` never produces a double slash —
|
// Trailing slashes are stripped so `${T3K_API}/api/...` never produces a double slash —
|
||||||
// Vercel 308-redirects double-slash paths, and redirects drop CORS headers.
|
// Vercel 308-redirects double-slash paths, and redirects drop CORS headers.
|
||||||
export const T3K_API = (
|
export const T3K_API = (
|
||||||
(import.meta.env.VITE_T3K_API_DOMAIN as string | undefined) ?? 'https://www.tone3000.com'
|
'https://www.tone3000.com'
|
||||||
).replace(/\/+$/, '');
|
).replace(/\/+$/, '');
|
||||||
|
|
||||||
export const PUBLISHABLE_KEY = import.meta.env.VITE_PUBLISHABLE_KEY as string;
|
export const PUBLISHABLE_KEY = "t3k_pub_bHrH8btdwXXTtxz5ryEU8sNLF-2TGRT9";
|
||||||
|
|
||||||
// Per-demo keys — fall back to the shared PUBLISHABLE_KEY for local dev
|
// Per-demo keys — fall back to the shared PUBLISHABLE_KEY for local dev
|
||||||
export const PUBLISHABLE_KEY_SELECT =
|
export const PUBLISHABLE_KEY_SELECT = PUBLISHABLE_KEY;
|
||||||
(import.meta.env.VITE_PUBLISHABLE_KEY_SELECT as string | undefined) ?? PUBLISHABLE_KEY;
|
export const PUBLISHABLE_KEY_LOAD = PUBLISHABLE_KEY;
|
||||||
export const PUBLISHABLE_KEY_LOAD =
|
export const PUBLISHABLE_KEY_FULL = PUBLISHABLE_KEY;
|
||||||
(import.meta.env.VITE_PUBLISHABLE_KEY_LOAD as string | undefined) ?? PUBLISHABLE_KEY;
|
|
||||||
export const PUBLISHABLE_KEY_FULL =
|
|
||||||
(import.meta.env.VITE_PUBLISHABLE_KEY_FULL as string | undefined) ?? PUBLISHABLE_KEY;
|
|
||||||
|
|
||||||
export const REDIRECT_URI =
|
|
||||||
(import.meta.env.VITE_REDIRECT_URI as string | undefined) ?? 'http://localhost:3001';
|
|
||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user