add proper support for typed arrays in remote (#13055)

This commit is contained in:
Milan Burda 2018-05-24 14:05:46 +02:00 коммит произвёл Cheng Zhao
Родитель a798a40026
Коммит 4cfe5ecaa4
6 изменённых файлов: 174 добавлений и 22 удалений

Просмотреть файл

@ -59,6 +59,7 @@
'lib/common/api/native-image.js',
'lib/common/api/shell.js',
'lib/common/atom-binding-setup.js',
'lib/common/buffer-utils.js',
'lib/common/init.js',
'lib/common/parse-features-string.js',
'lib/common/reset-search-paths.js',

Просмотреть файл

@ -1,6 +1,5 @@
'use strict'
const {Buffer} = require('buffer')
const electron = require('electron')
const {EventEmitter} = require('events')
const fs = require('fs')
@ -9,6 +8,7 @@ const v8Util = process.atomBinding('v8_util')
const {ipcMain, isPromise, webContents} = electron
const objectsRegistry = require('./objects-registry')
const bufferUtils = require('../common/buffer-utils')
const hasProp = {}.hasOwnProperty
@ -63,7 +63,7 @@ let valueToMeta = function (sender, value, optimizeSimpleObject = false) {
// Recognize certain types of objects.
if (value === null) {
meta.type = 'value'
} else if (ArrayBuffer.isView(value)) {
} else if (bufferUtils.isBuffer(value)) {
meta.type = 'buffer'
} else if (Array.isArray(value)) {
meta.type = 'array'
@ -95,7 +95,7 @@ let valueToMeta = function (sender, value, optimizeSimpleObject = false) {
meta.members = getObjectMembers(value)
meta.proto = getObjectPrototype(value)
} else if (meta.type === 'buffer') {
meta.value = Buffer.from(value)
meta.value = bufferUtils.bufferToMeta(value)
} else if (meta.type === 'promise') {
// Add default handler to prevent unhandled rejections in main process
// Instead they should appear in the renderer process
@ -180,7 +180,7 @@ const unwrapArgs = function (sender, args) {
case 'array':
return unwrapArgs(sender, meta.value)
case 'buffer':
return Buffer.from(meta.value)
return bufferUtils.metaToBuffer(meta.value)
case 'date':
return new Date(meta.value)
case 'promise':

Просмотреть файл

@ -0,0 +1,58 @@
// Note: Don't use destructuring assignment for `Buffer`, or we'll hit a
// browserify bug that makes the statement invalid, throwing an error in
// sandboxed renderer.
const Buffer = require('buffer').Buffer
const typedArrays = {
Buffer,
ArrayBuffer,
Int8Array,
Uint8Array,
Uint8ClampedArray,
Int16Array,
Uint16Array,
Int32Array,
Uint32Array,
Float32Array,
Float64Array
}
function getType (value) {
for (const type of Object.keys(typedArrays)) {
if (value instanceof typedArrays[type]) {
return type
}
}
return null
}
exports.isBuffer = function (value) {
return ArrayBuffer.isView(value) || value instanceof ArrayBuffer
}
exports.bufferToMeta = function (value) {
const buffer = (value instanceof ArrayBuffer)
? Buffer.from(value)
: Buffer.from(value.buffer, value.byteOffset, value.byteLength)
return {
type: getType(value),
data: buffer.toString('base64'),
length: value.length
}
}
exports.metaToBuffer = function (value) {
const constructor = typedArrays[value.type]
const data = Buffer.from(value.data, 'base64')
if (constructor === Buffer) {
return data
} else if (constructor === ArrayBuffer) {
return data.buffer
} else if (constructor) {
return new constructor(data.buffer, data.byteOffset, value.length)
} else {
return data
}
}

Просмотреть файл

@ -1,13 +1,11 @@
'use strict'
// Note: Don't use destructuring assignment for `Buffer`, or we'll hit a
// browserify bug that makes the statement invalid, throwing an error in
// sandboxed renderer.
const Buffer = require('buffer').Buffer
const v8Util = process.atomBinding('v8_util')
const {ipcRenderer, isPromise, CallbacksRegistry} = require('electron')
const resolvePromise = Promise.resolve.bind(Promise)
const bufferUtils = require('../../common/buffer-utils')
const callbacksRegistry = new CallbacksRegistry()
const remoteObjectCache = v8Util.createIDWeakMap()
@ -30,10 +28,10 @@ function wrapArgs (args, visited = new Set()) {
}
visited.delete(value)
return meta
} else if (ArrayBuffer.isView(value)) {
} else if (bufferUtils.isBuffer(value)) {
return {
type: 'buffer',
value: Buffer.from(value)
value: bufferUtils.bufferToMeta(value)
}
} else if (value instanceof Date) {
return {
@ -202,7 +200,7 @@ function metaToValue (meta) {
const types = {
value: () => meta.value,
array: () => meta.members.map((member) => metaToValue(member)),
buffer: () => Buffer.from(meta.value),
buffer: () => bufferUtils.metaToBuffer(meta.value),
promise: () => resolvePromise({then: metaToValue(meta.then)}),
error: () => metaToPlainObject(meta),
date: () => new Date(meta.value),

Просмотреть файл

@ -259,12 +259,94 @@ describe('remote module', () => {
assert.ok(arrayWithBuffer[2].equals(printName.echo(arrayWithBuffer)[2]))
})
it('supports TypedArray', () => {
const values = [1, 2, 3, 4]
assert.deepEqual(printName.typedArray(values), values)
it('supports instanceof ArrayBuffer', () => {
const buffer = new ArrayBuffer(8)
const view = new DataView(buffer)
const int16values = new Int16Array([1, 2, 3, 4])
assert.deepEqual(printName.typedArray(int16values), int16values)
view.setFloat64(0, Math.PI)
assert.deepEqual(printName.echo(buffer), buffer)
assert.equal(printName.print(buffer), 'ArrayBuffer')
})
it('supports instanceof Int8Array', () => {
const values = [1, 2, 3, 4]
assert.deepEqual(printName.typedArray('Int8Array', values), values)
const int8values = new Int8Array(values)
assert.deepEqual(printName.typedArray('Int8Array', int8values), int8values)
assert.equal(printName.print(int8values), 'Int8Array')
})
it('supports instanceof Uint8Array', () => {
const values = [1, 2, 3, 4]
assert.deepEqual(printName.typedArray('Uint8Array', values), values)
const uint8values = new Uint8Array(values)
assert.deepEqual(printName.typedArray('Uint8Array', uint8values), uint8values)
assert.equal(printName.print(uint8values), 'Uint8Array')
})
it('supports instanceof Uint8ClampedArray', () => {
const values = [1, 2, 3, 4]
assert.deepEqual(printName.typedArray('Uint8ClampedArray', values), values)
const uint8values = new Uint8ClampedArray(values)
assert.deepEqual(printName.typedArray('Uint8ClampedArray', uint8values), uint8values)
assert.equal(printName.print(uint8values), 'Uint8ClampedArray')
})
it('supports instanceof Int16Array', () => {
const values = [0x1234, 0x2345, 0x3456, 0x4567]
assert.deepEqual(printName.typedArray('Int16Array', values), values)
const int16values = new Int16Array(values)
assert.deepEqual(printName.typedArray('Int16Array', int16values), int16values)
assert.equal(printName.print(int16values), 'Int16Array')
})
it('supports instanceof Uint16Array', () => {
const values = [0x1234, 0x2345, 0x3456, 0x4567]
assert.deepEqual(printName.typedArray('Uint16Array', values), values)
const uint16values = new Uint16Array(values)
assert.deepEqual(printName.typedArray('Uint16Array', uint16values), uint16values)
assert.equal(printName.print(uint16values), 'Uint16Array')
})
it('supports instanceof Int32Array', () => {
const values = [0x12345678, 0x23456789]
assert.deepEqual(printName.typedArray('Int32Array', values), values)
const int32values = new Int32Array(values)
assert.deepEqual(printName.typedArray('Int32Array', int32values), int32values)
assert.equal(printName.print(int32values), 'Int32Array')
})
it('supports instanceof Uint32Array', () => {
const values = [0x12345678, 0x23456789]
assert.deepEqual(printName.typedArray('Uint32Array', values), values)
const uint32values = new Uint32Array(values)
assert.deepEqual(printName.typedArray('Uint32Array', uint32values), uint32values)
assert.equal(printName.print(uint32values), 'Uint32Array')
})
it('supports instanceof Float32Array', () => {
const values = [0.5, 1.0, 1.5]
assert.deepEqual(printName.typedArray('Float32Array', values), values)
const float32values = new Float32Array()
assert.deepEqual(printName.typedArray('Float32Array', float32values), float32values)
assert.equal(printName.print(float32values), 'Float32Array')
})
it('supports instanceof Float64Array', () => {
const values = [0.5, 1.0, 1.5]
assert.deepEqual(printName.typedArray('Float64Array', values), values)
const float64values = new Float64Array([0.5, 1.0, 1.5])
assert.deepEqual(printName.typedArray('Float64Array', float64values), float64values)
assert.equal(printName.print(float64values), 'Float64Array')
})
})

25
spec/fixtures/module/print_name.js поставляемый
Просмотреть файл

@ -6,10 +6,23 @@ exports.echo = function (obj) {
return obj
}
exports.typedArray = function (name) {
const int16 = new Int16Array(name.length)
for (let i = 0; i < name.length; ++i) {
int16[i] = name[i]
}
return int16
const typedArrays = {
Int8Array,
Uint8Array,
Uint8ClampedArray,
Int16Array,
Uint16Array,
Int32Array,
Uint32Array,
Float32Array,
Float64Array
}
exports.typedArray = function (type, values) {
const constructor = typedArrays[type]
const array = new constructor(values.length)
for (let i = 0; i < values.length; ++i) {
array[i] = values[i]
}
return array
}