From 70f646444b9ed39798737851edc9b401c759a3d2 Mon Sep 17 00:00:00 2001 From: enes Date: Mon, 9 Sep 2024 10:19:37 +0200 Subject: [PATCH 1/4] fix: add types to rootReducer, rename userRobotImage types --- package.json | 2 +- src/store/actions.ts | 4 ++++ src/store/auth/types.ts | 3 ++- src/store/rootReducer.ts | 20 ++++++++++++++++---- src/store/userRobotImage/reducer.ts | 4 ++-- src/store/userRobotImage/types.ts | 2 +- 6 files changed, 26 insertions(+), 9 deletions(-) diff --git a/package.json b/package.json index a2f074d..0bfde0a 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "scripts": { "dev": "vite", "build": "tsc && vite build", - "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 2", + "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0", "lint:fix": "eslint . --fix --ext ts,tsx --report-unused-disable-directives --max-warnings 0", "lint:staged": "eslint --fix --ext ts,tsx --report-unused-disable-directives --max-warnings 0", "formatter:check": "prettier --check \"src/**/*.{ts,tsx,js,jsx,html,css,sass,less,yml,md,graphql}\"", diff --git a/src/store/actions.ts b/src/store/actions.ts index aee594f..bca5438 100644 --- a/src/store/actions.ts +++ b/src/store/actions.ts @@ -18,6 +18,10 @@ export interface RestoreState { payload: State } +export interface UserLogout { + type: typeof ActionTypes.USER_LOGOUT +} + export const userLogOutAction = () => { return { type: ActionTypes.USER_LOGOUT diff --git a/src/store/auth/types.ts b/src/store/auth/types.ts index 18dafcf..a134a7b 100644 --- a/src/store/auth/types.ts +++ b/src/store/auth/types.ts @@ -1,5 +1,5 @@ import * as ActionTypes from '../actionTypes' -import { RestoreState } from '../actions' +import { RestoreState, UserLogout } from '../actions' export enum LoginMethods { extension = 'extension', @@ -54,3 +54,4 @@ export type AuthDispatchTypes = | UpdateKeyPair | UpdateNsecBunkerPubkey | UpdateNsecBunkerRelays + | UserLogout diff --git a/src/store/rootReducer.ts b/src/store/rootReducer.ts index b37a3cd..61b2837 100644 --- a/src/store/rootReducer.ts +++ b/src/store/rootReducer.ts @@ -3,12 +3,15 @@ import { combineReducers } from 'redux' import { UserAppData } from '../types' import * as ActionTypes from './actionTypes' import authReducer from './auth/reducer' -import { AuthState } from './auth/types' +import { AuthDispatchTypes, AuthState } from './auth/types' import metadataReducer from './metadata/reducer' import relaysReducer from './relays/reducer' -import { RelaysState } from './relays/types' +import { RelaysDispatchTypes, RelaysState } from './relays/types' import UserAppDataReducer from './userAppData/reducer' import userRobotImageReducer from './userRobotImage/reducer' +import { MetadataDispatchTypes } from './metadata/types' +import { UserAppDataDispatchTypes } from './userAppData/types' +import { UserRobotImageDispatchTypes } from './userRobotImage/types' export interface State { auth: AuthState @@ -18,6 +21,13 @@ export interface State { userAppData?: UserAppData } +type AppActions = + | AuthDispatchTypes + | MetadataDispatchTypes + | UserRobotImageDispatchTypes + | RelaysDispatchTypes + | UserAppDataDispatchTypes + export const appReducer = combineReducers({ auth: authReducer, metadata: metadataReducer, @@ -26,8 +36,10 @@ export const appReducer = combineReducers({ userAppData: UserAppDataReducer }) -// FIXME: define types -export default (state: any, action: any) => { +export default ( + state: ReturnType | undefined, + action: AppActions +) => { switch (action.type) { case ActionTypes.USER_LOGOUT: return appReducer(undefined, action) diff --git a/src/store/userRobotImage/reducer.ts b/src/store/userRobotImage/reducer.ts index 4235a48..913c2c5 100644 --- a/src/store/userRobotImage/reducer.ts +++ b/src/store/userRobotImage/reducer.ts @@ -1,11 +1,11 @@ import * as ActionTypes from '../actionTypes' -import { MetadataDispatchTypes } from './types' +import { UserRobotImageDispatchTypes } from './types' const initialState: string | null = null const reducer = ( state = initialState, - action: MetadataDispatchTypes + action: UserRobotImageDispatchTypes ): string | null | undefined => { switch (action.type) { case ActionTypes.SET_USER_ROBOT_IMAGE: diff --git a/src/store/userRobotImage/types.ts b/src/store/userRobotImage/types.ts index 05d1475..2bef640 100644 --- a/src/store/userRobotImage/types.ts +++ b/src/store/userRobotImage/types.ts @@ -6,4 +6,4 @@ export interface SetUserRobotImage { payload: string | null } -export type MetadataDispatchTypes = SetUserRobotImage | RestoreState +export type UserRobotImageDispatchTypes = SetUserRobotImage | RestoreState -- 2.34.1 From f0ba9da8af9abc24fdae0b6fe65b83326d904e44 Mon Sep 17 00:00:00 2001 From: enes Date: Mon, 9 Sep 2024 14:16:58 +0200 Subject: [PATCH 2/4] fix: outdated cache checks --- src/utils/relays.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/utils/relays.ts b/src/utils/relays.ts index 5b79f3d..bfef7aa 100644 --- a/src/utils/relays.ts +++ b/src/utils/relays.ts @@ -6,6 +6,7 @@ import { localCache } from '../services' import { RelayMap, RelaySet } from '../types' import { DEFAULT_LOOK_UP_RELAY_LIST, + ONE_DAY_IN_MS, ONE_WEEK_IN_MS, SIGIT_RELAY } from './const' @@ -56,7 +57,7 @@ const findRelayListInCache = async (hexKey: string): Promise => { // Check if the cached event is not older than one week if ( cachedRelayListMetadataEvent && - isOlderThanOneWeek(cachedRelayListMetadataEvent.cachedAt) + !isOlderThanOneWeek(cachedRelayListMetadataEvent.cachedAt) ) { return cachedRelayListMetadataEvent.event } @@ -88,11 +89,11 @@ const getDefaultRelayMap = (): RelayMap => ({ }) const isOlderThanOneWeek = (cachedAt: number) => { - return Date.now() - cachedAt < ONE_WEEK_IN_MS + return Date.now() - cachedAt > ONE_WEEK_IN_MS } const isOlderThanOneDay = (cachedAt: number) => { - return Date.now() - cachedAt < ONE_WEEK_IN_MS + return Date.now() - cachedAt > ONE_DAY_IN_MS } const isRelayTag = (tag: string[]): boolean => tag[0] === 'r' -- 2.34.1 From 235e76be4e3eada7668bf802ff063394d958ff17 Mon Sep 17 00:00:00 2001 From: enes Date: Thu, 12 Sep 2024 08:26:59 +0000 Subject: [PATCH 3/4] fix: processing gift wraps and notifications (#193) This change will potentially close multiple issues related to the gift-wrapped events processing (https://git.nostrdev.com/sigit/sigit.io/issues/168, https://git.nostrdev.com/sigit/sigit.io/issues/158). Further testing will be required to confirm before closing each. The commented-out code causes the race condition during the processing of the gift wraps with sigits. During the processing we perform checks to see if sigit is outdated. In cases where sigit includes multiple signers it's possible for a signer to receive multiple sigit updates at once (especially noticeable for 3rd, 4th signer). Due to async nature of processing we can have same sigit enter processing flow with different states. Since this code also updates user's app state, which includes uploads to the blossom server it takes time to upload local user state which causes both to check against the stale data and un-updated app state. This results in both sigits being "new" and both proceed to update user state and upload app data. We have no guarantees as in which event will update last, meaning that the final state we end up with could be already stale. The issue is also complicated due to the fact that we mark the gift wraps as processed and it's impossible to update the state without creating a new gift wrap with correct state and processing it last to overwrite stale state. This is temporary solution to stop broken sigit states until proper async implementation is ready. Co-authored-by: b Reviewed-on: https://git.nostrdev.com/sigit/sigit.io/pulls/193 Reviewed-by: eugene Co-authored-by: enes Co-committed-by: enes --- src/layouts/Main.tsx | 23 +++++++++++++++++++++-- src/utils/nostr.ts | 15 +++++++++++---- 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/src/layouts/Main.tsx b/src/layouts/Main.tsx index f3962eb..5a8cca2 100644 --- a/src/layouts/Main.tsx +++ b/src/layouts/Main.tsx @@ -27,6 +27,8 @@ import { import { useAppSelector } from '../hooks' import styles from './style.module.scss' +const UPDATE_INTERVAL_MS = 120000 + export const MainLayout = () => { const dispatch: Dispatch = useDispatch() const [isLoading, setIsLoading] = useState(true) @@ -35,7 +37,7 @@ export const MainLayout = () => { const usersAppData = useAppSelector((state) => state.userAppData) // Ref to track if `subscribeForSigits` has been called - const hasSubscribed = useRef(false) + const hasSubscribed = useRef(null) useEffect(() => { const metadataController = new MetadataController() @@ -109,10 +111,27 @@ export const MainLayout = () => { if (pubkey && !hasSubscribed.current) { // Call `subscribeForSigits` only if it hasn't been called before + // #193 disabled websocket subscribtion, keep updating the sigits on UPDATE_INTERVAL_MS until #194 is done + // Set up the update sigit loop, use setTimeout to make sure times between updates are consistent + // (not affected by execution duration of subscribeForSigits call) + const loop = () => { + hasSubscribed.current = window.setTimeout(async () => { + await subscribeForSigits(pubkey) + loop() + }, UPDATE_INTERVAL_MS) + } subscribeForSigits(pubkey) + loop() // Mark `subscribeForSigits` as called - hasSubscribed.current = true + //hasSubscribed.current = true + } + } + + return () => { + if (hasSubscribed.current) { + window.clearTimeout(hasSubscribed.current) + hasSubscribed.current = null } } }, [authState, usersAppData]) diff --git a/src/utils/nostr.ts b/src/utils/nostr.ts index eceb8d8..0a3e052 100644 --- a/src/utils/nostr.ts +++ b/src/utils/nostr.ts @@ -859,9 +859,16 @@ export const subscribeForSigits = async (pubkey: string) => { '#p': [pubkey] } - relayController.subscribeForEvents(filter, relaySet.read, (event) => { - processReceivedEvent(event) // Process the received event - }) + // Process the received event synchronously + const events = await relayController.fetchEvents(filter, relaySet.read) + for (const e of events) { + await processReceivedEvent(e) + } + + // Async processing of the events has a race condition + // relayController.subscribeForEvents(filter, relaySet.read, (event) => { + // processReceivedEvent(event) + // }) } const processReceivedEvent = async (event: Event, difficulty: number = 5) => { @@ -907,7 +914,7 @@ const processReceivedEvent = async (event: Event, difficulty: number = 5) => { if (!meta) return - updateUsersAppData(meta) + await updateUsersAppData(meta) } /** -- 2.34.1 From 5f0234a358788226b6bb0e71f95de8c70ef4bc3f Mon Sep 17 00:00:00 2001 From: enes Date: Thu, 12 Sep 2024 11:27:55 +0200 Subject: [PATCH 4/4] fix: remove unstable fetch events loop --- src/layouts/Main.tsx | 24 +++--------------------- 1 file changed, 3 insertions(+), 21 deletions(-) diff --git a/src/layouts/Main.tsx b/src/layouts/Main.tsx index 5a8cca2..9402e97 100644 --- a/src/layouts/Main.tsx +++ b/src/layouts/Main.tsx @@ -27,8 +27,6 @@ import { import { useAppSelector } from '../hooks' import styles from './style.module.scss' -const UPDATE_INTERVAL_MS = 120000 - export const MainLayout = () => { const dispatch: Dispatch = useDispatch() const [isLoading, setIsLoading] = useState(true) @@ -37,7 +35,7 @@ export const MainLayout = () => { const usersAppData = useAppSelector((state) => state.userAppData) // Ref to track if `subscribeForSigits` has been called - const hasSubscribed = useRef(null) + const hasSubscribed = useRef(false) useEffect(() => { const metadataController = new MetadataController() @@ -111,27 +109,11 @@ export const MainLayout = () => { if (pubkey && !hasSubscribed.current) { // Call `subscribeForSigits` only if it hasn't been called before - // #193 disabled websocket subscribtion, keep updating the sigits on UPDATE_INTERVAL_MS until #194 is done - // Set up the update sigit loop, use setTimeout to make sure times between updates are consistent - // (not affected by execution duration of subscribeForSigits call) - const loop = () => { - hasSubscribed.current = window.setTimeout(async () => { - await subscribeForSigits(pubkey) - loop() - }, UPDATE_INTERVAL_MS) - } + // #193 disabled websocket subscribtion, until #194 is done subscribeForSigits(pubkey) - loop() // Mark `subscribeForSigits` as called - //hasSubscribed.current = true - } - } - - return () => { - if (hasSubscribed.current) { - window.clearTimeout(hasSubscribed.current) - hasSubscribed.current = null + hasSubscribed.current = true } } }, [authState, usersAppData]) -- 2.34.1