- 投稿日:2020-04-07T21:54:43+09:00
【Node.js】複数のファイルパスをオブジェクトでの階層表現に変換する
経緯
Node.jsのfsを使って特定のディレクトリの中身をファイルパスにて取得した際に、ディレクトリの階層と互換性のあるオブジェクトに変換したかった。
結論
index.jsconst data = [ '/public/aaa/1.file', '/public/aaa/2.file', '/public/bbb/1.file', '/public/ccc/1.file', '/public/ccc/2.file', '/public/ccc/3.file', '/public/ddd/1.file' ]; const output = {}; let current; for (const path of data) { current = output; for (const segment of path.split('/')) { if (segment !== '') { if (!(segment in current)) { current[segment] = {}; } current = current[segment]; } } } console.log(output); /* 実行結果 { public: { aaa: { '1.file': {}, '2.file': {} }, bbb: { '1.file': {} }, ccc: { '1.file': {}, '2.file': {}, '3.file': {} }, ddd: { '1.file': {} } } } */あとは取得した結果から
子要素に値が入っていたらディレクトリ
子要素に値が入っていなかったらファイルと認識して分岐させれば色々使えると思う。
- 投稿日:2020-04-07T18:53:52+09:00
dotenvで環境変数ではなく .env 使う | Node.js
- 投稿日:2020-04-07T17:19:43+09:00
Node.js: child_process.fork()で起動したプロセスを子子孫孫殺す方法
本稿では、Node.jsにて、子プロセス、そこから派生した孫プロセス、さらにそこから派生したひ孫プロセス……を、一括して終了する方法を説明します。
※説明にあたって、実行環境はUNIX/Linuxを前提にしています。
子プロセスを殺しても、孫プロセスは死なない
Node.jsのchild_process.fork()は、子プロセスを起動できて便利です。子プロセスの中で、
fork()
を使って、孫プロセスを起動することもでき、さらに、孫プロセスでfork()
して、ひ孫プロセスを、といった具合に子プロセスはネストして起動することができます。起動した子プロセスはsubprocess.kill()で終了することができます。しかし、これは直接の子プロセスしか殺すことができません。どういうことかというと、
- oya.js が ko.js のプロセスを起動する。
- ko.js が mago.js のプロセスを起動する。
- このとき、 oya.js が ko.js のプロセスを
kill()
したとする。- ko.js は終了する。
- mago.js は生存する。 (※このとき、 mago.js はinitプロセスの養子に出され、親pidは1になる)
といった事態が発生します。
孫プロセスが残存するサンプルコード
上のようなシナリオを再現できるコードを書いてみたいと思います。
まず、oya.jsの実装:
oya.jsconsole.log('oya.js: running') // SIGINTを受け付けたとき process.on('SIGINT', () => { console.log('oya.js: SIGINT') process.exit() }) // プロセスが終了するとき process.on('exit', () => { console.log('oya.js: exit') }) // 子プロセスを起動 const ko = require('child_process') .fork(__dirname + '/ko.js') // 3秒後にproc2.jsを終了する setTimeout(() => { console.log('oya.js: ko.jsを終了させてます...') ko.kill('SIGINT') }, 3000) // ko.jsが終了したとき ko.on('exit', () => { console.log('> Ctrl-Cを押してください...') }) // このプロセスがずっと起動し続けるためのおまじない setInterval(() => null, 10000)oya.jsはko.jsを起動し、3秒後にko.jsを終了するコードになっています。ko.jsを
kill()
する際には、SIGINT
シグナルを送るようにしています。Linuxのシグナルについては、ここでは詳しく説明しません。ここでは単にSIGINT
シグナルはプロセス終了を指示するものと考えてください。次に、ko.js:
ko.jsconsole.log('ko.js: running') // SIGINTを受け付けたとき process.on('SIGINT', () => { console.log('ko.js: SIGINT') process.exit() }) // プロセスが終了するとき process.on('exit', () => { console.log('ko.js: exit') }) // 孫プロセスを起動する require('child_process') .fork(__dirname + '/mago.js') // このプロセスがずっと起動し続けるためのおまじない setInterval(() => null, 10000)最後に、mago.js:
mago.jsconsole.log('mago.js: running') // SIGINTを受け付けたとき process.on('SIGINT', () => { console.log('mago.js: SIGINT') process.exit() }) // プロセスが終了するとき process.on('exit', () => { console.log('mago.js: exit') }) // このプロセスがずっと起動し続けるためのおまじない setInterval(() => null, 10000)このコードを実行してみます:
$ node oya.js oya.js: running ko.js: running mago.js: running oya.js: ko.jsを終了させてます... ko.js: SIGINT ko.js: exit > Ctrl-Cを押してください...3秒後にこのような出力がされ、oya.jsがko.jsを
kill()
し、ko.jsが終了したことが確認できます。一方、mago.jsはまだ
SIGINT
を受け取っていませんし、終了もしておらず、残存しています。ここで、Ctrl-Cを押すと、oya.jsとmago.jsに
SIGINT
が送信されます:... > Ctrl-Cを押してください... ^Coya.js: SIGINT mago.js: SIGINT mago.js: exit oya.js: exitこのタイミングではじめて、mago.jsが終了することが分かります。
感想を言うと、ko.jsに
SIGINT
を送信したら、mago.jsにもSIGINT
が伝搬されていくものと誤解していたので、この結果は意外でした。起動したプロセスを子子孫孫殺す方法
では、起動した子プロセスを
kill()
したタイミングで、孫プロセスも終了になるようにするにはどうしたらいいのでしょうか? それについて、ここで説明したいと思います。プロセスグループ = 「世帯」
まず、Linuxのプロセスの基本として、プロセスグループというものがあります。これはプロセスの「世帯」のような概念で、親プロセス、子プロセス、孫プロセスをグループ化するものです。たとえば、Bashでnodeプロセスであるoya.jsを起動すると、そこから
fork()
したko.jsやmago.jsは、同じプロセスグループに属し、同一のグループIDが与えられます。
ps
コマンドでグループID(GPID)を確認すると、現に同じグループIDが3つのnodeプロセスに割り当てられていることが分かります:$ ps -xo pid,ppid,pgid,command | grep node | grep .js PID PPID GPID COMMAND 17553 3528 17553 node oya.js 17554 17553 17553 node ko.js 17555 17554 17553 node mago.jsこの結果をよく見ると分かりますが、GPIDはoya.jsのプロセスID(PID)と同じです。つまり、親のPIDが子孫のGPIDになるわけです。
プロセスを「世帯」ごと殺す方法
Node.jsでは、グループIDを指定して、プロセスを終了させることができます。やりかたは、process.kill()にGPIDを渡すだけです。このとき、与える値は負の数にしてあげます。正の数を渡してしまうと、プロセスグループではなく個別のプロセスを
kill()
するだけになるので注意です。const groupId = 123456 process.kill(-groupId, 'SIGINT')ちなみに、シェルでCtrl-Cを押したときに、親・子・孫がもろとも終了されるのは、Ctrl-Cが送る
SIGINT
が親プロセスに対してではなく、プロセスグループに対して送られているからです。(要出典)detached = 別世帯を作る
今回やりたいことは、oya.jsのプロセスは生かしつつ、ko.jsとmago.jsを
kill()
したいことです。しかし、GPIDを指定したkill()
では、oya.jsまで終了してしまいます。三者とも同じGPIDだからです:PID PPID GPID COMMAND 17553 3528 17553 node oya.js 17554 17553 17553 node ko.js 17555 17554 17553 node mago.jsko.jsとmago.jsを別のGPIDを割り振る必要があります。それをするには、
fork()
のオプションにdetached
を指定します。oya.js// 子プロセスを起動 const ko = require('child_process') .fork(__dirname + '/ko.js', [], {detached: true})これを指定すると、ko.jsとmago.jsがいわば「別世帯」になり、別のプロセスグループに属するようになります。GPIDもoya.jsとは別のものが割り当てられているのが確認できます:
$ ps -xo pid,ppid,pgid,command | grep node | grep .js PID PPID GPID COMMAND 21404 3528 21404 node oya.js 21405 21404 21405 node ko.js 21406 21405 21405 node mago.jsプロセスを子子孫孫殺すoya.jsの完成形
以上を踏まえて、oya.jsを子プロセス、孫プロセスを一括して終了できるように変更すると次のようになります:
oya.jsconsole.log('oya.js: running') // SIGINTを受け付けたとき process.on('SIGINT', () => { console.log('oya.js: SIGINT') process.exit() }) // プロセスが終了するとき process.on('exit', () => { console.log('oya.js: exit') }) // 子プロセスを起動 const ko = require('child_process') .fork(__dirname + '/ko.js', [], {detached: true}) // 重要な変更箇所! // 3秒後にko.jsを終了する setTimeout(() => { console.log('oya.js: ko.jsを終了させてます...') process.kill(-ko.pid, 'SIGINT') // 重要な変更箇所! }, 30000) // ko.jsが終了したとき ko.on('exit', () => { console.log('> Ctrl-Cを押してください...') }) // このプロセスがずっと起動し続けるためのおまじない setInterval(() => null, 10000)最後に、このoya.jsを実行して、ko.jsとmago.jsが一緒に終了しているか確認してみましょう:
$ node oya.js oya.js: running ko.js: running mago.js: running oya.js: ko.jsを終了させてます... mago.js: SIGINT ko.js: SIGINT mago.js: exit ko.js: exit > Ctrl-Cを押してください... ^Coya.js: SIGINT oya.js: exit期待通り、ko.jsとmago.jsは同じタイミングで
SIGINT
を受け取り終了しています。oya.jsはCtrl-Cを押すまで生存していることも分かります。以上、Node.jsの
child_process.fork()
で起動したプロセスを子子孫孫殺す方法についての説明でした。
- 投稿日:2020-04-07T13:54:13+09:00
【ReactNative+Typescript】ローカルDBでRealmを使う
概要
ReactNative
とTypescript
のプロジェクトにローカルDBとしてRealm
をインストール・使用する際のメモ。
環境は以下の通り。
- node @10.15.0
- react-native @0.61.5
- typescript @3.5.3
インストール
node
のバージョンが10.X
系にする必要がある。install --save realm※
react-native
のバージョンが0.59
以下の場合は要link
iOSの場合
要
CocoaPods
cd ios pod install実装
import Realm from 'realm' // スキーマ名 const HOGE_SCHEMA_NAME : string = 'HOGE'; // スキーマ定義 const HOGE_SCHEMA : Realm.ObjectSchema = { // スキーマ名 name : HOGE_SCHEMA_NAME , // 主キー(省略可) primaryKey : 'prop1', // プロパティ properties: { // 型のみ指定 prop1 : 'int', // 型と初期値を指定 prop2 : { type : 'string', default : 'hoge' }, } } // データIF interface Hoge { prop1 : number, prop2 : string, } // DB操作開始 Realm.open({ schema : [HOGE_SCHEMA] }).then((realm : Realm) => { // write()でトランザクションを開始する realm.write(() => { // primaryKeyを指定しているならcreate()はupsertとして働かせることもできる(その場合は第3引数にtrue)を渡す realm.create(HOGE_SCHEMA_NAME , { prop1: 0, prop2 : 'test' }); // 削除はdelete()もしくはdeleteAll() }); // objects(schemaName : string)でデータを取得 const datas : Realm.Results<Hoge> = realm.objects(HOGE_SCHEMA_NAME); });参考
- 投稿日:2020-04-07T10:39:49+09:00
Node.jsを使用したAWS S3への画像アップロード
まずは、ここからs3へのアクセスキーと、シークレットきーを取得してください。
S3 Bucketを作る
$ npm i --save aws-sdkcreate-bucket.jsconst AWS = require('aws-sdk'); // Enter copied or downloaded access ID and secret key here const ID = ''; const SECRET = ''; // The name of the bucket that you have created const BUCKET_NAME = 'test-bucket'; //同じバケット名は作れない ユニーク必須 const s3 = new AWS.S3({ accessKeyId: ID, secretAccessKey: SECRET }); const params = { Bucket: BUCKET_NAME, CreateBucketConfiguration: { // アジアパシフィック (東京) LocationConstraint: "ap-northeast-1" } }; s3.createBucket(params, function(err, data) { if (err) console.log(err, err.stack); else console.log('Bucket Created Successfully', data.Location); });こんな感じ。で、実行
$ node create-bucket.jsS3で画像をアップする
uplode-bucket.jsconst fs = require('fs'); const AWS = require('aws-sdk'); // Enter copied or downloaded access ID and secret key here const ID = ''; const SECRET = ''; const s3 = new AWS.S3({ accessKeyId: ID, secretAccessKey: SECRET }); const uploadFile = (fileName) => { // Read content from the file const fileContent = fs.readFileSync(fileName); // Setting up S3 upload parameters const params = { Bucket: "test-bucket", Key: 'uniquename.jpg', // s3へ保存される名前 ユニーク必須 Body: fileContent }; // Uploading files to the bucket s3.upload(params, function(err, data) { if (err) { throw err; } console.log(`File uploaded successfully. ${data.Location}`); }); }; uploadFile('/Users/user-name/Desktop/test.png'); //ここにファイルの実体を入れるこんな感じ。で、実行
$ node uplode-bucket.js参考
https://stackabuse.com/uploading-files-to-aws-s3-with-node-js/
- 投稿日:2020-04-07T10:39:49+09:00
『コピペOK』NodeでS3へ画像アップロード【2020】
まずは、ここからs3へのアクセスキーと、シークレットきーを取得してください。
S3 Bucketを作る
$ npm i --save aws-sdkcreate-bucket.jsconst AWS = require('aws-sdk'); // Enter copied or downloaded access ID and secret key here const ID = ''; const SECRET = ''; // The name of the bucket that you have created const BUCKET_NAME = 'test-bucket'; //同じバケット名は作れない ユニーク必須 const s3 = new AWS.S3({ accessKeyId: ID, secretAccessKey: SECRET }); const params = { Bucket: BUCKET_NAME, CreateBucketConfiguration: { // アジアパシフィック (東京) LocationConstraint: "ap-northeast-1" } }; s3.createBucket(params, function(err, data) { if (err) console.log(err, err.stack); else console.log('Bucket Created Successfully', data.Location); });こんな感じ。で、実行
$ node create-bucket.jsS3で画像をアップする
uplode-bucket.jsconst fs = require('fs'); const AWS = require('aws-sdk'); // Enter copied or downloaded access ID and secret key here const ID = ''; const SECRET = ''; const s3 = new AWS.S3({ accessKeyId: ID, secretAccessKey: SECRET }); const uploadFile = (fileName) => { // Read content from the file const fileContent = fs.readFileSync(fileName); // Setting up S3 upload parameters const params = { Bucket: "test-bucket", Key: 'uniquename.jpg', // s3へ保存される名前 ユニーク必須 Body: fileContent }; // Uploading files to the bucket s3.upload(params, function(err, data) { if (err) { throw err; } console.log(`File uploaded successfully. ${data.Location}`); }); }; uploadFile('/Users/user-name/Desktop/test.png'); //ここにファイルの実体を入れるこんな感じ。で、実行
$ node uplode-bucket.js参考
https://stackabuse.com/uploading-files-to-aws-s3-with-node-js/
- 投稿日:2020-04-07T09:51:30+09:00
IoT Agency PlatformをHeroku上にデプロイする
Sigfoxが提供していたIoT Agency PlatformがGNU Affero General Public Licenseに基づくオープンソースとなりました。ここでは、IoT Agency PlatformをHeroku上にデプロイする方法を説明します。
IoT Agency Platformは、SigfoxやMQTT、Webhookに対応したIoTデバイスからデータを取得し、グラフや地図形式でダッシュボード化できるアプリケーションです。使い方に関しては、こちらを参考にしてください。
全体の流れ
Sigfox IoT Agency PlatformをHeroku上にデプロイする方法は下記の通りの流れとなります。
1. sigfox platformのGithubからHerokuにアプリケーションをデプロイする
2. MongoDBを立ち上げ、データベースを紐づけるsigfox platformのGitHubからHerokuにアプリケーションをデプロイする
デプロイ方法は2種類あります。下記ボタンをクリックして、UIウィザードに従いデプロイする方法と
Heroku CLIで下記のようにデプロイする方法です。git clone https://github.com/IoT-Makers/sigfox-platform.git my-project cd my-project heroku apps:create my-project git push heroku masterここでは、前者の方法で説明します。
新しいアプリケーションを生成する
先程の"Deploy to Heroku"ボタンをクリックしApp nameとregionを選択します。App nameはユニークな名前になるように設定してください。
設定後、Deploy appボタンをクリックすると、デプロイが開始します。数分かかりますが、完成すると下記のような画面になります。
Manage Appボタンをクリックし、アプリケーションの管理画面に遷移します。MongoDBを立ち上げ、データベースを紐づける
ここでは、MongoDBのアドオンをアプリケーションにアタッチします。mLabはMongoDBをDBaaS(Database-as-a-Service)として提供するものです。
mLabはmongoDB.Altasに統合されたため、mongoDB.Altasでも同じようなことができると思いますが、ここでは、mLabで進めます。
mLab MongoDBアドオンの追加
Heroku管理画面のResourcesタグ内にあるQuickly add add-ons from Elements検索フィールドで"MongoDB"をキーに検索するとmLab MongoDBというアドオンが表示されます。
mLab MongoDBを選択すると、下図の画面になりますので、有償版でも結構ですが、まずの動作確認としては、無償版(Sandbox - Free)を選択し、Provisionボタンをクリックしてください。
mLab MongoDBとの接続
追加された"mLab MongoDB"をクリックします。
mLabの管理画面が表示されます。
画面上に、MongoDB URIで接続する(To connect using a driver via the standard MongoDB URI)と書かれた下にmongodB://からはじまるURIが表示されています。このURIをHeroku側に設定してあげればOKです。
HerokuのSettingタグに遷移し、Config Vars(環境変数設定)をします。
新たに、MONGODB_URIをキーとし、先程のURI(下記)を貼り付けます。ただし、dbuserとdbpassword、dbnameのところは、データベースの接続アカウントに置き換える必要があります。(MONGOLAB_CYAN_URIの値をコピー&ペーストしても良いかも)
mongodb://<dbuser>:<dbpassword>@ds253348.mlab.com:53348/<dbname>
アプリケーションの再起動
Herokuの"More"のところにある**Restart all dynos"を選択し、アプリケーションを再起動します。
再起動は1,2分内で終わると思いますので、再起動後、"Open app"をクリックし、アプリケーションを表示します。
下図のようなログイン及びサインアップ画面が表示されれば成功です。
なお、ソースコードは、
[リポジトリ名]\frontend\src
の中にあります。補足
ちなみに、下記のフレームワークを使っているようです。
- Backend: Loopback 3+
- Frontend: Angular 6+
- Real-time: Primus
- Database: MongoDB
- Pub-sub & queuing: RabbitMQ
なお、本投稿に当たっては、Antoine de Chassey、Louis Moreauそして、Guillaume Noelに感謝します。
- 投稿日:2020-04-07T09:23:15+09:00
npmパッケージのvulnerability対応フロー
概要
(GitHub等が親切に"We found potential security vulnerabilities in your dependencies."のように通知してくれるので便利)
対応フロー
ざっくり全体像は以下のとおり。
①最新のコードを取得する
いうまでもないが、手元のコードは最新のコードにしておく
git pull最新であることが確認された
Already up to date.ちなみに、今回は自作プロジェクト(https://github.com/riversun/simple-date-format) で実際にハンズオンした
②プロジェクトが使用しているnpmパッケージが最新かどうか確認する
脆弱性対応の前に、いま自分のプロジェクトが使っているnpmパッケージを最新のものにする。
プロジェクトが使っているnpmパッケージが最新かどうかは
npm outdated
コマンドで確認することができ、最新バージョンがある場合は、その情報を表示してくれるnpm outdatedするとこのように、最新版が存在するパッケージを一覧表示してくれる
いくつかのパッケージで最新版があるようだパッケージをアップデートする
package.jsonに記載されるnpmパッケージ一覧は以下のようになっている。
(「^」がついたキャレット表記についてはこちらで説明)package.json抜粋"@babel/core": "^7.8.4", "@babel/preset-env": "^7.8.4", "babel-jest": "^25.1.0", ...パッケージのバージョンの付け方セマンティックバージョニングに従っている。
セマンティックバージョニングにおいて、メジャーバージョン、マイナーバージョンは以下の意味をもっている。
これをふまえ、「パッケージを最新にする」には2種類の方法があるといえる。(パッチバージョンを上げるというのもいれれば3種類だが本筋にあまり影響ないので割愛)
- ②-1 マイナーバージョンまで最新にする
- ②-2 メジャーバージョンまで最新にする
②-1をとるか ②-2をとるかはポリシー次第だがメジャーバージョンを最新にする場合はAPIの後方互換が無いことを想定しておいたほうがいい。
②-1 マイナーバージョンまで最新にする場合
キャレット表記「^」つきで定義されたパッケージのバージョンを、マイナーバージョンまでを最新にするにはnpm updateコマンドで可能
npm update以下のように、マイナーバージョンまでが最新になった
(ただし、メジャーバージョンは最新になっていない。)+ jest@25.2.7 + babel-loader@8.1.0 + cross-env@7.0.2 + @babel/core@7.9.0 + babel-jest@25.2.6 + @babel/preset-env@7.9.0 + webpack@4.42.1 added 36 packages from 17 contributors, removed 6 packages, updated 140 packages, moved 1 package and audited 263490 packages in 18.399s
②-2 メジャーバージョンまで最新にする場合
npm update
では、マイナーバージョンまでしかアップデートしてくれなかったが、ここではメジャーバージョンまで容赦なくアップデートしてくれるパッケージnpm-check-updatesを導入する以下のようにしてnpm-check-updatesをインストールする
npm install -g npm-check-updatesnpm-check-updatesをインストールすると
ncu
というコマンドが使えるようになる。ちなみに、ncuコマンドだけをたたくと現在のパッケージバージョンと最新のパッケージバージョンを表示してくれるnpm outdatedコマンドのような動作をする
ncuを実行すると、以下のように現在のバージョンと最新バージョンが表示される。
つづいて、ncu -uを実行すれば、上でみたとおりパッケージが最新バージョンになるようにpackage.jsonを書き換えてくれる
ncu -unpm updateと違ってパッケージのインストールそのものはやってくれない。package.jsonが書き換わるだけなので、自分で npm install する必要がある
npm installこれでパッケージは最新になった
③npm auditで脆弱性のある依存パッケージを確認する
今、最新のパッケージにした状態だが、この状態でも脆弱性(valnerability)のあるパッケージが含まれていることがある。
npm auditコマンドを使えば脆弱性のあるパッケージを洗い出すことができる。npm auditをやってみたら、180個の脆弱性がみつかった。レベルはlow。
found 180 low severity vulnerabilities in 263397 scanned packages run `npm audit fix` to fix 174 of them. 6 vulnerabilities require manual review. See the full report for details.④npm audit fixで自動修復をこころみる
npm audit fixをすると、脆弱性のあるパッケージのバージョンを自動的に脆弱性の無いバージョンに置き換えてくれる(努力をしてくれる)
npm audit fixすると以下のようになった。
180個の脆弱性のうち174個が修正された。removed 1 package and updated 2 packages in 4.641s 31 packages are looking for funding run `npm fund` for details fixed 174 of 180 vulnerabilities in 263397 scanned packages 6 vulnerabilities required manual review and could not be updated残り6個はマニュアルレビューしてくれとかいてある。
⑤npm dedupeで重複したパッケージの整理統合をこころみる
npm dedupeを理解する
まず、dedupeの概念を理解するために以下の状態を考える
- 自プロジェクトがnpmパッケージAとnpmパッケージBに依存している
- npmパッケージAはnpmパッケージC @2.1.1に依存している。
- npmパッケージBはnpmパッケージC @2.2.0に依存している。
この場合、npmを使っていると1npmパッケージC @2.1.1もnpmパッケージC @2.2.0もインストールされる。
パッケージとしてはnpmパッケージCで同じなのに、npmパッケージC @2.1.1とnpmパッケージC @2.2.0でバージョンが違いがあるので両方保持されしまう。
だったら、バージョンを新しいほうの@2.2.0のほうに合わせて、npmパッケージC @2.2.0のほうを、npmパッケージAとnpmパッケージBで共通化して使いましょう、というのがdedupeの発想。
npm dedupeは新しいバージョンをインストールしてくれない
npm update等でdedupeはひととおりのパッケージを最新にした後にやる。
なぜなら、dedupe自身はパッケージの重複排除などはやってくれるが、最新のパッケージを入れてくれるわけではないので古いパッケージバージョンで状態でdedupeしてもあまり意味がない。dedupeする
さて、ではnpm dedupe (npm ddpでもOK)してみる
removed 10 packages and audited 263298 packages in 3.622s found 0 vulnerabilities脆弱性が0になった!
なぜdedupeで脆弱性がゼロになった?
これは、dedupeが脆弱性を排除しているというより、古いパッケージバージョンに依存していたライブラリが新しいパッケージバージョンを参照するようにdedupeが変更してくれた効果のため。
上の例でいうと以下のようになる。
- 自プロジェクトがnpmパッケージAとnpmパッケージBに依存している
- npmパッケージAはnpmパッケージC @2.1.1(脆弱性ありバージョン)に依存している。
- npmパッケージBはnpmパッケージC @2.2.0(安全バージョン)に依存している。
の状況をdedupeが↓のように変更してくれた効果
- 自プロジェクトがnpmパッケージAとnpmパッケージBに依存している
- npmパッケージAはnpmパッケージC @2.2.0(安全バージョン)に依存している。
- npmパッケージBはnpmパッケージC @2.2.0(安全バージョン)に依存している。
⑦回帰テストを実行する
さてここまでで、脆弱性の無い状態にできたら、最後にテストをしてパッケージバージョンを変更したことによるプロジェクトのデグレが発生していないかどうかを確認する。
npm testテスト無事通過!
(といっても、今回はdevDependenciesの依存のみだったけど)
これで対応完了!
途中でつまずいた場合
上述のコマンドだけでうまくいかず、つまずくことも多々ある。そうした場合は、コマンドだけで楽に突破できない状況になっている可能性があるので、それなりの調査分析工数を覚悟するしかない。
つまずき例
vulnerabilityが無くならなかった
- 対応案:
npm audit
でvulnerabilityのあるパッケージに依存している上位のパッケージを特定する。そのパッケージがdeprecateになっていないか。ちゃんとメンテされているか確認する。deprecatedだったりメンテされていなければ使うのをやめたりPR送ってみたり、自分で直してみたり、代替パッケージを探したり。そういった工数を覚悟、確保する。最後のテストでつまづいた
- 対応案:手順を1手ずつロールバック(手順を戻す)しながら、都度
npm test
を実行し、どの段階でつまづいたのか特定する。ありがちなのは②-1メジャーアップデートでAPIに破壊的変更まとめ
こういった関連サービスもあります
yarnは自動的にdedupeしてくれる(https://classic.yarnpkg.com/ja/docs/cli/dedupe/) ↩
- 投稿日:2020-04-07T03:30:58+09:00
obnizとLineBotで防犯ツールを作ってみた(NO MORE XX 泥棒)
この記事を見てできること
LINEBOTに「スタート」とメッセージを送ると遠隔操作で監視をしてくれるものが作れます。
異常があったら必要以上にしつこく知らせてくれます。
(処理をストップさせる処理は書いてないです)obnizの配線
コード内にも書いてありますが、人感センサーは
{vcc:11, signal:10, gnd:9}
につなぎます。ソースコード
はじめobniz.onconnectをするタイミングでハマって動かなかった。
handleEventよりも先にobniz.onconnectをしておく必要がある。line_sensor.js'use strict'; // obniz呼び出し const Obniz = require('obniz'); var obniz = new Obniz("XXXXXX"); // Obniz_ID に自分のIDを入れます const express = require('express'); const line = require('@line/bot-sdk'); const PORT = process.env.PORT || 3000; const config = { channelAccessToken: 'XXXXXX', channelSecret: 'XXXXXX' }; const app = express(); app.post('/webhook', line.middleware(config), (req, res) => { console.log(req.body.events); Promise .all(req.body.events.map(handleEvent)) .then((result) => res.json(result)); }); const client = new line.Client(config); // obniz接続////////// // スコープ(変数の影響範囲)を最上部に置いておく var sensor; var led; // 接続した段階でセンサーの準備はしておく obniz.onconnect = async function(){ obniz.display.clear(); obniz.display.print("obniz LINE bots"); sensor = obniz.wired("HC-SR505", {vcc:11, signal:10, gnd:9}); led = obniz.wired("LED",{anode:0,cathode:1}); } function handleEvent(event) { if (event.type !== 'message' || event.message.type !== 'text') { return Promise.resolve(null); } let mes = '' if(event.message.text === 'スタート'){ mes = 'OK!監視始めるね!'; //メッセージだけ先に処理 // ディスプレイ処理 obniz.display.clear(); // 一旦クリアする obniz.display.print("Hello obniz!!!!!!"); // Hello obniz!という文字を出す // setIntervalで間隔を作る setInterval(async function(){ // 非同期で取得 var detected = await sensor.getWait(); // console.log(detected); // displayに反映 obniz.display.clear(); // 一旦クリアする // obniz.display.print(detected); // 英語が出力できる // 近づいてきたら判定する if(detected == true ){ // 何かを感知したら obniz.display.clear(); // 一旦クリアする obniz.display.print("someone moving!"); led.on(); // ライトON getAskObniz(event.source.userId); // message }else{ led.off(); } },1000); // 1000ミリ秒 = 1秒 }else{ mes = event.message.text;} return client.replyMessage(event.replyToken, { type: 'text', text: mes }); } const getAskObniz = async (userId) => { await client.pushMessage(userId, { type: 'text', text: "誰かいるかも?", }); } app.listen(PORT); console.log(`Server running at ${PORT}`);XXXXXXになっている箇所は自分のObniz IDや、channelAccessToken、channelSecretを入れることをお忘れなく。
ほぼ完成
ここまで機能としては完成です。こんな感じで動きます。
人を感知すると知らせてくれます。このままでは終われない
こういった手で触れるものは見た目も大事。そして遊び心も必要です(たぶん)
この時点で平日の夜中2時を回っている。当然明日も朝から仕事である。
考えても何もアイデア浮かばない。。
ティッシュがあるからてるてる坊主?
いや、最近ティッシュやトイレットペーパーがなかなか売ってないから無駄使いはダメだ...こんな感じで動きます
人を検知すると光ります。#obniz #映画泥棒 pic.twitter.com/xFeI6oJ136
— shima-07 (@y_kawashima_) April 6, 2020obnizで作った映画泥棒くんは、誰かが来たことをLINEでお知らせしてくれる#obniz #IoT #人感センサー pic.twitter.com/sqEylRzefS
— shima-07 (@y_kawashima_) April 6, 2020最後に
物理的に触れるものは愛着湧きますね。もっと時間がある時にもっとそれっぽく作りたい。
あと、LINEでストップとメッセージしたらモニタリングがストップするような処理も書きたい。