Skip to content

Commit

Permalink
feat: Notification to prompt users to download hosts
Browse files Browse the repository at this point in the history
  • Loading branch information
Frederick888 committed Jan 24, 2024
1 parent 79b18db commit da42d61
Show file tree
Hide file tree
Showing 3 changed files with 125 additions and 3 deletions.
35 changes: 33 additions & 2 deletions extension/background.js
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ async function composeActionListener(tab, info) {
composeDetails.attachments = JSON.parse(JSON.stringify(attachments))
const request = {
configuration: {
version: manifest.version,
version,
shell: settings.shell,
template: settings.template,
temporaryDirectory: settings.temporaryDirectory,
Expand All @@ -125,9 +125,12 @@ async function composeActionListener(tab, info) {
}

async function nativeMessagingPing() {
const settings = await browser.storage.local.get(['bypassVersionCheck'])
await browser.storage.local.remove(['healthy'])
const request = {
ping: Date.now()
ping: Date.now(),
bypassVersionCheck: !!settings.bypassVersionCheck,
version,
}
console.debug(`${manifest.short_name} sending: `, request)
// no notifications for now. only used to show the Wiki link in options.
Expand All @@ -140,6 +143,24 @@ async function nativeMessagingListener(response) {
await browser.storage.local.set({
healthy: response.ping === response.pong,
})
if (!response.compatible) {
// unfortunately we have to check the setting again on top of response.compatible.
// when this is released, we want users to see it ASAP, so while response.compatible already takes bypassVersionCheck into account,
// the extension still needs to act according to the setting even if response.compatible is missing.
const settings = await browser.storage.local.get(['bypassVersionCheck'])
if (!settings.bypassVersionCheck) {
let message = ''
if (response.hostVersion) {
message = `Extension version is ${version} while host version is ${response.hostVersion}.\n`
}
message += 'Click here to download the compatible messaging host. (Please restart Thunderbird manually afterwards.)'
createBasicNotification(
'download-host',
`${manifest.short_name} messaging host may be incompatible!`,
message
)
}
}
} else if (response.title && response.message) {
await createBasicNotification('', response.title, response.message)
if (response.reset === true) {
Expand Down Expand Up @@ -192,6 +213,15 @@ async function nativeMessagingDisconnectListener(p) {
await createBasicNotification('port', `${manifest.short_name} messaging host disconnected`, message)
}

async function notificationOnClickListener(notificationId) {
if (notificationId != 'download-host') {
return
}
browser.tabs.create({
url: 'https://github.com/Frederick888/external-editor-revived/releases',
})
}

function toPlainObject(o) {
// https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Chrome_incompatibilities#data_cloning_algorithm
// Extension that rely on the toJSON() method of the JSON serialization
Expand Down Expand Up @@ -235,6 +265,7 @@ async function createBasicNotification(id, title, message, eventTime = 5000) {
messenger.commands.onCommand.addListener(commandListener)
messenger.browserAction.onClicked.addListener(browserActionListener)
messenger.composeAction.onClicked.addListener(composeActionListener)
browser.notifications.onClicked.addListener(notificationOnClickListener)
port.onMessage.addListener(nativeMessagingListener)
port.onDisconnect.addListener(nativeMessagingDisconnectListener)

Expand Down
71 changes: 70 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ where
T: transport::Transport,
{
request.pong = request.ping;
request.host_version = env!("CARGO_PKG_VERSION").to_string();
request.compatible = request.bypass_version_check
|| util::is_extension_compatible(env!("CARGO_PKG_VERSION"), &request.version);
if let Err(write_error) = T::write_message(&request) {
eprintln!("ExtEditorR failed to send response to Thunderbird: {write_error}");
}
Expand Down Expand Up @@ -232,7 +235,73 @@ mod tests {
let _guard = WRITE_MESSAGE_CONTEXT_LOCK.lock().unwrap();
let ctx = MockTr::write_message_context();
ctx.expect::<Ping>()
.withf(|p: &Ping| p.ping == 123456 && p.pong == 123456)
.withf(|p: &Ping| p.ping == 123456 && p.pong == 123456 && p.compatible)
.returning(|&_| Ok(()));
handle_ping::<MockTr>(ping);
ctx.checkpoint();
}

#[test]
fn ping_pong_successful_version_check_test() {
let host_version = env!("CARGO_PKG_VERSION");
let ping_json = format!(
r#"{{"ping": 123456, "bypassVersionCheck": false, "version": "{}"}}"#,
host_version
);
let ping: Ping = serde_json::from_str(&ping_json).unwrap();

let _guard = WRITE_MESSAGE_CONTEXT_LOCK.lock().unwrap();
let ctx = MockTr::write_message_context();
ctx.expect::<Ping>()
.withf(|p: &Ping| {
let host_version = host_version.to_string();
p.ping == 123456
&& p.pong == 123456
&& p.compatible
&& p.host_version == host_version
})
.returning(|&_| Ok(()));
handle_ping::<MockTr>(ping);
ctx.checkpoint();
}

#[test]
fn ping_pong_failed_version_check_test() {
let host_version = env!("CARGO_PKG_VERSION");
let ping_json = r#"{"ping": 123456, "bypassVersionCheck": false, "version": "0.0.0.0"}"#;
let ping: Ping = serde_json::from_str(ping_json).unwrap();

let _guard = WRITE_MESSAGE_CONTEXT_LOCK.lock().unwrap();
let ctx = MockTr::write_message_context();
ctx.expect::<Ping>()
.withf(|p: &Ping| {
let host_version = host_version.to_string();
p.ping == 123456
&& p.pong == 123456
&& !p.compatible
&& p.host_version == host_version
})
.returning(|&_| Ok(()));
handle_ping::<MockTr>(ping);
ctx.checkpoint();
}

#[test]
fn ping_pong_bypass_failed_version_check_test() {
let host_version = env!("CARGO_PKG_VERSION");
let ping_json = r#"{"ping": 123456, "bypassVersionCheck": true, "version": "0.0.0.0"}"#;
let ping: Ping = serde_json::from_str(ping_json).unwrap();

let _guard = WRITE_MESSAGE_CONTEXT_LOCK.lock().unwrap();
let ctx = MockTr::write_message_context();
ctx.expect::<Ping>()
.withf(|p: &Ping| {
let host_version = host_version.to_string();
p.ping == 123456
&& p.pong == 123456
&& p.compatible
&& p.host_version == host_version
})
.returning(|&_| Ok(()));
handle_ping::<MockTr>(ping);
ctx.checkpoint();
Expand Down
22 changes: 22 additions & 0 deletions src/model/messaging.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,25 @@ pub enum Exchange {
}

#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Ping {
pub ping: u64,
#[serde(default)]
pub pong: u64,
// don't run this check as part of ping-pong if the extension is somehow older which does not
// send this attribute
#[serde(default = "default_as_true")]
pub bypass_version_check: bool,
#[serde(default)]
pub version: String,
#[serde(default)]
pub host_version: String,
#[serde(default)]
pub compatible: bool,
}

fn default_as_true() -> bool {
true
}

#[derive(Clone, Debug, Deserialize, Serialize)]
Expand Down Expand Up @@ -1213,6 +1228,13 @@ pub mod tests {
refute_contains!(output, "X-ExtEditorR-Help");
}

#[test]
fn default_ping_bypass_version_check_test() {
let ping_json = r#"{"ping": 123456}"#;
let ping: Ping = serde_json::from_str(ping_json).unwrap();
assert!(ping.bypass_version_check);
}

fn to_eml_and_assert(compose: &Compose) -> String {
let mut buf = Vec::new();
let result = compose.to_eml(&mut buf);
Expand Down

0 comments on commit da42d61

Please sign in to comment.