Files: 94b5daa6362ac3c9f4a4c781894a73ad2c5160c5 / index.js
5565 bytesRaw
1 | const crypto = require('crypto') |
2 | const cbor = require('borc') |
3 | const EventEmitter = require('events') |
4 | const Buffer = require('safe-buffer').Buffer |
5 | |
6 | const TAGS = { |
7 | id: 41, |
8 | link: 42, |
9 | func: 43, |
10 | mod: 44 |
11 | } |
12 | |
13 | /** |
14 | * a cbor decoder for the objects |
15 | * @type {Object} |
16 | */ |
17 | const decoder = new cbor.Decoder({ |
18 | tags: { |
19 | [TAGS.id]: val => new ID(val), |
20 | [TAGS.func]: val => new FunctionRef({ |
21 | identifier: val[0], |
22 | params: val[1], |
23 | actorID: val[2], |
24 | gas: val[3] |
25 | }), |
26 | [TAGS.mod]: val => new ModuleRef(...val), |
27 | [TAGS.link]: val => { |
28 | return { |
29 | '/': val |
30 | } |
31 | } |
32 | } |
33 | }) |
34 | |
35 | /** |
36 | * an ID |
37 | */ |
38 | class ID { |
39 | /* |
40 | * @param {Buffer} id - the id as an buffer |
41 | */ |
42 | constructor (id) { |
43 | this.id = id |
44 | } |
45 | |
46 | toString () { |
47 | return this.id.toString('hex') |
48 | } |
49 | |
50 | toJSON () { |
51 | return `0x${this.toString()}` |
52 | } |
53 | |
54 | static fromJSON (arg) { |
55 | const { fromHex } = require('./utils') |
56 | return new ID(fromHex(arg)) |
57 | } |
58 | |
59 | encodeCBOR (gen) { |
60 | return gen.write(new cbor.Tagged(TAGS.id, this.id)) |
61 | } |
62 | } |
63 | |
64 | /** |
65 | * A function reference |
66 | */ |
67 | class FunctionRef { |
68 | /** |
69 | * @param {Object} opts |
70 | * @param {*} opts.identifier - the function's identifier |
71 | * @param {ID} opts.actorID - the id of the actor |
72 | * @param {Array} opts.params - the params of the function |
73 | */ |
74 | constructor (opts) { |
75 | this.identifier = opts.identifier |
76 | this.actorID = opts.actorID |
77 | this.params = opts.params |
78 | this.gas = opts.gas || 0 |
79 | } |
80 | |
81 | encodeCBOR (gen) { |
82 | return gen.write(new cbor.Tagged(TAGS.func, [ |
83 | this.identifier, |
84 | this.params, |
85 | this.actorID, |
86 | this.gas |
87 | ])) |
88 | } |
89 | |
90 | toJSON (includeParams = true) { |
91 | const json = { |
92 | '@FunctionRef': { |
93 | actorID: this.actorID.toJSON(), |
94 | private: this.identifier[0], |
95 | name: this.identifier[1], |
96 | gas: this.gas |
97 | } |
98 | } |
99 | if (includeParams) { |
100 | json['@FunctionRef'].params = this.params |
101 | } |
102 | return json |
103 | } |
104 | |
105 | static fromJSON (arg) { |
106 | const data = arg['@FunctionRef'] |
107 | return new FunctionRef({ |
108 | identifier: [data.private, data.name], |
109 | actorID: ID.fromJSON(data.actorID), |
110 | params: data.params, |
111 | gas: data.gas |
112 | }) |
113 | } |
114 | |
115 | /** |
116 | * Creates a copy of the funcRef |
117 | * @returns {FunctionRef} |
118 | */ |
119 | copy () { |
120 | return new FunctionRef({ |
121 | identifier: this.identifier, |
122 | actorID: this.actorID, |
123 | params: this.params, |
124 | gas: this.gas |
125 | }) |
126 | } |
127 | } |
128 | |
129 | /** |
130 | * A module reference |
131 | */ |
132 | class ModuleRef { |
133 | /** |
134 | * @param {Object} exports - a map of exported function to params for the funcion if any |
135 | * @param {ID} id - the id of the actor |
136 | */ |
137 | constructor (exports, id) { |
138 | this.exports = exports |
139 | this.id = id |
140 | } |
141 | |
142 | /** |
143 | * return a function refernce given the name of the function |
144 | * @param {string} name |
145 | * @returns {FunctionRef} |
146 | */ |
147 | getFuncRef (name) { |
148 | const params = this.exports[name] |
149 | |
150 | return new FunctionRef({ |
151 | identifier: [false, name], |
152 | params, |
153 | actorID: this.id |
154 | }) |
155 | } |
156 | |
157 | toJSON (includeExports = true) { |
158 | const json = { |
159 | '@ModuleRef': { |
160 | id: this.id.toJSON() |
161 | } |
162 | } |
163 | if (includeExports) { |
164 | json['@ModuleRef'].exports = this.exports |
165 | } |
166 | return json |
167 | } |
168 | |
169 | static fromJSON (arg) { |
170 | const data = arg['@ModuleRef'] |
171 | return new ModuleRef(data.exports, ID.fromJSON(data.id)) |
172 | } |
173 | |
174 | encodeCBOR (gen) { |
175 | return gen.write(new cbor.Tagged(TAGS.mod, [this.exports, this.id])) |
176 | } |
177 | } |
178 | |
179 | /** |
180 | * This implements Messages for Primea |
181 | */ |
182 | class Message extends EventEmitter { |
183 | /** |
184 | * @param {Object} opts |
185 | * @param {ArrayBuffer} opts.data - the payload of the message |
186 | * @param {Array<Object>} opts.caps - an array of capabilities to send in the message |
187 | */ |
188 | constructor (opts) { |
189 | super() |
190 | const defaults = this.constructor.defaults |
191 | this._opts = Object.assign(defaults, opts) |
192 | Object.keys(this._opts).forEach(key => { |
193 | Object.defineProperty(this, key, { |
194 | get: function () { |
195 | return this._opts[key] |
196 | }, |
197 | set: function (y) { |
198 | this._opts[key] = y |
199 | } |
200 | }) |
201 | }) |
202 | } |
203 | |
204 | static get defaults () { |
205 | return { |
206 | ticks: 0, |
207 | funcRef: null, |
208 | funcArguments: [], |
209 | funcParameters: [], |
210 | _fromId: new ID(Buffer.alloc(20)), |
211 | _fromTicks: 0 |
212 | } |
213 | } |
214 | } |
215 | |
216 | /** |
217 | * returns the type that the object is |
218 | * @param {*} obj |
219 | * @return {String} |
220 | */ |
221 | function getType (obj) { |
222 | if (obj) { |
223 | if (Buffer.isBuffer(obj)) { |
224 | return 'data' |
225 | } else if (Array.isArray(obj)) { |
226 | return 'elem' |
227 | } else if (obj['/']) { |
228 | return 'link' |
229 | } else if (obj.constructor === Message) { |
230 | return 'message' |
231 | } else if (obj.constructor === ID) { |
232 | return 'id' |
233 | } else if (obj.constructor === FunctionRef) { |
234 | return 'func' |
235 | } else if (obj.constructor === ModuleRef) { |
236 | return 'mod' |
237 | } |
238 | } |
239 | return 'invalid' |
240 | } |
241 | |
242 | /** |
243 | * returns the ID of an actor |
244 | * @param {Object} id |
245 | * @param {Number} id.nonce - the actor's nonce |
246 | * @param {ID} id.parent - the actor's parent's ID |
247 | * @return {ID} |
248 | */ |
249 | function generateActorId (id) { |
250 | const encoded = _encodeActorId(id) |
251 | const hashed = _hash(encoded) |
252 | return new ID(hashed) |
253 | } |
254 | |
255 | function _encodeActorId (id) { |
256 | if (id.parent) { |
257 | return cbor.encode([id.nonce, id.parent.id]) |
258 | } else { |
259 | return cbor.encode([id.nonce, null]) |
260 | } |
261 | } |
262 | |
263 | function _hash (buf) { |
264 | const hash = crypto.createHash('sha256') |
265 | hash.update(buf) |
266 | return hash.digest().slice(0, 20) |
267 | } |
268 | |
269 | module.exports = { |
270 | Message, |
271 | ID, |
272 | FunctionRef, |
273 | ModuleRef, |
274 | decoder, |
275 | getType, |
276 | generateActorId |
277 | } |
278 |
Built with git-ssb-web