ARとダウンロード処理を追加する

This commit is contained in:
ry.yamafuji 2025-03-26 06:11:42 +09:00
parent 5c9c5ba9e0
commit b76affe2f7
25 changed files with 782 additions and 0 deletions

4
docs/blockcheen.md Normal file
View File

@ -0,0 +1,4 @@
# [技術][2025]ブロックチェーンの利用ガイドライン
サプライチェーンにブロックチェーンを導入することで
トレーサビリティの確保、改ざん防止、透明性の向上といった効果が得られます

42
docs/front/ar/WebXR.html Normal file
View File

@ -0,0 +1,42 @@
<!-- index.html -->
<html>
<head>
<meta charset="utf-8" />
<title>Simple WebXR AR</title>
<script src="https://cdn.jsdelivr.net/npm/three@0.152.2/build/three.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.152.2/examples/jsm/webxr/ARButton.js"></script>
</head>
<body style="margin: 0; overflow: hidden;">
<script type="module">
import * as THREE from 'https://cdn.jsdelivr.net/npm/three@0.152.2/build/three.module.js';
import { ARButton } from 'https://cdn.jsdelivr.net/npm/three@0.152.2/examples/jsm/webxr/ARButton.js';
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.01, 20);
const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.xr.enabled = true;
document.body.appendChild(renderer.domElement);
document.body.appendChild(ARButton.createButton(renderer));
const geometry = new THREE.BoxGeometry(0.1, 0.1, 0.1);
const material = new THREE.MeshNormalMaterial();
const cube = new THREE.Mesh(geometry, material);
cube.position.set(0, 0, -0.5);
scene.add(cube);
function animate() {
renderer.setAnimationLoop(() => {
cube.rotation.y += 0.01;
renderer.render(scene, camera);
});
}
animate();
</script>
</body>
</html>

View File

@ -0,0 +1,74 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>WebXR AR Sample</title>
<style>
body {
margin: 0;
overflow: hidden;
}
canvas {
display: block;
}
</style>
</head>
<body>
<script type="module">
import * as THREE from 'https://cdn.skypack.dev/three@0.152.2';
import { ARButton } from 'https://cdn.skypack.dev/three@0.152.2/examples/jsm/webxr/ARButton.js';
let camera, scene, renderer;
let controller;
init();
animate();
function init() {
// Renderer
renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.xr.enabled = true;
document.body.appendChild(renderer.domElement);
// ARボタンを追加Hit-test機能必要
document.body.appendChild(
ARButton.createButton(renderer, { requiredFeatures: ['hit-test'] })
);
// SceneとCamera
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.01, 20);
// 光源
const light = new THREE.HemisphereLight(0xffffff, 0xbbbbff, 1);
light.position.set(0.5, 1, 0.25);
scene.add(light);
// 立方体を作成
const geometry = new THREE.BoxGeometry(0.2, 0.2, 0.2);
const material = new THREE.MeshStandardMaterial({ color: 0x00ff00 });
const cube = new THREE.Mesh(geometry, material);
cube.position.set(0, 0, -0.5); // カメラの前に表示
scene.add(cube);
// コントローラ
controller = renderer.xr.getController(0);
scene.add(controller);
}
function animate() {
renderer.setAnimationLoop(render);
}
function render() {
renderer.render(scene, camera);
}
</script>
</body>
</html>

21
docs/front/ar/aframe.html Normal file
View File

@ -0,0 +1,21 @@
<!DOCTYPE html>
<html>
<head>
<title>歩行型Webページ</title>
<script src="https://aframe.io/releases/1.4.2/aframe.min.js"></script>
</head>
<body>
<a-scene>
<!-- 地面 -->
<a-plane position="0 0 0" rotation="-90 0 0" width="50" height="50" color="#7BC8A4"></a-plane>
<!-- カメラとコントロールWASDキーで歩行可能 -->
<a-entity camera wasd-controls look-controls position="0 1.6 5"></a-entity>
<!-- 建物風のオブジェクト -->
<a-box position="0 0.5 -5" depth="5" height="1" width="5" color="#4CC3D9"></a-box>
<a-box position="10 0.5 -5" depth="5" height="1" width="5" color="#FFC65D"></a-box>
<a-sphere position="-10 1 -5" radius="1" color="#EF2D5E"></a-sphere>
</a-scene>
</body>
</html>

View File

View File

@ -0,0 +1,11 @@
ID,Name,Age,Email
1,User_1,44,user1@example.com
2,User_2,20,user2@example.com
3,User_3,67,user3@example.com
4,User_4,49,user4@example.com
5,User_5,56,user5@example.com
6,User_6,63,user6@example.com
7,User_7,31,user7@example.com
8,User_8,67,user8@example.com
9,User_9,41,user9@example.com
10,User_10,30,user10@example.com
1 ID Name Age Email
2 1 User_1 44 user1@example.com
3 2 User_2 20 user2@example.com
4 3 User_3 67 user3@example.com
5 4 User_4 49 user4@example.com
6 5 User_5 56 user5@example.com
7 6 User_6 63 user6@example.com
8 7 User_7 31 user7@example.com
9 8 User_8 67 user8@example.com
10 9 User_9 41 user9@example.com
11 10 User_10 30 user10@example.com

View File

@ -0,0 +1,11 @@
ID,Name,Age,Email
1,User_1,37,user1@example.com
2,User_2,30,user2@example.com
3,User_3,63,user3@example.com
4,User_4,42,user4@example.com
5,User_5,31,user5@example.com
6,User_6,63,user6@example.com
7,User_7,28,user7@example.com
8,User_8,20,user8@example.com
9,User_9,42,user9@example.com
10,User_10,69,user10@example.com
1 ID Name Age Email
2 1 User_1 37 user1@example.com
3 2 User_2 30 user2@example.com
4 3 User_3 63 user3@example.com
5 4 User_4 42 user4@example.com
6 5 User_5 31 user5@example.com
7 6 User_6 63 user6@example.com
8 7 User_7 28 user7@example.com
9 8 User_8 20 user8@example.com
10 9 User_9 42 user9@example.com
11 10 User_10 69 user10@example.com

View File

@ -0,0 +1,79 @@
/**
* @description downloadボタンを押下したらCSVファイルをzip圧縮してダウンロードする
*/
// ダウンロードボタン
const downloadButton = document.getElementById('download-button');
const downloadButtonFile = document.getElementById('download-button-file');
// ダウンロードボタンを押下した時の処理を記載する
downloadButton.addEventListener('click', async () => {
// ダウンロードボタンを無効化する
downloadButton.disabled = true;
// ダウンロード処理を実行する
try {
const zip = new JSZip();
// ZIPにファイルを追加
zip.file("hello.txt", "Hello, this is a ZIP file!");
zip.file("world.txt", "Hello, this is a ZIP file!");
// ZIPを生成してダウンロード
const zipBlob = await zip.generateAsync({ type: "blob" });
const a = document.createElement("a");
a.href = URL.createObjectURL(zipBlob);
a.download = "example.zip";
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
} catch (e) {
// エラーが発生した場合
console.error(e);
alert('ダウンロードに失敗しました');
} finally {
// ダウンロードボタンを有効化する
downloadButton.disabled = false;
}
});
downloadButtonFile.addEventListener('click', async () => {
// ダウンロードボタンを無効化する
downloadButtonFile.disabled = true;
try {
const files = [
{ name: "text1.csv", url: "assets/data/test_data_1.csv" },
{ name: "text2.csv", url: "assets/data/test_data_2.csv" }
];
const zip = new JSZip();
// CSV ファイルを取得して ZIP に追加
await Promise.all(
files.map(async (file) => {
const response = await fetch(file.url);
if (!response.ok) throw new Error(`Failed to fetch ${file.name}`);
const text = await response.text();
zip.file(file.name, text);
})
);
// ZIP を生成してダウンロード
zip.generateAsync({ type: "blob" }).then((blob) => {
const link = document.createElement("a");
link.href = URL.createObjectURL(blob);
link.download = "files.zip";
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}).catch(console.error)
} catch (e) {
// エラーが発生した場合
console.error(e);
alert('ダウンロードに失敗しました');
}
finally {
// ダウンロードボタンを有効化する
downloadButtonFile.disabled = false;
}
});

View File

@ -0,0 +1,72 @@
/**
* @description downloadボタンを押下したらCSVファイルをzip圧縮してダウンロードする
*/
// ダウンロードボタン
const downloadButtonServer = document.getElementById('download-button-server');
// ダウンロードボタンを押下した時の処理を記載する
downloadButtonServer.addEventListener('click', async () => {
// Blobで取得する方法
console.log('downloadButtonServer');
// ダウンロードボタンを無効化する
downloadButtonServer.disabled = true;
// ダウンロード処理を実行する
try {
// localhost:3000/downdload にリクエストを送る
const response = await fetch('http://localhost:3000/downdload');
if (!response.ok) throw new Error('Failed to fetch');
// ZIPファイルを取得
const zipBlob = await response.blob();
const a = document.createElement("a");
a.href = URL.createObjectURL(zipBlob);
a.download = "serverFile.zip";
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
} catch (e) {
// エラーが発生した場合
console.error(e);
alert('ダウンロードに失敗しました');
} finally {
// ダウンロードボタンを有効化する
downloadButtonServer.disabled = false;
}
});
// ダウンロードボタン(アップロード)
const downloadButtonUpload = document.getElementById('download-button-upload');
// ダウンロードボタンを押下した時の処理を記載する
downloadButtonUpload.addEventListener('click', async () => {
console.log('downloadButtonUpload');
// ダウンロードボタンを無効化する
downloadButtonUpload.disabled = true;
// サーバーにアップロード処理APIを送信する
try {
// localhost:3000/generate-zip にリクエストを送る
const response = await fetch('http://localhost:3000/generate-zip');
if (!response.ok) throw new Error('Failed to fetch');
// レスポンスからURLを取得
const { url } = await response.json();
// 取得したURLを開く
window.open(url);
} catch (e) {
// エラーが発生した場合
console.error(e);
alert('ダウンロードに失敗しました');
} finally {
// ダウンロードボタンを有効化する
downloadButtonUpload.disabled = false;
}
});

View File

@ -0,0 +1,5 @@
// Message
document.addEventListener("DOMContentLoaded", () => {
document.getElementById("message").textContent = "Hello, JavaScript!";
});

13
docs/front/assets/lib/jszip.min.js vendored Normal file

File diff suppressed because one or more lines are too long

21
docs/front/download.html Normal file
View File

@ -0,0 +1,21 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.1/jszip.min.js"></script>
<title>Download</title>
</head>
<body>
<h1>JavaScript Develop Download To Front Side</h1>
<p >Zip File Download</p>
<button id="download-button">Zip Download(From Content)</button>
<button id="download-button-file">Zip Download(From File)</button>
<p >Server </p>
<button id="download-button-server">Zip Download(From Server)</button>
<button id="download-button-upload">Zip Download(upload)</button>
<p >Google Storage Link</p>
<script src="assets/download.js"></script>
<script src="assets/downloadFromServer.js"></script>
</body>
</html>

15
docs/front/gcs.html Normal file
View File

@ -0,0 +1,15 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.1/jszip.min.js"></script>
<title>Google Cloud Storage</title>
</head>
<body>
<h1>JavaScript Develop Download To Google Cloud Storage</h1>
<p >Zip File Download</p>
<button id="download-button">Zip Download(GCS)</button>
<script src="assets/cloud-storage.js"></script>
</body>
</html>

13
docs/front/index.html Normal file
View File

@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h1>JavaScript Develop Debug</h1>
<p id="message">Open the console to see the output</p>
<script src="assets/index.js"></script>
</body>
</html>

44
docs/trend2025.md Normal file
View File

@ -0,0 +1,44 @@
## 空間コンピューティング / AR / XRの技術選定
```html
<!-- index.html -->
<html>
<head>
<meta charset="utf-8" />
<title>Simple WebXR AR</title>
<script src="https://cdn.jsdelivr.net/npm/three@0.152.2/build/three.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.152.2/examples/jsm/webxr/ARButton.js"></script>
</head>
<body style="margin: 0; overflow: hidden;">
<script type="module">
import * as THREE from 'https://cdn.jsdelivr.net/npm/three@0.152.2/build/three.module.js';
import { ARButton } from 'https://cdn.jsdelivr.net/npm/three@0.152.2/examples/jsm/webxr/ARButton.js';
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.01, 20);
const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.xr.enabled = true;
document.body.appendChild(renderer.domElement);
document.body.appendChild(ARButton.createButton(renderer));
const geometry = new THREE.BoxGeometry(0.1, 0.1, 0.1);
const material = new THREE.MeshNormalMaterial();
const cube = new THREE.Mesh(geometry, material);
cube.position.set(0, 0, -0.5);
scene.add(cube);
function animate() {
renderer.setAnimationLoop(() => {
cube.rotation.y += 0.01;
renderer.render(scene, camera);
});
}
animate();
</script>
</body>
</html>
```

42
src/front/ar/WebXR.html Normal file
View File

@ -0,0 +1,42 @@
<!-- index.html -->
<html>
<head>
<meta charset="utf-8" />
<title>Simple WebXR AR</title>
<script src="https://cdn.jsdelivr.net/npm/three@0.152.2/build/three.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.152.2/examples/jsm/webxr/ARButton.js"></script>
</head>
<body style="margin: 0; overflow: hidden;">
<script type="module">
import * as THREE from 'https://cdn.jsdelivr.net/npm/three@0.152.2/build/three.module.js';
import { ARButton } from 'https://cdn.jsdelivr.net/npm/three@0.152.2/examples/jsm/webxr/ARButton.js';
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.01, 20);
const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.xr.enabled = true;
document.body.appendChild(renderer.domElement);
document.body.appendChild(ARButton.createButton(renderer));
const geometry = new THREE.BoxGeometry(0.1, 0.1, 0.1);
const material = new THREE.MeshNormalMaterial();
const cube = new THREE.Mesh(geometry, material);
cube.position.set(0, 0, -0.5);
scene.add(cube);
function animate() {
renderer.setAnimationLoop(() => {
cube.rotation.y += 0.01;
renderer.render(scene, camera);
});
}
animate();
</script>
</body>
</html>

View File

@ -0,0 +1,74 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>WebXR AR Sample</title>
<style>
body {
margin: 0;
overflow: hidden;
}
canvas {
display: block;
}
</style>
</head>
<body>
<script type="module">
import * as THREE from 'https://cdn.skypack.dev/three@0.152.2';
import { ARButton } from 'https://cdn.skypack.dev/three@0.152.2/examples/jsm/webxr/ARButton.js';
let camera, scene, renderer;
let controller;
init();
animate();
function init() {
// Renderer
renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.xr.enabled = true;
document.body.appendChild(renderer.domElement);
// ARボタンを追加Hit-test機能必要
document.body.appendChild(
ARButton.createButton(renderer, { requiredFeatures: ['hit-test'] })
);
// SceneとCamera
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.01, 20);
// 光源
const light = new THREE.HemisphereLight(0xffffff, 0xbbbbff, 1);
light.position.set(0.5, 1, 0.25);
scene.add(light);
// 立方体を作成
const geometry = new THREE.BoxGeometry(0.2, 0.2, 0.2);
const material = new THREE.MeshStandardMaterial({ color: 0x00ff00 });
const cube = new THREE.Mesh(geometry, material);
cube.position.set(0, 0, -0.5); // カメラの前に表示
scene.add(cube);
// コントローラ
controller = renderer.xr.getController(0);
scene.add(controller);
}
function animate() {
renderer.setAnimationLoop(render);
}
function render() {
renderer.render(scene, camera);
}
</script>
</body>
</html>

21
src/front/ar/aframe.html Normal file
View File

@ -0,0 +1,21 @@
<!DOCTYPE html>
<html>
<head>
<title>歩行型Webページ</title>
<script src="https://aframe.io/releases/1.4.2/aframe.min.js"></script>
</head>
<body>
<a-scene>
<!-- 地面 -->
<a-plane position="0 0 0" rotation="-90 0 0" width="50" height="50" color="#7BC8A4"></a-plane>
<!-- カメラとコントロールWASDキーで歩行可能 -->
<a-entity camera wasd-controls look-controls position="0 1.6 5"></a-entity>
<!-- 建物風のオブジェクト -->
<a-box position="0 0.5 -5" depth="5" height="1" width="5" color="#4CC3D9"></a-box>
<a-box position="10 0.5 -5" depth="5" height="1" width="5" color="#FFC65D"></a-box>
<a-sphere position="-10 1 -5" radius="1" color="#EF2D5E"></a-sphere>
</a-scene>
</body>
</html>

48
src/front/ar/hover.html Normal file
View File

@ -0,0 +1,48 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>ホバーで説明表示</title>
<script src="https://aframe.io/releases/1.4.2/aframe.min.js"></script>
</head>
<body>
<a-scene>
<!-- 地面 -->
<a-plane position="0 0 0" rotation="-90 0 0" width="50" height="50" color="#7BC8A4"></a-plane>
<!-- カメラと移動 -->
<a-entity camera wasd-controls look-controls position="0 1.6 5"></a-entity>
<!-- 展示物 -->
<a-box id="exhibit" position="0 0.5 -5" color="#4CC3D9" depth="1" height="1" width="1"></a-box>
<!-- 説明テキスト(最初は非表示) -->
<a-text id="tooltip" value="これは展示物です" visible="false" position="0 1.5 -5" color="#000" align="center" width="4">
</a-text>
<!-- イベントスクリプト -->
<script>
AFRAME.registerComponent('show-tooltip', {
init: function () {
const tooltip = document.querySelector('#tooltip');
this.el.addEventListener('mouseenter', () => {
tooltip.setAttribute('visible', 'true');
});
this.el.addEventListener('mouseleave', () => {
tooltip.setAttribute('visible', 'false');
});
}
});
// 展示物にイベントコンポーネントを適用
document.addEventListener('DOMContentLoaded', () => {
const exhibit = document.querySelector('#exhibit');
exhibit.setAttribute('show-tooltip', '');
});
</script>
</a-scene>
</body>
</html>

View File

@ -0,0 +1,47 @@
/**
* @description downloadボタンを押下したらCSVファイルをzip圧縮してダウンロードする
*/
// ダウンロードボタン
const downloadButton = document.getElementById('download-button');
const downloadButtonBase64 = document.getElementById('download-button-base64');
// ダウンロードボタンを押下した時の処理を記載する
downloadButton.addEventListener('click', async () => {
// URLを別のウィンドウで開く
// GCSからZIPファイルのコンテンツが返る
window.open('http://localhost:3000/downdload-gcs');
});
downloadButtonBase64.addEventListener('click', async () => {
// ダウンロードボタンを無効化する
downloadButtonBase64.disabled = true;
try {
// localhost:3000/downdload-gcs-json にリクエストを送る
const response = await fetch('http://localhost:3000/downdload-gcs-json');
if (!response.ok ) throw new Error('Failed to fetch');
// JSONでdataにbase64が返ってくる
const res = await response.json();
const base64 = res.data;
// Base64をデコードしてZIPファイルを生成
const zipBlob = await fetch(`data:application/zip;base64,${base64}`).then(res => res.blob());
const a = document.createElement("a");
a.href = URL.createObjectURL(zipBlob);
a.download = "serverFile.zip";
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
} catch (e) {
// エラーが発生した場合
console.error(e);
alert('ダウンロードに失敗しました');
}
finally {
// ダウンロードボタンを有効化する
downloadButtonBase64.disabled = false;
}
});

View File

@ -9,7 +9,9 @@
<body>
<h1>JavaScript Develop Download To Google Cloud Storage</h1>
<p >Zip File Download</p>
<button id="download-button">Zip Download(GCS)</button>
<button id="download-button-base64">Zip Download(GCS JSON Base64)</button>
<script src="assets/cloud-storage.js"></script>
</body>
</html>

View File

@ -0,0 +1,53 @@
const fs = require('fs');
const path = require('path');
const fetch = require('node-fetch');
async function uploadFile(filePath) {
try {
// Step 1: Request a signed URL from the API
const apiResponse = await fetch('http://localhost:3000/api/get-signed-url', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
fileName: path.basename(filePath),
contentType: 'application/octet-stream',
}),
});
if (!apiResponse.ok) {
throw new Error(`Failed to retrieve signed URL: ${apiResponse.statusText}`);
}
const { signedUrl } = await apiResponse.json();
if (!signedUrl) {
throw new Error('Signed URL is missing in the response');
}
console.log('Signed URL received:', signedUrl);
// Step 2: Upload the file to the signed URL using PUT
const fileStream = fs.createReadStream(filePath);
const uploadResponse = await fetch(signedUrl, {
method: 'PUT',
headers: {
'Content-Type': 'application/octet-stream',
},
body: fileStream,
});
if (!uploadResponse.ok) {
throw new Error(`Failed to upload file: ${uploadResponse.statusText}`);
}
console.log('File uploaded successfully:', uploadResponse.status);
} catch (error) {
console.error('Error uploading file:', error.message);
}
}
// Example usage
const filePath = './example-file.bin'; // Replace with your file path
uploadFile(filePath);

View File

@ -32,6 +32,7 @@ const downloadFilesFromGCS = async (req, res) => {
const archive = archiver('zip', { zlib: { level: 9 } });
archive.on('error', (err) => res.status(500).send({ error: err.message }));
// レスポンスにアーカイブをパイプする
archive.pipe(res);

View File

@ -0,0 +1,65 @@
/**
* @fileoverview Google Cloud Storage (GCS) download module.
*/
const { Storage } = require('@google-cloud/storage');
const { PassThrough } = require('stream');
const { finished } = require('stream/promises');
const archiver = require('archiver');
const KEY_FILE_PATH = './keys/service-account.json'
const storage = new Storage({
keyFilename: KEY_FILE_PATH});
// Load environment variables
require('dotenv').config();
// バケット名を.envから取得する
const BUCKET_NAME = process.env.BUCKET_NAME;
console.log(`BUCKET_NAME: ${BUCKET_NAME}`);
/**
* GCStorageからファイルをダウンロードする
*
* @param {http.IncomingMessage} req
* @param {http.ServerResponse} res
*/
const downloadFilesFromGCSJson = async (req, res) => {
// バケットからファイル一覧を取得する
const [files] = await storage.bucket(BUCKET_NAME).getFiles();
const filesToZip = files.map((file) => file.name);
// レスポンスはJSONでBase64のZIP情報を返す
res.setHeader('Access-Control-Allow-Origin', '*'); // すべてのオリジンを許可
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
res.setHeader('Content-Type', 'application/json');
// Streamを作成する
const archive = archiver('zip', { zlib: { level: 9 } });
const pass = new PassThrough();
const chunks = [];
// チャンク収集
pass.on('data', chunk => chunks.push(chunk));
for (const fileName of filesToZip) {
const file = storage.bucket(BUCKET_NAME).file(fileName);
archive.append(file.createReadStream(), { name: fileName });
}
archive.pipe(pass);
archive.on('error', (err) => res.status(500).send({ error: err.message }));
//
await archive.finalize();
// アーカイブzipなどの入力の完了を宣言して書き込みを開始させる命令です。
await finished(pass);
// Base64エンコードしてJSONで返す
const base64 = Buffer.concat(chunks).toString('base64');
res.end(JSON.stringify({ data: base64 }));
};
module.exports = downloadFilesFromGCSJson;

View File

@ -2,6 +2,7 @@ const http = require('http');
const { downloadContents, generateZipUrl } = require('./download/download');
const downloadFilesFromGCS = require('./download/gcsArchive');
const downloadFilesFromGCSJson = require('./download/gcsArchiveJson');
@ -24,6 +25,9 @@ const server = http.createServer((req, res) => {
} else if (req.url === '/downdload-gcs') {
// GCSからZIPファイルのコンテンツをそのまま返す
downloadFilesFromGCS(req, res);
} else if (req.url === '/downdload-gcs-json') {
// GCSからZIPファイルのコンテンツをそのまま返す
downloadFilesFromGCSJson(req, res);
} else {
res.statusCode = 404;
res.setHeader('Content-Type', 'text/plain');