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.
- When online, users upload files.
- If the network connection is disconnected during upload, the upload request is saved in indexeddb.
- 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