[TypeScript] コンソール作成

Node.jsでは実行時に渡される引数の情報はprocess.argvにまとめられている
process.argv[0] = nodeコマンドのパス
process.argv[1] = スクリプトファイルのパス
process.argv[2]以降 = コマンド実行時に渡される引数

src/index.ts

console.log("Node path = " + process.argv[0])
console.log("Script file path = " + process.argv[1])

const data: number[] = []
for(var i = 2; i < process.argv.length; i++){
	data.push(Number(process.argv[i]))
}
console.log(data)

for (let item of data){
	const res = primeFactor(item)
	console.log(item + '= ' + res)
}

function primeFactor(a: number): number[] {
	const v: number[ ] = []
	let x = a
	let n = 2
	while(x > n){
	  if(x % n == 0){
	  	x = x / n
	  	v.push(n)
	  } else {
	  	n += n == 2 ? 1 : 2
	  }
	}
	v.push(x)
	return v
}

$ npm run build
$ node dist/main.js 100 1234 9876
Node path = /usr/bin/node
Script file path = /home/vagrant/dev/hands-on/dist/main.js
[ 100, 1234, 9876 ]
100= 2,2,5,5
1234= 2,617
9876= 2,2,3,823

console.log("Node path = " + process.argv[0])
console.log("Script file path = " + process.argv[1])

const data: number[] = []
for(var i = 2; i < process.argv.length; i++){
	data.push(Number(process.argv[i]))
}
console.log('parameters: ' + data)

const f = aggregate()


for (let item of data){
	const res = f(item)
	console.log(res)
}

function aggregate(): (n:number) => [number, number, number, number, number] {
	let total = 0
	let totalp = 0
	let totalt = 0
	return (n:number):[number, number, number, number, number] => {
		total += n
		let tax = Math.floor(n - n / 1.1)
		totalp += n - tax
		totalt += tax
		return [n, tax, total, totalp, totalt]
	}
}

$ node dist/main.js 1200 1870 3058 2765 1875
Node path = /usr/bin/node
Script file path = /home/vagrant/dev/hands-on/dist/main.js
parameters: 1200,1870,3058,2765,1875
[ 1200, 109, 1200, 1091, 109 ]
[ 1870, 170, 3070, 2791, 279 ]
[ 3058, 278, 6128, 5571, 557 ]
[ 2765, 251, 8893, 8085, 808 ]
[ 1875, 170, 10768, 9790, 978 ]

なるほど、ここまでの知識を使って何か作ってみたいですね

[Node.js] AWS Kinesis Video Streamのclipのmp4をDownloadする

### kvs起動
gst-launch-1.0 avfvideosrc device-index=0 ! videoconvert ! video/x-raw,format=I420,width=1280,height=720 ! vtenc_h264_hw allow-frame-reordering=FALSE realtime=TRUE max-keyframe-interval=45 bitrate=512 ! h264parse ! video/x-h264,stream-format=avc,alignment=au,profile=baseline ! kvssink stream-name=MyKinesisVideoStream storage-size=512 access-key=”YourAccessKeyId” secret-key=”YourSecretAccessKey” aws-region=”ap-northeast-1″

### node.js側

const fs = require('fs');
const AWS = require('aws-sdk')

AWS.config.update({accessKeyId: "***",
  secretAccessKey: "***",region: "ap-northeast-1"});

async function main(){

	const streamName = 'MyKinesisVideoStream';
	const kinesisvideo = new AWS.KinesisVideo();

	const param = {
		APIName: "GET_CLIP",
		StreamName: streamName
	};
	const e = await kinesisvideo.getDataEndpoint(param).promise();
	const kinesisvideoarchivedmedia = new AWS.KinesisVideoArchivedMedia({endpoint: e.DataEndpoint});

	startTime = new Date(2021, 10, 13, 23, 40, 30); // UTC時間
	endTime = new Date(2021, 10, 13, 23, 41, 38); // UTC時間

	const params = {
        ClipFragmentSelector: { 
          FragmentSelectorType: "PRODUCER_TIMESTAMP",
          TimestampRange: {
            EndTimestamp: endTime,
            StartTimestamp: startTime 
          }
        },
        StreamName: streamName
    };
    const data = await kinesisvideoarchivedmedia.getClip(params).promise();

	const filePath = "test.mp4"
	fs.writeFileSync(filePath, data.Payload);
}

main()

$ node get-mp4.js
うおおおおおおおおおおおおおおおおおおおお

### トラブルシューティング
ずっとこれが出てたんだが、何かなと思ってたら
$ node get-mp4.js
(node:137900) UnhandledPromiseRejectionWarning: ResourceNotFoundException: No fragments found in the stream for the clip request.

jsでtimestampを作るとき、monthは -1なのね。
new Date(2021, 10, 13, 23, 40, 30); // 2021/11/13 23:40:30

new Date(2021, 11, 13, 23, 40, 30) でやってたから、No fragments foundだった。。あほやわ
よっしゃあああああああああああああああああああ

[Node.js] aws-sdkでs3から複数jsonをdownloadして1つのjsonにまとめる

S3から複数のjsonをdownloadして、一つのjsonにまとめたい。
※後にgraphQLで出力する

objectを配列([])で宣言して、pushする

		var object = [];
		const s3Client = new AWS.S3({
				accessKeyId: 'fuga',
				secretAccessKey: 'hoge',
				region: 'ap-northeast-1'
			})
		
		function getObject(params){
			s3Client.getObject(params, function(err, data){
				if(err){
					console.log(err, err.stack);
				} else {
					object.push(JSON.parse(data.Body.toString()|| "null"));
					console.log(object)
					fs.writeFile('speech.json', JSON.stringify(object), function(err, result){
						if(err) console.log('error', err);
					});
				}
			})
		}

		const params1 = {
			Bucket: 'speech-dnn',
			Key: 'speech.json',
		}

		const params2 = {
			Bucket: 'speech-dnn',
			Key: 'speech2.json',
		}
		
		getObject(params1);
		getObject(params2);

$ node test.js
Server Now Running
$ node test.js
Server Now Running
[ { id: 1, text: ‘ 凄い技術ですね。\n’ } ]
[ { id: 1, text: ‘ 凄い技術ですね。\n’ }, { id: 2, text: ‘ びっくりしました。\n’ } ]

なるほど、これをgraphQLに入れる
※timeを追加
$ node server5.js
Express GraphQL Server Now Running On 192.168.34.10:8000/graphql
[ { id: 1, text: ‘ 凄い技術ですね。\n’, time: ‘2021/12/10 15:04:10’ } ]
[
{ id: 1, text: ‘ 凄い技術ですね。\n’, time: ‘2021/12/10 15:04:10’ },
{ id: 2, text: ‘ びっくりしました。\n’, time: ‘2021/12/10 15:04:12’ }

http://192.168.34.10:8000/graphql

OK、

[ubunut] apache2でサブドメインをnodeのexpressを動かしたい

### ローカル環境
挙動テスト用に簡単にインストールしてコードを書きます。
$ node –version
v14.17.6

$ npm install express

var express = require('express')
var app = express()
app.get('/', function(req, res){
	res.send('hello world')
})

app.listen(3000)

http://192.168.34.10:3000/

### vps
$ curl -sL https://deb.nodesource.com/setup_14.x -o nodesource_setup.sh
$ sudo bash nodesource_setup.sh
$ sudo apt install nodejs
$ node -v
v14.18.1
$ cd /var/www/app
$ sudo npm install express
$ sudo touch app.js
$ sudo vi app.js // 上記と同じ

$ sudo vi /etc/apache2/sites-available/virtual.host.conf

<VirtualHost *:80>
DocumentRoot /var/www/app
ServerName ****-test.site
ServerAlias www.****-test.site
ProxyPass / http://***.**.***.**:3000/
ProxyPassReverse / http://***.**.***.**:3000/
# Other directives here

</VirtualHost>

Invalid command ‘ProxyPass’, perhaps misspe>

$ sudo a2enmod proxy_http
$ sudo systemctl restart apache2

$ node app.js

var express = require('express')
var app = express()
app.get('/', function(req, res){
	res.send('hello node')
})

app.listen(3000)

OK

$ sudo vi /etc/apache2/sites-available/virtual.host.conf

<VirtualHost *:80>
DocumentRoot /var/www/app
ServerName ****-test.site
ServerAlias www.sample-test.site
ProxyPass / http://***.**.**.***:3000
ProxyPassReverse / http://***.**.**.***:3000
# Other directives here

</VirtualHost>

<VirtualHost *:80>
DocumentRoot /var/www/node
ServerName ***.****-test.site
# Other directives here

</VirtualHost>

こうすることで、一つのディレクトリはnodeで動かし、サブドメインの方はapacheで動かすということもできる

OKKKKKKKKKKK
さ、ラズパイやろう

[Node.js] S3からjsonをdownload

$ npm install aws-sdk

s3.js

const express = require('express')
const AWS = require('aws-sdk')
var fs = require('fs')

const app = express()

const s3Client = new AWS.S3({
	accessKeyId: '',
	secretAccessKey: '',
	region: 'ap-northeast-1'
})

const params = {
	Bucket: 'hogehoge',
	Key: 'address.json',
}

s3Client.getObject(params, function(err, data){
	if(err){
		console.log(err, err.stack);
	} else {
		var object = JSON.parse(data.Body.toString());
		fs.writeFile('hoge.json', JSON.stringify(object), function(err, result){
			if(err) console.log('error', err);
		});
	}
})


const jsonObject = JSON.parse(fs.readFileSync('hoge.json', 'utf8'));
console.log(jsonObject);


app.listen(8000, () => console.log('Server Now Running'));

これをgraphQLに応用すると、mysqlから取得した場合も、connection.queryで一時保存し、jsonを読み込んでfilterで処理できますね。ちょっと冗長ではありますが。

  connection.query(
    'SELECT * FROM master_zip',
    (error, results) => {
      var object = JSON.parse(JSON.stringify(results));
      fs.writeFile('address.json', JSON.stringify(object), function(err, result){
        if(err) console.log('error', err);
      });
    }
);

var getAddress = function(args){

	var zip_code = args.zip_code;
  const jsonObject = JSON.parse(fs.readFileSync('address.json', 'utf8'));

  return jsonObject.filter(address => {
      return address.zip_code == zip_code;
  })[0];
}

[Node.js] mysql2パッケージを使う

$ npm install mysql2

接続

var express = require('express');
const mysql = require('mysql2');

const app = express();

const db_setting = {
	host: 'localhost',
	user: 'root',
	password: 'hoge',
	database: 'test'
}
let mycon = null;

(async() => {
	try {
		mycon = await mysql.createConnection(db_setting);
		mycon.connect(function(err){
			if(err){
				console.log(err);
			} else {
				console.log("success");
			}
		});
	} catch(e){
		console.log(e);
	}
	if(mycon){
		mycon.end();
	}
})();

app.listen(8000);

うーむ、asyncの外で使いたいんだよなあ

[Node.js] mysqlと連携

1. mysqlパッケージをインストール
$ npm install mysql

var express = require('express');
var mysql = require('mysql');

const app = express();

const connection = mysql.createConnection({
	host: 'localhost',
	user: 'root',
	password: 'hoge',
	database: 'test'
});

connection.connect((err) => {
	if(err){
		console.log('error connecting:' + err.stack);
		return;
	}
	console.log('success');
});

app.get('/', (req, res) => {
	connection.query(
		'SELECT * FROM master_zip',
		(error, results) => {
			console.log(results);
		}
	);
});

app.listen(8000);

$ node app.js
success
[
RowDataPacket {
zip_code: ‘1690075’,
pref_name: ‘東京都’,
city_name: ‘新宿区’,
town_name: ”,
area_name: ‘高田馬場’
},
// 省略
]

mysql.createConnectionで接続して、connection.queryでqueryを実行するのね
基本はわかりました。

ただ、これをconnection.queryの外に変数を出そうとするとできない。

var getAddress = function(args){

	var zip_code = args.zip_code;

	const connection = mysql.createConnection({
		host: 'localhost',
		user: 'root',
		password: 'password',
		database: 'test'
	});
	// conection.queryは非同期関数なので外に出せない
	connection.query(
		'SELECT * FROM master_zip',
		(error, results) => {
			var db_results = JSON.parse(JSON.stringify(results));
			}
	);
	return db_results.filter(address => {
 			return address.zip_code == zip_code;
	})[0];
}

なかなか複雑…

Node.jsでGraphQLを動かす

$ npm init
$ npm install graphql express express-graphql -save

server.js

var express = require('express');
var express_graphql = require('express-graphql').graphqlHTTP;
var { buildSchema } = require('graphql');

var schema = buildSchema(`
	type Query {
		message: String
	}
`);

var root = {
	message: () => 'Hello World!'
};

var app = express();
app.use('/graphql', express_graphql({
 schema: schema,
 rootValue: root,
 graphiql: true
}));
app.listen(8000, () => console.log('Express GraphQL Server Now Running On 192.168.34.10:8000/graphql'))

{
	message
}
{
  "data": {
    "message": "Hello World!"
  }
}

$ curl -XPOST -H “Content-Type:application/json” ‘http://192.168.34.10:8000/graphql’ -d ‘{“query”: “query { message }”}’
{“data”:{“message”:”Hello World!”}}
L jsonでクエリをリクエストすると返ってくる

### パラメータを受け取る

var express = require('express');
var express_graphql = require('express-graphql').graphqlHTTP;
var { buildSchema } = require('graphql');

var schema = buildSchema(`
	type Query {
		course(id: Int!): Course
		courses(topic: String):[Course]
	},
	type Course {
		id: Int
		title: String
		author: String
		description: String
		topic: String
		url: String
	}
`);
var coursesData = [
{
	id: 1,
	title: '初めてのGraphQL ―Webサービスを作って学ぶ新世代API',
	author: 'Eve Porcello',
	description: '本書で紹介するGraphQLは2015年にFacebookによって公開されたRESTとは異なるアプローチのアーキテクチャです。',
	topic: 'GraphQL',
	url: 'https://www.amazon.co.jp/%E5%88%9D%E3%82%81%E3%81%A6%E3%81%AEGraphQL-%E2%80%95Web%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9%E3%82%92%E4%BD%9C%E3%81%A3%E3%81%A6%E5%AD%A6%E3%81%B6%E6%96%B0%E4%B8%96%E4%BB%A3API-Eve-Porcello/dp/487311893X/ref=sr_1_1?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&dchild=1&keywords=graphql&qid=1633041782&sr=8-1'
},
{
	id: 2,
	title: '基礎からはじめるGraphQL',
	author: '志村翔太',
	description: '本書ではGraohQLの基礎文法や概念を学び、実際にGraohQLを利用したアプリケーションの完成を目指していきます。',
	topic: 'GraphQL',
	url: 'https://www.amazon.co.jp/%E5%9F%BA%E7%A4%8E%E3%81%8B%E3%82%89%E3%81%AF%E3%81%98%E3%82%81%E3%82%8BGraphQL-%E5%BF%97%E6%9D%91%E7%BF%94%E5%A4%AA-ebook/dp/B08PC8H5HF/ref=sr_1_2?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&dchild=1&keywords=graphql&qid=1633071074&sr=8-2'
},
{
	id: 3,
	title: 'Node.js超入門 第3版',
	author: '掌田津耶乃',
	description: 'Node.jsの入門者向け書籍です。2018/8に出た「Node.js超入門 第2版」の改訂版です。改訂内容は新バージョン14対応、データベースはSQLite3、ORMはSequelizeに変更しています。CSS関連はBootstrap利用、Expressは最初からGeneratorを使う形で解説しています。',
	topic: 'NodeJS',
	url: 'https://www.amazon.co.jp/Node-js%E8%B6%85%E5%85%A5%E9%96%80-%E7%AC%AC3%E7%89%88-%E6%8E%8C%E7%94%B0%E6%B4%A5%E8%80%B6%E4%B9%83/dp/479806243X/ref=sr_1_1_sspa?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&dchild=1&keywords=nodejs&qid=1633071225&sr=8-1-spons&psc=1&spLa=ZW5jcnlwdGVkUXVhbGlmaWVyPUEyNEMxVzdLVUtWOU1ZJmVuY3J5cHRlZElkPUEwNjIwNjAzMkhaN1dYSzZVSEw2NiZlbmNyeXB0ZWRBZElkPUExSkVDRkoyVzMwTlBBJndpZGdldE5hbWU9c3BfYXRmJmFjdGlvbj1jbGlja1JlZGlyZWN0JmRvTm90TG9nQ2xpY2s9dHJ1ZQ=='
}
]
var getCourse = function(args){
	var id = args.id;
	return coursesData.filter(course => {
		return course.id == id;
	})[0];
}
var getCourses = function(args){
	if(args.topic){
		var topic = args.topic;
		return coursesData.filter(course = course.topic === topic);
	} else {
		return coursesData;
	}
}
var root = {
	course: getCourse,
	courses: getCourses
};

var app = express();
app.use('/graphql', express_graphql({
 schema: schema,
 rootValue: root,
 graphiql: true
}));
app.listen(8000, () => console.log('Express GraphQL Server Now Running On 192.168.34.10:8000/graphql'))
query getSingleCourse($courseID: Int!) {
 course(id: $courseID) {
  title
  author
  description
  topic
  url
 }
}

{ 
 "topic":"Node.js"
}

$ curl -XPOST -H “Content-Type:application/json” ‘http://192.168.34.10:8000/graphql’ -d ‘{“query”: “query getSingleCourse($courseID:Int!){course(id:$courseID){title author description topic url}}”, “variables”: {“courseID”:1}}’
{“data”:{“course”:{“title”:”初めてのGraphQL ―Webサービスを作って学ぶ新世代API”,”author”:”Eve Porcello”,”description”:”本書で紹介するGraphQLは2015年にFacebookによって公開されたRESTとは異なるアプローチのアーキテクチャです。”,”topic”:”GraphQL”,”url”:”https://www.amazon.co.jp/%E5%88%9D%E3%82%81%E3%81%A6%E3%81%AEGraphQL-%E2%80%95Web%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9%E3%82%92%E4%BD%9C%E3%81%A3%E3%81%A6%E5%AD%A6%E3%81%B6%E6%96%B0%E4%B8%96%E4%BB%A3API-Eve-Porcello/dp/487311893X/ref=sr_1_1?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&dchild=1&keywords=graphql&qid=1633041782&sr=8-1″}}}

query getCourses($topic: String!) {
 courses(topic: $topic) {
  title
  url
 }
}

{
  "topic": "GraphQL"
}

{
“errors”: [
{
“message”: “course is not defined”,
“locations”: [
{
“line”: 2,
“column”: 2
}
],
“path”: [
“courses”
]
}
],
“data”: {
“courses”: null
}
}

なんやろう、ようわからんね

[pickr] color pickerを実装したい

RGBを入力するのは、RGBを調べるという手間が入るので、color pickerを実装したい。
pickrというライブラリがある様なので、それを使う。

$ npm install @simonwep/pickr

githubそのままですが、

<!DOCTYPE html>
<html lang="en">
<head>
	<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
	<meta charset="UTF-8">
	<title>Document</title>
	<link href="/node_modules/@simonwep/pickr/dist/themes/classic.min.css" rel="stylesheet">
	<link href="/node_modules/@simonwep/pickr/dist/themes/monolith.min.css" rel="stylesheet">
	<link href="/node_modules/@simonwep/pickr/dist/themes/nano.min.css" rel="stylesheet">

	<script src="/node_modules/@simonwep/pickr/dist/pickr.min.js"></script>
	<script src="/node_modules/@simonwep/pickr/dist/pickr.es5.min.js"></script>
</head>
<body>
	<div class="color-picker"></div>
	<script>
		const pickr = Pickr.create({
		    el: '.color-picker',
		    theme: 'classic', 

		    swatches: [
		        'rgba(244, 67, 54, 1)',
		        'rgba(233, 30, 99, 0.95)',
		        'rgba(156, 39, 176, 0.9)',
		        'rgba(103, 58, 183, 0.85)',
		        'rgba(63, 81, 181, 0.8)',
		        'rgba(33, 150, 243, 0.75)',
		        'rgba(3, 169, 244, 0.7)',
		        'rgba(0, 188, 212, 0.7)',
		        'rgba(0, 150, 136, 0.75)',
		        'rgba(76, 175, 80, 0.8)',
		        'rgba(139, 195, 74, 0.85)',
		        'rgba(205, 220, 57, 0.9)',
		        'rgba(255, 235, 59, 0.95)',
		        'rgba(255, 193, 7, 1)'
		    ],

		    components: {

		        // Main components
		        preview: true,
		        opacity: true,
		        hue: true,

		        // Input / output Options
		        interaction: {
		            hex: true,
		            rgba: true,
		            hsla: true,
		            hsva: true,
		            cmyk: true,
		            input: true,
		            clear: true,
		            save: true
		        }
		    }
		});
	</script>
</body>
</html>

これは凄い。使いたいな。