Compare commits

...

5 Commits

Author SHA1 Message Date
Lendemor
d2b183e3f9 Merge branch 'main' into lendemor/fix_duplicate_tab_issue 2025-02-20 15:12:04 +01:00
Lendemor
2f215a350e fix issue 2025-01-09 16:21:35 +01:00
Lendemor
2825500e26 review changes 2025-01-09 11:22:40 +01:00
Lendemor
41d8cfae57 Merge branch 'main' into lendemor/fix_duplicate_tab_issue 2025-01-08 17:20:06 +01:00
Lendemor
b11328160a fix duplicate tab issue 2025-01-08 17:17:34 +01:00
2 changed files with 42 additions and 21 deletions

View File

@ -227,8 +227,8 @@ export const applyEvent = async (event, socket) => {
a.href = eval?.( a.href = eval?.(
event.payload.url.replace( event.payload.url.replace(
"getBackendURL(env.UPLOAD)", "getBackendURL(env.UPLOAD)",
`"${getBackendURL(env.UPLOAD)}"`, `"${getBackendURL(env.UPLOAD)}"`
), )
); );
} }
a.download = event.payload.filename; a.download = event.payload.filename;
@ -341,7 +341,7 @@ export const applyRestEvent = async (event, socket) => {
event.payload.files, event.payload.files,
event.payload.upload_id, event.payload.upload_id,
event.payload.on_upload_progress, event.payload.on_upload_progress,
socket, socket
); );
return false; return false;
} }
@ -408,7 +408,7 @@ export const connect = async (
dispatch, dispatch,
transports, transports,
setConnectErrors, setConnectErrors,
client_storage = {}, client_storage = {}
) => { ) => {
// Get backend URL object from the endpoint. // Get backend URL object from the endpoint.
const endpoint = getBackendURL(EVENTURL); const endpoint = getBackendURL(EVENTURL);
@ -419,6 +419,7 @@ export const connect = async (
transports: transports, transports: transports,
protocols: [reflexEnvironment.version], protocols: [reflexEnvironment.version],
autoUnref: false, autoUnref: false,
query: { token: getToken() },
}); });
// Ensure undefined fields in events are sent as null instead of removed // Ensure undefined fields in events are sent as null instead of removed
socket.current.io.encoder.replacer = (k, v) => (v === undefined ? null : v); socket.current.io.encoder.replacer = (k, v) => (v === undefined ? null : v);
@ -479,6 +480,10 @@ export const connect = async (
event_processing = false; event_processing = false;
queueEvents([...initialEvents(), event], socket); queueEvents([...initialEvents(), event], socket);
}); });
socket.current.on("new_token", async (new_token) => {
token = new_token;
window.sessionStorage.setItem(TOKEN_KEY, new_token);
});
document.addEventListener("visibilitychange", checkVisibility); document.addEventListener("visibilitychange", checkVisibility);
}; };
@ -499,7 +504,7 @@ export const uploadFiles = async (
files, files,
upload_id, upload_id,
on_upload_progress, on_upload_progress,
socket, socket
) => { ) => {
// return if there's no file to upload // return if there's no file to upload
if (files === undefined || files.length === 0) { if (files === undefined || files.length === 0) {
@ -604,7 +609,7 @@ export const Event = (
name, name,
payload = {}, payload = {},
event_actions = {}, event_actions = {},
handler = null, handler = null
) => { ) => {
return { name, payload, handler, event_actions }; return { name, payload, handler, event_actions };
}; };
@ -631,7 +636,7 @@ export const hydrateClientStorage = (client_storage) => {
for (const state_key in client_storage.local_storage) { for (const state_key in client_storage.local_storage) {
const options = client_storage.local_storage[state_key]; const options = client_storage.local_storage[state_key];
const local_storage_value = localStorage.getItem( const local_storage_value = localStorage.getItem(
options.name || state_key, options.name || state_key
); );
if (local_storage_value !== null) { if (local_storage_value !== null) {
client_storage_values[state_key] = local_storage_value; client_storage_values[state_key] = local_storage_value;
@ -642,7 +647,7 @@ export const hydrateClientStorage = (client_storage) => {
for (const state_key in client_storage.session_storage) { for (const state_key in client_storage.session_storage) {
const session_options = client_storage.session_storage[state_key]; const session_options = client_storage.session_storage[state_key];
const session_storage_value = sessionStorage.getItem( const session_storage_value = sessionStorage.getItem(
session_options.name || state_key, session_options.name || state_key
); );
if (session_storage_value != null) { if (session_storage_value != null) {
client_storage_values[state_key] = session_storage_value; client_storage_values[state_key] = session_storage_value;
@ -667,7 +672,7 @@ export const hydrateClientStorage = (client_storage) => {
const applyClientStorageDelta = (client_storage, delta) => { const applyClientStorageDelta = (client_storage, delta) => {
// find the main state and check for is_hydrated // find the main state and check for is_hydrated
const unqualified_states = Object.keys(delta).filter( const unqualified_states = Object.keys(delta).filter(
(key) => key.split(".").length === 1, (key) => key.split(".").length === 1
); );
if (unqualified_states.length === 1) { if (unqualified_states.length === 1) {
const main_state = delta[unqualified_states[0]]; const main_state = delta[unqualified_states[0]];
@ -701,7 +706,7 @@ const applyClientStorageDelta = (client_storage, delta) => {
const session_options = client_storage.session_storage[state_key]; const session_options = client_storage.session_storage[state_key];
sessionStorage.setItem( sessionStorage.setItem(
session_options.name || state_key, session_options.name || state_key,
delta[substate][key], delta[substate][key]
); );
} }
} }
@ -721,7 +726,7 @@ const applyClientStorageDelta = (client_storage, delta) => {
export const useEventLoop = ( export const useEventLoop = (
dispatch, dispatch,
initial_events = () => [], initial_events = () => [],
client_storage = {}, client_storage = {}
) => { ) => {
const socket = useRef(null); const socket = useRef(null);
const router = useRouter(); const router = useRouter();
@ -735,7 +740,7 @@ export const useEventLoop = (
event_actions = events.reduce( event_actions = events.reduce(
(acc, e) => ({ ...acc, ...e.event_actions }), (acc, e) => ({ ...acc, ...e.event_actions }),
event_actions ?? {}, event_actions ?? {}
); );
const _e = args.filter((o) => o?.preventDefault !== undefined)[0]; const _e = args.filter((o) => o?.preventDefault !== undefined)[0];
@ -763,7 +768,7 @@ export const useEventLoop = (
debounce( debounce(
combined_name, combined_name,
() => queueEvents(events, socket), () => queueEvents(events, socket),
event_actions.debounce, event_actions.debounce
); );
} else { } else {
queueEvents(events, socket); queueEvents(events, socket);
@ -782,7 +787,7 @@ export const useEventLoop = (
query, query,
asPath, asPath,
}))(router), }))(router),
})), }))
); );
sentHydrate.current = true; sentHydrate.current = true;
} }
@ -828,7 +833,7 @@ export const useEventLoop = (
dispatch, dispatch,
["websocket"], ["websocket"],
setConnectErrors, setConnectErrors,
client_storage, client_storage
); );
} }
} }
@ -876,7 +881,7 @@ export const useEventLoop = (
vars[storage_to_state_map[e.key]] = e.newValue; vars[storage_to_state_map[e.key]] = e.newValue;
const event = Event( const event = Event(
`${state_name}.reflex___state____update_vars_internal_state.update_vars_internal`, `${state_name}.reflex___state____update_vars_internal_state.update_vars_internal`,
{ vars: vars }, { vars: vars }
); );
addEvents([event], e); addEvents([event], e);
} }
@ -969,7 +974,7 @@ export const getRefValues = (refs) => {
return refs.map((ref) => return refs.map((ref) =>
ref.current ref.current
? ref.current.value || ref.current.getAttribute("aria-valuenow") ? ref.current.value || ref.current.getAttribute("aria-valuenow")
: null, : null
); );
}; };

View File

@ -13,6 +13,8 @@ import io
import json import json
import sys import sys
import traceback import traceback
import urllib.parse
import uuid
from datetime import datetime from datetime import datetime
from pathlib import Path from pathlib import Path
from timeit import default_timer as timer from timeit import default_timer as timer
@ -1834,13 +1836,16 @@ class EventNamespace(AsyncNamespace):
self.sid_to_token = {} self.sid_to_token = {}
self.app = app self.app = app
def on_connect(self, sid: str, environ: dict): async def on_connect(self, sid: str, environ: dict):
"""Event for when the websocket is connected. """Event for when the websocket is connected.
Args: Args:
sid: The Socket.IO session id. sid: The Socket.IO session id.
environ: The request information, including HTTP headers. environ: The request information, including HTTP headers.
""" """
query_params = urllib.parse.parse_qs(environ.get("QUERY_STRING"))
await self.link_token_to_sid(sid, query_params.get("token", [])[0])
subprotocol = environ.get("HTTP_SEC_WEBSOCKET_PROTOCOL") subprotocol = environ.get("HTTP_SEC_WEBSOCKET_PROTOCOL")
if subprotocol and subprotocol != constants.Reflex.VERSION: if subprotocol and subprotocol != constants.Reflex.VERSION:
console.warn( console.warn(
@ -1909,9 +1914,6 @@ class EventNamespace(AsyncNamespace):
f"Failed to deserialize event data: {fields}." f"Failed to deserialize event data: {fields}."
) from ex ) from ex
self.token_to_sid[event.token] = sid
self.sid_to_token[sid] = event.token
# Get the event environment. # Get the event environment.
if self.app.sio is None: if self.app.sio is None:
raise RuntimeError("Socket.IO is not initialized.") raise RuntimeError("Socket.IO is not initialized.")
@ -1944,3 +1946,17 @@ class EventNamespace(AsyncNamespace):
""" """
# Emit the test event. # Emit the test event.
await self.emit(str(constants.SocketEvent.PING), "pong", to=sid) await self.emit(str(constants.SocketEvent.PING), "pong", to=sid)
async def link_token_to_sid(self, sid: str, token: str):
"""Link a token to a session id.
Args:
sid: The Socket.IO session id.
token: The client token.
"""
if token in self.sid_to_token.values() and sid != self.token_to_sid.get(token):
token = str(uuid.uuid4())
await self.emit("new_token", token, to=sid)
self.token_to_sid[token] = sid
self.sid_to_token[sid] = token