DEV: Use online/offline window events to track network connectivity (#22243)

This commit is contained in:
Mark VanLandingham 2023-06-22 09:09:28 -05:00 committed by GitHub
parent dccdbd52a3
commit fcaa9757f3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 79 additions and 57 deletions

View File

@ -3,10 +3,10 @@ import { action } from "@ember/object";
import { inject as service } from "@ember/service";
export default class OfflineIndicator extends Component {
@service messageBusConnectivity;
@service networkConnectivity;
get showing() {
return !this.messageBusConnectivity.connected;
return !this.networkConnectivity.connected;
}
@action

View File

@ -6,16 +6,12 @@ import userPresent, { onPresenceChange } from "discourse/lib/user-presence";
const LONG_POLL_AFTER_UNSEEN_TIME = 1200000; // 20 minutes
function ajax(opts, messageBusConnectivity, appState) {
function ajax(opts) {
if (opts.complete) {
const oldComplete = opts.complete;
opts.complete = function (xhr, stat) {
handleLogoff(xhr);
oldComplete(xhr, stat);
messageBusConnectivity.setConnectivity(
xhr.readyState === 4 || stat === "abort" || appState.background
);
};
} else {
opts.complete = handleLogoff;
@ -35,9 +31,7 @@ export default {
const messageBus = owner.lookup("service:message-bus"),
user = owner.lookup("service:current-user"),
siteSettings = owner.lookup("service:site-settings"),
appState = owner.lookup("service:app-state"),
messageBusConnectivity = owner.lookup("service:message-bus-connectivity");
siteSettings = owner.lookup("service:site-settings");
messageBus.alwaysLongPoll = !isProduction();
messageBus.shouldLongPollCallback = () =>
@ -92,7 +86,7 @@ export default {
if (userPresent()) {
opts.headers["Discourse-Present"] = "true";
}
return ajax(opts, messageBusConnectivity, appState);
return ajax(opts);
};
} else {
messageBus.ajax = function (opts) {
@ -100,7 +94,7 @@ export default {
if (userPresent()) {
opts.headers["Discourse-Present"] = "true";
}
return ajax(opts, messageBusConnectivity, appState);
return ajax(opts);
};
messageBus.baseUrl = getURL("/");

View File

@ -1,28 +0,0 @@
import Service, { inject as service } from "@ember/service";
export default class AppState extends Service {
@service capabilities;
constructor() {
super(...arguments);
if (this.capabilities.isAppWebview) {
window.addEventListener("AppStateChange", (event) => {
// Possible states: "active", "inactive", and "background"
this._state = event.detail?.newAppState;
});
}
}
get active() {
return this._state === "active";
}
get inactive() {
return this._state === "inactive";
}
get background() {
return this._state === "background";
}
}

View File

@ -1,17 +0,0 @@
import Service from "@ember/service";
import { tracked } from "@glimmer/tracking";
const CONNECTIVITY_ERROR_CLASS = "message-bus-offline";
export default class MessageBusConnectivity extends Service {
@tracked connected = true;
setConnectivity(connected) {
this.connected = connected;
document.documentElement.classList.toggle(
CONNECTIVITY_ERROR_CLASS,
!connected
);
}
}

View File

@ -0,0 +1,47 @@
import Service from "@ember/service";
import { ajax } from "discourse/lib/ajax";
import { tracked } from "@glimmer/tracking";
const CONNECTIVITY_ERROR_CLASS = "network-disconnected";
export default class NetworkConnectivity extends Service {
@tracked connected = true;
constructor() {
super(...arguments);
this.setConnectivity(navigator.onLine);
window.addEventListener("offline", () => {
this.handleConnectivityChangeEvent(false);
});
window.addEventListener("online", () => {
this.handleConnectivityChangeEvent(true);
});
}
handleConnectivityChangeEvent(connected) {
if (connected) {
// Make a super cheap request to the server. If we get a response, we are connected!
return ajax("/srv/status", { dataType: "text" })
.then((response) => {
this.setConnectivity(response === "ok");
})
.catch(() => {
this.setConnectivity(false);
});
} else {
this.setConnectivity(false);
}
}
setConnectivity(connected) {
this.connected = connected;
document.documentElement.classList.toggle(
CONNECTIVITY_ERROR_CLASS,
!connected
);
}
}

View File

@ -0,0 +1,26 @@
# frozen_string_literal: true
RSpec.describe "Network Disconnected", type: :system do
def with_network_disconnected
page.driver.browser.network_conditions = { offline: true }
yield
page.driver.browser.network_conditions = { offline: false }
end
it "NetworkConnectivity service adds class to DOM and displays offline indicator" do
SiteSetting.enable_offline_indicator = true
visit("/c")
expect(page).to have_no_css("html.network-disconnected")
expect(page).to have_no_css(".offline-indicator")
with_network_disconnected do
# Message bus connectivity services adds the disconnected class to the DOM
expect(page).to have_css("html.network-disconnected")
# Offline indicator is rendered
expect(page).to have_css(".offline-indicator")
end
end
end