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,11 +7,13 @@ import { Session } from 'src/session/Session';
|
|||||||
import { Admin } from 'src/admin/Admin';
|
import { Admin } from 'src/admin/Admin';
|
||||||
import { StoreContextProvider } from 'context/StoreContext';
|
import { StoreContextProvider } from 'context/StoreContext';
|
||||||
import { AppContextProvider } from 'context/AppContext';
|
import { AppContextProvider } from 'context/AppContext';
|
||||||
|
import { ProfileContextProvider } from 'context/ProfileContext';
|
||||||
|
|
||||||
export default function App() {
|
export default function App() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StoreContextProvider>
|
<StoreContextProvider>
|
||||||
|
<ProfileContextProvider>
|
||||||
<AppContextProvider>
|
<AppContextProvider>
|
||||||
<NativeRouter>
|
<NativeRouter>
|
||||||
<Routes>
|
<Routes>
|
||||||
@ -24,6 +26,7 @@ export default function App() {
|
|||||||
</Routes>
|
</Routes>
|
||||||
</NativeRouter>
|
</NativeRouter>
|
||||||
</AppContextProvider>
|
</AppContextProvider>
|
||||||
|
</ProfileContextProvider>
|
||||||
</StoreContextProvider>
|
</StoreContextProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { checkResponse, fetchWithTimeout } from './fetchUtil';
|
import { checkResponse, fetchWithTimeout } from './fetchUtil';
|
||||||
|
|
||||||
export async function getProfile(token) {
|
export async function getProfile(server, token) {
|
||||||
let profile = await fetchWithTimeout(`/profile?agent=${token}`, { method: 'GET' });
|
let profile = await fetchWithTimeout(`https://${server}/profile?agent=${token}`, { method: 'GET' });
|
||||||
checkResponse(profile)
|
checkResponse(profile)
|
||||||
return await profile.json()
|
return await profile.json()
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
export function getProfileImageUrl(token, revision) {
|
export function getProfileImageUrl(server, token, revision) {
|
||||||
return '/profile/image?agent=' + token + "&revision=" + revision
|
return `https://${server}/profile/image?agent=${token}&revision=${revision}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import { checkResponse, fetchWithTimeout } from './fetchUtil';
|
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 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)
|
checkResponse(profile)
|
||||||
return await profile.json()
|
return await profile.json()
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { checkResponse, fetchWithTimeout } from './fetchUtil';
|
import { checkResponse, fetchWithTimeout } from './fetchUtil';
|
||||||
|
|
||||||
export async function setProfileImage(token, image) {
|
export async function setProfileImage(server, token, image) {
|
||||||
let profile = await fetchWithTimeout(`/profile/image?agent=${token}`, { method: 'PUT', body: JSON.stringify(image) });
|
let profile = await fetchWithTimeout(`https://${server}/profile/image?agent=${token}`, { method: 'PUT', body: JSON.stringify(image) });
|
||||||
checkResponse(profile)
|
checkResponse(profile)
|
||||||
return await profile.json()
|
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 { addAccount } from 'api/addAccount';
|
||||||
import { getUsername } from 'api/getUsername';
|
import { getUsername } from 'api/getUsername';
|
||||||
import { StoreContext } from 'context/StoreContext';
|
import { StoreContext } from 'context/StoreContext';
|
||||||
|
import { ProfileContext } from 'context/ProfileContext';
|
||||||
|
|
||||||
export function useAppContext() {
|
export function useAppContext() {
|
||||||
const [state, setState] = useState({
|
const [state, setState] = useState({
|
||||||
session: null,
|
session: null,
|
||||||
disconnected: null,
|
disconnected: null,
|
||||||
});
|
});
|
||||||
const [appRevision, setAppRevision] = useState();
|
|
||||||
const store = useContext(StoreContext);
|
const store = useContext(StoreContext);
|
||||||
|
const profile = useContext(ProfileContext);
|
||||||
|
|
||||||
const delay = useRef(2);
|
const delay = useRef(2);
|
||||||
const ws = useRef(null);
|
const ws = useRef(null);
|
||||||
const revision = useRef(null);
|
|
||||||
|
|
||||||
const updateState = (value) => {
|
const updateState = (value) => {
|
||||||
setState((s) => ({ ...s, ...value }))
|
setState((s) => ({ ...s, ...value }))
|
||||||
}
|
}
|
||||||
|
|
||||||
const resetData = () => {
|
useEffect(() => {
|
||||||
revision.current = null;
|
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 = {
|
const actions = {
|
||||||
@ -32,19 +54,22 @@ export function useAppContext() {
|
|||||||
create: async (server, username, password, token) => {
|
create: async (server, username, password, token) => {
|
||||||
await addAccount(server, username, password, token);
|
await addAccount(server, username, password, token);
|
||||||
const access = await setLogin(username, server, password)
|
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) => {
|
access: async (server, token) => {
|
||||||
const access = await setAccountAccess(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) => {
|
login: async (username, password) => {
|
||||||
const acc = username.split('@');
|
const acc = username.split('@');
|
||||||
const access = await setLogin(acc[0], acc[1], password)
|
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 () => {
|
logout: async () => {
|
||||||
resetData();
|
await clearSession();
|
||||||
await store.actions.clearSession();
|
await store.actions.clearSession();
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -55,7 +80,7 @@ export function useAppContext() {
|
|||||||
ws.current.onmessage = (ev) => {
|
ws.current.onmessage = (ev) => {
|
||||||
try {
|
try {
|
||||||
const rev = JSON.parse(ev.data);
|
const rev = JSON.parse(ev.data);
|
||||||
setAppRevision(rev);
|
profile.actions.setRevision(rev.profileRevision);
|
||||||
updateState({ disconnected: false });
|
updateState({ disconnected: false });
|
||||||
}
|
}
|
||||||
catch (err) {
|
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 }
|
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';
|
const DATABAG_DB = 'databag_v001.db';
|
||||||
|
|
||||||
export function useStoreContext() {
|
export function useStoreContext() {
|
||||||
const [state, setState] = useState({
|
const [state, setState] = useState({});
|
||||||
init: false,
|
|
||||||
session: null,
|
|
||||||
sessionId: 0,
|
|
||||||
profileRevision: null,
|
|
||||||
cardRevision: null,
|
|
||||||
channelRevision: null,
|
|
||||||
accountRevision: null,
|
|
||||||
});
|
|
||||||
|
|
||||||
const db = useRef(null);
|
const db = useRef(null);
|
||||||
const session = useRef(null);
|
|
||||||
const sessionId = useRef(0);
|
|
||||||
|
|
||||||
const updateState = (value) => {
|
const updateState = (value) => {
|
||||||
setState((s) => ({ ...s, ...value }))
|
setState((s) => ({ ...s, ...value }))
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
const actions = {
|
||||||
initialize();
|
init: async () => {
|
||||||
}, []);
|
|
||||||
|
|
||||||
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.DEBUG(false);
|
||||||
SQLite.enablePromise(true);
|
SQLite.enablePromise(true);
|
||||||
db.current = await SQLite.openDatabase({ name: DATABAG_DB, location: "default" });
|
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("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);");
|
await db.current.executeSql("INSERT OR IGNORE INTO app (key, value) values ('session', null);");
|
||||||
|
return await getAppValue(db.current, 'session');
|
||||||
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 = {
|
|
||||||
setSession: async (access) => {
|
setSession: async (access) => {
|
||||||
await db.current.executeSql("UPDATE app SET value=? WHERE key='session';", [encodeObject(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 () => {
|
clearSession: async () => {
|
||||||
await db.current.executeSql("UPDATE app set value=? WHERE key='session';", [null]);
|
await db.current.executeSql("UPDATE app set value=? WHERE key='session';", [null]);
|
||||||
session.current = null;
|
|
||||||
updateState({ session: null });
|
|
||||||
},
|
},
|
||||||
setProfileRevision: (id, profileRevision) => {
|
getProfile: async (guid) => {
|
||||||
if (sessionId.current === id) {
|
const dataId = `${guid}_profile`;
|
||||||
updateState({ profileRevision });
|
return await getAppValue(db.current, dataId, {});
|
||||||
}
|
|
||||||
},
|
},
|
||||||
setAccountRevision: (id, accountRevision) => {
|
setProfile: async (guid, profile) => {
|
||||||
if (sessionId.current === id) {
|
const dataId = `${guid}_profile`;
|
||||||
updateState({ accountRevision });
|
await db.current.executeSql("UPDATE app SET value=? WHERE key='?';", [encodeObject(profile)], dataId);
|
||||||
}
|
|
||||||
},
|
},
|
||||||
setCardRevision: (id, cardRevision) => {
|
getProfileRevision: async (guid) => {
|
||||||
if (sessionId.current === id) {
|
const dataId = `${guid}_profileRevision`;
|
||||||
updateState({ cardRevision });
|
return await getAppValue(db.current, dataId, 0);
|
||||||
}
|
|
||||||
},
|
},
|
||||||
setChannelRevision: (channelRevision) => {
|
setProfileRevision: async (guid, revision) => {
|
||||||
if (sessionId.current === id) {
|
const dataId = `${guid}_profileRevision`;
|
||||||
updateState({ channelRevision });
|
await db.current.executeSql("UPDATE app SET value=? WHERE key='?';", [encodeObject(revision)], dataId);
|
||||||
}
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
return { state, actions }
|
return { state, actions }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user