Skip to content

Commit

Permalink
fix: sessionId management (#2862)
Browse files Browse the repository at this point in the history
moves sessionId to be held in sessionStorage to provide a stable id for the lifetime of the browser tab
  • Loading branch information
gavinbarron authored Nov 17, 2023
1 parent f278f22 commit e8fbbea
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -369,8 +369,8 @@ export class GraphNotificationClient {
}

public async subscribeToChatNotifications(chatId: string, sessionId: string) {
// if we have a "previous" chat state at present, unsubscribe
if (this.chatId && this.sessionId && chatId !== this.chatId && sessionId !== this.sessionId) {
// if we have a "previous" chat state at present, unsubscribe for the previous chatId
if (this.chatId && this.sessionId && chatId !== this.chatId) {
await this.unsubscribeFromChatNotifications(this.chatId, this.sessionId);
}
this.chatId = chatId;
Expand Down
42 changes: 37 additions & 5 deletions packages/mgt-chat/src/statefulClient/useGraphChatClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,45 @@ import { v4 as uuid } from 'uuid';
import { StatefulGraphChatClient } from './StatefulGraphChatClient';
import { log } from '@microsoft/mgt-element';

/**
* The key name to use for storing the sessionId in session storage
*/
const keyName = 'mgt-chat-session-id';

/**
* reads a string from session storage, or if there is no string for the keyName, generate a new uuid and place in storage
*/
const getOrGenerateSessionId = () => {
const value = sessionStorage.getItem(keyName);

if (value) {
return value;
} else {
const newValue = uuid();
sessionStorage.setItem(keyName, newValue);
return newValue;
}
};

/**
* Provides a stable sessionId for the lifetime of the browser tab.
* @returns a string that is either read from session storage or generated and placed in session storage
*/
const useSessionId = (): string => {
// when a function is passed to useState, it is only invoked on the first render
const [sessionId] = useState<string>(getOrGenerateSessionId);

return sessionId;
};

/**
* Custom hook to abstract the creation of a stateful graph chat client.
* @param {string} chatId the current chatId to be rendered
* @returns {StatefulGraphChatClient} a stateful graph chat client that is subscribed to the given chatId
*/
export const useGraphChatClient = (chatId: string): StatefulGraphChatClient => {
const [sessionId, setSessionId] = useState<string | undefined>();
const sessionId = useSessionId();
const [chatClient] = useState<StatefulGraphChatClient>(() => new StatefulGraphChatClient());
// generate a new sessionId when the chatId changes
useEffect(() => {
setSessionId(uuid());
}, [chatId]);

// when chatId or sessionId changes this effect subscribes or unsubscribes
// the component to/from web socket based notifications for the given chatId
Expand Down

0 comments on commit e8fbbea

Please sign in to comment.