diff --git a/CMakeLists.txt b/CMakeLists.txt index 53876c5..8bf9318 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.21) -project(venmic LANGUAGES CXX VERSION 2.1.4) +project(venmic LANGUAGES CXX VERSION 3.0.0) # -------------------------------------------------------------------------------------------------------- # Library options diff --git a/addon/addon.cpp b/addon/addon.cpp index 7ae2ec3..8756a04 100644 --- a/addon/addon.cpp +++ b/addon/addon.cpp @@ -140,35 +140,28 @@ struct patchbay : public Napi::ObjectWrap auto data = info[0].ToObject(); - if (!data.Has("props") || !data.Has("mode")) + if (!data.Has("include") && !data.Has("exclude")) { - Napi::Error::New(env, "[venmic] expected keys 'props' and 'mode'").ThrowAsJavaScriptException(); - return Napi::Boolean::New(env, false); - } - - auto mode = convert(data.Get("mode")); - auto props = to_array(data.Get("props")); - - if (!mode || !props) - { - Napi::Error::New(env, "[venmic] expected 'mode' to be string and 'props' to be array of key-value pairs") + Napi::Error::New(env, "[venmic] expected at least one of keys 'include' or 'exclude'") .ThrowAsJavaScriptException(); return Napi::Boolean::New(env, false); } - if (mode.value() != "include" && mode.value() != "exclude") + auto include = to_array(data.Get("include")); + auto exclude = to_array(data.Get("exclude")); + + if (!include && !exclude) { - Napi::Error::New(env, "[venmic] expected mode to be either exclude or include") + Napi::Error::New(env, "[venmic] expected either 'include' or 'exclude' or both to be present and to be " + "arrays of key-value pairs") .ThrowAsJavaScriptException(); return Napi::Boolean::New(env, false); } - vencord::patchbay::get().link({ - .mode = mode.value() == "include" ? vencord::target_mode::include : vencord::target_mode::exclude, - .props = props.value(), - }); + vencord::patchbay::get().link(include.value_or(std::vector{}), + exclude.value_or(std::vector{})); return Napi::Boolean::New(env, true); } diff --git a/include/vencord/patchbay.hpp b/include/vencord/patchbay.hpp index 86b3629..f352aa7 100644 --- a/include/vencord/patchbay.hpp +++ b/include/vencord/patchbay.hpp @@ -1,9 +1,9 @@ #pragma once + #include #include #include #include -#include namespace vencord { @@ -19,12 +19,6 @@ namespace vencord std::string value; }; - struct target - { - target_mode mode; - std::vector props; - }; - using node = std::map; class patchbay @@ -41,7 +35,7 @@ namespace vencord patchbay(); public: - void link(target targets); + void link(std::vector include, std::vector exclude); public: void unlink(); diff --git a/lib/module.d.ts b/lib/module.d.ts index 6e4c10a..3912432 100644 --- a/lib/module.d.ts +++ b/lib/module.d.ts @@ -16,7 +16,7 @@ export class PatchBay unlink(): void; list(props?: T[]): Record, string>[]; - link(data: {props: Prop[], mode: "include" | "exclude"}): boolean; + link(data: {include: Prop[], exclude: Prop[]}): boolean; static hasPipeWire(): boolean; } diff --git a/package.json b/package.json index 91df3f6..b1d124a 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ "private": false, "license": "MIT", "author": "Curve (https://github.com/Curve)", - "version": "2.1.4", + "version": "3.0.0", "main": "./lib/index.js", "types": "./lib/module.d.ts", "scripts": { diff --git a/private/message.hpp b/private/message.hpp index b303bfe..c4a68e9 100644 --- a/private/message.hpp +++ b/private/message.hpp @@ -15,6 +15,12 @@ namespace vencord std::vector props; }; + struct set_target + { + std::vector include; + std::vector exclude; + }; + struct unset_target { }; @@ -28,8 +34,6 @@ namespace vencord bool success{true}; }; - struct target; - - using pw_recipe = pw::recipe; + using pw_recipe = pw::recipe; using cr_recipe = cr::recipe, ready>; } // namespace vencord diff --git a/private/patchbay.impl.hpp b/private/patchbay.impl.hpp index e43c25d..7028326 100644 --- a/private/patchbay.impl.hpp +++ b/private/patchbay.impl.hpp @@ -36,12 +36,13 @@ namespace vencord std::unique_ptr receiver; private: - std::optional target; - std::multimap created; + std::vector include; + std::vector exclude; private: std::unique_ptr mic; std::optional speaker; + std::multimap created; private: std::map links; diff --git a/server/main.cpp b/server/main.cpp index 96435d2..1af7dcc 100644 --- a/server/main.cpp +++ b/server/main.cpp @@ -21,11 +21,17 @@ struct glz::meta static constexpr auto value = object("key", &T::key, "value", &T::value); }; +struct targets +{ + std::vector include; + std::vector exclude; +}; + template <> -struct glz::meta +struct glz::meta { - using T = vencord::target; - static constexpr auto value = object("mode", &T::mode, "props", &T::props); + using T = targets; + static constexpr auto value = object("include", &T::include, "exclude", &T::exclude); }; int main(int argc, char **args) @@ -67,7 +73,8 @@ int main(int argc, char **args) server.Post("/link", [](const auto &req, auto &response) { - vencord::target parsed; + targets parsed; + auto error = glz::read(parsed, req.body); if (error) @@ -76,7 +83,7 @@ int main(int argc, char **args) return; } - patchbay::get().link(parsed); + patchbay::get().link(parsed.include, parsed.exclude); response.status = 200; }); diff --git a/src/patchbay.cpp b/src/patchbay.cpp index c986eeb..7bf067d 100644 --- a/src/patchbay.cpp +++ b/src/patchbay.cpp @@ -11,9 +11,9 @@ namespace vencord patchbay::patchbay() : m_impl(std::make_unique()) {} - void patchbay::link(target target) + void patchbay::link(std::vector include, std::vector exclude) { - m_impl->sender->send(target); + m_impl->sender->send(set_target{.include = std::move(include), .exclude = std::move(exclude)}); } void patchbay::unlink() diff --git a/src/patchbay.impl.cpp b/src/patchbay.impl.cpp index cda74eb..611ece2 100644 --- a/src/patchbay.impl.cpp +++ b/src/patchbay.impl.cpp @@ -65,6 +65,11 @@ namespace vencord { created.erase(id); + if (!mic) + { + return; + } + if (!nodes.contains(id)) { return; @@ -119,10 +124,10 @@ namespace vencord for (auto &other : others) { - auto link = core->create(pw::link_factory{ - other.id, - port.id, - }) + auto link = core->create({ + other.id, + port.id, + }) .get(); if (!link.has_value()) @@ -258,12 +263,7 @@ namespace vencord void patchbay::impl::on_link(std::uint32_t id) { - if (!target || !speaker) - { - return; - } - - if (target->mode != target_mode::exclude) + if (!include.empty() || !speaker) { return; } @@ -279,12 +279,12 @@ namespace vencord // "Output" = the node that is emitting sound auto &output = nodes[info.output.node]; - auto match = [&](const auto &target) + auto match = [&](const auto &prop) { - return output.info.props[target.key] == target.value; + return output.info.props[prop.key] == prop.value; }; - if (ranges::any_of(target->props, match)) + if (ranges::any_of(exclude, match)) { return; } @@ -296,24 +296,25 @@ namespace vencord void patchbay::impl::on_node(std::uint32_t id) { - if (!target) + if (include.empty()) { return; } - if (target->mode != target_mode::include) + auto match = [&](const auto &prop) { - return; - } + return nodes[id].info.props[prop.key] == prop.value; + }; - auto match = [&](const auto &target) + if (ranges::any_of(exclude, match)) { - return nodes[id].info.props[target.key] == target.value; - }; + logger::get()->debug("ignoring {}: explicitly excluded", id); + return; + } - if (!ranges::any_of(target->props, match)) + if (!ranges::any_of(include, match)) { - logger::get()->debug("ignoring {}: no props match", id); + logger::get()->debug("ignoring {}: no target matched", id); return; } @@ -370,7 +371,7 @@ namespace vencord } template <> - void patchbay::impl::receive([[maybe_unused]] cr_recipe::sender &, vencord::target &req) + void patchbay::impl::receive([[maybe_unused]] cr_recipe::sender &, set_target &req) { if (!mic) { @@ -378,7 +379,9 @@ namespace vencord } created.clear(); - target.emplace(std::move(req)); + + include = std::move(req.include); + exclude = std::move(req.exclude); for (const auto &[id, info] : nodes) { @@ -394,7 +397,9 @@ namespace vencord template <> void patchbay::impl::receive([[maybe_unused]] cr_recipe::sender &, [[maybe_unused]] unset_target &) { - target.reset(); + include.clear(); + exclude.clear(); + created.clear(); mic.reset(); diff --git a/tests/node/api.test.js b/tests/node/api.test.js index 6538095..7cac44d 100644 --- a/tests/node/api.test.js +++ b/tests/node/api.test.js @@ -25,11 +25,15 @@ assert.throws(() => patchbay.list([10]), /expected list of strings/ig); assert.throws(() => patchbay.link(10), /expected link object/ig); -assert.throws(() => patchbay.link({ a: "A", b: "B", c: "C" }), /expected keys/ig); -assert.throws(() => patchbay.link({ key: "node.name", value: "Firefox", mode: "gibberish" }), /expected keys/ig); +assert.throws(() => patchbay.link({ }), /'include' and 'exclude'/ig); +assert.throws(() => patchbay.link({ a: "A", b: "B", c: "C" }), /'include' and 'exclude'/ig); +assert.throws(() => patchbay.link({ key: "node.name", value: "Firefox", mode: "gibberish" }), /'include' and 'exclude'/ig); -assert.throws(() => patchbay.link({ props: [{ a: 0, b: 0 }], mode: "gibberish" }), /key-value/ig); -assert.throws(() => patchbay.link({ props: [{ key: "", value: "" }], mode: "gibberish" }), /expected mode/ig); +assert.throws(() => patchbay.link({ include: "Firefox" }), /key-value/ig); +assert.throws(() => patchbay.link({ include: {} }), /key-value/ig); + +assert.doesNotThrow(() => patchbay.link({ include: [{ key: "node.name", value: "Firefox" }] })); +assert.doesNotThrow(() => patchbay.link({ exclude: [{ key: "node.name", value: "Firefox" }] })); +assert.doesNotThrow(() => patchbay.link({ include: [{ key: "node.name", value: "Firefox" }], exclude: [{ key: "object.id", value: "100" }] })); -assert.doesNotThrow(() => patchbay.link({ props: [{ key: "node.name", value: "Firefox" }], mode: "include" })); assert.doesNotThrow(() => patchbay.unlink());