mirror of
https://github.com/balzack/databag.git
synced 2025-02-12 03:29:16 +00:00
syncing profile
This commit is contained in:
parent
80fb1472e4
commit
4ca0f53da1
@ -7,23 +7,26 @@ import { Session } from 'src/session/Session';
|
||||
import { Admin } from 'src/admin/Admin';
|
||||
import { StoreContextProvider } from 'context/StoreContext';
|
||||
import { AppContextProvider } from 'context/AppContext';
|
||||
import { ProfileContextProvider } from 'context/ProfileContext';
|
||||
|
||||
export default function App() {
|
||||
|
||||
return (
|
||||
<StoreContextProvider>
|
||||
<AppContextProvider>
|
||||
<NativeRouter>
|
||||
<Routes>
|
||||
<Route path="/" element={ <Root /> } />
|
||||
<Route path="/admin" element={ <Admin /> } />
|
||||
<Route path="/login" element={ <Access mode="login" /> } />
|
||||
<Route path="/reset" element={ <Access mode="reset" /> } />
|
||||
<Route path="/create" element={ <Access mode="create" /> } />
|
||||
<Route path="/session" element={ <Session/> } />
|
||||
</Routes>
|
||||
</NativeRouter>
|
||||
</AppContextProvider>
|
||||
<ProfileContextProvider>
|
||||
<AppContextProvider>
|
||||
<NativeRouter>
|
||||
<Routes>
|
||||
<Route path="/" element={ <Root /> } />
|
||||
<Route path="/admin" element={ <Admin /> } />
|
||||
<Route path="/login" element={ <Access mode="login" /> } />
|
||||
<Route path="/reset" element={ <Access mode="reset" /> } />
|
||||
<Route path="/create" element={ <Access mode="create" /> } />
|
||||
<Route path="/session" element={ <Session/> } />
|
||||
</Routes>
|
||||
</NativeRouter>
|
||||
</AppContextProvider>
|
||||
</ProfileContextProvider>
|
||||
</StoreContextProvider>
|
||||
);
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { checkResponse, fetchWithTimeout } from './fetchUtil';
|
||||
|
||||
export async function getProfile(token) {
|
||||
let profile = await fetchWithTimeout(`/profile?agent=${token}`, { method: 'GET' });
|
||||
export async function getProfile(server, token) {
|
||||
let profile = await fetchWithTimeout(`https://${server}/profile?agent=${token}`, { method: 'GET' });
|
||||
checkResponse(profile)
|
||||
return await profile.json()
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
export function getProfileImageUrl(token, revision) {
|
||||
return '/profile/image?agent=' + token + "&revision=" + revision
|
||||
export function getProfileImageUrl(server, token, revision) {
|
||||
return `https://${server}/profile/image?agent=${token}&revision=${revision}`;
|
||||
}
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { checkResponse, fetchWithTimeout } from './fetchUtil';
|
||||
|
||||
export async function setProfileData(token, name, location, description) {
|
||||
export async function setProfileData(server, token, name, location, description) {
|
||||
let data = { name: name, location: location, description: description };
|
||||
let profile = await fetchWithTimeout(`/profile/data?agent=${token}`, { method: 'PUT', body: JSON.stringify(data) });
|
||||
let profile = await fetchWithTimeout(`https://${server}/profile/data?agent=${token}`, { method: 'PUT', body: JSON.stringify(data) });
|
||||
checkResponse(profile)
|
||||
return await profile.json()
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { checkResponse, fetchWithTimeout } from './fetchUtil';
|
||||
|
||||
export async function setProfileImage(token, image) {
|
||||
let profile = await fetchWithTimeout(`/profile/image?agent=${token}`, { method: 'PUT', body: JSON.stringify(image) });
|
||||
export async function setProfileImage(server, token, image) {
|
||||
let profile = await fetchWithTimeout(`https://${server}/profile/image?agent=${token}`, { method: 'PUT', body: JSON.stringify(image) });
|
||||
checkResponse(profile)
|
||||
return await profile.json()
|
||||
}
|
||||
|
14
app/mobile/src/context/ProfileContext.js
Normal file
14
app/mobile/src/context/ProfileContext.js
Normal file
@ -0,0 +1,14 @@
|
||||
import { createContext } from 'react';
|
||||
import { useProfileContext } from './useProfileContext.hook';
|
||||
|
||||
export const ProfileContext = createContext({});
|
||||
|
||||
export function ProfileContextProvider({ children }) {
|
||||
const { state, actions } = useProfileContext();
|
||||
return (
|
||||
<ProfileContext.Provider value={{ state, actions }}>
|
||||
{children}
|
||||
</ProfileContext.Provider>
|
||||
);
|
||||
}
|
||||
|
@ -5,25 +5,47 @@ import { setAccountAccess } from 'api/setAccountAccess';
|
||||
import { addAccount } from 'api/addAccount';
|
||||
import { getUsername } from 'api/getUsername';
|
||||
import { StoreContext } from 'context/StoreContext';
|
||||
import { ProfileContext } from 'context/ProfileContext';
|
||||
|
||||
export function useAppContext() {
|
||||
const [state, setState] = useState({
|
||||
session: null,
|
||||
disconnected: null,
|
||||
});
|
||||
const [appRevision, setAppRevision] = useState();
|
||||
const store = useContext(StoreContext);
|
||||
const profile = useContext(ProfileContext);
|
||||
|
||||
const delay = useRef(2);
|
||||
const ws = useRef(null);
|
||||
const revision = useRef(null);
|
||||
|
||||
const updateState = (value) => {
|
||||
setState((s) => ({ ...s, ...value }))
|
||||
}
|
||||
|
||||
const resetData = () => {
|
||||
revision.current = null;
|
||||
useEffect(() => {
|
||||
init();
|
||||
}, []);
|
||||
|
||||
const init = async () => {
|
||||
const access = await store.actions.init();
|
||||
if (access) {
|
||||
await setSession(access);
|
||||
}
|
||||
else {
|
||||
updateState({ session: false });
|
||||
}
|
||||
}
|
||||
|
||||
const setSession = async (access) => {
|
||||
profile.actions.setSession(access);
|
||||
updateState({ session: true });
|
||||
setWebsocket(access.server, access.appToken);
|
||||
}
|
||||
|
||||
const clearSession = async () => {
|
||||
profile.actions.clearSession();
|
||||
updateState({ session: false });
|
||||
clearWebsocket();
|
||||
}
|
||||
|
||||
const actions = {
|
||||
@ -32,19 +54,22 @@ export function useAppContext() {
|
||||
create: async (server, username, password, token) => {
|
||||
await addAccount(server, username, password, token);
|
||||
const access = await setLogin(username, server, password)
|
||||
store.actions.setSession({ ...access, server });
|
||||
await setSession({ ...access, server });
|
||||
await store.actions.setSession({ ...access, server});
|
||||
},
|
||||
access: async (server, token) => {
|
||||
const access = await setAccountAccess(server, token);
|
||||
store.actions.setSession({ ...access, server });
|
||||
await setSession({ ...access, server });
|
||||
await store.actions.setSession({ ...access, server});
|
||||
},
|
||||
login: async (username, password) => {
|
||||
const acc = username.split('@');
|
||||
const access = await setLogin(acc[0], acc[1], password)
|
||||
store.actions.setSession({ ...access, server: acc[1] });
|
||||
await setSession({ ...access, server: acc[1] });
|
||||
await store.actions.setSession({ ...access, server: acc[1]});
|
||||
},
|
||||
logout: async () => {
|
||||
resetData();
|
||||
await clearSession();
|
||||
await store.actions.clearSession();
|
||||
},
|
||||
}
|
||||
@ -55,7 +80,7 @@ export function useAppContext() {
|
||||
ws.current.onmessage = (ev) => {
|
||||
try {
|
||||
const rev = JSON.parse(ev.data);
|
||||
setAppRevision(rev);
|
||||
profile.actions.setRevision(rev.profileRevision);
|
||||
updateState({ disconnected: false });
|
||||
}
|
||||
catch (err) {
|
||||
@ -95,20 +120,6 @@ export function useAppContext() {
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (store.state.init) {
|
||||
if (store.state.session) {
|
||||
const { server, appToken } = store.state.session;
|
||||
setWebsocket(server, appToken);
|
||||
updateState({ session: true });
|
||||
}
|
||||
else {
|
||||
clearWebsocket();
|
||||
updateState({ session: false });
|
||||
}
|
||||
}
|
||||
}, [store.state.session, store.state.init]);
|
||||
|
||||
return { state, actions }
|
||||
}
|
||||
|
||||
|
72
app/mobile/src/context/useProfileContext.hook.js
Normal file
72
app/mobile/src/context/useProfileContext.hook.js
Normal file
@ -0,0 +1,72 @@
|
||||
import { useState, useRef, useContext } from 'react';
|
||||
import { getProfile } from 'api/getProfile';
|
||||
import { setProfileData } from 'api/setProfileData';
|
||||
import { setProfileImage } from 'api/setProfileImage';
|
||||
import { getProfileImageUrl } from 'api/getProfileImageUrl';
|
||||
import { StoreContext } from 'context/StoreContext';
|
||||
|
||||
export function useProfileContext() {
|
||||
const [state, setState] = useState({
|
||||
profile: {},
|
||||
imageUrl: null,
|
||||
});
|
||||
const store = useContext(StoreContext);
|
||||
|
||||
const session = useRef(null);
|
||||
const curRevision = useRef(null);
|
||||
const setRevision = useRef(null);
|
||||
const syncing = useRef(false);
|
||||
|
||||
const updateState = (value) => {
|
||||
setState((s) => ({ ...s, ...value }))
|
||||
}
|
||||
|
||||
const sync = async () => {
|
||||
if (!syncing.current && setRevision.current !== curRevision.current) {
|
||||
syncing.current = true;
|
||||
|
||||
const revision = curRevision.current;
|
||||
const { server, appToken, guid } = session.current;
|
||||
const profile = await getProfile(server, appToken);
|
||||
await store.actions.setProfile(guid, profile);
|
||||
await store.actions.setProfileRevision(guid, revision);
|
||||
updateState({ profile, imageUrl: getProfileImageUrl(server, appToken, revision) });
|
||||
setRevision.current = revision;
|
||||
|
||||
syncing.current = false;
|
||||
sync();
|
||||
}
|
||||
};
|
||||
|
||||
const actions = {
|
||||
setSession: async (access) => {
|
||||
const { guid, server, appToken } = access;
|
||||
const profile = await store.actions.getProfile(guid);
|
||||
const revision = await store.actions.getProfileRevision(guid);
|
||||
updateState({ profile, imageUrl: getProfileImageUrl(server, appToken, revision) });
|
||||
setRevision.current = revision;
|
||||
curRevision.current = revision;
|
||||
session.current = access;
|
||||
},
|
||||
clearSession: () => {
|
||||
session.current = {};
|
||||
updateState({ profile: null });
|
||||
},
|
||||
setRevision: (rev) => {
|
||||
curRevision.current = rev;
|
||||
sync();
|
||||
},
|
||||
setProfileData: async (name, location, description) => {
|
||||
const { server, appToken } = session.current;
|
||||
await setProfileData(server, appToken, name, location, description);
|
||||
},
|
||||
setProfileImage: async (image) => {
|
||||
const { server, appToken } = session.current;
|
||||
await setProfileImage(server, appToken, image);
|
||||
},
|
||||
}
|
||||
|
||||
return { state, actions }
|
||||
}
|
||||
|
||||
|
@ -4,97 +4,45 @@ import SQLite from "react-native-sqlite-storage";
|
||||
const DATABAG_DB = 'databag_v001.db';
|
||||
|
||||
export function useStoreContext() {
|
||||
const [state, setState] = useState({
|
||||
init: false,
|
||||
session: null,
|
||||
sessionId: 0,
|
||||
profileRevision: null,
|
||||
cardRevision: null,
|
||||
channelRevision: null,
|
||||
accountRevision: null,
|
||||
});
|
||||
|
||||
const [state, setState] = useState({});
|
||||
const db = useRef(null);
|
||||
const session = useRef(null);
|
||||
const sessionId = useRef(0);
|
||||
|
||||
const updateState = (value) => {
|
||||
setState((s) => ({ ...s, ...value }))
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
initialize();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (state.init && state.session && sessionId.current === state.sessionId) {
|
||||
const revision = {
|
||||
accountRevision: state.accountRevision,
|
||||
profileRevision: state.profileRevision,
|
||||
cardRevision: state.cardRevision,
|
||||
channelRevision: state.channelRevision,
|
||||
}
|
||||
const revisionId = `${session.current.guid}_revision`;
|
||||
db.current.executeSql(`UPDATE app SET value=? WHERE key='${revisionId}';`, [encodeObject(revision)]);
|
||||
}
|
||||
}, [state]);
|
||||
|
||||
const initialize = async () => {
|
||||
SQLite.DEBUG(false);
|
||||
SQLite.enablePromise(true);
|
||||
db.current = await SQLite.openDatabase({ name: DATABAG_DB, location: "default" });
|
||||
await db.current.executeSql("CREATE TABLE IF NOT EXISTS app (key text, value text, unique(key));");
|
||||
await db.current.executeSql("INSERT OR IGNORE INTO app (key, value) values ('session', null);");
|
||||
|
||||
session.current = await getAppValue(db.current, 'session');
|
||||
if (!session.current) {
|
||||
updateState({ init: true });
|
||||
}
|
||||
else {
|
||||
const revisionId = `${session.current.guid}_revision`;
|
||||
const revision = await getAppValue(db.current, revisionId, {});
|
||||
updateState({ init: true, session: session.current, ...revision });
|
||||
}
|
||||
};
|
||||
|
||||
const actions = {
|
||||
init: async () => {
|
||||
SQLite.DEBUG(false);
|
||||
SQLite.enablePromise(true);
|
||||
db.current = await SQLite.openDatabase({ name: DATABAG_DB, location: "default" });
|
||||
await db.current.executeSql("CREATE TABLE IF NOT EXISTS app (key text, value text, unique(key));");
|
||||
await db.current.executeSql("INSERT OR IGNORE INTO app (key, value) values ('session', null);");
|
||||
return await getAppValue(db.current, 'session');
|
||||
},
|
||||
setSession: async (access) => {
|
||||
await db.current.executeSql("UPDATE app SET value=? WHERE key='session';", [encodeObject(access)]);
|
||||
|
||||
const revisionId = `${access.guid}_revision`;
|
||||
const revision = await getAppValue(db.current, revisionId, {});
|
||||
|
||||
session.current = access;
|
||||
sessionId.current++;
|
||||
updateState({ session: access, sessionId: sessionId.current, ...revision });
|
||||
},
|
||||
clearSession: async () => {
|
||||
await db.current.executeSql("UPDATE app set value=? WHERE key='session';", [null]);
|
||||
session.current = null;
|
||||
updateState({ session: null });
|
||||
},
|
||||
setProfileRevision: (id, profileRevision) => {
|
||||
if (sessionId.current === id) {
|
||||
updateState({ profileRevision });
|
||||
}
|
||||
getProfile: async (guid) => {
|
||||
const dataId = `${guid}_profile`;
|
||||
return await getAppValue(db.current, dataId, {});
|
||||
},
|
||||
setAccountRevision: (id, accountRevision) => {
|
||||
if (sessionId.current === id) {
|
||||
updateState({ accountRevision });
|
||||
}
|
||||
setProfile: async (guid, profile) => {
|
||||
const dataId = `${guid}_profile`;
|
||||
await db.current.executeSql("UPDATE app SET value=? WHERE key='?';", [encodeObject(profile)], dataId);
|
||||
},
|
||||
setCardRevision: (id, cardRevision) => {
|
||||
if (sessionId.current === id) {
|
||||
updateState({ cardRevision });
|
||||
}
|
||||
getProfileRevision: async (guid) => {
|
||||
const dataId = `${guid}_profileRevision`;
|
||||
return await getAppValue(db.current, dataId, 0);
|
||||
},
|
||||
setChannelRevision: (channelRevision) => {
|
||||
if (sessionId.current === id) {
|
||||
updateState({ channelRevision });
|
||||
}
|
||||
setProfileRevision: async (guid, revision) => {
|
||||
const dataId = `${guid}_profileRevision`;
|
||||
await db.current.executeSql("UPDATE app SET value=? WHERE key='?';", [encodeObject(revision)], dataId);
|
||||
},
|
||||
}
|
||||
|
||||
return { state, actions }
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user