Even more work to create a sane way to replace scripts while they're active. This adds a way to await changes, to ensure they were actually made if we quickly need to use them.
continuous-integration/drone/push Build is passing
Details
continuous-integration/drone/push Build is passing
Details
This commit is contained in:
parent
dd535b30af
commit
2e19005a30
|
@ -12,8 +12,8 @@ pub mod volatile_scripts;
|
||||||
macro_rules! script_hook {
|
macro_rules! script_hook {
|
||||||
($hook_name: ident, $source: ident, $($parameters: expr),*) => {
|
($hook_name: ident, $source: ident, $($parameters: expr),*) => {
|
||||||
let mut aggregator = $source.get_script_iterator();
|
let mut aggregator = $source.get_script_iterator();
|
||||||
while let Some(script) = aggregator.get_next() {
|
while let Some(script_container) = aggregator.get_next() {
|
||||||
let script = script.get();
|
let script = script_container.get();
|
||||||
if let Some(script) = script {
|
if let Some(script) = script {
|
||||||
if let Some(script) = script.read().as_deref() {
|
if let Some(script) = script.read().as_deref() {
|
||||||
if !script.is_suppressed() {
|
if !script.is_suppressed() {
|
||||||
|
|
|
@ -12,6 +12,7 @@ use std::fmt::{Debug, Formatter};
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
|
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use std::thread::JoinHandle;
|
||||||
|
|
||||||
pub trait Script: Send + Sync {
|
pub trait Script: Send + Sync {
|
||||||
fn name(&self) -> &StringKey;
|
fn name(&self) -> &StringKey;
|
||||||
|
@ -144,15 +145,17 @@ impl Debug for dyn Script {
|
||||||
|
|
||||||
type ScriptHolder = Arc<RwLock<Option<Arc<dyn Script>>>>;
|
type ScriptHolder = Arc<RwLock<Option<Arc<dyn Script>>>>;
|
||||||
|
|
||||||
#[derive(Default, Debug, Clone)]
|
#[derive(Default, Debug)]
|
||||||
pub struct ScriptContainer {
|
pub struct ScriptContainer {
|
||||||
script: ScriptHolder,
|
script: ScriptHolder,
|
||||||
|
pub(crate) join_handle: RwLock<Option<JoinHandle<()>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ScriptContainer {
|
impl ScriptContainer {
|
||||||
pub fn new(script: Arc<dyn Script>) -> ScriptContainer {
|
pub fn new(script: Arc<dyn Script>) -> ScriptContainer {
|
||||||
Self {
|
Self {
|
||||||
script: Arc::new(RwLock::new(Some(script))),
|
script: Arc::new(RwLock::new(Some(script))),
|
||||||
|
join_handle: RwLock::new(None),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -169,14 +172,16 @@ impl ScriptContainer {
|
||||||
|
|
||||||
pub fn set(&self, script: Arc<dyn Script>) -> Arc<dyn Script> {
|
pub fn set(&self, script: Arc<dyn Script>) -> Arc<dyn Script> {
|
||||||
if let Some(v) = self.script.read().deref() {
|
if let Some(v) = self.script.read().deref() {
|
||||||
|
v.on_remove();
|
||||||
v.mark_for_deletion();
|
v.mark_for_deletion();
|
||||||
}
|
}
|
||||||
if self.script.is_locked() {
|
if self.script.is_locked() {
|
||||||
let holder = self.script.clone();
|
let holder = self.script.clone();
|
||||||
let new = script.clone();
|
let new = script.clone();
|
||||||
std::thread::spawn(move || {
|
let handle = std::thread::spawn(move || {
|
||||||
holder.write().replace(new);
|
holder.write().replace(new);
|
||||||
});
|
});
|
||||||
|
self.join_handle.write().replace(handle);
|
||||||
} else {
|
} else {
|
||||||
self.script.write().replace(script.clone());
|
self.script.write().replace(script.clone());
|
||||||
};
|
};
|
||||||
|
@ -185,6 +190,7 @@ impl ScriptContainer {
|
||||||
|
|
||||||
pub fn clear(&self) {
|
pub fn clear(&self) {
|
||||||
if let Some(v) = self.script.read().deref() {
|
if let Some(v) = self.script.read().deref() {
|
||||||
|
v.on_remove();
|
||||||
v.mark_for_deletion();
|
v.mark_for_deletion();
|
||||||
}
|
}
|
||||||
if !self.script.is_locked() {
|
if !self.script.is_locked() {
|
||||||
|
@ -207,7 +213,19 @@ impl ScriptContainer {
|
||||||
|
|
||||||
impl From<ScriptHolder> for ScriptContainer {
|
impl From<ScriptHolder> for ScriptContainer {
|
||||||
fn from(a: ScriptHolder) -> Self {
|
fn from(a: ScriptHolder) -> Self {
|
||||||
Self { script: a }
|
Self {
|
||||||
|
script: a,
|
||||||
|
join_handle: RwLock::new(None),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Clone for ScriptContainer {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
Self {
|
||||||
|
script: self.script.clone(),
|
||||||
|
join_handle: RwLock::new(None),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -215,8 +233,6 @@ impl From<ScriptHolder> for ScriptContainer {
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use std::sync::atomic::{AtomicBool, AtomicPtr};
|
use std::sync::atomic::{AtomicBool, AtomicPtr};
|
||||||
use std::thread::sleep;
|
|
||||||
use std::time::Duration;
|
|
||||||
|
|
||||||
pub struct TestScript {
|
pub struct TestScript {
|
||||||
name: StringKey,
|
name: StringKey,
|
||||||
|
@ -361,7 +377,12 @@ mod tests {
|
||||||
.downcast_ref::<ReplaceTestScript>()
|
.downcast_ref::<ReplaceTestScript>()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.test(script2);
|
.test(script2);
|
||||||
sleep(Duration::from_micros(500));
|
let mut jh = container.join_handle.write();
|
||||||
|
if jh.is_some() {
|
||||||
|
let h = jh.take().unwrap();
|
||||||
|
h.join().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
container.script.read().as_ref().unwrap().name(),
|
container.script.read().as_ref().unwrap().name(),
|
||||||
&StringKey::new("script2")
|
&StringKey::new("script2")
|
||||||
|
|
Loading…
Reference in New Issue