Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# Changelog

## [0.1.3]

- A system's sites: Trunk Recorder Pro now has systems with several sites, and a
call heard on more than one is saved once, in the system's folder. Scripts get
`SHORT_NAME`, `SITE` (the site the call was kept from) and `TALKGROUP` in
their environment, so one can tell sites apart without reading the JSON.
- Built with trunk-recorder-plugin 0.4.0.

## [0.1.2]

- A system can override the script and the time limit (a script set in the system's own settings still comes first).
Expand Down
6 changes: 3 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "upload-script"
version = "0.1.2"
version = "0.1.3"
edition = "2024"
description = "Runs a script of yours on each recorded call, as Trunk Recorder's uploadScript does."
license = "GPL-3.0-or-later"
Expand All @@ -9,7 +9,7 @@ authors = ["Luke Berndt <lukekb@gmail.com>"]
publish = false

[dependencies]
trunk-recorder-plugin = "0.3.0"
trunk-recorder-plugin = "0.4.0"
schemars = "1"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
Expand Down
9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ The M4A is there when the recorder has an M4A encoder (built into macOS;
install [ffmpeg](https://ffmpeg.org) elsewhere). Without one, the third path
is where it would be, and there's no file there.

In its environment: `SHORT_NAME` (the call's system), `SITE` (the site it was
kept from) and `TALKGROUP`, the same as in its JSON. A system can have several
sites, and a call heard on more than one is saved once, in the system's folder:
a script that told sites apart by their short name or folder can use `SITE`.

The script runs in the recorder's capture folder.

## When it fails
Expand All @@ -51,7 +56,9 @@ are kept, and run again when it starts. (Trunk Recorder never retries.)

Paste each system's `uploadScript` into its **Script** (or set one for all of
them), with the script's full path in place of `./`. The arguments are the
same, in the same order.
same, in the same order. Trunk Recorder systems that are sites of one system
(`multiSite`) are one system here, with one script: it can tell them apart by
`SITE`.

What becomes of the call's files afterwards is up to the recorder's
`audioArchive`, `callLog` and `archiveFilesOnFailure` settings, as in Trunk
Expand Down
16 changes: 15 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,10 @@ impl Plugin for UploadScript {
};
// (Where it would be, as Trunk Recorder passes it, when it couldn't be made.)
let m4a = call.files.m4a.clone().unwrap_or_else(|| call.files.wav.with_extension("m4a"));
script.run(&[&call.files.wav, &call.files.json, &m4a], &cwd, &log, &call.path)
// Which system, site and talkgroup, without reading the JSON (a system's sites share its folder).
let c = &call.call;
let env = [("SHORT_NAME", c.short_name.clone()), ("SITE", c.site.clone()), ("TALKGROUP", c.talkgroup.to_string())];
script.run(&[&call.files.wav, &call.files.json, &m4a], &env, &cwd, &log, &call.path)
});
Ok(UploadScript { queue })
}
Expand Down Expand Up @@ -156,6 +159,17 @@ mod tests {
assert_eq!(args.lines().collect::<Vec<_>>(), want);
}

/// A call heard on several sites of a system is its system's: the site it was kept from comes as SITE.
#[test]
fn the_system_site_and_talkgroup_in_its_environment() {
let dir = testing::temp_dir("upload-script");
let s = script(&dir, "up.sh", r#"echo "$SHORT_NAME $SITE $TALKGROUP" > "$(dirname "$0")/env.txt""#);
let mut call = testing::call(&dir, "sys1", 101);
call.call.site = "south".into();
testing::run::<UploadScript>([hello(&dir, json!({ "script": s }), Value::Null), HostMessage::CallConcluded(call)]);
assert_eq!(std::fs::read_to_string(dir.join("env.txt")).unwrap(), "sys1 south 101\n");
}

#[test]
fn a_failing_script_says_why() {
let dir = testing::temp_dir("upload-script");
Expand Down
6 changes: 4 additions & 2 deletions src/script.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,12 @@ impl Script {
Ok(Script { program, args: words, timeout, text: text.to_string() })
}

/// Run it with `files` after its own arguments, in `cwd`; `call`: for the log.
pub fn run(&self, files: &[&Path], cwd: &Path, log: &Host, call: &str) -> Attempt {
/// Run it with `files` after its own arguments and `env` in its
/// environment, in `cwd`; `call`: for the log.
pub fn run(&self, files: &[&Path], env: &[(&str, String)], cwd: &Path, log: &Host, call: &str) -> Attempt {
let mut c = Command::new(&self.program);
c.args(&self.args).args(files).current_dir(cwd).stdin(Stdio::null()).stdout(Stdio::piped()).stderr(Stdio::piped());
c.envs(env.iter().map(|(k, v)| (k, v)));
// A group of its own, so what it starts can be stopped with it.
#[cfg(unix)]
std::os::unix::process::CommandExt::process_group(&mut c, 0);
Expand Down
Loading