Using service worker in React.js (Background sync with Indexeddb)

Viewed 786

I am uploading a file to s3 using dropzone in a web application. (I used aws-sdk.)

And when I am disconnected from the network using a service worker, I want to save the request to indexeddb so that when the Internet is reconnected re-upload from the point where it was disconnected. (like youtube studio)

Below is the process of the service worker I thought of.

  1. When online, users upload files.
  2. If the network connection is disconnected during upload, the upload request is saved in indexeddb.
  3. When the Internet is reconnected, the request stored in the indexeddb is fetched again.

I heard that the service worker only handles GET requests, so I'm implementing logic that responds to POST / PUT requests. But I don't think it's going the way I thought.

I don't know what to do. Please let me know if there is a good reference for me to look at or if there is a way.

In addition, I do everything on the client side without a server.

Here is my code

saga.js

import AWS from 'aws-sdk';

require('dotenv').config();

AWS.config.update({
    accessKeyId: process.env.REACT_APP_AWS_ACCESS_KEY,
    secretAccessKey: process.env.REACT_APP_AWS_SECRET_KEY,
    region: process.env.REACT_APP_AWS_REGION,
});

const s3 = new AWS.S3();

// ...code

function uploadFileToS3(file) {
    const options = {
        Bucket: process.env.REACT_APP_AWS_BUCKET_NAME,
        Key: file.name,
        ContentType: 'multipart/form-data',
        Body: file,
    };

    s3.upload(options)
        .on('httpUploadProgress', progress => {
            const { loaded, total } = progress;
            const progressPercentage = parseInt((loaded / total) * 100);

            const data = {
                name: file.name,
                percentage: progressPercentage,
                uploadedAt: new Date(),
            };

            dispatch(getUploadingProgress(data));
        })
        .send((err, response) => {
            if (err) console.log(err);
            console.log(response, 'response');
        });

}

service-worker.js

console.warn('sw file in public folder');

const CACHE_NAME = 'v1';
const cacheFiles = [
    '/',
    '/index.html',
    '/static/js/main.chunk.js',
    '/static/js/bundle.js',
    '/static/js/vendors~main.chunk.js',
    '/manifest.json',
    '/favicon.ico',
];
const FOLDER_NAME = 's3-request';
const DB_NAME = 'requestDB';
let form_data;
let our_db;

self.addEventListener('install', function (event) {
    event.waitUntil(
        caches.open(CACHE_NAME).then(function (cache) {
            console.log('Opened cache');
            return cache.addAll(cacheFiles);
        })
    );
});

function getObjectStore(storeName, mode) {
    return our_db.transaction(storeName, mode).objectStore(storeName);
}

function savePostRequests(url, method, payload) {
    const request = getObjectStore(FOLDER_NAME, 'readwrite').add({
        url: url,
        payload: payload,
        method: method,
    });
    request.onsuccess = function () {
        console.log('a new request has been added to indexedb');
    };

    request.onerror = function (error) {
        console.error(error);
    };
}

function openDatabase() {
    var indexedDBOpenRequest = indexedDB.open('s3-request');

    indexedDBOpenRequest.onerror = function (error) {
        console.error('IndexedDB error:', error);
    };

    indexedDBOpenRequest.onupgradeneeded = function () {
        this.result.createObjectStore(FOLDER_NAME, {
            autoIncrement: true,
            keyPath: 'id',
        });
    };

    indexedDBOpenRequest.onsuccess = function () {
        our_db = this.result;
    };
}

openDatabase();

self.addEventListener('fetch', function (event) {
    console.log('I am a request with url: ', event.request.clone().url);

    if (event.request.method === 'GET') {
        event.respondWith(
            caches.match(event.request).then(function (response) {
                if (response) {
                    return response;
                }
                return fetch(event.request);
            })
        );
    }

    if (event.request.clone().method === ('POST' || 'PUT')) {
        event.respondWith(
            fetch(event.request.clone()).catch(function () {
                savePostRequests(event.request.clone().url, event.request.clone().method, form_data);
            })
        );
    }
});

self.addEventListener('message', function (event) {
    if (event.data.hasOwnProperty('form_data')) {
        form_data = event.data.form_data;
    }
});

function sendPostToServer() {
    const savedRequests = [];
    const req = getObjectStore(FOLDER_NAME).openCursor();

    req.onsuccess = async function (event) {
        const cursor = event.target.result;

        if (cursor) {
            savedRequests.push(cursor.value);
            cursor.continue();
        } else {
            for (let savedRequest of savedRequests) {
                console.log('saved request', savedRequest);
                const requestUrl = savedRequest.url;
                const payload = JSON.stringify(savedRequest.payload);
                const method = savedRequest.method;

                const headers = {
                    Accept: 'application/json',
                    'Content-Type': 'application/json',
                };

                fetch(requestUrl, {
                    headers: headers,
                    method: method,
                    body: payload,
                })
                    .then(function (response) {
                        console.log('server response', response);
                        if (response.status < 400) {
                            getObjectStore(FOLDER_NAME, 'readwrite').delete(savedRequest.id);
                        }
                    })
                    .catch(function (error) {
                        console.error('Send to Server failed:', error);
                        throw error;
                    });
            }
        }
    };
}

self.addEventListener('sync', function (event) {
    console.log('now online');
    if (event.tag === 'sendFormData') {
        event.waitUntil(sendPostToServer());
    }
});

I have register, unregister function in serviceworkerRegistration.js

0 Answers
Related