Skip to content

Commit

Permalink
Refactor content script and Reader
Browse files Browse the repository at this point in the history
  • Loading branch information
jo-es committed Jul 31, 2020
1 parent 0fb3328 commit 11e7949
Show file tree
Hide file tree
Showing 5 changed files with 154 additions and 169 deletions.
153 changes: 91 additions & 62 deletions public/content.js
Original file line number Diff line number Diff line change
@@ -1,74 +1,103 @@
/* global chrome */

chrome.runtime.onMessage.addListener(function (request, sender, callback) {
main();
main();
});

function main() {
// eslint-disable-next-line no-undef
const extensionOrigin = 'chrome-extension://' + chrome.runtime.id;
// eslint-disable-next-line no-restricted-globals
if (!location.ancestorOrigins.contains(extensionOrigin)) {
// Fetch the local React index.html page
// eslint-disable-next-line no-undef
fetch(chrome.runtime.getURL('index.html') /*, options */)
.then((response) => response.text())
.then((html) => {
const styleStashHTML = html.replace(/\/static\//g, `${extensionOrigin}/static/`);
// eslint-disable-next-line no-undef
$(styleStashHTML).appendTo('body');
})
.catch((error) => {
console.warn(error);
});
}
// eslint-disable-next-line no-undef
const extensionOrigin = 'chrome-extension://' + chrome.runtime.id;
// eslint-disable-next-line no-restricted-globals
if (!location.ancestorOrigins.contains(extensionOrigin)) {
// Fetch the local React index.html page
// eslint-disable-next-line no-undef
fetch(chrome.runtime.getURL('index.html') /*, options */)
.then((response) => response.text())
.then((html) => {
const styleStashHTML = html.replace(/\/static\//g, `${extensionOrigin}/static/`);
// eslint-disable-next-line no-undef
$(styleStashHTML).appendTo('body');
})
.catch((error) => {
console.warn(error);
});
}
}

window.addEventListener("message", function (event) {
if (event.source !== window) return;
onDidReceiveMessage(event);
window.addEventListener('message', function (event) {
if (event.source !== window) return;
onDidReceiveMessage(event);
});

async function getAnnotationData(cid) {
try {
const response = await fetch('https://gateway.pinata.cloud/ipfs' + '/' + cid);

if (response.status !== 200) { throw new Error(response); }

try {
return await response.json();
} catch (error) {
throw new Error('Response body is empty.')
}
} catch (error) {
throw new Error('Could not query IPFS node: ' + error);
}
}

async function onDidReceiveMessage(event) {
// we should probably add a switch here to handle multiple types of requests
if (event.data.type && (event.data.type === "GET_ANNOTATIONS")) {
// TODO: this data is hardcoded, it has to come from the event
var data = JSON.stringify({ "query": "\n {\n annotations(first: 10, skip: 0, where: { ref_contains: \"1281904943700619265\" }) {\n cid\n ref\n }\n }\n " });
// I used XMLHttpRequest instead of fetch just because it was the first example on Postman,
// on the getAnnotationData above we're using fetch, so we should refactor this function to also use fetch.
var xhr = new XMLHttpRequest();

xhr.addEventListener("readystatechange", async function () {
if (this.readyState === 4) {
console.log(this.responseText)
const {data: annotations} = JSON.parse(this.responseText)
const documents = await Promise.all(annotations.annotations.map(({cid}) => getAnnotationData(cid)))
// Components.Reader.js has an event listener which handles this message
window.postMessage({type:"GET_ANNOTATIONS_RESPONSE" , documents}, "*");
}
});

xhr.open("POST", "https://api.thegraph.com/subgraphs/name/public-annotation-network/subgraph");
xhr.setRequestHeader("Content-Type", "application/json");
xhr.withCredentials = false
xhr.send(data);
}
// SUBGRAPH QUERIES
if (event.data.type && (event.data.type === 'QUERY_SUBGRAPH')) {
try {
const response = await fetch(
event.data.url,
{ method: 'POST', headers: { 'Content-Type': 'application/json' }, body: event.data.query }
);
if (response.status !== 200) { throw new Error(response); }
try {
const result = await response.json();
window.postMessage({ type: 'QUERY_SUBGRAPH_RESPONSE', result }, '*');
} catch (error) {
console.log(error);
throw new Error('Response body is empty.')
}
} catch (error) {
throw new Error('Could not send HTTP request: ' + error);
}
}
// IPFS QUERIES
if (event.data.type && (event.data.type === 'QUERY_IPFS')) {
try {
const response = await fetch(event.data.url);
if (response.status !== 200) { throw new Error(response); }
try {
const result = await response.json();
window.postMessage({ type: 'QUERY_IPFS_RESPONSE', result }, '*');
} catch (error) {
console.log(error);
throw new Error('Response body is empty.')
}
} catch(error) {
throw new Error('Could not send HTTP request: ' + error);
}
}
// PUBLISHER QUERIES
if (event.data.type && (event.data.type === 'QUERY_PUBLISHER')) {
try {
const response = await fetch(event.data.url);
if (response.status !== 200) { throw new Error(response); }
try {
const result = await response.json();
window.postMessage({ type: 'QUERY_PUBLISHER_RESPONSE', result }, '*');
} catch (error) {
console.log(error);
throw new Error('Response body is empty.')
}
} catch(error) {
throw new Error('Could not send HTTP request: ' + error);
}
}
// PUBLISHER POSTS
if (event.data.type && (event.data.type === 'POST_PUBLISHER')) {
try {
const response = await fetch(
event.data.url,
{ method: 'POST', headers: { 'Content-Type': 'application/json' }, body: event.data.body }
);
if (response.status !== 200) { throw new Error(response); }
try {
const result = await response.json();
window.postMessage({ type: 'POST_PUBLISHER_RESPONSE', result }, '*');
} catch (error) {
console.log(error);
throw new Error('Response body is empty.')
}
} catch (error) {
throw new Error('Could not send HTTP request: ' + error);
}
}
}


26 changes: 9 additions & 17 deletions src/Components/Reader.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@ import React, { useEffect, useState } from 'react';
import { connectMetamask, signV4 } from '../services/ethereum'

import Annotation from '../Models/Annotation'
//getAnnotationCIDsByReference(first, skip, reference) {
import Logo from '../images/logo'
import { ModalContext } from '../Contexts/ModalProvider';
import { getAnnotationCIDs } from '../services/publisher'
// import { getAnnotationCIDs } from '../services/publisher'
import { getAnnotationCIDsByReference } from '../services/graph'
import { getAnnotationData } from '../services/ipfs'
import { getTweetData } from '../helpers'
Expand All @@ -15,23 +14,16 @@ const Reader = ({ setPage }) => {
const [title, setTitle] = useState("nothing...")
const [tweetAnnotations, setTweetAnnotations] = useState([])

window.addEventListener("message", function (event) {
// event handler that handles the event emitted in content.js
// todo: we should move these event handlers all to the same place, probably the Context file. Since
// context will probably end up acting as our redux store
if (event.data.type && (event.data.type === "GET_ANNOTATIONS_RESPONSE")) {
let annotations = event.data.documents
annotations = annotations.map(payload => new Annotation({ payload }))
setTweetAnnotations(annotations)
}
})

useEffect(() => {
const fetchData = async () => {
(async () => {
const { tweetId, tweetAuthor } = getTweetData()
const annotationCIDs = await getAnnotationCIDsByReference({ reference: tweetId })
}
fetchData()
const annotationCIDs = await getAnnotationCIDsByReference({ reference: tweetId });
const annotations = [];
for (const annotationCID of annotationCIDs) {
annotations.push(new Annotation({ payload: await getAnnotationData(annotationCID) }));
}
setTweetAnnotations(annotations);
})();
}, [])

return (
Expand Down
60 changes: 22 additions & 38 deletions src/services/graph.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,15 @@
import fetch from 'cross-fetch';

const SUBGRAPH_URL = 'https://api.thegraph.com/subgraphs/name/public-annotation-network/subgraph';


async function sendQuery(query) {
try {
const response = await fetch(
SUBGRAPH_URL,
{ method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ query }) }
);

if (response.status !== 200) { throw new Error(response); }

try {
return await response.json();
} catch (error) {
throw new Error('Response body is empty.')
}
} catch (error) {
throw new Error('Could not query subgraph: ' + error);
}
return new Promise(async (resolve) => {
window.postMessage({ type: 'QUERY_SUBGRAPH', url: SUBGRAPH_URL, query: JSON.stringify({ query }) }, '*');
window.addEventListener('message', async (event) => {
if (event.data.type && (event.data.type === 'QUERY_SUBGRAPH_RESPONSE')) {
resolve(event.data.result);
}
});
});
}

export async function getAnnotationBatchCIDs(first, skip) {
Expand Down Expand Up @@ -59,27 +49,21 @@ export async function getAnnotationCIDs({ first = 10, skip = 0 }) {
return result.data.annotations.map(({ cid }) => cid);
}



export async function getAnnotationCIDsByReference({ first = 10, skip = 0, reference }) {
// this now only sends the request to the content.js script.
// TODO: pass reference as a parameter in the message so that content.js can include it in the POST body
window.postMessage({type:"GET_ANNOTATIONS" ,reference}, "*");
// const result = await sendQuery(
// `
// {
// annotations(first: ${first}, skip: ${skip}, where: { ref_contains: "${reference}" }) {
// cid
// ref
// }
// }
// `
// );
const result = await sendQuery(
`
{
annotations(first: ${first}, skip: ${skip}, where: { ref_contains: "${reference}" }) {
cid
ref
}
}
`
);

// if (!result || !result.data || !result.data.annotations) {
// throw new Error('Unexpected response format.');
// }
if (!result || !result.data || !result.data.annotations) {
throw new Error('Unexpected response format.');
}

// return result.data.annotations.map(({ cid }) => cid);
return []
return result.data.annotations.map(({ cid }) => cid);
}
23 changes: 8 additions & 15 deletions src/services/ipfs.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,13 @@
import fetch from 'cross-fetch';

const IPFS_URL = 'https://gateway.pinata.cloud/ipfs';


export async function getAnnotationData(cid) {
try {
const response = await fetch(IPFS_URL + '/' + cid);

if (response.status !== 200) { throw new Error(response); }

try {
return await response.json();
} catch (error) {
throw new Error('Response body is empty.')
}
} catch (error) {
throw new Error('Could not query IPFS node: ' + error);
}
return new Promise((resolve) => {
window.postMessage({ type: 'QUERY_IPFS', url: IPFS_URL + '/' + cid }, '*');
window.addEventListener('message', (event) => {
if (event.data.type && (event.data.type === 'QUERY_IPFS_RESPONSE')) {
resolve(event.data.result);
}
});
});
}
Loading

0 comments on commit 11e7949

Please sign in to comment.