mirror of
https://github.com/balzack/databag.git
synced 2025-02-15 21:19:16 +00:00
cleanup on channel context
This commit is contained in:
parent
fbd46b3f3f
commit
b1b26b3fe4
@ -1,6 +1,6 @@
|
|||||||
import { checkResponse, fetchWithTimeout } from './fetchUtil';
|
import { checkResponse, fetchWithTimeout } from './fetchUtil';
|
||||||
|
|
||||||
export async function addChannelTopic(token, channelId, datatype, message, assets ): string {
|
export async function addChannelTopic(token, channelId, datatype, message, assets ) {
|
||||||
|
|
||||||
if (message == null && (assets == null || assets.length === 0)) {
|
if (message == null && (assets == null || assets.length === 0)) {
|
||||||
let topic = await fetchWithTimeout(`/content/channels/${channelId}/topics?agent=${token}`,
|
let topic = await fetchWithTimeout(`/content/channels/${channelId}/topics?agent=${token}`,
|
||||||
|
@ -14,216 +14,107 @@ import { setChannelSubject } from 'api/setChannelSubject';
|
|||||||
import { setChannelCard } from 'api/setChannelCard';
|
import { setChannelCard } from 'api/setChannelCard';
|
||||||
import { clearChannelCard } from 'api/clearChannelCard';
|
import { clearChannelCard } from 'api/clearChannelCard';
|
||||||
import { UploadContext } from 'context/UploadContext';
|
import { UploadContext } from 'context/UploadContext';
|
||||||
import CryptoJS from 'crypto-js';
|
|
||||||
import { JSEncrypt } from 'jsencrypt'
|
|
||||||
|
|
||||||
export function useChannelContext() {
|
export function useChannelContext() {
|
||||||
const [state, setState] = useState({
|
const [state, setState] = useState({
|
||||||
init: false,
|
offsync: false,
|
||||||
channels: new Map(),
|
channels: new Map(),
|
||||||
});
|
});
|
||||||
const upload = useContext(UploadContext);
|
const upload = useContext(UploadContext);
|
||||||
const access = useRef(null);
|
const access = useRef(null);
|
||||||
const revision = useRef(null);
|
const setRevision = useRef(null);
|
||||||
|
const curRevision = useRef(null);
|
||||||
const channels = useRef(new Map());
|
const channels = useRef(new Map());
|
||||||
const next = useRef(null);
|
const syncing = useRef(false);
|
||||||
|
|
||||||
const updateState = (value) => {
|
const updateState = (value) => {
|
||||||
setState((s) => ({ ...s, ...value }))
|
setState((s) => ({ ...s, ...value }))
|
||||||
}
|
}
|
||||||
|
|
||||||
const unsealKey = (seals, sealKey) => {
|
const sync = async () => {
|
||||||
let unsealedKey;
|
if (!syncing.current && setRevision.current !== curRevision.current) {
|
||||||
if (seals?.length) {
|
syncing.current = true;
|
||||||
seals.forEach(seal => {
|
|
||||||
if (seal.publicKey === sealKey.public) {
|
|
||||||
let crypto = new JSEncrypt();
|
|
||||||
crypto.setPrivateKey(sealKey.private);
|
|
||||||
unsealedKey = crypto.decrypt(seal.sealedKey);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return unsealedKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
const updateChannels = async () => {
|
try {
|
||||||
let delta = await getChannels(access.current, revision.current);
|
const token = access.current;
|
||||||
for (let channel of delta) {
|
const revision = curRevision.current;
|
||||||
if (channel.data) {
|
const delta = await getChannels(token, setRevision.current);
|
||||||
let cur = channels.current.get(channel.id);
|
for (let channel of delta) {
|
||||||
if (cur == null) {
|
if (channel.data) {
|
||||||
cur = { id: channel.id, data: { } }
|
let cur = channels.current.get(channel.id);
|
||||||
}
|
if (cur == null) {
|
||||||
if (cur.data.detailRevision !== channel.data.detailRevision) {
|
cur = { id: channel.id, data: { } }
|
||||||
if (channel.data.channelDetail != null) {
|
}
|
||||||
cur.data.channelDetail = channel.data.channelDetail;
|
if (cur.data.detailRevision !== channel.data.detailRevision) {
|
||||||
|
if (channel.data.channelDetail != null) {
|
||||||
|
cur.data.channelDetail = channel.data.channelDetail;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
let detail = await getChannelDetail(token, channel.id);
|
||||||
|
cur.data.channelDetail = detail;
|
||||||
|
}
|
||||||
|
cur.data.unsealedSubject = null;
|
||||||
|
cur.data.detailRevision = channel.data.detailRevision;
|
||||||
|
}
|
||||||
|
if (cur.data.topicRevision !== channel.data.topicRevision) {
|
||||||
|
if (channel.data.channelSummary != null) {
|
||||||
|
cur.data.channelSummary = channel.data.channelSummary;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
let summary = await getChannelSummary(token, channel.id);
|
||||||
|
cur.data.channelSummary = summary;
|
||||||
|
}
|
||||||
|
cur.data.unsealedSummary = null;
|
||||||
|
cur.data.topicRevision = channel.data.topicRevision;
|
||||||
|
}
|
||||||
|
cur.revision = channel.revision;
|
||||||
|
channels.current.set(channel.id, cur);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
let detail = await getChannelDetail(access.current, channel.id);
|
channels.current.delete(channel.id);
|
||||||
cur.data.channelDetail = detail;
|
|
||||||
}
|
}
|
||||||
cur.data.unsealedChannel = null;
|
|
||||||
cur.data.detailRevision = channel.data.detailRevision;
|
|
||||||
}
|
}
|
||||||
if (cur.data.topicRevision !== channel.data.topicRevision) {
|
setRevision.current = revision;
|
||||||
if (channel.data.channelSummary != null) {
|
updateState({ offsync: false, channels: channels.current });
|
||||||
cur.data.channelSummary = channel.data.channelSummary;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
let summary = await getChannelSummary(access.current, channel.id);
|
|
||||||
cur.data.channelSummary = summary;
|
|
||||||
}
|
|
||||||
cur.data.unsealedSummary = null;
|
|
||||||
cur.data.topicRevision = channel.data.topicRevision;
|
|
||||||
}
|
|
||||||
cur.revision = channel.revision;
|
|
||||||
channels.current.set(channel.id, { ...cur });
|
|
||||||
}
|
}
|
||||||
else {
|
catch(err) {
|
||||||
channels.current.delete(channel.id);
|
console.log(err);
|
||||||
|
syncing.current = false;
|
||||||
|
updateState({ offsync: true });
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const setChannels = async (rev) => {
|
syncing.current = false;
|
||||||
let force = false;
|
await sync();
|
||||||
if (rev == null) {
|
|
||||||
force = true;
|
|
||||||
rev = revision.current;
|
|
||||||
}
|
|
||||||
if (next.current == null) {
|
|
||||||
next.current = rev;
|
|
||||||
if (force || revision.current !== rev) {
|
|
||||||
await updateChannels();
|
|
||||||
updateState({ init: true, channels: channels.current });
|
|
||||||
revision.current = rev;
|
|
||||||
}
|
|
||||||
let r = next.current;
|
|
||||||
next.current = null;
|
|
||||||
if (revision.current !== r) {
|
|
||||||
setChannels(r);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
next.current = rev;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const actions = {
|
const actions = {
|
||||||
setToken: (token) => {
|
setToken: (token) => {
|
||||||
|
if (access.current || syncing.current) {
|
||||||
|
throw new Error("invalid session state");
|
||||||
|
}
|
||||||
access.current = token;
|
access.current = token;
|
||||||
|
channels.current = new Map();
|
||||||
|
curRevision.current = null;
|
||||||
|
setRevision.current = null;
|
||||||
|
setState({ offsync: false, channels: new Map() });
|
||||||
},
|
},
|
||||||
clearToken: () => {
|
clearToken: () => {
|
||||||
access.current = null;
|
access.current = null;
|
||||||
channels.current = new Map();
|
|
||||||
revision.current = null;
|
|
||||||
setState({ init: false, channels: new Map() });
|
|
||||||
},
|
},
|
||||||
setRevision: async (rev) => {
|
setRevision: async (rev) => {
|
||||||
setChannels(rev);
|
curRevision.current = rev;
|
||||||
|
await sync();
|
||||||
},
|
},
|
||||||
addBasicChannel: async (cards, subject) => {
|
addChannel: async (type, subject, cards) => {
|
||||||
return await addChannel(access.current, 'superbasic', cards, { subject });
|
return await addChannel(access.current, type, cards, subject);
|
||||||
},
|
},
|
||||||
addSealedChannel: async (cards, subject, keys) => {
|
removeChannel: async (channelId) => {
|
||||||
const key = CryptoJS.lib.WordArray.random(256 / 8);
|
return await removeChannel(access.current, channelId);
|
||||||
const iv = CryptoJS.lib.WordArray.random(128 / 8);
|
|
||||||
const encrypted = CryptoJS.AES.encrypt(JSON.stringify({ subject }), key, { iv: iv });
|
|
||||||
const subjectEncrypted = encrypted.ciphertext.toString(CryptoJS.enc.Base64)
|
|
||||||
const subjectIv = iv.toString();
|
|
||||||
const keyHex = key.toString();
|
|
||||||
|
|
||||||
let seals = [];
|
|
||||||
let crypto = new JSEncrypt();
|
|
||||||
keys.forEach(publicKey => {
|
|
||||||
crypto.setPublicKey(publicKey);
|
|
||||||
const sealedKey = crypto.encrypt(keyHex);
|
|
||||||
seals.push({ publicKey, sealedKey });
|
|
||||||
});
|
|
||||||
|
|
||||||
const data = { subjectEncrypted, subjectIv, seals };
|
|
||||||
return await addChannel(access.current, 'sealed', cards, data);
|
|
||||||
},
|
},
|
||||||
unsealChannelSubject: (channelId, sealKey) => {
|
setChannelSubject: async (channelId, type, subject) => {
|
||||||
try {
|
return await setChannelSubject(access.current, channelId, type, subject);
|
||||||
const channel = channels.current.get(channelId);
|
|
||||||
const { subjectEncrypted, subjectIv, seals } = JSON.parse(channel.data.channelDetail.data);
|
|
||||||
const unsealedKey = unsealKey(seals, sealKey);
|
|
||||||
if (unsealKey) {
|
|
||||||
const iv = CryptoJS.enc.Hex.parse(subjectIv);
|
|
||||||
const key = CryptoJS.enc.Hex.parse(unsealedKey);
|
|
||||||
const enc = CryptoJS.enc.Base64.parse(subjectEncrypted);
|
|
||||||
const 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));
|
|
||||||
channels.current.set(channel.id, { ...channel });
|
|
||||||
updateState({ channels: channels.current });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch(err) {
|
|
||||||
console.log(err);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
isUnsealed: (channelId, sealKey) => {
|
|
||||||
try {
|
|
||||||
const channel = channels.current.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: (channelId, sealKey) => {
|
|
||||||
try {
|
|
||||||
const channel = channels.current.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 (unsealKey) {
|
|
||||||
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));
|
|
||||||
channels.current.set(channel.id, { ...channel });
|
|
||||||
updateState({ channels: channels.current });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch(err) {
|
|
||||||
console.log(err);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
setChannelSubject: async (channelId, subject) => {
|
|
||||||
return await setChannelSubject(access.current, channelId, 'superbasic', { subject });
|
|
||||||
},
|
|
||||||
setChannelSealedSubject: async (channelId, subject, sealKey) => {
|
|
||||||
const channel = channels.current.get(channelId);
|
|
||||||
|
|
||||||
let { seals, subjectEncrypted, subjectIv } = JSON.parse(channel.data.channelDetail.data);
|
|
||||||
if (seals?.length) {
|
|
||||||
seals.forEach(seal => {
|
|
||||||
if (seal.publicKey === sealKey.public) {
|
|
||||||
let crypto = new JSEncrypt();
|
|
||||||
crypto.setPrivateKey(sealKey.private);
|
|
||||||
const unsealedKey = crypto.decrypt(seal.sealedKey);
|
|
||||||
const key = CryptoJS.enc.Hex.parse(unsealedKey);
|
|
||||||
|
|
||||||
const iv = CryptoJS.lib.WordArray.random(128 / 8);
|
|
||||||
const encrypted = CryptoJS.AES.encrypt(JSON.stringify({ subject }), key, { iv: iv });
|
|
||||||
subjectEncrypted = encrypted.ciphertext.toString(CryptoJS.enc.Base64)
|
|
||||||
subjectIv = iv.toString();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
const data = { subjectEncrypted, subjectIv, seals };
|
|
||||||
return await setChannelSubject(access.current, channelId, 'sealed', data);
|
|
||||||
},
|
},
|
||||||
setChannelCard: async (channelId, cardId) => {
|
setChannelCard: async (channelId, cardId) => {
|
||||||
return await setChannelCard(access.current, channelId, cardId);
|
return await setChannelCard(access.current, channelId, cardId);
|
||||||
@ -231,47 +122,28 @@ export function useChannelContext() {
|
|||||||
clearChannelCard: async (channelId, cardId) => {
|
clearChannelCard: async (channelId, cardId) => {
|
||||||
return await clearChannelCard(access.current, channelId, cardId);
|
return await clearChannelCard(access.current, channelId, cardId);
|
||||||
},
|
},
|
||||||
removeChannel: async (channelId) => {
|
unsealChannelSubject: async (channelId, unsealed, revision) => {
|
||||||
return await removeChannel(access.current, channelId);
|
const channel = channels.current.get(channelId);
|
||||||
},
|
if (channel.revision === revision) {
|
||||||
removeChannelTopic: async (channelId, topicId) => {
|
channel.data.unsealedSubject = unsealed;
|
||||||
await removeChannelTopic(access.current, channelId, topicId);
|
channels.current.set(channelId, channel);
|
||||||
try {
|
updateState({ channels: channels.current });
|
||||||
await setChannels(null);
|
|
||||||
}
|
|
||||||
catch (err) {
|
|
||||||
console.log(err);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
setChannelTopicSubject: async (channelId, topicId, data) => {
|
unsealChannelSummary: async (channelId, unsealed, revision) => {
|
||||||
await setChannelTopicSubject(access.current, channelId, topicId, 'superbasictopic', data);
|
const channel = channels.current.get(channelId);
|
||||||
try {
|
if (channel.revision === revision) {
|
||||||
await setChannels(null);
|
channel.data.unsealedSummary = unsealed;
|
||||||
}
|
channels.current.set(channelId, chanel);
|
||||||
catch (err) {
|
updateState({ channels: channels.current });
|
||||||
console.log(err);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
setSealedChannelTopicSubject: async (channelId, topicId, data, sealKey) => {
|
addTopic: async (channelId, type, message, files) => {
|
||||||
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 setChannelTopicSubject(access.current, channelId, topicId, 'sealedtopic', { messageEncrypted, messageIv });
|
|
||||||
try {
|
|
||||||
await setChannels(null);
|
|
||||||
}
|
|
||||||
catch (err) {
|
|
||||||
console.log(err);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
addChannelTopic: async (channelId, message, files) => {
|
|
||||||
if (files?.length) {
|
if (files?.length) {
|
||||||
const topicId = await addChannelTopic(access.current, channelId, null, null, null);
|
const topicId = await addChannelTopic(access.current, channelId, null, null, null);
|
||||||
upload.actions.addTopic(access.current, channelId, topicId, files, async (assets) => {
|
upload.actions.addTopic(access.current, channelId, topicId, files, async (assets) => {
|
||||||
message.assets = assets;
|
const subject = message(assets);
|
||||||
await setChannelTopicSubject(access.current, channelId, topicId, 'superbasictopic', message);
|
await setChannelTopicSubject(access.current, channelId, topicId, type, subject);
|
||||||
}, async () => {
|
}, async () => {
|
||||||
try {
|
try {
|
||||||
await removeChannelTopic(access.current, channelId, topicId);
|
await removeChannelTopic(access.current, channelId, topicId);
|
||||||
@ -282,7 +154,8 @@ export function useChannelContext() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
await addChannelTopic(access.current, channelId, 'superbasictopic', message, files);
|
const subject = message([]);
|
||||||
|
await addChannelTopic(access.current, channelId, type, subject);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
await setChannels(null);
|
await setChannels(null);
|
||||||
@ -290,21 +163,16 @@ export function useChannelContext() {
|
|||||||
catch (err) {
|
catch (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
addSealedChannelTopic: async (channelId, sealKey, message) => {
|
removeTopic: async (channelId, topicId) => {
|
||||||
const iv = CryptoJS.lib.WordArray.random(128 / 8);
|
await removeChannelTopic(access.current, channelId, topicId);
|
||||||
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 addChannelTopic(access.current, channelId, 'sealedtopic', { messageEncrypted, messageIv });
|
|
||||||
},
|
},
|
||||||
getChannel: (channelId) => {
|
setTopicSubject: async (channelId, topicId, type, subject) => {
|
||||||
return channels.current.get(channelId);
|
await setChannelTopicSubject(access.current, channelId, topicId, type, subject);
|
||||||
},
|
},
|
||||||
getChannelRevision: (channelId) => {
|
getChannelTopicAssetUrl: (channelId, topicId, assetId) => {
|
||||||
let channel = channels.current.get(channelId);
|
return getChannelTopicAssetUrl(access.current, channelId, topicId, assetId);
|
||||||
return channel?.revision;
|
|
||||||
},
|
},
|
||||||
getChannelTopics: async (channelId, revision, count, begin, end) => {
|
getChannelTopics: async (channelId, revision, count, begin, end) => {
|
||||||
return await getChannelTopics(access.current, channelId, revision, count, begin, end);
|
return await getChannelTopics(access.current, channelId, revision, count, begin, end);
|
||||||
@ -312,10 +180,10 @@ export function useChannelContext() {
|
|||||||
getChannelTopic: async (channelId, topicId) => {
|
getChannelTopic: async (channelId, topicId) => {
|
||||||
return await getChannelTopic(access.current, channelId, topicId);
|
return await getChannelTopic(access.current, channelId, topicId);
|
||||||
},
|
},
|
||||||
getChannelTopicAssetUrl: (channelId, topicId, assetId) => {
|
resync: async () => {
|
||||||
return getChannelTopicAssetUrl(access.current, channelId, topicId, assetId);
|
await sync();
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
|
|
||||||
return { state, actions }
|
return { state, actions }
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ import { getProfileImageUrl } from 'api/getProfileImageUrl';
|
|||||||
|
|
||||||
export function useProfileContext() {
|
export function useProfileContext() {
|
||||||
const [state, setState] = useState({
|
const [state, setState] = useState({
|
||||||
|
offsync: false,
|
||||||
identity: {},
|
identity: {},
|
||||||
imageUrl: null,
|
imageUrl: null,
|
||||||
});
|
});
|
||||||
@ -24,36 +25,41 @@ export function useProfileContext() {
|
|||||||
syncing.current = true;
|
syncing.current = true;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
const token = access.current;
|
||||||
const revision = curRevision.current;
|
const revision = curRevision.current;
|
||||||
const identity = await getProfile(access.current);
|
const identity = await getProfile(access.current);
|
||||||
const imageUrl = identity.image ? getProfileImageUrl(access.current, revision) : null;
|
const imageUrl = identity.image ? getProfileImageUrl(token, revision) : null;
|
||||||
updateState({ identity, imageUrl });
|
|
||||||
setRevision.current = revision;
|
setRevision.current = revision;
|
||||||
|
updateState({ offsync: false, identity, imageUrl });
|
||||||
}
|
}
|
||||||
catch(err) {
|
catch(err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
syncing.current = false;
|
syncing.current = false;
|
||||||
|
updateState({ offsync: true });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
syncing.current = false;
|
syncing.current = false;
|
||||||
sync();
|
await sync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const actions = {
|
const actions = {
|
||||||
setToken: (token) => {
|
setToken: (token) => {
|
||||||
|
if (access.current || syncing.current) {
|
||||||
|
throw new Error("invalid session state");
|
||||||
|
}
|
||||||
access.current = token;
|
access.current = token;
|
||||||
|
curRevision.current = null;
|
||||||
|
setRevision.current = null;
|
||||||
|
setState({ offsync: false, identity: {}, imageUrl: null });
|
||||||
},
|
},
|
||||||
clearToken: () => {
|
clearToken: () => {
|
||||||
access.current = null;
|
access.current = null;
|
||||||
curRevision.current = null;
|
|
||||||
setRevision.current = null;
|
|
||||||
setState({ identity: {}, imageUrl: null });
|
|
||||||
},
|
},
|
||||||
setRevision: (rev) => {
|
setRevision: async (rev) => {
|
||||||
curRevision.current = rev;
|
curRevision.current = rev;
|
||||||
sync();
|
await sync();
|
||||||
},
|
},
|
||||||
setProfileData: async (name, location, description) => {
|
setProfileData: async (name, location, description) => {
|
||||||
await setProfileData(access.current, name, location, description);
|
await setProfileData(access.current, name, location, description);
|
||||||
@ -64,6 +70,9 @@ export function useProfileContext() {
|
|||||||
getHandleStatus: async (name) => {
|
getHandleStatus: async (name) => {
|
||||||
return await getUsername(name, access.current);
|
return await getUsername(name, access.current);
|
||||||
},
|
},
|
||||||
|
resync: async () => {
|
||||||
|
await sync();
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
return { state, actions }
|
return { state, actions }
|
||||||
|
61
net/web/test/Channel.test.js
Normal file
61
net/web/test/Channel.test.js
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
import React, { useState, useEffect, useContext } from 'react';
|
||||||
|
import {render, act, screen, waitFor, fireEvent} from '@testing-library/react'
|
||||||
|
import { ChannelContextProvider, ChannelContext } from 'context/ChannelContext';
|
||||||
|
import * as fetchUtil from 'api/fetchUtil';
|
||||||
|
|
||||||
|
let channelContext = null;
|
||||||
|
function ChannelView() {
|
||||||
|
const [renderCount, setRenderCount] = useState(0);
|
||||||
|
const channel = useContext(ChannelContext);
|
||||||
|
channelContext = channel;
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setRenderCount(renderCount + 1);
|
||||||
|
}, [channel.state]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<span data-testid="count">{ renderCount }</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function ChannelTestApp() {
|
||||||
|
return (
|
||||||
|
<ChannelContextProvider>
|
||||||
|
<ChannelView />
|
||||||
|
</ChannelContextProvider>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const realFetchWithTimeout = fetchUtil.fetchWithTimeout;
|
||||||
|
const realFetchWithCustomTimeout = fetchUtil.fetchWithCustomTimeout;
|
||||||
|
|
||||||
|
let fetching = (url, options) => Promise.resolve({ json: () => Promise.resolve([])});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
const mockFetch = jest.fn().mockImplementation((url, options) => fetching(url, options));
|
||||||
|
fetchUtil.fetchWithTimeout = mockFetch;
|
||||||
|
fetchUtil.fetchWithCustomTimeout = mockFetch;
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
fetchUtil.fetchWithTimeout = realFetchWithTimeout;
|
||||||
|
fetchUtil.fetchWithCustomTimeout = realFetchWithCustomTimeout;
|
||||||
|
});
|
||||||
|
|
||||||
|
test('testing channel sync', async () => {
|
||||||
|
render(<ChannelTestApp />);
|
||||||
|
|
||||||
|
await waitFor(async () => {
|
||||||
|
expect(channelContext).not.toBe(null);
|
||||||
|
});
|
||||||
|
|
||||||
|
await act( async () => {
|
||||||
|
channelContext.actions.setToken('abc123');
|
||||||
|
await channelContext.actions.setRevision(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -60,7 +60,7 @@ afterEach(() => {
|
|||||||
fetchUtil.fetchWithCustomTimeout = realFetchWithCustomTimeout;
|
fetchUtil.fetchWithCustomTimeout = realFetchWithCustomTimeout;
|
||||||
});
|
});
|
||||||
|
|
||||||
test('testing', async () => {
|
test('testing profile sync', async () => {
|
||||||
render(<ProfileTestApp />);
|
render(<ProfileTestApp />);
|
||||||
|
|
||||||
await waitFor(async () => {
|
await waitFor(async () => {
|
||||||
@ -107,10 +107,6 @@ test('testing', async () => {
|
|||||||
await profileContext.actions.clearToken();
|
await profileContext.actions.clearToken();
|
||||||
});
|
});
|
||||||
|
|
||||||
await waitFor(async () => {
|
|
||||||
expect(screen.getByTestId('name').textContent).toBe("");
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user