separating contexts

This commit is contained in:
Roland Osborne 2022-04-24 00:27:28 -07:00
parent 212a1575d4
commit 6b85537400
11 changed files with 297 additions and 58 deletions

View File

@ -0,0 +1,9 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function getCardDetail(token, cardId) {
let param = "?agent=" + token
let detail = await fetchWithTimeout(`/contact/cards/${cardId}/detail${param}`, { method: 'GET' });
checkResponse(detail);
return await detail.json()
}

View File

@ -0,0 +1,8 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function getCardProfile(token, cardId) {
let profile = await fetchWithTimeout(`/contact/cards/${cardId}/profile?agent=${token}`, { method: 'GET' });
checkResponse(profile);
return await profile.json()
}

View File

@ -0,0 +1,12 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function getCards(token, revision) {
let param = "agent=" + token
if (revision != null) {
param += '&revision=' + revision
}
let cards = await fetchWithTimeout(`/contact/cards?${param}`, { method: 'GET' });
checkResponse(cards)
return await cards.json()
}

View File

@ -0,0 +1,8 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function getContactProfile(server, guid, token) {
let profile = await fetchWithTimeout(`https://${server}/profile/message?contact=${guid}.${token}`, { method: 'GET', });
checkResponse(profile);
return await profile.json()
}

View File

@ -0,0 +1,8 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function setCardProfile(token, cardId, message) {
let profile = await fetchWithTimeout(`/contact/cards/${cardId}/profile?agent=${token}`, { method: 'PUT', body: JSON.stringify(message) });
checkResponse(profile);
return await profile.json()
}

View File

@ -4,37 +4,40 @@ import { getAccountStatus } from '../Api/getAccountStatus';
export function useAccountContext() { export function useAccountContext() {
const [state, setState] = useState({ const [state, setState] = useState({
token: null,
revision: 0,
status: null, status: null,
}); });
const access = useRef(null);
const revision = useRef(null);
const next = useRef(null); const next = useRef(null);
const updateState = (value) => { const updateState = (value) => {
setState((s) => ({ ...s, ...value })) setState((s) => ({ ...s, ...value }))
} }
const setStatus = async (revision) => { const setStatus = async (rev) => {
if (next.current == null) { if (next.current == null) {
let status = await getAccountStatus(state.token); if (revision.current != rev) {
updateState({ revision, status }); let status = await getAccountStatus(access.current);
updateState({ status });
revision.current = rev;
}
if (next.current != null) { if (next.current != null) {
let rev = next.current; let r = next.current;
next.current = null; next.current = null;
setStatus(rev); setStatus(r);
} }
} }
else { else {
next.current = revision; next.current = rev;
} }
} }
const actions = { const actions = {
setToken: async (token) => { setToken: async (token) => {
updateState({ token }); access.current = token;
}, },
setRevision: async (revision) => { setRevision: async (rev) => {
setStatus(revision); setStatus(rev);
}, },
setSearchable: async (flag) => { setSearchable: async (flag) => {
await setAccountSearchable(state.token, flag); await setAccountSearchable(state.token, flag);

View File

@ -1,24 +1,157 @@
import { useEffect, useState, useRef } from 'react'; import { useEffect, useState, useRef } from 'react';
import { getContactChannels } from '../Api/getContactChannels';
import { getContactChannel } from '../Api/getContactChannel';
import { getContactProfile } from '../Api/getContactProfile';
import { setCardProfile } from '../Api/setCardProfile';
import { getCards } from '../Api/getCards';
import { getCardImageUrl } from '../Api/getCardImageUrl';
import { getCardProfile } from '../Api/getCardProfile';
import { getCardDetail } from '../Api/getCardDetail';
export function useCardContext() { export function useCardContext() {
const [state, setState] = useState({ const [state, setState] = useState({
token: null, cards: new Map(),
revision: 0,
}); });
const access = useRef(null);
const revision = useRef(null);
const next = useRef(null);
const cards = useRef(new Map());
const updateState = (value) => { const updateState = (value) => {
setState((s) => ({ ...s, ...value })) setState((s) => ({ ...s, ...value }))
} }
const updateCards = async () => {
let delta = await getCards(access.current, revision.current);
for (let card of delta) {
if (card.data) {
let cur = cards.current.get(card.id);
if (cur == null) {
cur = { id: card.id, data: { articles: new Map() }, channels: new Map() }
}
if (cur.data.detailRevision != card.data.detailRevision) {
if (card.data.cardDetail != null) {
cur.data.cardDetail = card.data.cardDetail;
}
else {
cur.data.cardDetail = await getCardDetail(access.current, card.id);
}
cur.data.detailRevision = card.data.detailRevision;
}
if (cur.data.profileRevision != card.data.profileRevision) {
if (card.data.cardProfile != null) {
cur.data.cardProfile = card.data.cardProfile;
}
else {
cur.data.cardProfile = await getCardProfile(access.current, card.id);
}
cur.data.profileRevision = card.data.profileRevision;
}
const { cardDetail, cardProfile } = cur.data;
if (cardDetail.status === 'connected') {
if (cur.data.profileRevision != card.data.notifiedProfile) {
let message = await getContactProfile(cardProfile.node, cardProfile.guid, cardDetail.token);
await setCardProfile(access.current, card.id, message);
// update remote profile
cur.data.notifiedProfile = card.data.notifiedProfile;
}
if (cur.data.notifiedView != card.data.notifiedView) {
// update remote articles and channels
cur.data.articles = new Map();
cur.channels = new Map();
let contactToken = cur.data.cardProfile.guid + "." + cur.data.cardDetail.token
await updateContactChannels(contactToken, cur.data.notifiedView, cur.dataNotifiedChannel, cur.channels);
await updateContactArticles(contactToken, cur.data.notifiedView, cur.dataNotifiedArticle, cur.data.articles);
// update view
cur.data.notifiedArticle = card.data.notifiedArticle;
cur.data.notifiedChannel = card.data.notifiedChannel;
cur.data.notifiedView = card.data.notifiedView;
}
if (cur.data.notifiedArticle != card.data.notifiedArticle) {
// update remote articles
let contactToken = cur.data.cardProfile.guid + "." + cur.data.cardDetail.token
await updateContactArticles(contactToken, cur.data.notifiedView, cur.dataNotifiedArticle, cur.data.articles);
cur.data.notifiedArticle = card.data.notifiedArticle;
}
if (cur.data.notifiedChannel != card.data.notifiedChannel) {
// update remote channels
let contactToken = cur.data.cardProfile.guid + "." + cur.data.cardDetail.token
await updateContactChannels(contactToken, cur.data.notifiedView, cur.dataNotifiedChannel, cur.channels);
cur.data.notifiedChannel = card.data.notifiedChannel;
}
}
cur.revision = card.revision;
cards.current.set(card.id, cur);
}
else {
cards.current.delete(card.id);
}
}
}
const updateContactChannels = async (token, viewRevision, channelRevision, channelMap) => {
let delta = await getContactChannels(token, viewRevision, channelRevision);
for (let channel of delta) {
if (channel.data) {
let cur = channelMap.get(channel.id);
if (cur == null) {
cur = { id: channel.id, data: { } }
}
if (cur.data.detailRevision != channel.data.detailRevision) {
if (channel.data.channelDetail != null) {
cur.data.channelDetail = channel.data.channelDetail;
cur.data.detailRevision = channel.data.detailRevision;
}
else {
let slot = await getContactChannel(token, channel.id);
cur.data.channelDetail = slot.data.channelDetail;
cur.data.detailRevision = slot.data.detailRevision;
}
}
cur.data.topicRevision = channel.data.topicRevision;
cur.revision = channel.revision;
channelMap.set(channel.id, cur);
}
else {
channelMap.delete(channel.id);
}
}
}
const updateContactArticles = async (token, viewRevision, articleRevision, articleMap) => {
console.log("update contact articles");
}
const setCards = async (rev) => {
if (next.current == null) {
await updateCards();
updateState({ cards: cards.current });
revision.current = rev;
if (next.current != null) {
let r = next.current;
next.current = null;
setCards(r);
}
}
else {
next.current = rev;
}
}
const actions = { const actions = {
setToken: async (token) => { setToken: async (token) => {
updateState({ token }); access.current = token;
}, },
setRevision: async (revision) => { setRevision: async (rev) => {
updateState({ revision }); setCards(rev);
}, },
} }
console.log(state);
return { state, actions } return { state, actions }
} }

View File

@ -1,21 +1,73 @@
import { useEffect, useState, useRef } from 'react'; import { useEffect, useState, useRef } from 'react';
import { getChannels } from '../Api/getChannels';
import { getChannel } from '../Api/getChannel';
export function useChannelContext() { export function useChannelContext() {
const [state, setState] = useState({ const [state, setState] = useState({
token: null, channels: new Map(),
revision: 0,
}); });
const access = useRef(null);
const revision = useRef(null);
const channels = useRef(new Map());
const next = useRef(null);
const updateState = (value) => { const updateState = (value) => {
setState((s) => ({ ...s, ...value })) setState((s) => ({ ...s, ...value }))
} }
const updateChannels = async () => {
let delta = await getChannels(access.current, revision.current);
for (let channel of delta) {
if (channel.data) {
let cur = channels.current.get(channel.id);
if (cur == null) {
cur = { id: channel.id, data: { } }
}
if (cur.data.detailRevision != channel.data.detailRevision) {
if (channel.data.channelDetail != null) {
cur.data.channelDetail = channel.data.channelDetail;
cur.data.detailRevision = channel.data.detailRevision;
}
else {
let slot = await getChannel(state.token, channel.id);
cur.data.channelDetail = slot.data.channelDetail;
cur.data.detailRevision = slot.data.detailRevision;
}
}
cur.data.topicRevision = channel.data.topicRevision;
cur.revision = channel.revision;
channels.current.set(channel.id, cur);
}
else {
channels.current.delete(channel.id);
}
}
}
const setChannels = async (rev) => {
if (next.current == null) {
if (revision.current != rev) {
await updateChannels();
updateState({ channels: channels.current });
revision.current = rev;
}
if (next.current != null) {
let r = next.current;
next.current = null;
setChannels(r);
}
}
else {
next.current = rev;
}
}
const actions = { const actions = {
setToken: (token) => { setToken: (token) => {
updateState({ token }); access.current = token;
}, },
setRevision: async (revision) => { setRevision: async (rev) => {
updateState({ revision }); setChannels(rev);
}, },
} }

View File

@ -3,49 +3,53 @@ import { getGroups } from '../Api/getGroups';
export function useGroupContext() { export function useGroupContext() {
const [state, setState] = useState({ const [state, setState] = useState({
token: null,
revision: null,
groups: new Map(), groups: new Map(),
}); });
const next = useRef(null); const access = useRef(null);
const revision = useRef(null);
const groups = useRef(new Map()); const groups = useRef(new Map());
const next = useRef(null);
useEffect(() => {
}, []);
const updateState = (value) => { const updateState = (value) => {
setState((s) => ({ ...s, ...value })) setState((s) => ({ ...s, ...value }))
} }
const setGroups = async (revision) => { const updateGroups = async () => {
if (next.current == null) { let delta = await getGroups(access.current, revision.current);
let delta = await getGroups(state.token, state.revision); for (let group of delta) {
for (let group of delta) { if (group.data) {
if (group.data) { groups.set(group.id, group);
groups.set(group.id, group); }
} else {
else { groups.delete(group.id);
groups.delete(group.id); }
} }
}
const setGroups = async (rev) => {
if (next.current == null) {
if (revision.current != rev) {
await updateGroups();
updateState({ groups: groups.current });
revision.current = rev;
} }
updateState({ revision, groups });
if (next.current != null) { if (next.current != null) {
let rev = next.current; let r = next.current;
next.current = null; next.current = null;
setGroups(rev); setGroups(r);
} }
} }
else { else {
next.current = revision; next.current = rev;
} }
} }
const actions = { const actions = {
setToken: async (token) => { setToken: async (token) => {
updateState({ token }); access.current = token;
}, },
setRevision: async (revision) => { setRevision: async (rev) => {
setGroups(revision); setGroups(rev);
}, },
} }

View File

@ -6,37 +6,40 @@ import { getProfileImageUrl } from '../Api/getProfileImageUrl';
export function useProfileContext() { export function useProfileContext() {
const [state, setState] = useState({ const [state, setState] = useState({
token: null,
revision: 0,
profile: {}, profile: {},
}); });
const access = useRef(null);
const revision = useRef(null);
const next = useRef(null); const next = useRef(null);
const updateState = (value) => { const updateState = (value) => {
setState((s) => ({ ...s, ...value })) setState((s) => ({ ...s, ...value }))
} }
const setProfile = async (revision) => { const setProfile = async (rev) => {
if (next.current == null) { if (next.current == null) {
let profile = await getProfile(state.token); if (revision.current != rev) {
updateState({ revision, profile }); let profile = await getProfile(access.current);
updateState({ profile });
revision.current = rev;
}
if (next.current != null) { if (next.current != null) {
let rev = next.current; let r = next.current;
next.current = null; next.current = null;
setProfile(rev); setProfile(r);
} }
} }
else { else {
next.current = revision; next.current = rev;
} }
} }
const actions = { const actions = {
setToken: (token) => { setToken: (token) => {
updateState({ token }); access.current = token;
}, },
setRevision: (revision) => { setRevision: (rev) => {
setProfile(revision); setProfile(rev);
}, },
setProfileData: async (name, location, description) => { setProfileData: async (name, location, description) => {
await setProfileData(state.token, name, location, description); await setProfileData(state.token, name, location, description);
@ -44,7 +47,7 @@ export function useProfileContext() {
setProfileImage: async (image) => { setProfileImage: async (image) => {
await setProfileImage(state.token, image); await setProfileImage(state.token, image);
}, },
profileImageUrl: () => getProfileImageUrl(state.token, state.Data?.profile?.revision), profileImageUrl: () => getProfileImageUrl(access.current, revision.current),
} }
return { state, actions } return { state, actions }

View File

@ -37,7 +37,6 @@ export function useConversation() {
if (conversation?.revision != state.revision) { if (conversation?.revision != state.revision) {
let token = contact.data.cardProfile.guid + "." + contact.data.cardDetail.token; let token = contact.data.cardProfile.guid + "." + contact.data.cardDetail.token;
let slots = await getContactChannelTopics(token, channel, state.revision); let slots = await getContactChannelTopics(token, channel, state.revision);
for (let topic of slots) { for (let topic of slots) {
if (topic.data == null) { if (topic.data == null) {
topics.current.delete(topic.id); topics.current.delete(topic.id);
@ -65,7 +64,7 @@ export function useConversation() {
updateState({ updateState({
topics: Array.from(topics.current.values()), topics: Array.from(topics.current.values()),
revision: conversation.Revision, revision: conversation.revision,
}); });
} }
} }