Skip to content

Commit

Permalink
feat: Add automatic data synchronization settings and implementation,…
Browse files Browse the repository at this point in the history
… enabling auto-sync after completing replies or deleting conversations
  • Loading branch information
李超 committed Aug 15, 2024
1 parent 621b148 commit eae593d
Show file tree
Hide file tree
Showing 6 changed files with 61 additions and 7 deletions.
15 changes: 15 additions & 0 deletions app/components/settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,21 @@ function SyncConfigModal(props: { onClose?: () => void }) {
</select>
</ListItem>

<ListItem
title={Locale.Settings.Sync.Config.EnableAutoSync.Title}
subTitle={Locale.Settings.Sync.Config.EnableAutoSync.SubTitle}
>
<input
type="checkbox"
checked={syncStore.enableAutoSync}
onChange={(e) => {
syncStore.update(
(config) => (config.enableAutoSync = e.currentTarget.checked),
);
}}
></input>
</ListItem>

<ListItem
title={Locale.Settings.Sync.Config.Proxy.Title}
subTitle={Locale.Settings.Sync.Config.Proxy.SubTitle}
Expand Down
4 changes: 4 additions & 0 deletions app/locales/cn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,10 @@ const cn = {
Title: "同步类型",
SubTitle: "选择喜爱的同步服务器",
},
EnableAutoSync: {
Title: "自动同步设置",
SubTitle: "在回复完成或删除消息后自动同步数据",
},
Proxy: {
Title: "启用代理",
SubTitle: "在浏览器中同步时,必须启用代理以避免跨域限制",
Expand Down
5 changes: 5 additions & 0 deletions app/locales/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,11 @@ const en: LocaleType = {
Title: "Sync Type",
SubTitle: "Choose your favorite sync service",
},
EnableAutoSync: {
Title: "Auto Sync Settings",
SubTitle:
"Automatically synchronize data after replying or deleting messages",
},
Proxy: {
Title: "Enable CORS Proxy",
SubTitle: "Enable a proxy to avoid cross-origin restrictions",
Expand Down
14 changes: 14 additions & 0 deletions app/store/chat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import { nanoid } from "nanoid";
import { createPersistStore } from "../utils/store";
import { collectModelsWithDefaultModel } from "../utils/model";
import { useAccessStore } from "./access";
import { useSyncStore } from "./sync";
import { isDalle3 } from "../utils";

export type ChatMessage = RequestMessage & {
Expand Down Expand Up @@ -168,6 +169,15 @@ function fillTemplateWith(input: string, modelConfig: ModelConfig) {
return output;
}

let cloudSyncTimer: any = null;
function noticeCloudSync(): void {
const syncStore = useSyncStore.getState();
cloudSyncTimer && clearTimeout(cloudSyncTimer);
cloudSyncTimer = setTimeout(() => {
syncStore.autoSync();
}, 500);
}

const DEFAULT_CHAT_STATE = {
sessions: [createEmptySession()],
currentSessionIndex: 0,
Expand Down Expand Up @@ -297,12 +307,15 @@ export const useChatStore = createPersistStore(
deletedSessionIds,
}));

noticeCloudSync();

showToast(
Locale.Home.DeleteToast,
{
text: Locale.Home.Revert,
onClick() {
set(() => restoreState);
noticeCloudSync();
},
},
5000,
Expand Down Expand Up @@ -330,6 +343,7 @@ export const useChatStore = createPersistStore(
});
get().updateStat(message);
get().summarizeSession();
noticeCloudSync();
},

async onUserInput(content: string, attachImages?: string[]) {
Expand Down
22 changes: 19 additions & 3 deletions app/store/sync.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export type SyncStore = GetStoreState<typeof useSyncStore>;

const DEFAULT_SYNC_STATE = {
provider: ProviderType.WebDAV,
enableAutoSync: true,
useProxy: true,
proxyUrl: corsPath(ApiPath.Cors),

Expand Down Expand Up @@ -91,6 +92,11 @@ export const useSyncStore = createPersistStore(
},

async sync() {
const enableAutoSync = get().enableAutoSync;
if (!enableAutoSync) {
return;
}

const localState = getLocalAppState();
const provider = get().provider;
const config = get()[provider];
Expand All @@ -100,15 +106,17 @@ export const useSyncStore = createPersistStore(
const remoteState = await client.get(config.username);
if (!remoteState || remoteState === "") {
await client.set(config.username, JSON.stringify(localState));
console.log("[Sync] Remote state is empty, using local state instead.");
return
console.log(
"[Sync] Remote state is empty, using local state instead.",
);
return;
} else {
const parsedRemoteState = JSON.parse(
await client.get(config.username),
) as AppState;
mergeAppState(localState, parsedRemoteState);
setLocalAppState(localState);
}
}
} catch (e) {
console.log("[Sync] failed to get remote state", e);
throw e;
Expand All @@ -123,6 +131,14 @@ export const useSyncStore = createPersistStore(
const client = this.getClient();
return await client.check();
},

async autoSync() {
const { lastSyncTime, provider } = get();
const syncStore = useSyncStore.getState();
if (lastSyncTime && syncStore.cloudSync()) {
syncStore.sync();
}
},
}),
{
name: StoreKey.Sync,
Expand Down
8 changes: 4 additions & 4 deletions app/utils/sync.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,10 +130,10 @@ const MergeStates: StateMerger = {
});

// sort local sessions with date field in desc order
localState.sessions.sort(
(a, b) =>
new Date(b.lastUpdate).getTime() - new Date(a.lastUpdate).getTime(),
);
// localState.sessions.sort(
// (a, b) =>
// new Date(b.lastUpdate).getTime() - new Date(a.lastUpdate).getTime(),
// );

const deletedSessionIds = {
...remoteDeletedSessionIds,
Expand Down

0 comments on commit eae593d

Please sign in to comment.