seed.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. #!/usr/bin/env node
  2. const crypto = require('crypto');
  3. const path = require('path');
  4. const hash = (n) => crypto.randomBytes(n || 4).toString('hex');
  5. const longHash = () => hash(16);
  6. const TAGS_POOL = ['music', 'tech', 'art', 'science', 'philosophy', 'p2p', 'oasis', 'libre', 'open-source', 'community', 'demo', 'seed'];
  7. const pickTags = (n) => {
  8. const out = new Set();
  9. while (out.size < n) out.add(TAGS_POOL[Math.floor(Math.random() * TAGS_POOL.length)]);
  10. return [...out];
  11. };
  12. const fakeBlob = (prefix) => `[${prefix}](&${hash(2)}${'0'.repeat(40)}${hash(2)}.sha256)`;
  13. const cooler = require(path.join(__dirname, '..', 'src', 'client', 'gui'));
  14. const ssbConfig = require(path.join(__dirname, '..', 'src', 'server', 'ssb_config'));
  15. async function open() {
  16. const c = cooler({ offline: ssbConfig.offline });
  17. return await c.open();
  18. }
  19. async function step(name, fn) {
  20. process.stdout.write(` → ${name}... `);
  21. try {
  22. const r = await fn();
  23. console.log(`OK${r ? ' (' + JSON.stringify(r).slice(0, 60) + ')' : ''}`);
  24. return r;
  25. } catch (e) {
  26. console.log(`FAIL (${e.message})`);
  27. return null;
  28. }
  29. }
  30. (async () => {
  31. console.log('Oasis seeder — generating dummy content...\n');
  32. await open();
  33. const tribeCrypto = require(path.join(__dirname, '..', 'src', 'models', 'crypto'))(ssbConfig.path, 'tribes');
  34. const chatCrypto = require(path.join(__dirname, '..', 'src', 'models', 'crypto'))(ssbConfig.path, 'chats');
  35. const padCrypto = require(path.join(__dirname, '..', 'src', 'models', 'crypto'))(ssbConfig.path, 'pads');
  36. const mapCrypto = require(path.join(__dirname, '..', 'src', 'models', 'crypto'))(ssbConfig.path, 'maps');
  37. const calendarCrypto = require(path.join(__dirname, '..', 'src', 'models', 'crypto'))(ssbConfig.path, 'calendars');
  38. const sCooler = require(path.join(__dirname, '..', 'src', 'client', 'gui'))({ offline: ssbConfig.offline });
  39. const models = {
  40. feed: require(path.join(__dirname, '..', 'src', 'models', 'feed_model'))({ cooler: sCooler }),
  41. audios: require(path.join(__dirname, '..', 'src', 'models', 'audios_model'))({ cooler: sCooler, tribeCrypto }),
  42. videos: require(path.join(__dirname, '..', 'src', 'models', 'videos_model'))({ cooler: sCooler, tribeCrypto }),
  43. images: require(path.join(__dirname, '..', 'src', 'models', 'images_model'))({ cooler: sCooler, tribeCrypto }),
  44. documents: require(path.join(__dirname, '..', 'src', 'models', 'documents_model'))({ cooler: sCooler, tribeCrypto }),
  45. bookmarks: require(path.join(__dirname, '..', 'src', 'models', 'bookmarking_model'))({ cooler: sCooler, tribeCrypto }),
  46. forum: require(path.join(__dirname, '..', 'src', 'models', 'forum_model'))({ cooler: sCooler }),
  47. transfers: require(path.join(__dirname, '..', 'src', 'models', 'transfers_model'))({ cooler: sCooler, tribeCrypto }),
  48. votes: require(path.join(__dirname, '..', 'src', 'models', 'votes_model'))({ cooler: sCooler, tribeCrypto }),
  49. events: require(path.join(__dirname, '..', 'src', 'models', 'events_model'))({ cooler: sCooler }),
  50. tasks: require(path.join(__dirname, '..', 'src', 'models', 'tasks_model'))({ cooler: sCooler, tribeCrypto }),
  51. market: require(path.join(__dirname, '..', 'src', 'models', 'market_model'))({ cooler: sCooler, tribeCrypto }),
  52. jobs: require(path.join(__dirname, '..', 'src', 'models', 'jobs_model'))({ cooler: sCooler, tribeCrypto }),
  53. projects: require(path.join(__dirname, '..', 'src', 'models', 'projects_model'))({ cooler: sCooler, tribeCrypto }),
  54. reports: require(path.join(__dirname, '..', 'src', 'models', 'reports_model'))({ cooler: sCooler, tribeCrypto }),
  55. shops: require(path.join(__dirname, '..', 'src', 'models', 'shops_model'))({ cooler: sCooler, tribeCrypto }),
  56. pixelia: require(path.join(__dirname, '..', 'src', 'models', 'pixelia_model'))({ cooler: sCooler, tribeCrypto }),
  57. torrents: require(path.join(__dirname, '..', 'src', 'models', 'torrents_model'))({ cooler: sCooler, tribeCrypto }),
  58. tribes: null
  59. };
  60. const tribesModel = require(path.join(__dirname, '..', 'src', 'models', 'tribes_model'))({ cooler: sCooler, tribeCrypto });
  61. models.tribes = tribesModel;
  62. models.tribesContent = require(path.join(__dirname, '..', 'src', 'models', 'tribes_content_model'))({ cooler: sCooler, tribeCrypto, tribesModel });
  63. models.pads = require(path.join(__dirname, '..', 'src', 'models', 'pads_model'))({ cooler: sCooler, cipherModel: { encryptECB: x => x, decryptECB: x => x }, tribeCrypto, padCrypto, tribesModel });
  64. models.chats = require(path.join(__dirname, '..', 'src', 'models', 'chats_model'))({ cooler: sCooler, tribeCrypto, chatCrypto, tribesModel });
  65. models.calendars = require(path.join(__dirname, '..', 'src', 'models', 'calendars_model'))({ cooler: sCooler, tribeCrypto, calendarCrypto, tribesModel });
  66. models.maps = require(path.join(__dirname, '..', 'src', 'models', 'maps_model'))({ cooler: sCooler, tribeCrypto, mapCrypto, tribesModel });
  67. console.log('SEED: feed');
  68. for (let i = 0; i < 3; i++) {
  69. await step(`feed post #${i}`, () => models.feed.createFeed(`Seed feed ${hash(3)} — hello oasis #${i}`, []));
  70. }
  71. console.log('\nSEED: posts (with self-mention so /mentions has content)');
  72. const meIdEarly = (await sCooler.open()).id;
  73. for (let i = 0; i < 2; i++) {
  74. const text = `Hello [@me](${meIdEarly}) — seed post #${i} ${hash(3)}`;
  75. await step(`post mentioning self #${i}`, () => new Promise((res, rej) => sCooler.open().then(ssb => ssb.publish({
  76. type: 'post',
  77. text,
  78. mentions: [{ link: meIdEarly, name: 'me' }]
  79. }, (e, m) => e ? rej(e) : res(m)))));
  80. }
  81. console.log('\nSEED: media');
  82. for (let i = 0; i < 2; i++) {
  83. await step(`audio ${i}`, () => models.audios.createAudio(fakeBlob('a'), pickTags(2), `Track ${hash(2)}`, `Audio dummy ${hash(3)}`, ''));
  84. await step(`video ${i}`, () => models.videos.createVideo(fakeBlob('v'), pickTags(2), `Vid ${hash(2)}`, `Video dummy ${hash(3)}`, ''));
  85. await step(`image ${i}`, () => models.images.createImage(fakeBlob('i'), pickTags(2), `Pic ${hash(2)}`, `Image ${hash(3)}`, false, ''));
  86. await step(`doc ${i}`, () => models.documents.createDocument(fakeBlob('d'), pickTags(2), `Doc ${hash(2)}`, `${longHash()}`));
  87. await step(`bookmark ${i}`, () => models.bookmarks.createBookmark(`https://example.com/${hash(3)}`, pickTags(2), `bookmark dummy ${hash(2)}`, 'demo', new Date().toISOString()));
  88. }
  89. console.log('\nSEED: forum');
  90. const forumIds = [];
  91. for (let i = 0; i < 2; i++) {
  92. const r = await step(`forum thread ${i}`, () => models.forum.createForum('general', `Topic ${hash(3)}`, `Forum body ${longHash()}`));
  93. if (r && r.key) forumIds.push(r.key);
  94. }
  95. for (const fid of forumIds) {
  96. await step(`forum reply`, () => models.forum.addMessageToForum(fid, { text: `reply ${hash(2)}`, category: 'general', title: 'reply' }));
  97. }
  98. console.log('\nSEED: votes');
  99. await step('votation', () => models.votes.createVote(`Should we ${hash(2)}?`, futureISO(30), ['YES', 'NO', 'ABSTENTION']));
  100. console.log('\nSEED: events');
  101. await step('event', () => models.events.createEvent(`Meetup ${hash(2)}`, `Description ${longHash()}`, futureISO(14), 'remote', 0, '', [], ['demo'], 'public', ''));
  102. console.log('\nSEED: tasks');
  103. await step('task', () => models.tasks.createTask(`Task ${hash(2)}`, `desc ${hash(4)}`, futureISO(1), futureISO(5), 'LOW', 'remote', ['demo'], 'public'));
  104. console.log('\nSEED: transfers (3 categories)');
  105. const meId = (await sCooler.open()).id;
  106. await step('transfer ECONOMIC', () => models.transfers.createTransfer(meId, `Pay ${hash(2)}`, '10', futureISO(30), ['demo'], 'ECONOMIC'));
  107. await step('transfer TIME', () => models.transfers.createTransfer(meId, `Help ${hash(2)}`, '2', futureISO(30), ['demo'], 'TIME'));
  108. await step('transfer TRUST', () => models.transfers.createTransfer(meId, `Vouch ${hash(2)}`, '1', futureISO(30), ['demo'], 'TRUST'));
  109. console.log('\nSEED: profile about');
  110. await step('profile name', () => new Promise((res, rej) => sCooler.open().then(ssb => ssb.publish({ type: 'about', about: meId, name: `Seed user ${hash(2)}`, description: 'Auto-generated dummy profile' }, (e, m) => e ? rej(e) : res(m)))));
  111. console.log('\nSEED: market (public + hidden)');
  112. await step('market exchange (public)', () => models.market.createItem('exchange', `Item ${hash(2)}`, `desc ${longHash()}`, null, 5, ['demo'], 'NEW', futureISO(30), false, 1, '', {}, 'PUBLIC'));
  113. await step('market exchange (hidden)', () => models.market.createItem('exchange', `Hidden ${hash(2)}`, `desc ${longHash()}`, null, 7, ['demo'], 'USED', futureISO(30), false, 1, '', {}, 'HIDDEN'));
  114. await step('market auction', () => models.market.createItem('auction', `Auction ${hash(2)}`, `${longHash()}`, null, 10, ['demo'], 'USED', futureISO(30), false, 1, ''));
  115. console.log('\nSEED: jobs');
  116. await step('job', () => models.jobs.createJob({ title: `Job ${hash(2)}`, description: 'demo', location: 'remote', job_type: 'freelancer', job_time: 'partial', vacants: 1, salary: 1000, requirements: 'demo', tags: ['demo'], status: 'OPEN' }));
  117. console.log('\nSEED: projects');
  118. await step('project', () => models.projects.createProject({ title: `Project ${hash(2)}`, description: 'demo', goal: '100', deadline: futureISO(60), tags: ['demo'], status: 'ACTIVE' }));
  119. console.log('\nSEED: reports');
  120. await step('report', () => models.reports.createReport(`Issue ${hash(2)}`, `report demo ${longHash()}`, 'tech', null, ['demo'], 'low', {}));
  121. console.log('\nSEED: shops');
  122. const shop = await step('shop', () => models.shops.createShop(`Shop ${hash(2)}`, 'short', 'long', null, '', 'remote', ['demo'], 'OPEN', ''));
  123. if (shop && shop.key) {
  124. await step('shop product', () => models.shops.createProduct(shop.key, `Product ${hash(2)}`, 'desc', null, 5, 10, false));
  125. }
  126. console.log('\nSEED: torrents');
  127. await step('torrent', () => models.torrents.createTorrent(fakeBlob('t'), pickTags(2), `Torrent ${hash(2)}`, `${longHash()}`, 1000, null));
  128. console.log('\nSEED: pixelia');
  129. for (let i = 0; i < 5; i++) {
  130. const x = Math.floor(Math.random() * 50) + 1;
  131. const y = Math.floor(Math.random() * 200) + 1;
  132. const col = `#${hash(3)}`;
  133. await step(`pixel (${x},${y})`, () => models.pixelia.paintPixel(x, y, col));
  134. }
  135. console.log('\nSEED: standalone chats / pads / calendars / maps');
  136. await step('chat', () => models.chats.createChat(`Chat ${hash(2)}`, 'demo', null, 'general', 'OPEN', ['demo'], null));
  137. await step('pad', () => models.pads.createPad(`Pad ${hash(2)}`, 'OPEN', futureISO(30), ['demo'], null));
  138. await step('calendar', () => models.calendars.createCalendar({ title: `Cal ${hash(2)}`, status: 'OPEN', deadline: futureISO(60), tags: ['demo'], firstDate: futureISO(10), firstDateLabel: 'first', firstNote: '', tribeId: null }));
  139. await step('map (SINGLE)', () => models.maps.createMap(40.4, -3.7, 'Madrid', 'SINGLE', ['demo'], `Map ${hash(2)}`, null, 'pin', null));
  140. console.log('\nSEED: tribes + content inside');
  141. const tribe = await step('public tribe', () => tribesModel.createTribe(`Tribe ${hash(2)}`, 'public tribe demo', null, '', ['demo'], false, false, 'strict', null, 'OPEN', ''));
  142. if (tribe && tribe.key) {
  143. await step('feed inside tribe', () => models.tribesContent.create(tribe.key, 'feed', { description: `tribe feed ${longHash()}` }));
  144. await step('event inside tribe', () => models.tribesContent.create(tribe.key, 'event', { title: `tribe event ${hash(2)}`, description: 'demo', date: futureISO(15) }));
  145. }
  146. const priv = await step('private tribe', () => tribesModel.createTribe(`Secret ${hash(2)}`, 'private demo', null, '', ['demo'], false, true, 'strict', null, 'OPEN', ''));
  147. if (priv && priv.key) {
  148. await step('feed inside private tribe', () => models.tribesContent.create(priv.key, 'feed', { description: `private demo ${longHash()}` }));
  149. const code = await step('generate invite', () => tribesModel.generateInvite(priv.key));
  150. if (code) console.log(` (invite code: ${code})`);
  151. }
  152. console.log('\nDONE. Boot oasis (sh oasis.sh) to visually inspect the seeded content.');
  153. process.exit(0);
  154. })().catch(err => {
  155. console.error('FATAL:', err.message);
  156. process.exit(1);
  157. });
  158. function futureISO(days) {
  159. const d = new Date();
  160. d.setDate(d.getDate() + days);
  161. return d.toISOString();
  162. }