Skip to content

Instantly share code, notes, and snippets.

@soichisumi
Created December 12, 2018 13:41
Show Gist options
  • Save soichisumi/765c4f6a0aa4400487efdad308149021 to your computer and use it in GitHub Desktop.
Save soichisumi/765c4f6a0aa4400487efdad308149021 to your computer and use it in GitHub Desktop.
const functions = require('firebase-functions');
const rp = require('request-promise');
const projectId = process.env.GCP_PROJECT;
const region = 'us-central1';
// GCF の List API を利用するためのサービスアカウント
// service account をリポジトリに含めたくない場合は下記のように機密データを取得する
// 設定方法: https://github.com/firebase/firebase-tools/issues/406#issuecomment-353017349
const serviceAccount = functions.config().list.cert;
// callable functionを呼ぶために使用する
const firebase = require('firebase');
firebase.initializeApp({
projectId: process.env.GCP_PROJECT
})
async function getAccessToken() {
const { google } = require('googleapis');
// ref: https://developers.google.com/identity/protocols/googlescopes
const scopes = ['https://www.googleapis.com/auth/cloudfunctions', 'https://www.googleapis.com/auth/cloud-platform'];
const jwtClient = new google.auth.JWT(
serviceAccount.client_email,
undefined,
serviceAccount.private_key,
scopes,
undefined
);
const authorization = await jwtClient.authorize();
return authorization.access_token;
}
async function listFunction() {
try {
const accessToken = await getAccessToken();
const endpoint = `https://cloudfunctions.googleapis.com/v1/projects/${projectId}/locations/${region}/functions`;
const option = {
uri: endpoint,
method: 'GET',
headers: {
Authorization: `Bearer ${accessToken}`
},
qs: {
pageSize: 100
},
json: true
};
// ref: https://cloud.google.com/functions/docs/reference/rest/v1/projects.locations.functions/list
const res = await rp.get(option);
return res.functions;
} catch (err) {
console.log(`error occurred when listing function: ${JSON.stringify(err)}`);
return err;
}
}
async function callHttpFunctions(urls){
for (const url of urls){
const option = {
uri: url,
method: "POST",
body:{
},
json: true
};
const res = await rp(option);
console.log(`function: ${url} is called.`)
}
}
async function callCallableFunctions(funcNames){
for(funcName of funcNames){
try{
await firebase.functions().httpsCallable(funcName)()
console.log(`function: ${funcName} called.`)
}catch(err){
console.log(`error: ${JSON.stringify(err)}`);
}
}
}
exports.WarmupFunctions = functions
.pubsub
.topic("WarmupFunctions")
.onPublish(async (msg)=>{
const urls = new Array();
const callableFuncNames = new Array();
const funcs = await listFunction();
funcs.forEach(func => {
if(!func.httpsTrigger){
console.log(`function: ${func.name} is not https function`)
return
}
const url = func.httpsTrigger.url;
if(func.labels["deployment-callable"] === "true" ){
callableFuncNames.push(url.split('/').slice(-1)[0]);
}else {
urls.push(url);
}
console.log(`function: ${func.name} is target`);
})
await callHttpFunctions(urls);
await callCallableFunctions(callableFuncNames);
console.log(`all functions are waked up. httpFuncs: ${urls.length}, CallableFuncs: ${callableFuncNames.length}`);
})
// 以下は動作確認用の関数
// 通常のHTTP関数
exports.HttpsFunction = functions.https.onRequest((req, res)=>{
console.log(`req.body: ${req.body}`)
return res.status(200).json({
message: "OK",
body: req.body
})
})
// Callable関数
exports.CallableFunction = functions.https.onCall((data, context)=>{
// uncomment in production use
// if(!context.auth){
// throw new functions.https.HttpsError('unauthenticated', 'The function must be called while authenticated.');
// }
console.log(`function called. data: ${data}, uid: ${context.auth}`)
return {
message: "OK",
data: data,
ctx: context
}
})
// バックグラウンド関数(pubsub トリガー)
exports.BackgroundFunction = functions.pubsub.topic("PubsubSample").onPublish(async (msg)=>{
console.log(msg)
return msg
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment