mirror of
https://github.com/rstudio/shiny.git
synced 2026-01-11 07:58:11 -05:00
Compare commits
1 Commits
schloerke-
...
fix-cswsh
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
42b40e2fd1 |
@@ -6433,10 +6433,10 @@ ${duplicateIdMsg}`;
|
||||
};
|
||||
this._init();
|
||||
}
|
||||
connect(initialInput) {
|
||||
async connect(initialInput) {
|
||||
if (this.$socket)
|
||||
throw "Connect was already called on this application object";
|
||||
this.$socket = this.createSocket();
|
||||
this.$socket = await this.createSocket();
|
||||
this.$initialInput = initialInput;
|
||||
import_jquery38.default.extend(this.$inputValues, initialInput);
|
||||
this.$updateConditionals();
|
||||
@@ -6444,16 +6444,16 @@ ${duplicateIdMsg}`;
|
||||
isConnected() {
|
||||
return !!this.$socket;
|
||||
}
|
||||
reconnect() {
|
||||
async reconnect() {
|
||||
clearTimeout(this.scheduledReconnect);
|
||||
if (this.isConnected())
|
||||
throw "Attempted to reconnect, but already connected.";
|
||||
this.$socket = this.createSocket();
|
||||
this.$socket = await this.createSocket();
|
||||
this.$initialInput = import_jquery38.default.extend({}, this.$inputValues);
|
||||
this.$updateConditionals();
|
||||
}
|
||||
createSocket() {
|
||||
const createSocketFunc = getShinyCreateWebsocket() || (() => {
|
||||
async createSocket() {
|
||||
const createSocketFunc = getShinyCreateWebsocket() || (async () => {
|
||||
let protocol = "ws:";
|
||||
if (window.location.protocol === "https:")
|
||||
protocol = "wss:";
|
||||
@@ -6467,13 +6467,17 @@ ${duplicateIdMsg}`;
|
||||
if (!/\/$/.test(defaultPath))
|
||||
defaultPath += "/";
|
||||
defaultPath += "websocket/";
|
||||
const sessionId = await this.$getSessionId();
|
||||
if (sessionId) {
|
||||
defaultPath += "?session_id=" + sessionId;
|
||||
}
|
||||
const ws = new WebSocket(
|
||||
protocol + "//" + window.location.host + defaultPath
|
||||
);
|
||||
ws.binaryType = "arraybuffer";
|
||||
return ws;
|
||||
});
|
||||
const socket = createSocketFunc();
|
||||
const socket = await createSocketFunc();
|
||||
let hasOpened = false;
|
||||
socket.onopen = () => {
|
||||
hasOpened = true;
|
||||
@@ -6511,6 +6515,26 @@ ${duplicateIdMsg}`;
|
||||
};
|
||||
return socket;
|
||||
}
|
||||
async $getSessionId() {
|
||||
if (this.config) {
|
||||
return this.config.sessionId;
|
||||
}
|
||||
try {
|
||||
const response = await fetch("/new_shiny_session/");
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
return data.session_id;
|
||||
}
|
||||
if (response.status === 404) {
|
||||
return null;
|
||||
}
|
||||
console.error("Error fetching session ID:", response);
|
||||
return null;
|
||||
} catch (error) {
|
||||
console.error("Error fetching session ID:", error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
async startActionQueueLoop() {
|
||||
while (true) {
|
||||
try {
|
||||
@@ -6540,8 +6564,8 @@ ${duplicateIdMsg}`;
|
||||
this.$socket = null;
|
||||
}
|
||||
$scheduleReconnect(delay) {
|
||||
this.scheduledReconnect = window.setTimeout(() => {
|
||||
this.reconnect();
|
||||
this.scheduledReconnect = window.setTimeout(async () => {
|
||||
await this.reconnect();
|
||||
}, delay);
|
||||
}
|
||||
onDisconnected(reloading = false) {
|
||||
@@ -7579,7 +7603,7 @@ ${duplicateIdMsg}`;
|
||||
}
|
||||
});
|
||||
inputsNoResend.reset(initialValues);
|
||||
shinyapp.connect(initialValues);
|
||||
await shinyapp.connect(initialValues);
|
||||
(0, import_jquery39.default)(document).one("shiny:connected", () => {
|
||||
initDeferredIframes();
|
||||
});
|
||||
|
||||
File diff suppressed because one or more lines are too long
2
inst/www/shared/shiny.min.js
vendored
2
inst/www/shared/shiny.min.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -82,7 +82,7 @@ class ShinyClass {
|
||||
addCustomMessageHandler: typeof addCustomMessageHandler;
|
||||
|
||||
// The following are added in the initialization, by initShiny()
|
||||
createSocket?: () => WebSocket;
|
||||
createSocket?: () => Promise<WebSocket>;
|
||||
user?: string;
|
||||
progressHandlers?: ShinyApp["progressHandlers"];
|
||||
shinyapp?: ShinyApp;
|
||||
@@ -669,7 +669,7 @@ class ShinyClass {
|
||||
|
||||
// We've collected all the initial values--start the server process!
|
||||
inputsNoResend.reset(initialValues);
|
||||
shinyapp.connect(initialValues);
|
||||
await shinyapp.connect(initialValues);
|
||||
$(document).one("shiny:connected", () => {
|
||||
initDeferredIframes();
|
||||
});
|
||||
|
||||
@@ -92,7 +92,7 @@ function setFileInputBinding(fileInputBinding_: FileInputBinding): void {
|
||||
fileInputBinding = fileInputBinding_;
|
||||
}
|
||||
|
||||
function getShinyCreateWebsocket(): (() => WebSocket) | void {
|
||||
function getShinyCreateWebsocket(): (() => Promise<WebSocket>) | void {
|
||||
return validateShinyHasBeenSet().createSocket;
|
||||
}
|
||||
|
||||
|
||||
@@ -159,11 +159,11 @@ class ShinyApp {
|
||||
this._init();
|
||||
}
|
||||
|
||||
connect(initialInput: InputValues): void {
|
||||
async connect(initialInput: InputValues): Promise<void> {
|
||||
if (this.$socket)
|
||||
throw "Connect was already called on this application object";
|
||||
|
||||
this.$socket = this.createSocket();
|
||||
this.$socket = await this.createSocket();
|
||||
this.$initialInput = initialInput;
|
||||
$.extend(this.$inputValues, initialInput);
|
||||
|
||||
@@ -176,7 +176,7 @@ class ShinyApp {
|
||||
|
||||
private scheduledReconnect: number | undefined = undefined;
|
||||
|
||||
reconnect(): void {
|
||||
async reconnect(): Promise<void> {
|
||||
// This function can be invoked directly even if there's a scheduled
|
||||
// reconnect, so be sure to clear any such scheduled reconnects.
|
||||
clearTimeout(this.scheduledReconnect);
|
||||
@@ -184,15 +184,15 @@ class ShinyApp {
|
||||
if (this.isConnected())
|
||||
throw "Attempted to reconnect, but already connected.";
|
||||
|
||||
this.$socket = this.createSocket();
|
||||
this.$socket = await this.createSocket();
|
||||
this.$initialInput = $.extend({}, this.$inputValues);
|
||||
this.$updateConditionals();
|
||||
}
|
||||
|
||||
createSocket(): ShinyWebSocket {
|
||||
const createSocketFunc: () => ShinyWebSocket =
|
||||
async createSocket(): Promise<ShinyWebSocket> {
|
||||
const createSocketFunc: () => Promise<ShinyWebSocket> =
|
||||
getShinyCreateWebsocket() ||
|
||||
(() => {
|
||||
(async () => {
|
||||
let protocol = "ws:";
|
||||
|
||||
if (window.location.protocol === "https:") protocol = "wss:";
|
||||
@@ -211,6 +211,12 @@ class ShinyApp {
|
||||
if (!/\/$/.test(defaultPath)) defaultPath += "/";
|
||||
defaultPath += "websocket/";
|
||||
|
||||
const sessionId = await this.$getSessionId();
|
||||
if (sessionId) {
|
||||
defaultPath += "?session_id=" + sessionId;
|
||||
}
|
||||
|
||||
// Fail gracefully if the server does not support this endpoint
|
||||
const ws: ShinyWebSocket = new WebSocket(
|
||||
protocol + "//" + window.location.host + defaultPath
|
||||
);
|
||||
@@ -220,7 +226,7 @@ class ShinyApp {
|
||||
return ws;
|
||||
});
|
||||
|
||||
const socket = createSocketFunc();
|
||||
const socket = await createSocketFunc();
|
||||
let hasOpened = false;
|
||||
|
||||
socket.onopen = () => {
|
||||
@@ -277,6 +283,39 @@ class ShinyApp {
|
||||
return socket;
|
||||
}
|
||||
|
||||
async $getSessionId(): Promise<string | null> {
|
||||
// If the session ID has been received through a websocket message,
|
||||
// no need to create a new one.
|
||||
if (this.config) {
|
||||
return this.config.sessionId;
|
||||
}
|
||||
|
||||
// Fetch this client's session ID from the server. When successful, the
|
||||
// server will require a (valid) session ID when establishing a websocket
|
||||
// connection.
|
||||
try {
|
||||
const response = await fetch("/new_shiny_session/");
|
||||
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
return data.session_id;
|
||||
}
|
||||
|
||||
// If the endpoint doesn't exist, then a session ID isn't required
|
||||
// to establish a websocket connection.
|
||||
if (response.status === 404) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// If other problems happen, we probably want to know about it.
|
||||
console.error("Error fetching session ID:", response);
|
||||
return null;
|
||||
} catch (error) {
|
||||
console.error("Error fetching session ID:", error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
async startActionQueueLoop(): Promise<void> {
|
||||
// eslint-disable-next-line no-constant-condition
|
||||
while (true) {
|
||||
@@ -314,8 +353,8 @@ class ShinyApp {
|
||||
}
|
||||
|
||||
$scheduleReconnect(delay: Parameters<typeof setTimeout>[1]): void {
|
||||
this.scheduledReconnect = window.setTimeout(() => {
|
||||
this.reconnect();
|
||||
this.scheduledReconnect = window.setTimeout(async () => {
|
||||
await this.reconnect();
|
||||
}, delay);
|
||||
}
|
||||
|
||||
|
||||
2
srcts/types/src/shiny/index.d.ts
vendored
2
srcts/types/src/shiny/index.d.ts
vendored
@@ -35,7 +35,7 @@ declare class ShinyClass {
|
||||
renderHtmlAsync: typeof renderHtmlAsync;
|
||||
renderHtml: typeof renderHtml;
|
||||
addCustomMessageHandler: typeof addCustomMessageHandler;
|
||||
createSocket?: () => WebSocket;
|
||||
createSocket?: () => Promise<WebSocket>;
|
||||
user?: string;
|
||||
progressHandlers?: ShinyApp["progressHandlers"];
|
||||
shinyapp?: ShinyApp;
|
||||
|
||||
2
srcts/types/src/shiny/initedMethods.d.ts
vendored
2
srcts/types/src/shiny/initedMethods.d.ts
vendored
@@ -19,5 +19,5 @@ declare function shinyAppUnbindOutput(id: string, binding: OutputBindingAdapter)
|
||||
declare function getShinyOnCustomMessage(): Handler | null;
|
||||
declare function getFileInputBinding(): FileInputBinding;
|
||||
declare function setFileInputBinding(fileInputBinding_: FileInputBinding): void;
|
||||
declare function getShinyCreateWebsocket(): (() => WebSocket) | void;
|
||||
declare function getShinyCreateWebsocket(): (() => Promise<WebSocket>) | void;
|
||||
export { setShinyObj, shinySetInputValue, shinyShinyApp, setShinyUser, shinyForgetLastInputValue, shinyBindAll, shinyUnbindAll, shinyInitializeInputs, shinyAppBindOutput, shinyAppUnbindOutput, getShinyOnCustomMessage, getFileInputBinding, setFileInputBinding, getShinyCreateWebsocket, };
|
||||
|
||||
7
srcts/types/src/shiny/shinyapp.d.ts
vendored
7
srcts/types/src/shiny/shinyapp.d.ts
vendored
@@ -52,11 +52,12 @@ declare class ShinyApp {
|
||||
$nextRequestId: number;
|
||||
$allowReconnect: boolean | "force";
|
||||
constructor();
|
||||
connect(initialInput: InputValues): void;
|
||||
connect(initialInput: InputValues): Promise<void>;
|
||||
isConnected(): boolean;
|
||||
private scheduledReconnect;
|
||||
reconnect(): void;
|
||||
createSocket(): ShinyWebSocket;
|
||||
reconnect(): Promise<void>;
|
||||
createSocket(): Promise<ShinyWebSocket>;
|
||||
$getSessionId(): Promise<string | null>;
|
||||
startActionQueueLoop(): Promise<void>;
|
||||
sendInput(values: InputValues): void;
|
||||
$notifyDisconnected(): void;
|
||||
|
||||
Reference in New Issue
Block a user