Compare commits

...

1 Commits

10 changed files with 98 additions and 34 deletions

View File

@@ -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

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -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();
});

View File

@@ -92,7 +92,7 @@ function setFileInputBinding(fileInputBinding_: FileInputBinding): void {
fileInputBinding = fileInputBinding_;
}
function getShinyCreateWebsocket(): (() => WebSocket) | void {
function getShinyCreateWebsocket(): (() => Promise<WebSocket>) | void {
return validateShinyHasBeenSet().createSocket;
}

View File

@@ -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);
}

View File

@@ -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;

View File

@@ -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, };

View File

@@ -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;