ipfsUpload.js 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. // Copyright 2017-2020 @polkadot/apps authors & contributors
  2. // This software may be modified and distributed under the terms
  3. // of the Apache-2.0 license. See the LICENSE file for details.
  4. const fs = require('fs');
  5. const pinataSDK = require('@pinata/sdk');
  6. const cloudflare = require('dnslink-cloudflare');
  7. const execSync = require('@polkadot/dev/scripts/execSync');
  8. const createEndpoints = require('../packages/apps-config/build/settings/endpoints').default;
  9. const lernaInfo = require('../lerna.json');
  10. // https://gateway.pinata.cloud/ipfs/
  11. const GATEWAY = 'https://ipfs.io/ipfs/';
  12. const DOMAIN = 'dotapps.io';
  13. const DST = 'packages/apps/build';
  14. const SRC = 'packages/apps/public';
  15. const WOPTS = { encoding: 'utf8', flag: 'w' };
  16. const PINMETA = { name: DOMAIN };
  17. const repo = `https://${process.env.GH_PAT}@github.com/${process.env.GITHUB_REPOSITORY}.git`;
  18. const pinata = pinataSDK(process.env.PINATA_API_KEY, process.env.PINATA_SECRET_KEY);
  19. function writeFiles (name, content) {
  20. [DST, SRC].forEach((root) =>
  21. fs.writeFileSync(`${root}/ipfs/${name}`, content, WOPTS)
  22. );
  23. }
  24. function updateGh (hash) {
  25. execSync('git add --all .');
  26. execSync(`git commit --no-status --quiet -m "[CI Skip] publish/ipfs ${hash}
  27. skip-checks: true"`);
  28. execSync(`git push ${repo} HEAD:${process.env.GITHUB_REF}`, true);
  29. }
  30. async function pin () {
  31. const result = await pinata.pinFromFS(DST, { pinataMetadata: PINMETA });
  32. const url = `${GATEWAY}${result.IpfsHash}/`;
  33. const html = `<!DOCTYPE html>
  34. <html>
  35. <head>
  36. <title>Redirecting to ipfs gateway</title>
  37. <meta http-equiv="refresh" content="0; url=${url}" />
  38. <style>
  39. body { font-family: sans-serif; line-height: 1.5rem; padding: 2rem; text-align: center }
  40. p { margin: 0 }
  41. </style>
  42. </head>
  43. <body>
  44. <p>Redirecting to</p>
  45. <p><a href="${url}">${url}</a></p>
  46. </body>
  47. </html>`;
  48. writeFiles('index.html', html);
  49. writeFiles('pin.json', JSON.stringify(result));
  50. updateGh(result.IpfsHash);
  51. console.log(`Pinned ${result.IpfsHash}`);
  52. return result.IpfsHash;
  53. }
  54. async function unpin (exclude) {
  55. const result = await pinata.pinList({ metadata: PINMETA, status: 'pinned' });
  56. if (result.count > 1) {
  57. const filtered = result.rows
  58. .map(({ ipfs_pin_hash: hash }) => hash)
  59. .filter((hash) => hash !== exclude);
  60. if (filtered.length) {
  61. await Promise.all(
  62. filtered.map((hash) =>
  63. pinata
  64. .unpin(hash)
  65. .then(() => console.log(`Unpinned ${hash}`))
  66. .catch(console.error)
  67. )
  68. );
  69. }
  70. }
  71. }
  72. async function dnslink (hash) {
  73. const records = createEndpoints(() => '')
  74. .map(({ dnslink }) => dnslink)
  75. .filter((dnslink) => !!dnslink)
  76. .reduce((all, dnslink) => {
  77. if (!all.includes(dnslink)) {
  78. all.push(dnslink);
  79. }
  80. return all;
  81. }, [null])
  82. .map((sub) =>
  83. ['_dnslink', sub, DOMAIN]
  84. .filter((entry) => !!entry)
  85. .join('.')
  86. );
  87. await Promise.all(records.map((record) =>
  88. cloudflare(
  89. { token: process.env.CF_API_TOKEN },
  90. { link: `/ipfs/${hash}`, record, zone: DOMAIN }
  91. )
  92. ));
  93. console.log(`Dnslink ${hash} for ${records.join(', ')}`);
  94. }
  95. async function main () {
  96. // only run on non-beta versions
  97. if (!lernaInfo.version.includes('-beta.')) {
  98. const hash = await pin();
  99. await dnslink(hash);
  100. await unpin(hash);
  101. }
  102. }
  103. main()
  104. .catch(console.error)
  105. .finally(() => process.exit());