testing card context for web

This commit is contained in:
balzack 2023-01-06 23:04:38 -08:00
parent 1a63381813
commit 6f972788a6
6 changed files with 340 additions and 402 deletions

View File

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

View File

@ -1,7 +1,6 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function setContactChannelTopicSubject(server, token, channelId, topicId, datatype, data) {
console.log(data);
let host = "";
if (server) {
host = `https://${server}`;

View File

@ -23,155 +23,177 @@ import { getContactChannelTopicAssetUrl } from 'api/getContactChannelTopicAssetU
import { addCard } from 'api/addCard';
import { removeCard } from 'api/removeCard';
import { UploadContext } from 'context/UploadContext';
import CryptoJS from 'crypto-js';
import { JSEncrypt } from 'jsencrypt'
export function useCardContext() {
const [state, setState] = useState({
init: false,
offsync: false,
cards: new Map(),
});
const upload = useContext(UploadContext);
const access = useRef(null);
const revision = useRef(null);
const next = useRef(null);
const syncing = useRef(false);
const setRevision = useRef(null);
const curRevision = useRef(null);
const cards = useRef(new Map());
const resync = useRef([]);
const forceCard = useRef(null);
const force = useRef(false);
const updateState = (value) => {
setState((s) => ({ ...s, ...value }))
}
const updateCard = async (cardId) => {
let card = cards.current.get(cardId);
const { cardDetail, cardProfile } = card.data;
if (cardDetail.status === 'connected' && card.error) {
let message = await getContactProfile(cardProfile.node, cardProfile.guid, cardDetail.token);
await setCardProfile(access.current, card.id, message);
card.channels = new Map();
await updateContactChannels(card.data.cardProfile.node, card.id, card.data.cardProfile.guid, card.data.cardDetail.token, null, null, card.channels);
card.data.articles = new Map();
await updateContactArticles(card.data.cardProfile.node, card.id, card.data.cardProfile.guid, card.data.cardDetail.token, null, null, card.data.articles);
cards.current.set(card.id, { ...card, error: false });
const resync = async () => {
try {
force.current = true;
await sync();
}
}
const unsealKey = (seals, sealKey) => {
let unsealedKey;
if (seals?.length) {
seals.forEach(seal => {
if (seal.publicKey === sealKey.public) {
let crypto = new JSEncrypt();
crypto.setPrivateKey(sealKey.private);
unsealedKey = crypto.decrypt(seal.sealedKey);
}
});
catch (err) {
console.log(err);
}
return unsealedKey;
};
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() }, error: false, notifiedProfile: null, 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' && !cur.error) {
try {
if (cur.data.profileRevision !== card.data.notifiedProfile && cur.notifiedProfile !== card.data.notifiedProfile) {
let message = await getContactProfile(cardProfile.node, cardProfile.guid, cardDetail.token);
await setCardProfile(access.current, card.id, message);
const resyncCard = async (cardId) => {
if (cardId) {
forceCard.current = cardId;
}
if (!syncing.current && forceCard.current) {
syncing.current = true;
forceCard.current = null;
// update remote profile
cur.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();
await updateContactChannels(cur.data.cardProfile.node, card.id, cur.data.cardProfile.guid, cur.data.cardDetail.token, cur.data.notifiedView, cur.data.notifiedChannel, cur.channels);
await updateContactArticles(cur.data.cardProfile.node, card.id, cur.data.cardProfile.guid, cur.data.cardDetail.token, cur.data.notifiedView, cur.data.notifiedArticle, 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
await updateContactArticles(cur.data.cardProfile.node, card.id, cur.data.cardProfile.guid, cur.data.cardDetail.token, cur.data.notifiedView, cur.data.notifiedArticle, cur.data.articles);
cur.data.notifiedArticle = card.data.notifiedArticle;
}
if (cur.data.notifiedChannel !== card.data.notifiedChannel) {
// update remote channels
await updateContactChannels(cur.data.cardProfile.node, card.id, cur.data.cardProfile.guid, cur.data.cardDetail.token, cur.data.notifiedView, cur.data.notifiedChannel, cur.channels);
cur.data.notifiedChannel = card.data.notifiedChannel;
}
}
catch (err) {
// contact update failed
console.log(err);
cur.channels = new Map();
cur.articles = new Map();
cur.revision = 0;
cards.current.set(card.id, { ...cur, error: true });
continue;
}
}
else {
cur.channels = new Map();
cur.articles = new Map();
}
cur.revision = card.revision;
cards.current.set(card.id, { ...cur });
try {
const card = cards.current.get(card.id);
await syncCard(card);
cards.current.set(card.id, card);
}
else {
cards.current.delete(card.id);
catch(err) {
console.log(err);
}
syncing.current = false;
await sync();
}
}
const updateContactChannels = async (node, cardId, guid, token, viewRevision, channelRevision, channelMap) => {
let delta = await getContactChannels(node, guid + "." + token, viewRevision, channelRevision);
const sync = async () => {
if (!syncing.current && (setRevision.current !== curRevision.current || force.current)) {
syncing.current = true;
force.current = false;
try {
const token = access.current;
const revision = curRevision.current;
const delta = await getCards(token, setRevision.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() }, offsync: false, 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;
}
if (cur.data.cardDetail.status === 'connected' && !cur.offsync) {
cur.data.curNotifiedView = card.data.notifiedView;
cur.data.curNotifiedProfile = card.data.notifiedProfile;
cur.data.curNotifiedArticle = card.data.notifiedArticle;
cur.data.curNotifiedChannel = card.data.notifiedChannel;
try {
await syncCard(cur);
}
catch (err) {
console.log(err);
cur.offsync = true;
}
}
cards.current.set(cur.id, cur);
}
else {
cards.current.delete(cur.id);
}
}
updateState({ offsync: false, cards: cards.current });
}
catch (err) {
console.log(err);
syncing.current = false;
updateState({ offsync: true });
return;
}
syncing.current = false;
await sync();
}
};
const syncCard = async (token, card) => {
const { cardProfile, cardDetail } = card;
// sync profile
if (card.data.setNotifiedProfile !== card.data.curNotifiedProfile) {
if (card.data.profileRevision != card.data.curNotifiedProfile) {
const token = `${cardProfile.guid}.${cardDetail.token}`;
const message = await getContactProfile(cardProfile.node, token);
await setCardProfile(token, card.id, message);
}
}
card.data.setNotifiedProfile = card.data.curNotifiedProfile;
// sync channels & articles
if (card.data.setNotifiedArticle !== card.data.curNotifiedArticle || card.data.setNotifiedView !== card.data.curNotifiedView) {
await syncCardArticles(card);
}
if (card.data.setNotifiedChannel !== card.data.curNotifiedChannel || card.data.setNotifiedView !== card.data.curNotifiedView) {
await syncCardChannels(card);
}
card.data.setNotifiedArticle = card.data.curNotifiedArticle;
card.data.setNotifiedChannel = card.data.curNotifiedChannel;
card.data.setNotifiedView = card.data.curNotifiedView;
card.offsync = false;
}
const syncCardArticles = async (card) => {
console.log("update contact articles");
}
const syncCardChannels = async (card) => {
const { cardProfile, cardDetail } = card;
const token = `${cardProfile.guid}.${cardDetail.token}`;
let delta;
if (card.data.setNotifiedView !== card.data.curNotifiedView) {
card.channels = new Map();
delta = await getContactChannels(node, token);
}
else {
const { setNotifiedView, setNotifiedChannel } = card.data;
delta = await getContactChannels(node, notifiedView, notifiedChannel);
}
for (let channel of delta) {
if (channel.data) {
let cur = channelMap.get(channel.id);
let cur = card.channels.get(channel.id);
if (cur == null) {
cur = { guid, cardId, id: channel.id, data: { } }
cur = { guid, cardId, id: channel.id, data: {} };
}
if (cur.data.detailRevision !== channel.data.detailRevision) {
if (channel.data.channelDetail != null) {
cur.data.channelDetail = channel.data.channelDetail;
}
else {
let detail = await getContactChannelDetail(node, guid + "." + token, channel.id);
cur.data.channelDetail = detail;
else {
cur.data.channelDetail = await getContactChannelDetail(node, token, channel.id);
}
cur.data.unsealedChannel = null;
cur.data.detailRevision = channel.data.detailRevision;
@ -181,286 +203,37 @@ export function useCardContext() {
cur.data.channelSummary = channel.data.channelSummary;
}
else {
let summary = await getContactChannelSummary(node, guid + "." + token, channel.id);
cur.data.channelSummary = summary;
cur.data.channelSummary = getContactChannelSummary(node, token, channel.id);
}
cur.data.unsealedSummary = null;
cur.data.topicRevision = channel.data.topicRevision;
}
cur.revision = channel.revision;
channelMap.set(channel.id, { ...cur });
card.channels.set(channel.id, cur);
}
else {
channelMap.delete(channel.id);
else {
card.channels.delete(channel.id);
}
}
}
const updateContactArticles = async (node, cardId, guid, token, viewRevision, articleRevision, articleMap) => {
console.log("update contact articles");
}
const setCards = async (rev) => {
if (next.current == null) {
if (rev == null) {
rev = revision.curren;
}
next.current = rev;
if (revision.current !== rev) {
try {
await updateCards();
}
catch(err) {
console.log(err);
}
updateState({ init: true, cards: cards.current });
revision.current = rev;
}
while (resync.current.length) {
try {
await updateCard(resync.current.shift());
updateState({ cards: cards.current });
}
catch (err) {
console.log(err);
}
}
let r = next.current;
next.current = null;
if (revision.current !== r) {
setCards(r);
}
}
else {
if (rev != null) {
next.current = rev;
}
}
}
const getCardByGuid = (guid) => {
let card = null;
cards.current.forEach((value, key, map) => {
if(value?.data?.cardProfile?.guid === guid) {
card = value;
}
});
return card;
}
const actions = {
setToken: (token) => {
if (access.current || syncing.current) {
throw new Error("invalid session state");
}
access.current = token;
cards.current = new Map();
curRevision.current = null;
setRevision.current = null;
setState({ offsync: false, cards: new Map() });
},
clearToken: () => {
access.current = null;
cards.current = new Map();
revision.current = null;
setState({ init: false, cards: new Map() });
},
},
setRevision: async (rev) => {
setCards(rev);
},
getCardByGuid: getCardByGuid,
getCardProfileByGuid: (guid) => {
let card = getCardByGuid(guid);
if (card) {
let { name, handle } = card.data.cardProfile;
if (card.data.cardProfile.imageSet) {
return { name, handle, imageUrl: getCardImageUrl(access.current, card.id, card.data.profileRevision) };
}
return { name, handle }
}
return {};
},
getImageUrl: (cardId) => {
let card = cards.current.get(cardId);
if (!card || !card.data.cardProfile.imageSet) {
return null;
}
return getCardImageUrl(access.current, cardId, card.data.profileRevision)
},
getName: (cardId) => {
let card = cards.current.get(cardId);
if (!card) {
return null;
}
return card.data.cardProfile.name;
},
unsealChannelSubject: (cardId, channelId, sealKey) => {
try {
const card = cards.current.get(cardId);
const channel = card.channels.get(channelId);
const { subjectEncrypted, subjectIv, seals } = JSON.parse(channel.data.channelDetail.data);
const unsealedKey = unsealKey(seals, sealKey);
if (unsealedKey) {
const iv = CryptoJS.enc.Hex.parse(subjectIv);
const key = CryptoJS.enc.Hex.parse(unsealedKey);
const enc = CryptoJS.enc.Base64.parse(subjectEncrypted);
let cipher = CryptoJS.lib.CipherParams.create({ ciphertext: enc, iv: iv });
const dec = CryptoJS.AES.decrypt(cipher, key, { iv: iv });
channel.data.unsealedChannel = JSON.parse(dec.toString(CryptoJS.enc.Utf8));
card.channels.set(channel.id, { ...channel });
cards.current.set(cardId, { ...card });
updateState({ cards: cards.current });
}
}
catch(err) {
console.log(err);
}
},
isUnsealed: (cardId, channelId, sealKey) => {
try {
const card = cards.current.get(cardId);
const channel = card.channels.get(channelId);
const { seals } = JSON.parse(channel.data.channelDetail.data);
for (let i = 0; i < seals.length; i++) {
if (seals[i].publicKey === sealKey.public) {
return sealKey.private != null;
}
}
}
catch(err) {
console.log(err);
}
return false;
},
unsealChannelSummary: (cardId, channelId, sealKey) => {
try {
const card = cards.current.get(cardId);
const channel = card.channels.get(channelId);
const { seals } = JSON.parse(channel.data.channelDetail.data);
const { messageEncrypted, messageIv } = JSON.parse(channel.data.channelSummary.lastTopic.data);
const unsealedKey = unsealKey(seals, sealKey);
if (unsealedKey) {
const iv = CryptoJS.enc.Hex.parse(messageIv);
const key = CryptoJS.enc.Hex.parse(unsealedKey);
const enc = CryptoJS.enc.Base64.parse(messageEncrypted);
const cipher = CryptoJS.lib.CipherParams.create({ ciphertext: enc, iv: iv });
const dec = CryptoJS.AES.decrypt(cipher, key, { iv: iv });
channel.data.unsealedSummary = JSON.parse(dec.toString(CryptoJS.enc.Utf8));
card.channels.set(channel.id, { ...channel });
cards.current.set(cardId, { ...card });
updateState({ cards: cards.current });
}
}
catch(err) {
console.log(err);
}
},
removeChannel: async (cardId, channelId) => {
let { cardProfile, cardDetail } = cards.current.get(cardId).data;
let token = cardProfile.guid + '.' + cardDetail.token;
let node = cardProfile.node;
await removeContactChannel(node, token, channelId);
},
removeChannelTopic: async (cardId, channelId, topicId) => {
let { cardProfile, cardDetail } = cards.current.get(cardId).data;
let token = cardProfile.guid + '.' + cardDetail.token;
let node = cardProfile.node;
await removeContactChannelTopic(node, token, channelId, topicId);
try {
resync.current.push(cardId);
await setCards(null);
}
catch (err) {
console.log(err);
}
},
setChannelTopicSubject: async (cardId, channelId, topicId, data) => {
let { cardProfile, cardDetail } = cards.current.get(cardId).data;
let token = cardProfile.guid + '.' + cardDetail.token;
let node = cardProfile.node;
await setContactChannelTopicSubject(node, token, channelId, topicId, 'superbasictopic', data);
try {
resync.current.push(cardId);
await setCards(null);
}
catch (err) {
console.log(err);
}
},
setSealedChannelTopicSubject: async (cardId, channelId, topicId, data, sealKey) => {
let { cardProfile, cardDetail } = cards.current.get(cardId).data;
let token = cardProfile.guid + '.' + cardDetail.token;
let node = cardProfile.node;
const iv = CryptoJS.lib.WordArray.random(128 / 8);
const key = CryptoJS.enc.Hex.parse(sealKey);
const encrypted = CryptoJS.AES.encrypt(JSON.stringify({ message: data }), key, { iv: iv });
const messageEncrypted = encrypted.ciphertext.toString(CryptoJS.enc.Base64)
const messageIv = iv.toString();
await setContactChannelTopicSubject(node, token, channelId, topicId, 'sealedtopic', { messageEncrypted, messageIv });
try {
resync.current.push(cardId);
await setCards(null);
}
catch (err) {
console.log(err);
}
},
addChannelTopic: async (cardId, channelId, message, files) => {
let { cardProfile, cardDetail } = cards.current.get(cardId).data;
let token = cardProfile.guid + '.' + cardDetail.token;
let node = cardProfile.node;
if (files?.length) {
const topicId = await addContactChannelTopic(node, token, channelId, null, null, null);
upload.actions.addContactTopic(node, token, cardId, channelId, topicId, files, async (assets) => {
message.assets = assets;
await setContactChannelTopicSubject(node, token, channelId, topicId, message);
}, async () => {
try {
await removeContactChannelTopic(node, token, channelId, topicId);
}
catch(err) {
console.log(err);
}
});
}
else {
await addContactChannelTopic(node, token, channelId, 'superbasictopic', message, files);
}
try {
resync.current.push(cardId);
await setCards(null);
}
catch (err) {
console.log(err);
}
},
addSealedChannelTopic: async (cardId, channelId, sealKey, message) => {
let { cardProfile, cardDetail } = cards.current.get(cardId).data;
let token = cardProfile.guid + '.' + cardDetail.token;
let node = cardProfile.node;
const iv = CryptoJS.lib.WordArray.random(128 / 8);
const key = CryptoJS.enc.Hex.parse(sealKey);
const encrypted = CryptoJS.AES.encrypt(JSON.stringify({ message }), key, { iv: iv });
const messageEncrypted = encrypted.ciphertext.toString(CryptoJS.enc.Base64)
const messageIv = iv.toString();
await addContactChannelTopic(node, token, channelId, 'sealedtopic', { messageEncrypted, messageIv });
},
getChannel: (cardId, channelId) => {
let card = cards.current.get(cardId);
let channel = card.channels.get(channelId);
return channel;
},
getChannelRevision: (cardId, channelId) => {
let card = cards.current.get(cardId);
let channel = card.channels.get(channelId);
return channel?.revision;
},
getChannelTopics: async (cardId, channelId, revision, count, begin, end) => {
let card = cards.current.get(cardId);
let node = card.data.cardProfile.node;
let token = card.data.cardProfile.guid + '.' + card.data.cardDetail.token;
return await getContactChannelTopics(node, token, channelId, revision, count, begin, end);
},
getChannelTopic: async (cardId, channelId, topicId) => {
let card = cards.current.get(cardId);
let node = card.data.cardProfile.node;
let token = card.data.cardProfile.guid + '.' + card.data.cardDetail.token;
return await getContactChannelTopic(node, token, channelId, topicId);
curRevision.current = rev;
await sync();
},
addCard: async (message) => {
return await addCard(access.current, message);
@ -490,16 +263,91 @@ export function useCardContext() {
setCardCloseMessage: async (server, message) => {
return await setCardCloseMessage(server, message);
},
getContactChannelTopicAssetUrl: (cardId, channelId, topicId, assetId) => {
let card = cards.current.get(cardId);
let node = card.data.cardProfile.node;
let token = card.data.cardProfile.guid + "." + card.data.cardDetail.token;
removeChannel: async (cardId, channelId) => {
let { cardProfile, cardDetail } = cards.current.get(cardId).data;
let token = cardProfile.guid + '.' + cardDetail.token;
let node = cardProfile.node;
await removeContactChannel(node, token, channelId);
},
unsealChannelSubject: async (cardId, channelId, unsealed, revision) => {
const card = cards.current.get(cardId);
const channel = card.channels.get(channelId);
if (channel.revision === revision) {
channel.data.unsealedSubject = unsealed;
card.channels.set(channelId, channel);
cards.current.set(cardId, card);
updateState({ cards: cards.current });
}
},
unsealChannelSummary: async (channelId, unsealed, revision) => {
const card = cards.current.get(cardId);
const channel = card.channels.get(channelId);
if (channel.revision === revision) {
channel.data.unsealedSummary = unsealed;
card.channels.set(channelId, channel);
cards.current.set(cardId, card);
updateState({ cards: cards.current });
}
},
addTopic: async (cardId, channelId, type, message, files) => {
let { cardProfile, cardDetail } = cards.current.get(cardId).data;
let token = cardProfile.guid + '.' + cardDetail.token;
let node = cardProfile.node;
if (files?.length) {
const topicId = await addContactChannelTopic(node, token, channelId, null, null, null);
upload.actions.addContactTopic(node, token, cardId, channelId, topicId, files, async (assets) => {
const subject = message(assets);
await setContactChannelTopicSubject(node, token, channelId, topicId, type, subject);
}, async () => {
try {
await removeContactChannelTopic(node, token, channelId, topicId);
}
catch(err) {
console.log(err);
}
});
}
else {
const subject = message([]);
await addContactChannelTopic(node, token, channelId, type, subject, files);
}
resyncCard(cardId);
},
removeChannelTopic: async (cardId, channelId, topicId) => {
let { cardProfile, cardDetail } = cards.current.get(cardId).data;
let token = cardProfile.guid + '.' + cardDetail.token;
let node = cardProfile.node;
await removeContactChannelTopic(node, token, channelId, topicId);
resyncCard(cardId);
},
setChannelTopicSubject: async (cardId, channelId, topicId, type, subject) => {
let { cardProfile, cardDetail } = cards.current.get(cardId).data;
let token = cardProfile.guid + '.' + cardDetail.token;
let node = cardProfile.node;
await setContactChannelTopicSubject(node, token, channelId, topicId, type, subject);
resyncCard(cardId);
},
getChannelTopicAssetUrl: (cardId, channelId, topicId, assetId) => {
let { cardProfile, cardDetail } = cards.current.get(cardId).data;
let token = cardProfile.guid + '.' + cardDetail.token;
let node = cardProfile.node;
return getContactChannelTopicAssetUrl(node, token, channelId, topicId, assetId);
},
resync: async (cardId) => {
resync.current.push(cardId);
await setCards(null);
}
getChannelTopics: async (channelId, revision, count, begin, end) => {
let { cardProfile, cardDetail } = cards.current.get(cardId).data;
let token = cardProfile.guid + '.' + cardDetail.token;
let node = cardProfile.node;
return await getContactChannelTopics(node, token, channelId, revision, count, begin, end);
},
getChannelTopic: async (channelId, topicId) => {
let { cardProfile, cardDetail } = cards.current.get(cardId).data;
let token = cardProfile.guid + '.' + cardDetail.token;
let node = cardProfile.node;
return await getChannelTopic(node, token, channelId, topicId);
},
resync: async () => {
await resync();
},
}
return { state, actions }

View File

@ -26,14 +26,26 @@ export function useChannelContext() {
const curRevision = useRef(null);
const channels = useRef(new Map());
const syncing = useRef(false);
const force = useRef(false);
const updateState = (value) => {
setState((s) => ({ ...s, ...value }))
}
const resync = async () => {
try {
force.current = true;
await sync();
}
catch (err) {
console.log(err);
}
};
const sync = async () => {
if (!syncing.current && setRevision.current !== curRevision.current) {
if (!syncing.current && (setRevision.current !== curRevision.current || force.current)) {
syncing.current = true;
force.current = false;
try {
const token = access.current;
@ -157,19 +169,15 @@ export function useChannelContext() {
const subject = message([]);
await addChannelTopic(access.current, channelId, type, subject);
}
try {
await setChannels(null);
}
catch (err) {
console.log(err);
}
await resync();
},
removeTopic: async (channelId, topicId) => {
await removeChannelTopic(access.current, channelId, topicId);
await resync();
},
setTopicSubject: async (channelId, topicId, type, subject) => {
await setChannelTopicSubject(access.current, channelId, topicId, type, subject);
await resync();
},
getChannelTopicAssetUrl: (channelId, topicId, assetId) => {
return getChannelTopicAssetUrl(access.current, channelId, topicId, assetId);
@ -181,7 +189,7 @@ export function useChannelContext() {
return await getChannelTopic(access.current, channelId, topicId);
},
resync: async () => {
await sync();
await resync();
},
};

84
net/web/test/Card.test.js Normal file
View File

@ -0,0 +1,84 @@
import React, { useState, useEffect, useContext } from 'react';
import { prettyDOM } from '@testing-library/dom'
import {render, act, screen, waitFor, fireEvent} from '@testing-library/react'
import { CardContextProvider, CardContext } from 'context/CardContext';
import * as fetchUtil from 'api/fetchUtil';
let cardContext = null;
function CardView() {
const [renderCount, setRenderCount] = useState(0);
const [cards, setCards] = useState([]);
const card = useContext(CardContext);
cardContext = card;
useEffect(() => {
const rendered = []
const entries = Array.from(card.state.cards.values());
entries.forEach(entry => {
rendered.push(
<div key={entry.id} data-testid="card">
</div>);
});
setCards(rendered);
setRenderCount(renderCount + 1);
}, [card.state])
return (
<div data-testid="cards" count={renderCount} offsync={card.state.offsync.toString()}>
{ cards }
</div>
);
}
function CardTestApp() {
return (
<CardContextProvider>
<CardView />
</CardContextProvider>
)
}
const realFetchWithTimeout = fetchUtil.fetchWithTimeout;
const realFetchWithCustomTimeout = fetchUtil.fetchWithCustomTimeout;
let statusCards;
let fetchCards;
beforeEach(() => {
statusCards = 200;
fetchCards =[];
const mockFetch = jest.fn().mockImplementation((url, options) => {
return Promise.resolve({
url: 'getChannels',
status: statusChannels,
json: () => Promise.resolve(fetchChannels),
});
});
fetchUtil.fetchWithTimeout = mockFetch;
fetchUtil.fetchWithCustomTimeout = mockFetch;
});
afterEach(() => {
fetchUtil.fetchWithTimeout = realFetchWithTimeout;
fetchUtil.fetchWithCustomTimeout = realFetchWithCustomTimeout;
});
test('boilerplate', async () => {
render(<CardTestApp />);
await waitFor(async () => {
expect(cardContext).not.toBe(null);
});
await act( async () => {
cardContext.actions.setToken('abc123');
});
await act( async () => {
cardContext.actions.clearToken();
});
});

View File

@ -15,7 +15,6 @@ function ChannelView() {
const rendered = []
const entries = Array.from(channel.state.channels.values());
entries.forEach(entry => {
console.log(entry.data.unsealedSubject);
rendered.push(
<div key={entry.id} data-testid="channel">