Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

failed to replicate Large document Attachments over WebRTC in browsers #6520

Open
haouarihk opened this issue Oct 22, 2024 · 2 comments
Open

Comments

@haouarihk
Copy link

haouarihk commented Oct 22, 2024

Have you found a bug?

WebRTC in browsers is only limited to 16kb,
however this limit is not present in nodejs environment.

Did you make a unit test?

As far as i can tell, there are no browser based unit test in this project, but i made the test anyway for future implementation.

Do you have a feature request?

The solution to this problem is to send large contents in chunks, rather than sending them all as one blob. this could also open us for another event listener for "syncing".

if i missed anything, be sure to let me know.

PR: #6521

@haouarihk
Copy link
Author

here's the test file:

import assert from 'assert';
import config from './config.ts';
import {
    randomCouchString,
    createRxDatabase
} from '../../plugins/core/index.mjs';
import {
    replicateWebRTC,
    getConnectionHandlerSimplePeer,
    SimplePeerWrtc
} from '../../plugins/replication-webrtc/index.mjs';
import {
    isFastMode,
    isDeno,
    isNode
} from '../../plugins/test-utils/index.mjs';
import { waitUntil } from 'async-test-util';
import { wrappedAttachmentsCompressionStorage } from '../../plugins/attachments-compression/index.mjs';

describe('large-document-webrtc.test.ts', function () {
    this.timeout(1000 * 60); // 1 minute

    if (
        !config.storage.hasReplication ||
        !config.storage.hasPersistence ||
        !config.storage.hasAttachments ||
        isDeno
    ) {
        return;
    }

    let wrtc: SimplePeerWrtc;
    let webSocketConstructor: WebSocket;
    const signalingServerUrl = 'ws://localhost:18006';

    before(async () => {
        if (isNode) {
            const wrtcModule = await import('node-datachannel/polyfill');
            wrtc = wrtcModule.default as any;

            const wsModule = await import('ws');
            webSocketConstructor = wsModule.WebSocket as any;
        }
    });

    it('should replicate large attachments over WebRTC', async function () {
        if (isFastMode()) {
            return;
        }

        const createCollection = async (name: string) => {
            const db = await createRxDatabase({
                name: randomCouchString(10),
                storage: wrappedAttachmentsCompressionStorage({
                    storage: config.storage.getStorage()
                })
            });

            const collections = await db.addCollections({
                [name]: {
                    schema: {
                        version: 0,
                        type: 'object',
                        primaryKey: 'id',
                        properties: {
                            id: {
                                type: 'string'
                            },
                            name: {
                                type: 'string'
                            }
                        },
                        attachments: {
                            compression: 'gzip'
                        }
                    }
                }
            });

            return collections[name];
        };

        const c1 = await createCollection('humans1');
        const c2 = await createCollection('humans2');

        const topic = randomCouchString(10);

        const replicationStates = await Promise.all([c1, c2].map(collection =>
            replicateWebRTC({
                collection,
                topic,
                connectionHandlerCreator: getConnectionHandlerSimplePeer({
                    signalingServerUrl,
                    wrtc,
                    webSocketConstructor
                }),
                pull: {},
                push: {}
            })
        ));

        // Create a large attachment (1GB)
        const largeData = new Uint8Array(1 * 1024 * 1024 * 1024);
        for (let i = 0; i < largeData.length; i++) {
            largeData[i] = Math.floor(Math.random() * 256);
        }

        const doc = await c1.insert({
            id: 'doc1',
            name: 'Large Document'
        });

        await doc.putAttachment({
            id: 'large-attachment',
            data: Buffer.from(largeData),
            type: 'application/octet-stream'
        });

        // Wait for replication
        await waitUntil(async () => {
            const docInC2 = await c2.findOne('doc1').exec();
            return docInC2 && docInC2.allAttachments().length > 0;
        });

        const replicatedDoc = await c2.findOne('doc1').exec();
        assert.ok(replicatedDoc, 'Document should be replicated');

        const attachment = replicatedDoc.getAttachment('large-attachment');
        assert.ok(attachment, 'Attachment should be replicated');

        const attachmentData = await attachment.getData();
        const replicatedData = new Uint8Array(await attachmentData.arrayBuffer());

        assert.strictEqual(replicatedData.length, largeData.length, 'Attachment size should match');
        assert.deepStrictEqual(replicatedData, largeData, 'Attachment content should match');

        // Clean up
        await Promise.all(replicationStates.map(state => state.cancel()));
        await c1.database.destroy();
        await c2.database.destroy();
    });
});

Copy link

stale bot commented Oct 29, 2024

This issue has been automatically marked as stale because it has not had recent activity. It will be closed soon. Please update it or it may be closed to keep our repository organized. The best way is to add some more information or make a pull request with a test case. Also you might get help in fixing it at the RxDB Community Chat If you know you will continue working on this, just write any message to the issue (like "ping") to remove the stale tag.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants