Track upload progress using Peerjs - webrtc

Is there any method to track the upload progress while sending file/data to a WebRTC peer using peerjs?
import Peer from 'peerjs';
const peer = new Peer(peerId, { host: 'cloudbreeze-peer.onrender.com', secure: true })
peer.on('connection', conn => {
const file = html_file_object
const peerName = conn.metadata.username || 'Anonymous user'
conn.on('open', () => {
conn.send({ file, name: file.name, size: file.size, type: 'file' })
// track the progress of the file sent ('progress' listener is not available)
conn.on('progress', bytes => console.log(bytes * 100 / file.size))
})
}
I tried a way to divide the file into small chunks, it helped to track the progress on the receiving end, but I still couldn't track the uploading progress.
import Peer from 'peerjs';
const peer = new Peer(peerId, { host: 'cloudbreeze-peer.onrender.com', secure: true })
peer.on('connection', conn => {
const file = html_file_object
const peerName = conn.metadata.username || 'Anonymous user'
conn.on('open', () => {
const chunkSize = 1024 * 1024 // In bytes
const chunks = Math.ceil(size / chunkSize)
for (let i = 0; i < chunks; i++) {
const offset = i * chunkSize
conn.send({ file: file.slice(offset, offset + chunkSize), name, size, type: 'file' })
// still no way to track the progress
}
})
}
Thanks in advance for helping me out!

sent back received data percentages info to that sender as a text message

Related

Keep client connected to WebSocket in react native and express server

I have a react native application where i have two users using the app (customer and restaurant)
So on checkout I connect the customer to websocket on the express server and once the order is placed i send a message to the restaurant which is supposed to be connected to websocket all time.
However, sometimes the restaurant is disconnected somehow, so I am trying to keep the restaurant connected, and if disconnected then reconnect again automatically.
In react native restaurant side implementation i have the following code :
this is useWebSocketLite hook to handle connection, send, receive messages and retry connection to server when closed:
function useWebSocketLite({ socketUrl, retry: defaultRetry = 3, retryInterval = 1000 }) {
const [data, setData] = useState();
const [send, setSend] = useState(() => () => undefined);
const [retry, setRetry] = useState(defaultRetry);
const [readyState, setReadyState] = useState(false);
useEffect(() => {
const ws = new WebSocket(socketUrl);
ws.onopen = () => {
setReadyState(true);
setSend(() => {
return (data) => {
try {
const d = JSON.stringify(data);
ws.send(d);
return true;
} catch (err) {
return false;
}
};
});
ws.onmessage = (event) => {
const msg = formatMessage(event.data);
setData({ message: msg, timestamp: getTimestamp() });
};
};
ws.onclose = () => {
setReadyState(false);
if (retry > 0) {
setTimeout(() => {
setRetry((retry) => retry - 1);
}, retryInterval);
}
};
return () => {
ws.close();
};
}, [retry]);
return { send, data, readyState };
}
So based on this, every-time the connection is closed, the connection will retry again.
Besides, when a restaurant launches the app the following code will be implemented:
const ws = useWebSocketLite({
socketUrl: `wss://${url}/id=${user.user_id}&role=restaurant`
});
This useEffect to establish the connection:
useEffect(() => {
if (ws.readyState === true) {
setConnectionOpen(true);
}
}, [ws.readyState]);
and this useEffect to handle incoming messages
useEffect(() => {
if (ws.data) {
const message = ws.data;
//dispatch...
}
}, [ws.data]);
Express server implementation:
This is the code where i handle socket connections and messages in express server:
var webSockets = {}
function setupWebSocket(server) {
server.on('connection', (socket, req) => {
if (req) {
var clientId = req.url
let regexReplace = /[\[\]/]/g
let regex = /([^=#&]+)=([^?&#]*)/g,
params = {},
match;
while ((match = regex.exec(clientId))) {
params[decodeURIComponent(match[1]).replace(regexReplace, '')] = decodeURIComponent(match[2])
}
if (params.role === 'restaurant') {
webSockets[params.id] = socket
}
}
socket.on('message', data => {
let sData = JSON.parse(JSON.parse(data))
let {id, data} = sData.data
sendToClient(id, 'order', data)
})
socket.on('error', (err) => {
console.log(err)
})
socket.on('close', (code, req) => {
var clientId = req.url
let regexReplace = /[\[\]/]/g
let regex = /([^=#&]+)=([^?&#]*)/g,
params = {},
match;
while ((match = regex.exec(clientId))) {
params[decodeURIComponent(match[1]).replace(regexReplace, '')] = decodeURIComponent(match[2])
}
if (params.role === 'restaurant') {
delete webSockets[clientId]
console.log(`${webSockets[clientId]} disconnected with code ${code} !`);
}
});
});
// sends a message to a specific client
const sendToClient = (clientId, type, data = {}) => {
const payload = { type, data }
const messageToSend = JSON.stringify({ error: false, message: payload })
if (webSockets[clientId]) {
webSockets[clientId].send(messageToSend)
console.log(`${clientId} client notified with this order`)
} else {
console.log(`${clientId} websocket client is not connected.`)
}
}
}
So most of the time I get 13 websocket client is not connected. which means the restaurant has already been deleted from the webSockets object and its connection already closed.
Apologise for long question and hope someone can help me regarding this.
First of all, you should know that this is not a good practice of websockets, where you are forcing the client (the restaurant) to be connected.
Whatever, at the current state of your code, there is an illogical behavior: at the end of the useEffect of your “useWebSocketLite” function, you are closing the socket connection:
return () => {
ws.close();
};
Knowing that the useEffect hook is called twice: after the first render of the component, and then after every change of the dependencies (the “retry” state in your case); Your code can be ridden like so: everytime the “retry” state changes, we will close the socket! So for me that is why you got the client disconnected.

script to query data from BigQuery, export result to CSV format, and sFTP transfer to destination folder

I am looking for a reliable script to perform sFTP transfer from Google Cloud Storage bucket to the destination sFTP folder. Currently I'm using pandas/python to query data from Big Query and save the result to Google Storage and it's working flawlessly, and I use Google Cloud function to do the sFTP transfer and it's been working sporadically, sometimes it didn't run, and other times the file transfer was incomplete, and also it takes very long time for it to run (around 15 min via Google could function versus 5 secs if I transfer the same file manually). Attached is the Cloud function currently used. Any help is very much appreciated. Thanks
/**
* Triggered from a change to a Cloud Storage bucket.
*
* #param {!Object} event Event payload.
* #param {!Object} context Metadata for the event.
*/
exports.gcfSendToSftp = (event, context) => {
const Storage = require('#google-cloud/storage');
const os = require("os");
const fs = require("fs");
const Client = require('ssh2-sftp-client');
// Creates a client
const storage = new Storage();
const path = require('path');
const cwd = os.tmpdir()
const MyDate = new Date();
const formatted_year = MyDate.getFullYear();
const formatted_month = ('0' + (MyDate.getMonth()+1)).slice(-2);
const formatted_day = ('0' + MyDate.getDate()).slice(-2);
TRANSACTIONS_LOG_FILENAME='W2G_TransactionsLog_' + formatted_year + formatted_month + formatted_day + '.csv'
destFilename = path.join(cwd, TRANSACTIONS_LOG_FILENAME)
srcFilename=TRANSACTIONS_LOG_FILENAME
async function sendSFTP() {
const stats = fs.statSync(destFilename)
const fileSizeInBytes = stats["size"]
console.log(destFilename + " file size in bytes "+ fileSizeInBytes);
// let data = fs.createReadStream(destFilename);
let data = destFilename;
let remote = '/Home/w2g/W2GInventoryIntegration/'+ srcFilename;
let client = new Client();
client.connect({
host: '111.11.11.11',
port: '22',
username: 'test',
password: 'hokcqqEHH10g',
readyTimeout: 0,
debug: console.log
}).then(() => {
client.fastPut(data, remote);
}).catch(err => {
console.log(err, 'catch error');
});
}
async function downloadFile() {
bucketName='data_export_vw_transactions_log';
const options = {
// The path to which the file should be downloaded, e.g. "./file.txt"
destination: destFilename,
};
// Downloads the file
await storage.bucket(bucketName).file(srcFilename).download(options);
console.log(
`gs://${bucketName}/${srcFilename} downloaded to ${destFilename}.`
);
}
downloadFile().then( () => { sendSFTP() })
};

React Native: Failed to execute 'append' on 'FormData': parameter 2 is not of type 'Blob'. at new ApolloError

I am trying to upload image from my react native app to graphql by using Apollo client with createUploadLink(). When I am trying to mutate data by passing a ReactNativeFile as a variable, then it says
"network request failed: Failed to execute 'append' on 'FormData': parameter 2 is not of type 'Blob'. at new ApolloError ".
This this the mutation which i am trying to use
mutation publishPost(
$content: String!
$LocationInput: LocationInput!
$InputPostAttachment: [InputPostAttachment!]
) {
publishPost(
content: $content
location: $LocationInput
attachments: $InputPostAttachment
) {
content
}
}
InputPostAttachment has type
type InputPostAttachment {
type: PostAttachmentType!
file: Upload!
}
Apollo client settings and i am using apollo-upload-client
const httpLink = createUploadLink({
uri: 'http://localhost:8000/graphql',
});
const authLink = setContext(async (headers: any) => {
const token = await getToken();
return {
...headers,
headers: {
authorization: token ? `Bearer ${token}` : null,
},
};
});
const link = authLink.concat(httpLink);
// create an inmemory cache instance for caching graphql data
const cache = new InMemoryCache();
// instantiate apollo client with apollo link instance and cache instance
export const client = new ApolloClient({
link,
cache,
});
File upload Function and i am using react-native-image-crop-picker for multi image selection
const [image, setimage] = useState([]);
const _pickImage = () => {
ImagePicker.openPicker({
includeBase64: true,
multiple: true,
}).then((images: any) => {
let imageData: any = [];
images.map((data: any) => {
const file = new ReactNativeFile({
uri: data.path,
name: data.filename,
type: data.mime,
});
imageData.push({
type: 'IMAGE',
file: file,
});
});
setimage(imageData);
console.log(images);
});
};
const handlePost = async () => {
const InputPostAttachment: any = [...image];
const LocationInput = {
place: place,
vicinity: vicinity,
province: province,
};
publishPost({variables: {content, LocationInput, InputPostAttachment}})
.then(({data}) => {
console.log(data);
props.navigation.navigate('Home');
})
.catch((err) => {
console.log('err happened');
console.log(err);
});
};
could someone please help me out from this?
In addition to the chrome debugger issue, this error also happens on the expo web.
To anyone uploading images on expo web (or react-native web), here's a working solution:
/** Load image from camera/roll. */
const result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.All,
allowsEditing: true,
quality: 1,
});
if (result.cancelled) {
return;
}
/** web platform: blob. */
const convertBase64ToBlob = async (base64) => {
const response = await fetch(base64);
const blob = await response.blob();
return blob;
};
/** android/ios platform: ReactNativeFile.*/
const createReactNativeFile = (uri) => {
const file = new ReactNativeFile({
uri,
type: mime.lookup(uri) || 'image',
name: `file-${Date.now()}`,
});
return file;
};
/** Use blob for web, ReactNativeFile otherwise. */
const file = Platform.OS === 'web'
? await convertBase64ToBlob(result.uri)
: createReactNativeFile(result.uri);
/** Upload image with apollo. */
mutate({ variables: { file } });
On the web platform, ImagePicker returns a base64 value instead of a file path. This problem doesn't happen if the platform is Android or iOS, as ImagePicker returns a file path, which is expected by apollo-upload-client.
The solution is to detect if the URI is base64 (which happens when the platform is "web") and convert it to a blob.
My apollo-client was configured using apollo-boost and i was using chrome debugger to intercept the network was causing me this issue.
To be more specific I was using the below code to get the network requests sent by my app in the chrome debugger
global.XMLHttpRequest =
global.originalXMLHttpRequest || global.XMLHttpRequest;
global.FormData = global.originalFormData || global.FormData;
if (window.FETCH_SUPPORT) {
window.FETCH_SUPPORT.blob = false;
} else {
global.Blob = global.originalBlob || global.Blob;
global.FileReader = global.originalFileReader || global.FileReader;
}
apollo-upload-client wont send the data in multipart data if we are using chrome debugger. We will face network issue.This issue has the answer. or I had not removed apollo-boost and some part of my app was using it that was also a issue.

Sending Images Using React Native

I am trying to add sending images feature in my react native mobile application using base64. Is tha essential thing to use following all prameters when use base64 ?fs.writeFile(./uploads/${req.body.imageName}.${req.body.imageExt}, binaryData, err =
//const Order = require("../models/image.model.js");
const mongoose = require("mongoose");
const fs = require('fs')
exports.submit = (req, res) => {
const binaryData = new Buffer(req.body.image, 'base64');
fs.writeFile(`./uploads/${req.body.imageName}.${req.body.imageExt}`, binaryData, err => {
if(err) {
console.log(err)
res.status(400).json({
message: "Couldn't upload"
})
} else {
// Image saved
res.status(200).json({
message: "Success"
})
/*
Use GCP bucket
Upload -> callback -> fetchUrl
*/
}
})
};

Expo: Anyway of adding Speech to Text?

I want to include speech-to-text in my Expo app.
There are api's available such as google's speech to text and watson etc...
Has anyone come up with a solution or has any advice on how to include Speech-to-Text in their Expo or React-Native application?
I have looked at various github repos that provide Speech-to-Text for React-Native applications but they do not look production ready, and are strictly React-Native solutions as you need access to Java/Swift code.
I am not disinclined towards that if that is the only option but would prefer a Expo solution if possible.
Regards,
Emir
If you want to implement Speech-To-Text on expo then you need to create an api and deploy it else you need to detach the project and use the library react-native-google-speech-api
This is what i have implemented using google app engine, google cloud storage and google speech to text.
const format = require('util').format;
const fs = require('fs');
const express = require('express');
const multer = require('multer');
const requestHttp = require('request');
const {Storage} = require('#google-cloud/storage');
// Instantiate a storage client
const storage = new Storage();
// const upload = multer();
const app = express();
// Imports the Google Cloud client library
const speech = require('#google-cloud/speech');
// Creates a client
const client = new speech.SpeechClient();
/**
* TODO(developer): Uncomment the following lines before running the sample.
*/
const encoding = 'LINEAR16';
const sampleRateHertz = 16000;
const languageCode = 'en-US';
const upload = multer({
storage: multer.memoryStorage(),
limits: {
fileSize: 5 * 1024 * 1024, // no larger than 5mb, you can change as needed.
},
});
const bucket = storage.bucket(process.env.GCLOUD_STORAGE_BUCKET);
app.post('/upload', upload.single('file') , async (req, res) => {
const file = await req.file
if (!file) {
const error = new Error('Please upload a file')
error.httpStatusCode = 400
return next(error)
}
// Create a new blob in the bucket and upload the file data.
const blob = bucket.file(req.file.originalname);
const blobStream = blob.createWriteStream({
resumable: false,
});
blobStream.on('error', err => {
next(err);
});
blobStream.on('finish', async () => {
// The public URL can be used to directly access the file via HTTP.
const publicUrl = await format(
`https://storage.googleapis.com/${bucket.name}/${blob.name}`
);
const request = {
config: {
encoding: encoding,
sampleRateHertz: sampleRateHertz,
languageCode: languageCode,
},
audio: {
uri: 'gs://YOUR-Bucket-Name/File-name.ext'
}
};
// Stream the audio to the Google Cloud Speech API
const [response] = await client.recognize(request);
const transcription = response.results
.map(result => result.alternatives[0].transcript)
.join('\n');
console.log(`Transcription: `, transcription);
res.status(200)
.send({
success: 'true',
message: 'Text retrieved successfully',
text: transcription
})
.end();
});
blobStream.end(req.file.buffer);
});
const PORT = process.env.PORT || 8080;
app.listen(PORT, () => {
console.log(`App listening on port ${PORT}`);
console.log('Press Ctrl+C to quit.');
});