Skip to content
This repository was archived by the owner on Mar 5, 2025. It is now read-only.

IpcProvider chunks handling fix #2545

Merged
merged 13 commits into from
Mar 22, 2019
37 changes: 29 additions & 8 deletions packages/web3-providers/src/providers/IpcProvider.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export default class IpcProvider extends AbstractSocketProvider {
constructor(connection, path) {
super(connection, null);
this.host = path;
this.chunks = '';
this.lastChunk = '';
}

/**
Expand Down Expand Up @@ -71,16 +71,37 @@ export default class IpcProvider extends AbstractSocketProvider {
* @param {String|Buffer} message
*/
onMessage(message) {
const chunk = message.toString('utf8');
let result = null;
let returnValues = [];
let dechunkedData = message
.toString()
.replace(/\}[\n\r]?\{/g, '}|--|{') // }{
.replace(/\}\][\n\r]?\[\{/g, '}]|--|[{') // }][{
.replace(/\}[\n\r]?\[\{/g, '}|--|[{') // }[{
.replace(/\}\][\n\r]?\{/g, '}]|--|{') // }]{
.split('|--|');

dechunkedData.forEach((data) => {
result = null;
if (this.lastChunk) {
data = this.lastChunk + data;
}

if (chunk.indexOf('\n') < 0) {
this.chunks += chunk;
try {
result = JSON.parse(data);
} catch (error) {
this.lastChunk = data;

return;
}
return;
}

super.onMessage(this.chunks + chunk.substring(0, chunk.indexOf('\n')));
this.chunks = chunk.substring(chunk.indexOf('\n') + 1);
this.lastChunk = null;
returnValues.push(result);
});

returnValues.forEach((chunk) => {
super.onMessage(chunk);
});
}

/**
Expand Down
47 changes: 45 additions & 2 deletions packages/web3-providers/tests/src/providers/IpcProviderTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,16 +66,59 @@ describe('IpcProviderTest', () => {
expect(socketMock.connect).toHaveBeenCalledWith({path: ipcProvider.path});
});

it('calls onMessage', () => {
it('calls onMessage with one chunk', (done) => {
const objWithToString = {
toString: jest.fn(() => {
return '{"id":"0x0"}';
})
};

ipcProvider.on('0x0', (response) => {
expect(response).toEqual({id: '0x0'});

done();
});

ipcProvider.onMessage(objWithToString);

expect(objWithToString.toString).toHaveBeenCalled();
expect(objWithToString.toString).toHaveBeenCalledWith();
});

it('calls onMessage with more than one chunk', (done) => {
let callCount = 0;
const firstChunk = {
toString: jest.fn(() => {
return '{"id":"0x0"}{"id":"0x0"}';
})
};
const secondChunk = {
toString: jest.fn(() => {
return '{"id":"0x0"}{"id":"0x';
})
};
const thirdChunk = {
toString: jest.fn(() => {
return '0"}';
})
};

ipcProvider.on('0x0', (response) => {
expect(response).toEqual({id: '0x0'});

if (callCount === 1) {
done();
}

callCount++;
});

ipcProvider.onMessage(firstChunk);
ipcProvider.onMessage(secondChunk);
ipcProvider.onMessage(thirdChunk);

expect(firstChunk.toString).toHaveBeenCalledWith();
expect(secondChunk.toString).toHaveBeenCalledWith();
expect(thirdChunk.toString).toHaveBeenCalledWith();
});

it('calls registEventListener with a Socket object as connection', () => {
Expand Down