git ssb

0+

cel-desktop / ssb-pkg



Tree: 65191f9a9664f013ebe726bb95a1a54b086e1bd5

Files: 65191f9a9664f013ebe726bb95a1a54b086e1bd5 / lib / producer.js

7108 bytesRaw
1import { STORE_BLOB, STORE_CONTENT, snapshotify } from '../prelude/common.js';
2import { log, wasReported } from './log.js';
3import Multistream from 'multistream';
4import assert from 'assert';
5import { fabricateTwice } from './fabricator.js';
6import fs from 'fs';
7import intoStream from 'into-stream';
8import streamMeter from 'stream-meter';
9
10function discoverPlaceholder (binaryBuffer, searchString, padder) {
11 const placeholder = Buffer.from(searchString);
12 const position = binaryBuffer.indexOf(placeholder);
13 if (position === -1) return { notFound: true };
14 return { position, size: placeholder.length, padder };
15}
16
17function injectPlaceholder (fd, placeholder, value, cb) {
18 const { notFound, position, size, padder } = placeholder;
19 if (notFound) assert(false, 'Placeholder for not found');
20 if (typeof value === 'number') value = value.toString();
21 if (typeof value === 'string') value = Buffer.from(value);
22 const padding = Buffer.from(padder.repeat(size - value.length));
23 value = Buffer.concat([ value, padding ]);
24 fs.write(fd, value, 0, value.length, position, cb);
25}
26
27function discoverPlaceholders (binaryBuffer) {
28 return {
29 BAKERY: discoverPlaceholder(binaryBuffer, '\0' + '// BAKERY '.repeat(20), '\0'),
30 PAYLOAD_POSITION: discoverPlaceholder(binaryBuffer, '// PAYLOAD_POSITION //', ' '),
31 PAYLOAD_SIZE: discoverPlaceholder(binaryBuffer, '// PAYLOAD_SIZE //', ' '),
32 PRELUDE_POSITION: discoverPlaceholder(binaryBuffer, '// PRELUDE_POSITION //', ' '),
33 PRELUDE_SIZE: discoverPlaceholder(binaryBuffer, '// PRELUDE_SIZE //', ' ')
34 };
35}
36
37function injectPlaceholders (fd, placeholders, values, cb) {
38 injectPlaceholder(fd, placeholders.BAKERY, values.BAKERY, (error) => {
39 if (error) return cb(error);
40 injectPlaceholder(fd, placeholders.PAYLOAD_POSITION, values.PAYLOAD_POSITION, (error2) => {
41 if (error2) return cb(error2);
42 injectPlaceholder(fd, placeholders.PAYLOAD_SIZE, values.PAYLOAD_SIZE, (error3) => {
43 if (error3) return cb(error3);
44 injectPlaceholder(fd, placeholders.PRELUDE_POSITION, values.PRELUDE_POSITION, (error4) => {
45 if (error4) return cb(error4);
46 injectPlaceholder(fd, placeholders.PRELUDE_SIZE, values.PRELUDE_SIZE, cb);
47 });
48 });
49 });
50 });
51}
52
53function makeBakeryValueFromBakes (bakes) {
54 const parts = [];
55 if (bakes.length) {
56 for (let i = 0; i < bakes.length; i += 1) {
57 parts.push(Buffer.from(bakes[i]));
58 parts.push(Buffer.alloc(1));
59 }
60 parts.push(Buffer.alloc(1));
61 }
62 return Buffer.concat(parts);
63}
64
65function replaceDollarWise (s, sf, st) {
66 return s.replace(sf, () => st);
67}
68
69function makePreludeBufferFromPrelude (prelude) {
70 return Buffer.from(
71 '(function(process, require, console, EXECPATH_FD, PAYLOAD_POSITION, PAYLOAD_SIZE) { ' +
72 prelude +
73 '\n})' // dont remove \n
74 );
75}
76
77export default function ({ backpack, bakes, slash, target }) {
78 return new Promise((resolve, reject) => {
79 if (!Buffer.alloc) {
80 throw wasReported('Your node.js does not have Buffer.alloc. Please upgrade!');
81 }
82
83 let { prelude, entrypoint, stripes } = backpack;
84 entrypoint = snapshotify(entrypoint, slash);
85 stripes = stripes.slice();
86
87 const vfs = {};
88 for (const stripe of stripes) {
89 let { snap } = stripe;
90 snap = snapshotify(snap, slash);
91 if (!vfs[snap]) vfs[snap] = {};
92 }
93
94 let meter;
95 let count = 0;
96
97 function pipeToNewMeter (s) {
98 meter = streamMeter();
99 return s.pipe(meter);
100 }
101
102 function next (s) {
103 count += 1;
104 return pipeToNewMeter(s);
105 }
106
107 const binaryBuffer = fs.readFileSync(target.binaryPath);
108 const placeholders = discoverPlaceholders(binaryBuffer);
109
110 let track = 0;
111 let prevStripe;
112
113 let payloadPosition;
114 let payloadSize;
115 let preludePosition;
116 let preludeSize;
117
118 new Multistream((cb) => {
119 if (count === 0) {
120 return cb(undefined, next(
121 intoStream(binaryBuffer)
122 ));
123 } else
124 if (count === 1) {
125 payloadPosition = meter.bytes;
126 return cb(undefined, next(
127 intoStream(Buffer.alloc(0))
128 ));
129 } else
130 if (count === 2) {
131 if (prevStripe && !prevStripe.skip) {
132 let { snap, store } = prevStripe;
133 snap = snapshotify(snap, slash);
134 vfs[snap][store] = [ track, meter.bytes ];
135 track += meter.bytes;
136 }
137
138 if (stripes.length) {
139 // clone to prevent 'skip' propagate
140 // to other targets, since same stripe
141 // is used for several targets
142 const stripe = Object.assign({}, stripes.shift());
143 prevStripe = stripe;
144
145 if (stripe.buffer) {
146 if (stripe.store === STORE_BLOB) {
147 const snap = snapshotify(stripe.snap, slash);
148 return fabricateTwice(bakes, target.fabricator, snap, stripe.buffer, (error, buffer) => {
149 if (error) {
150 log.warn(error.message);
151 stripe.skip = true;
152 return cb(undefined, intoStream(Buffer.alloc(0)));
153 }
154
155 cb(undefined, pipeToNewMeter(intoStream(buffer)));
156 });
157 } else {
158 return cb(undefined, pipeToNewMeter(intoStream(stripe.buffer)));
159 }
160 } else
161 if (stripe.file) {
162 if (stripe.file === target.output) {
163 return cb(wasReported(
164 'Trying to take executable into executable', stripe.file
165 ));
166 }
167
168 assert.equal(stripe.store, STORE_CONTENT); // others must be buffers from walker
169 return cb(undefined, pipeToNewMeter(fs.createReadStream(stripe.file)));
170 } else {
171 assert(false, 'producer: bad stripe');
172 }
173 } else {
174 payloadSize = track;
175 preludePosition = payloadPosition + payloadSize;
176 return cb(undefined, next(
177 intoStream(makePreludeBufferFromPrelude(
178 replaceDollarWise(
179 replaceDollarWise(prelude, '%VIRTUAL_FILESYSTEM%', JSON.stringify(vfs)),
180 '%DEFAULT_ENTRYPOINT%', JSON.stringify(entrypoint))
181 ))
182 ));
183 }
184 } else {
185 return cb();
186 }
187 }).on('error', (error) => {
188 reject(error);
189 }).pipe(
190 fs.createWriteStream(target.output)
191 ).on('error', (error) => {
192 reject(error);
193 }).on('close', () => {
194 preludeSize = meter.bytes;
195 fs.open(target.output, 'r+', (error, fd) => {
196 if (error) return reject(error);
197 injectPlaceholders(fd, placeholders, {
198 BAKERY: makeBakeryValueFromBakes(bakes),
199 PAYLOAD_POSITION: payloadPosition,
200 PAYLOAD_SIZE: payloadSize,
201 PRELUDE_POSITION: preludePosition,
202 PRELUDE_SIZE: preludeSize
203 }, (error2) => {
204 if (error2) return reject(error2);
205 fs.close(fd, (error3) => {
206 if (error3) return reject(error3);
207 resolve();
208 });
209 });
210 });
211 });
212 });
213}
214

Built with git-ssb-web