From 970b436fd8b6e61291b169584e2c64ed339e7b55 Mon Sep 17 00:00:00 2001 From: Benjamin Klum Date: Sat, 2 Mar 2024 22:54:58 +0100 Subject: [PATCH] Playtime: Add support for adding license --- CONTRIBUTING.adoc | 8 +-- Cargo.lock | 1 + api/Cargo.toml | 1 + api/src/runtime/info_event.rs | 2 +- api/src/runtime/licensing.rs | 13 ++++ api/src/runtime/mod.rs | 3 + .../infrastructure/data/license_management.rs | 34 +++++++-- main/src/infrastructure/data/mod.rs | 2 - .../infrastructure/plugin/backbone_shell.rs | 46 +++++++++--- main/src/infrastructure/proto/ext.rs | 48 ++++++++++++- main/src/infrastructure/proto/generated.rs | 71 ++++++++++++++++++- main/src/infrastructure/proto/hub.rs | 14 +++- .../infrastructure/proto/initial_events.rs | 2 + .../infrastructure/proto/request_handler.rs | 15 +++- main/src/infrastructure/proto/service_impl.rs | 11 ++- main/src/infrastructure/ui/app/app_library.rs | 3 + playtime-clip-engine | 2 +- 17 files changed, 244 insertions(+), 32 deletions(-) create mode 100644 api/src/runtime/licensing.rs diff --git a/CONTRIBUTING.adoc b/CONTRIBUTING.adoc index e1e427ba0..c797cf76a 100644 --- a/CONTRIBUTING.adoc +++ b/CONTRIBUTING.adoc @@ -41,7 +41,7 @@ See link:ARCHITECTURE.adoc[here]. |`/macros` |Various Rust macros for usage in this project only |`/main` |Main crate: The actual ReaLearn instrument plug-in (`realearn`) |`/playtime-api` |Playtime data structures for describing e.g. clip engine presets -|`/playtime-clip-engine` |Playtime Clip Engine for playing/recording clips (currently a private submodule) +|`/playtime-clip-engine` |Playtime Clip Engine for playing/recording clips (currently a private submodule). Is a workspace member because that makes it much simpler to use the same dependency versions everywhere. |`/playtime-clip-engine-placeholder` |A placeholder crate for the Playtime Clip Engine. Users who don't have access to the Playtime Clip Engine submodule, must rename this directory to `playtime-clip-engine` in order to be able to build ReaLearn without feature `playtime`. @@ -124,7 +124,7 @@ git clone https://github.com/helgoboss/realearn.git` cd realearn # ONLY For users who DON'T HAVE access to the private submodules -git submodule update --init main/lib/WDL main/lib/helgoboss-learn +git submodule update --init main/lib/WDL main/lib/helgoboss-learn helgoboss-license-api rmdir playtime-clip-engine mv playtime-clip-engine-placeholder playtime-clip-engine @@ -162,7 +162,7 @@ git clone https://github.com/helgoboss/realearn.git cd realearn # ONLY For users who DON'T HAVE access to the private submodules -git submodule update --init main/lib/WDL main/lib/helgoboss-learn +git submodule update --init main/lib/WDL main/lib/helgoboss-learn helgoboss-license-api rmdir playtime-clip-engine mv playtime-clip-engine-placeholder playtime-clip-engine @@ -210,7 +210,7 @@ git clone https://github.com/helgoboss/realearn.git cd realearn # ONLY For users who DON'T HAVE access to the private submodules -git submodule update --init main/lib/WDL main/lib/helgoboss-learn +git submodule update --init main/lib/WDL main/lib/helgoboss-learn helgoboss-license-api rmdir playtime-clip-engine mv playtime-clip-engine-placeholder playtime-clip-engine diff --git a/Cargo.lock b/Cargo.lock index 9d16f227f..710c1d315 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5036,6 +5036,7 @@ dependencies = [ "enum-map", "enumset", "heck", + "helgoboss-license-api", "mlua", "num_enum 0.7.2", "playtime-api", diff --git a/api/Cargo.toml b/api/Cargo.toml index 480915cb9..8030887bd 100644 --- a/api/Cargo.toml +++ b/api/Cargo.toml @@ -21,6 +21,7 @@ strum.workspace = true num_enum.workspace = true enum-map.workspace = true enumset = { workspace = true, features = ["serde", "alloc"]} +helgoboss-license-api.workspace = true [dev-dependencies] # For testing Lua compatibility diff --git a/api/src/runtime/info_event.rs b/api/src/runtime/info_event.rs index eebb30364..9ad2849a4 100644 --- a/api/src/runtime/info_event.rs +++ b/api/src/runtime/info_event.rs @@ -3,8 +3,8 @@ use serde::{Deserialize, Serialize}; #[derive(Clone, Eq, PartialEq, Debug, Serialize, Deserialize)] #[serde(tag = "kind")] pub enum InfoEvent { - /// Contains controller ID AutoAddedController(AutoAddedControllerEvent), + PlaytimeActivatedSuccessfully, } #[derive(Clone, Eq, PartialEq, Debug, Serialize, Deserialize)] diff --git a/api/src/runtime/licensing.rs b/api/src/runtime/licensing.rs new file mode 100644 index 000000000..620c9b50e --- /dev/null +++ b/api/src/runtime/licensing.rs @@ -0,0 +1,13 @@ +use helgoboss_license_api::persistence::LicenseData; +use serde::Serialize; + +#[derive(Clone, Eq, PartialEq, Debug, Serialize)] +pub struct LicenseInfo { + pub licenses: Vec, +} + +#[derive(Clone, Eq, PartialEq, Debug, Serialize)] +pub struct ValidatedLicense { + pub license: LicenseData, + pub valid: bool, +} diff --git a/api/src/runtime/mod.rs b/api/src/runtime/mod.rs index 00dc1dbd9..ee990188e 100644 --- a/api/src/runtime/mod.rs +++ b/api/src/runtime/mod.rs @@ -6,3 +6,6 @@ pub use info_event::*; mod reaper; pub use reaper::*; + +mod licensing; +pub use licensing::*; diff --git a/main/src/infrastructure/data/license_management.rs b/main/src/infrastructure/data/license_management.rs index 5d10104ef..a9454e83b 100644 --- a/main/src/infrastructure/data/license_management.rs +++ b/main/src/infrastructure/data/license_management.rs @@ -2,13 +2,23 @@ use anyhow::{anyhow, Context}; use helgoboss_license_api::persistence::{LicenseData, LicenseKey}; use helgoboss_license_api::runtime::License; use serde::{Deserialize, Serialize}; +use std::cell::RefCell; +use std::fmt::Debug; use std::fs; use std::path::PathBuf; +use std::rc::Rc; + +pub type SharedLicenseManager = Rc>; + +pub trait LicenseManagerEventHandler: Debug { + fn licenses_changed(&self, source: &LicenseManager); +} #[derive(Debug)] pub struct LicenseManager { licensing_file_path: PathBuf, licensing: Licensing, + event_handler: Box, } #[derive(Debug, Default, Serialize, Deserialize)] @@ -25,15 +35,32 @@ impl LicenseManager { /// Creates a manager using the given licensing file. /// /// Immediately loads the licenses from the licensing file if it exists. - pub fn new(licensing_file_path: PathBuf) -> Self { + pub fn new( + licensing_file_path: PathBuf, + event_handler: Box, + ) -> Self { let mut manager = Self { licensing_file_path, licensing: Default::default(), + event_handler, }; let _ = manager.load(); manager } + pub fn licenses(&self) -> &[License] { + &self.licensing.licenses + } + + pub fn add_license(&mut self, key: LicenseKey) -> anyhow::Result<()> { + let license_data = LicenseData::try_from_key(&key)?; + let license = License::try_from(license_data)?; + self.licensing.licenses.push(license); + self.save()?; + self.event_handler.licenses_changed(self); + Ok(()) + } + fn load(&mut self) -> anyhow::Result<()> { let json = fs::read_to_string(&self.licensing_file_path) .with_context(|| "couldn't read licensing file")?; @@ -43,7 +70,6 @@ impl LicenseManager { Ok(()) } - #[allow(dead_code)] fn save(&mut self) -> anyhow::Result<()> { let data: LicensingData = self.licensing.clone().into(); let json = serde_json::to_string_pretty(&data) @@ -58,10 +84,6 @@ impl LicenseManager { .with_context(|| "couldn't write licensing file")?; Ok(()) } - - pub fn licenses(&self) -> impl Iterator + ExactSizeIterator { - self.licensing.licenses.iter() - } } impl From for Licensing { diff --git a/main/src/infrastructure/data/mod.rs b/main/src/infrastructure/data/mod.rs index dc672b9f6..52fbbb6dd 100644 --- a/main/src/infrastructure/data/mod.rs +++ b/main/src/infrastructure/data/mod.rs @@ -55,9 +55,7 @@ pub use osc_device_management::*; mod virtual_control; pub use virtual_control::*; -#[allow(unused)] mod license_management; -#[allow(unused)] pub use license_management::*; mod common; diff --git a/main/src/infrastructure/plugin/backbone_shell.rs b/main/src/infrastructure/plugin/backbone_shell.rs index 8931d6be8..7cf98abe7 100644 --- a/main/src/infrastructure/plugin/backbone_shell.rs +++ b/main/src/infrastructure/plugin/backbone_shell.rs @@ -21,8 +21,9 @@ use crate::domain::{ use crate::infrastructure::data::{ CommonCompartmentPresetManager, CompartmentPresetManagerEventHandler, ControllerManager, ControllerManagerEventHandler, FileBasedControllerPresetManager, FileBasedMainPresetManager, - FileBasedPresetLinkManager, MainPresetSelectionConditions, OscDevice, OscDeviceManager, - SharedControllerManager, SharedControllerPresetManager, SharedMainPresetManager, + FileBasedPresetLinkManager, LicenseManager, LicenseManagerEventHandler, + MainPresetSelectionConditions, OscDevice, OscDeviceManager, SharedControllerManager, + SharedControllerPresetManager, SharedLicenseManager, SharedMainPresetManager, SharedOscDeviceManager, SharedPresetLinkManager, }; use crate::infrastructure::server; @@ -161,6 +162,7 @@ pub struct BackboneShell { /// RAII _metrics_hook: Option, state: RefCell, + license_manager: SharedLicenseManager, controller_preset_manager: SharedControllerPresetManager, main_preset_manager: SharedMainPresetManager, preset_link_manager: SharedPresetLinkManager, @@ -337,9 +339,14 @@ impl BackboneShell { .expect("couldn't get IsInRealTimeAudio function from REAPER"), ), ); + // License management + let license_manager = LicenseManager::new( + BackboneShell::helgoboss_resource_dir_path().join("licensing.json"), + Box::new(BackboneLicenseManagerEventHandler), + ); // This just initializes the clip engine, it doesn't add any clip matrix yet, so resource consumption is low. #[cfg(feature = "playtime")] - Self::init_clip_engine(); + Self::init_clip_engine(&license_manager); // This is the backbone representation in the domain layer, of course we need this now already. let backbone_state = Backbone::new( additional_feedback_event_sender.clone(), @@ -437,6 +444,7 @@ impl BackboneShell { _tracing_hook: tracing_hook, _metrics_hook: metrics_hook, state: RefCell::new(AppState::Sleeping(sleeping_state)), + license_manager: Rc::new(RefCell::new(license_manager)), controller_preset_manager: Rc::new(RefCell::new(controller_preset_manager)), main_preset_manager: Rc::new(RefCell::new(main_preset_manager)), preset_link_manager: Rc::new(RefCell::new(preset_link_manager)), @@ -532,11 +540,8 @@ impl BackboneShell { } #[cfg(feature = "playtime")] - fn init_clip_engine() { + fn init_clip_engine(license_manager: &LicenseManager) { use playtime_clip_engine::ClipEngine; - let license_manager = crate::infrastructure::data::LicenseManager::new( - BackboneShell::helgoboss_resource_dir_path().join("licensing.json"), - ); #[derive(Debug)] struct RealearnMetricsRecorder; impl playtime_clip_engine::MetricsRecorder for RealearnMetricsRecorder { @@ -962,6 +967,10 @@ impl BackboneShell { Ok(f(&state.async_runtime)) } + pub fn license_manager(&self) -> &SharedLicenseManager { + &self.license_manager + } + pub fn controller_preset_manager(&self) -> &SharedControllerPresetManager { &self.controller_preset_manager } @@ -2534,6 +2543,27 @@ impl ControllerManagerEventHandler for BackboneControllerManagerEventHandler { } } +#[derive(Debug)] +pub struct BackboneLicenseManagerEventHandler; + +impl LicenseManagerEventHandler for BackboneLicenseManagerEventHandler { + fn licenses_changed(&self, source: &LicenseManager) { + #[cfg(feature = "playtime")] + { + let success = + playtime_clip_engine::ClipEngine::get().handle_changed_licenses(source.licenses()); + if success { + BackboneShell::get() + .proto_hub() + .notify_about_global_info_event(InfoEvent::PlaytimeActivatedSuccessfully); + } + } + BackboneShell::get() + .proto_hub() + .notify_licenses_changed(source); + } +} + #[derive(Debug)] pub struct BackboneControllerPresetManagerEventHandler; @@ -2739,7 +2769,7 @@ async fn maybe_create_controller_for_device( .save_controller(controller)?; BackboneShell::get() .proto_hub() - .notify_about_info_event(InfoEvent::AutoAddedController(AutoAddedControllerEvent { + .notify_about_global_info_event(InfoEvent::AutoAddedController(AutoAddedControllerEvent { controller_id: outcome.id, })); Ok(()) diff --git a/main/src/infrastructure/proto/ext.rs b/main/src/infrastructure/proto/ext.rs index 21d612a28..bb805986c 100644 --- a/main/src/infrastructure/proto/ext.rs +++ b/main/src/infrastructure/proto/ext.rs @@ -1,8 +1,10 @@ +use helgoboss_license_api::persistence::LicenseData; +use helgoboss_license_api::runtime::License; use reaper_high::Reaper; use reaper_medium::ReaperString; use crate::infrastructure::data::{ - ControllerManager, FileBasedControllerPresetManager, FileBasedMainPresetManager, + ControllerManager, FileBasedControllerPresetManager, FileBasedMainPresetManager, LicenseManager, }; use crate::infrastructure::plugin::InstanceShell; @@ -19,7 +21,7 @@ use crate::infrastructure::proto::{ QualifiedOccasionalColumnUpdate, QualifiedOccasionalRowUpdate, QualifiedOccasionalSlotUpdate, QualifiedOccasionalTrackUpdate, SlotAddress, }; -use realearn_api::runtime::{ControllerPreset, MainPreset}; +use realearn_api::runtime::{ControllerPreset, LicenseInfo, MainPreset, ValidatedLicense}; impl occasional_instance_update::Update { pub fn settings(instance_shell: &InstanceShell) -> Self { @@ -94,6 +96,48 @@ impl occasional_global_update::Update { .expect("couldn't represent controller config as JSON"); Self::ControllerConfig(json) } + + pub fn playtime_is_licensed() -> Self { + let value = { + #[cfg(feature = "playtime")] + { + playtime_clip_engine::ClipEngine::get().has_valid_license() + } + #[cfg(not(feature = "playtime"))] + { + false + } + }; + Self::PlaytimeIsLicensed(value) + } + + pub fn license_info(license_manager: &LicenseManager) -> Self { + let license_info = LicenseInfo { + licenses: license_manager + .licenses() + .iter() + .map(|license| { + let valid = { + #[cfg(not(feature = "playtime"))] + { + false + } + #[cfg(feature = "playtime")] + { + playtime_clip_engine::ClipEngine::validate_license(license).is_ok() + } + }; + ValidatedLicense { + license: license.clone().into(), + valid, + } + }) + .collect(), + }; + let json = + serde_json::to_string(&license_info).expect("couldn't represent license info as JSON"); + Self::LicenseInfo(json) + } } impl MidiInputDevices { diff --git a/main/src/infrastructure/proto/generated.rs b/main/src/infrastructure/proto/generated.rs index a335f6267..2b33ac74f 100644 --- a/main/src/infrastructure/proto/generated.rs +++ b/main/src/infrastructure/proto/generated.rs @@ -47,7 +47,7 @@ pub mod reply { pub struct CommandRequest { #[prost( oneof = "command_request::Value", - tags = "1, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 37, 40, 25, 26, 27, 34, 28, 29, 31, 32, 33, 35, 36, 38, 39, 41" + tags = "1, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 37, 40, 25, 26, 27, 34, 28, 29, 31, 32, 33, 35, 36, 38, 39, 41, 42" )] pub value: ::core::option::Option, } @@ -137,6 +137,8 @@ pub mod command_request { DeleteController(super::DeleteControllerRequest), #[prost(message, tag = "41")] SetInstanceSettings(super::SetInstanceSettingsRequest), + #[prost(message, tag = "42")] + AddLicense(super::AddLicenseRequest), } } /// Envelope for queries. @@ -428,6 +430,12 @@ pub struct SetTrackInputRequest { pub struct Empty {} #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] +pub struct AddLicenseRequest { + #[prost(string, tag = "1")] + pub license_key: ::prost::alloc::string::String, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] pub struct SaveControllerRequest { /// Controller as JSON #[prost(string, tag = "1")] @@ -913,7 +921,10 @@ pub struct QualifiedOccasionalTrackUpdate { #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct OccasionalGlobalUpdate { - #[prost(oneof = "occasional_global_update::Update", tags = "1, 2, 3, 4, 5, 6, 7")] + #[prost( + oneof = "occasional_global_update::Update", + tags = "1, 2, 3, 4, 5, 6, 7, 8, 9" + )] pub update: ::core::option::Option, } /// Nested message and enum types in `OccasionalGlobalUpdate`. @@ -942,6 +953,12 @@ pub mod occasional_global_update { /// Info event as JSON. #[prost(string, tag = "7")] InfoEvent(::prost::alloc::string::String), + /// License info as JSON. + #[prost(string, tag = "8")] + LicenseInfo(::prost::alloc::string::String), + /// Whether Playtime is licensed. + #[prost(bool, tag = "9")] + PlaytimeIsLicensed(bool), } } #[allow(clippy::derive_partial_eq_without_eq)] @@ -2122,6 +2139,10 @@ pub mod helgobox_service_server { tonic::Status, >; /// Global commands + async fn add_license( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status>; async fn save_controller( &self, request: tonic::Request, @@ -2760,6 +2781,52 @@ pub mod helgobox_service_server { }; Box::pin(fut) } + "/generated.HelgoboxService/AddLicense" => { + #[allow(non_camel_case_types)] + struct AddLicenseSvc(pub Arc); + impl< + T: HelgoboxService, + > tonic::server::UnaryService + for AddLicenseSvc { + type Response = super::Empty; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::add_license(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = AddLicenseSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } "/generated.HelgoboxService/SaveController" => { #[allow(non_camel_case_types)] struct SaveControllerSvc(pub Arc); diff --git a/main/src/infrastructure/proto/hub.rs b/main/src/infrastructure/proto/hub.rs index 78575b842..1193c46d4 100644 --- a/main/src/infrastructure/proto/hub.rs +++ b/main/src/infrastructure/proto/hub.rs @@ -1,5 +1,5 @@ use crate::infrastructure::data::{ - ControllerManager, FileBasedControllerPresetManager, FileBasedMainPresetManager, + ControllerManager, FileBasedControllerPresetManager, FileBasedMainPresetManager, LicenseManager, }; use crate::infrastructure::plugin::InstanceShell; use crate::infrastructure::proto::helgobox_service_server::HelgoboxServiceServer; @@ -8,6 +8,7 @@ use crate::infrastructure::proto::{ OccasionalGlobalUpdate, OccasionalInstanceUpdate, OccasionalInstanceUpdateBatch, ProtoRequestHandler, ProtoSenders, }; +use helgoboss_license_api::runtime::License; use realearn_api::runtime::InfoEvent; #[derive(Debug)] @@ -39,7 +40,7 @@ impl ProtoHub { )) } - pub fn notify_about_info_event(&self, info_event: InfoEvent) { + pub fn notify_about_global_info_event(&self, info_event: InfoEvent) { self.send_occasional_global_updates(|| { [occasional_global_update::Update::info_event(info_event)] }); @@ -76,6 +77,15 @@ impl ProtoHub { }); } + pub fn notify_licenses_changed(&self, license_manager: &LicenseManager) { + self.send_occasional_global_updates(|| { + [ + occasional_global_update::Update::license_info(license_manager), + occasional_global_update::Update::playtime_is_licensed(), + ] + }); + } + pub fn notify_controller_config_changed(&self, controller_manager: &ControllerManager) { self.send_occasional_global_updates(|| { [occasional_global_update::Update::controller_config( diff --git a/main/src/infrastructure/proto/initial_events.rs b/main/src/infrastructure/proto/initial_events.rs index 21bc35395..4c541cc50 100644 --- a/main/src/infrastructure/proto/initial_events.rs +++ b/main/src/infrastructure/proto/initial_events.rs @@ -20,6 +20,8 @@ pub fn create_initial_global_updates() -> Vec { Update::controller_presets(&BackboneShell::get().controller_preset_manager().borrow()), Update::main_presets(&BackboneShell::get().main_preset_manager().borrow()), Update::controller_config(&BackboneShell::get().controller_manager().borrow()), + Update::license_info(&BackboneShell::get().license_manager().borrow()), + Update::playtime_is_licensed(), ]; create(global_updates.into_iter()) } diff --git a/main/src/infrastructure/proto/request_handler.rs b/main/src/infrastructure/proto/request_handler.rs index 903a1105d..d2fea6f60 100644 --- a/main/src/infrastructure/proto/request_handler.rs +++ b/main/src/infrastructure/proto/request_handler.rs @@ -1,7 +1,7 @@ use crate::infrastructure::plugin::{BackboneShell, InstanceShell}; use crate::infrastructure::proto::{ - DeleteControllerRequest, DragClipRequest, DragColumnRequest, DragRowRequest, DragSlotRequest, - Empty, GetArrangementInfoReply, GetArrangementInfoRequest, GetClipDetailReply, + AddLicenseRequest, DeleteControllerRequest, DragClipRequest, DragColumnRequest, DragRowRequest, + DragSlotRequest, Empty, GetArrangementInfoReply, GetArrangementInfoRequest, GetClipDetailReply, GetClipDetailRequest, GetHostInfoReply, GetHostInfoRequest, GetProjectDirReply, GetProjectDirRequest, ImportFilesRequest, ProveAuthenticityReply, ProveAuthenticityRequest, SaveControllerRequest, SetClipDataRequest, SetClipNameRequest, SetColumnSettingsRequest, @@ -14,6 +14,7 @@ use crate::infrastructure::proto::{ HOST_API_VERSION, }; use base::spawn_in_main_thread; +use helgoboss_license_api::persistence::LicenseKey; use tonic::{Response, Status}; @@ -183,6 +184,16 @@ impl ProtoRequestHandler { } } + pub fn add_license(&self, req: AddLicenseRequest) -> Result, Status> { + let license_key = LicenseKey::new(req.license_key); + BackboneShell::get() + .license_manager() + .borrow_mut() + .add_license(license_key) + .map_err(|e| Status::invalid_argument(e.to_string()))?; + Ok(Response::new(Empty {})) + } + pub fn save_controller(&self, req: SaveControllerRequest) -> Result, Status> { let controller = serde_json::from_str(&req.controller) .map_err(|e| Status::invalid_argument(e.to_string()))?; diff --git a/main/src/infrastructure/proto/service_impl.rs b/main/src/infrastructure/proto/service_impl.rs index 99b5f5afc..d86a37c74 100644 --- a/main/src/infrastructure/proto/service_impl.rs +++ b/main/src/infrastructure/proto/service_impl.rs @@ -4,8 +4,8 @@ use crate::infrastructure::proto::playtime_not_available_status; use crate::infrastructure::proto::senders::{ProtoSenders, WithSessionId}; use crate::infrastructure::proto::{ create_initial_global_updates, create_initial_instance_updates, helgobox_service_server, - DeleteControllerRequest, DragClipRequest, DragColumnRequest, DragRowRequest, DragSlotRequest, - Empty, GetArrangementInfoReply, GetArrangementInfoRequest, GetClipDetailReply, + AddLicenseRequest, DeleteControllerRequest, DragClipRequest, DragColumnRequest, DragRowRequest, + DragSlotRequest, Empty, GetArrangementInfoReply, GetArrangementInfoRequest, GetClipDetailReply, GetClipDetailRequest, GetContinuousColumnUpdatesReply, GetContinuousColumnUpdatesRequest, GetContinuousMatrixUpdatesReply, GetContinuousMatrixUpdatesRequest, GetContinuousSlotUpdatesReply, GetContinuousSlotUpdatesRequest, GetOccasionalClipUpdatesReply, @@ -601,6 +601,13 @@ impl helgobox_service_server::HelgoboxService for HelgoboxServiceImpl { self.command_handler.import_files(request.into_inner()) } + async fn add_license( + &self, + request: Request, + ) -> Result, Status> { + self.command_handler.add_license(request.into_inner()) + } + async fn save_controller( &self, request: Request, diff --git a/main/src/infrastructure/ui/app/app_library.rs b/main/src/infrastructure/ui/app/app_library.rs index baf289318..c4d215a86 100644 --- a/main/src/infrastructure/ui/app/app_library.rs +++ b/main/src/infrastructure/ui/app/app_library.rs @@ -507,6 +507,9 @@ fn process_command( } } // Normal commands + AddLicense(req) => { + handler.add_license(req)?; + } SaveController(req) => { handler.save_controller(req)?; } diff --git a/playtime-clip-engine b/playtime-clip-engine index ae7142d6f..579ec5ba1 160000 --- a/playtime-clip-engine +++ b/playtime-clip-engine @@ -1 +1 @@ -Subproject commit ae7142d6f3e7d078305535cac29a53207150a590 +Subproject commit 579ec5ba1597b0e7eaa6afa8cd6f1871af95f4a4