Я собираюсь упростить приведенный ниже код и добавлю комментарии по всему.
Общая идея заключается в том, что после того, как "лидер продаж" сохранен (звонок клиента) в моем приложении android (для Строительный концерт моего попса), я собираю сайт с pupeeteer, чтобы собрать некоторые данные об адресе. У меня уже все это работало, но (пока - успешно) я сохранял «внешний URL-адрес» с очищенного веб-сайта, но теперь я хотел бы просто взять внешний URL-адрес, получить изображение, загрузить его в свое хранилище Firestore Получите подписанный URL, а затем обновите документ Firestore с помощью этого «подписанного URL» (вместо внешнего URL). Кажется, все работает хорошо. Хорошо-я sh, но не в том порядке. Я получаю URL-адрес изображения и успешно сохраняю его в хранилище пожарного хранилища, но мой подписанный URL возвращается слишком поздно. Я просто озадачен обработкой обратных вызовов (или функций asyn c) здесь. Мне не обязательно нужен код (но я не откажусь от него! Ха-ха), может быть, просто общее руководство, как мне нужно организовать свой код. Я прочитал много информации о обратных вызовах, обещаниях и т. Д. c, но просто не могу обернуться и / или применить это к этому конкретному примеру.
Спасибо за любую помощь! Очень ценится!
exports.fetchData = functions.https.onCall(async (data, context) => {
const urlLib = require("url");
const pathLib = require("path");
//Check for authentication
if (!context.auth) { //not authed -> error
throw new functions.https.HttpsError('failed-precondition', 'The function must be called ' +
'while authenticated.');
} else { //authed -> good to go
var salesLeadId = data.salesLeadId; //grab leadID which is passed from my android app into this function (unique ID to identify the record I need to update)
try {
//Example URL
let url = 'http://www.example.com'; //I left out code here where I build a custom URL etc.
const browser = await puppeteer.launch();
const [page] = await browser.pages();
//Emulate Headless Chrome instance
await page.emulate({
name: 'Desktop 1920x1080',
userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36',
viewport: {
width: 1920,
height: 1080
}
});
//Opens Page, and waitws until loading is done
await page.goto(url, { waitUntil: 'networkidle0' });
//Read Data from web page and return as data object
var data = await page.evaluate(() => {
var scrapedPhoto = document.querySelector("#imgExamplePhoto").getAttribute('src'); //This is the external URL to the image
// [...] grabbing other info here and adding it to "data"
var accNo = "123456789"; //Example Data but in reality also fetched via document.queryselector
var pId "12-44-66-88-88"; //Example Data but in reality also fetched via document.queryselector
// etc...
return { scrapedPhoto, accNo, pId }; //return all scraped data in var data
});
await browser.close();
//below function is to grab the external URL, save it to Firestore Storage and return a Signed URL which I would then save with my lead document
var uploadedPhotoUrl = await saveToStorage(data.scrapedPhoto); // THIS IS WHERE MY PROBLEM IS....the code keeps going. The function eventually returns the correct URL but way too late.
//Firestore Document Reference for record to be updated
let leadRef = admin.firestore().collection("sales_leads").doc(salesLeadId);
//I've changed this in every way that I can think of by trial and error (i.e. tried chaining "thens", but unsuccessfully). I assume first I need to resolve the saveStorage function before proceeding to update my firestore document
return leadRef.update({ //Here is where I'm going back to my Firestore Document and update it with this "new data"
photo: uploadedPhotoUrl, //Problem: this is undefined because my code does NOT wait on "saveToStorage" above (Previously this was just the external "scrapedPhotoUrl" and thus worked fine. But instead of saving the external URL, I'm trying to save this image to firestore to avoid constant calls to their web page)
pId: data.pID,
accNo: data.accNo
}).then(writeResult => {
console.log(`Sales Lead updated with Data on: ${writeResult.writeTime.toDate()}`);
return `Sales Lead updated with Data on: ${writeResult.writeTime.toDate()}`
});
} catch (err) {
console.error(err);
return 'Error';
}
}
});
async function saveToStorage(fileUrl) {
var storage = admin.storage();
var fetch = require("node-fetch");
var urlLib = require("url");
var pathLib = require("path");
//Get File Name from provided URL
var parsed = urlLib.parse(fileUrl);
var fileName = pathLib.basename(parsed.pathname);
//Create Storage Reference with new File Name
var bucket = storage.bucket('gs://myprojetname.appspot.com');
var folderPath = 'sales/photos/';
var internalFilePath = folderPath + fileName;
var file = bucket.file(internalFilePath);
//Fetch file from url
return await fetch(fileUrl).then(res => {
const contentType = res.headers.get('content-type');
const writeStream = file.createWriteStream({
metadata: {
contentType
}
});
return res.body.pipe(writeStream)
.on('finish', () => {
console.log('Image saved')
return getDownloadURL(file); //so this eventually returns the corret URL, but by the time this "comes back" my main function has finished execution
})
.on('error', err => {
writeStream.end();
return console.error(err);
});
});
}
//Get Signed Download URL from Firestore Storage. This works fine for me.
function getDownloadURL(file) {
const config = {
action: 'read',
expires: '10-30-2050'
};
return file.getSignedUrl(config).then((downloadUrl) => {
let result = downloadUrl[0];
return result;
}).catch(error => {
console.error(error);
return 'Error';
});
}