- 投稿日:2019-11-27T23:47:24+09:00
WSLのUbuntu環境でPC内音楽データをWeb操作する(おまけでyoutube音楽とGooglehomeで伝言)
はじめに
●PC内音楽データをWEBで操作し、PCスピーカで再生できるようにする。
(Googlehomeで声で操作するのWeb操作版です。声でキーワードがうまく入力できない場合に使用してます)
【操作例】WEBから「竹内まりや」と入力する
PC音楽ボタンを押すと次の曲が再生します。(複数のファイルが検索一致した場合)
●おまけ
youtube音楽:下記の記事と同じです。
WSLのUbuntu環境でyoutube音楽をWeb操作する(おまけでradikoとサイマルラジオ)
伝言:Googlehomeで伝言を再生します。google-home-notifierを使用。環境
●Windows10 HOMEのPCにWSLのubuntuをインストールする。
●ubuntuでapache2,npm,node.js,youtube-dl,mplayerをインストールする
●WSLのubuntuでpulseaudioでPCのスピーカを使うようにする
●Windows側でpulseaudioサーバのインストールが必要です
https://www.cendio.com/thinlinc/download の 「Client Bundle」のリンクからダウンロードできますPC内音楽データを再生するプログラム(pcplay.js)
●単体で起動する方法
$node pcplay.js 検索キー(例 竹内まりや)const exec = require('child_process').exec; var limit = 1; var items; var item; var title; var id; //値取得 const value = process.argv[2]; if (!value) return console.log(value) // キーワードから検索し、音楽データのパスを取得する。 play_pcmusic(value); // 音楽ファイルのパスを取得し、再生する。 function play_pcmusic(keyword) { command = 'cat /mnt/j/music/htdocs/music/list.txt | grep "' + keyword + '"'; var exec = require('child_process').exec; exec(command, {maxBuffer: 40000*1024}, function(error, stdout, stderr) { if (error !== null) { command = 'curl -X POST -d "text=指定された曲はありません" http://192.168.1.82:8080/google-home-notifier' exec(command, {maxBuffer: 40000*1024}, function(error, stdout, stderr) { if (error !== null) { console.log('Exec error: ' + error); } }); } else { console.log(stdout); } }); command = 'cat /mnt/j/music/htdocs/music/list.txt | grep "' + keyword + '">/mnt/j/music/htdocs/music/playlist'; console.log(command) var exec = require('child_process').exec; exec(command, {maxBuffer: 40000*1024}, function(error, stdout, stderr) { if (error !== null) { console.log('Exec error: ' + error); } }); command = 'mplayer -shuffle -playlist /mnt/j/music/htdocs/music/playlist'; console.log(command) var exec = require('child_process').exec; exec(command, {maxBuffer: 40000*1024}, function(error, stdout, stderr) { if (error !== null) { console.log('Exec error: ' + error); } }); }index.php
<?php if(isset($_GET['comment1'])){ $comment = $_GET['comment1']; exec("killall mplayer"); exec("node /home/ユーザ名/ytplay.js " .$comment); } if(isset($_GET['comment2'])){ $comment = $_GET['comment2']; exec("killall mplayer"); exec("node /home/ユーザ名/pcplay.js " .$comment); } if(isset($_GET['comment3'])){ $comment = $_GET['comment3']; exec("killall mplayer"); exec("curl -X POST -d 'text=".$comment."' http://192.168.1.82:8080/google-home-notifier"); } if(isset($_GET['id'])){ $id = $_GET['id']; if($id=="stop"){ exec("killall mplayer"); } } ?> <html> <head> <meta name="viewport" content="width=device-width"> </head> <body> <p><a href="index.php?id=stop">stop</a></p> <form action="index.php" method="get"> <input type="text" name=comment1> <input type="submit" value="youtube"> </form> <form action="index.php" method="get"> <input type="text" name=comment2> <input type="submit" value="PC音楽"> </form> <form action="index.php" method="get"> <input type="text" name=comment3> <input type="submit" value="伝言"> </form> </body> </html>まとめ
●お気に入りのPCスピーカでPC内の音楽データを再生します
●プログラムはラズパイでも同様に動作しますが、youtube-dlの動作が遅く、再生開始に少々時間がかかります。参考
WSLのUbuntuでyoutube音楽をGoogleHomeで操作する
WSLのUbuntuでPC内の音楽データをGoogleHomeで操作する
WSLのUbuntu環境でyoutube音楽をWeb操作する
- 投稿日:2019-11-27T22:39:12+09:00
Axiosの前処理でAPIレスポンスのスネークケースをキャメルケースに変換する
はじめに
サーバサイドからのAPIレスポンスが
some_id
のようにスネークケースで定義されていると、JS側で毎回キャメルケースに変換することになりますよね。{ some_id: 1, some_name: "name", }今回はそんな変換処理をAxiosの共通処理でまとめてみました。
レスポンスをキャメルケースに変換する
import { camelCase, snakeCase } from 'change-case'; const isObject = (target: any): boolean => Object.prototype.toString.call(target).slice(8, -1) .toLowerCase() === 'object'; const convertSnakeToCamel = (target: any): void => { if (Array.isArray(target)) { target.forEach((t) => convertSnakeToCamel(t)); } if (isObject(target)) { Object.keys(target).forEach((key) => { if (isObject(target[key]) || Array.isArray(target[key])) { convertSnakeToCamel(target[key]); } // スネークケースをキャメルケースに変換する if (key.includes('_')) { target[camelCase(key)] = target[key]; delete target[key]; } }); } };キャメル変換する部分は
change-case
というライブラリを入れましたが、そこまで複雑ではないので自作でもよさそう参考:javascriptでキャメルケースとスネークケースの相互変換
Axiosに組み込む
import axios, { AxiosInstance } from 'axios'; const Axios: AxiosInstance = axios.create(); Axios.interceptors.request.use((request) => { // リクエストの共通処理 return request; }); Axios.interceptors.response.use((response) => { if (response.data) { convertSnakeToCamel(response.data); } return response; }); export default Axios;interceptorsを使うことでできました。interceptorsを使いこなせば、他にも、リクエストに共通のヘッダを毎回差し込んだり、レスポンスでエラー処理をしたりと、何かと便利にできそうです。
- 投稿日:2019-11-27T21:47:47+09:00
Authorizationヘッダーを使ったPOSTリクエストのTypeScript / Node.jsサンプル各種
POSTの例を
Node.js上動くアプリから、POSTリクエストを投げるコードを書くことが最近多いので、パターンをいくつか書き残そうと思いました。モジュールによって変わる使用感やコードの量、デバッグ方法などを比較したかったため、複数の方法を残します。
なお、ここではコードサンプルを残すのみで、特に比較や分析は述べてません。ここに記録しているコード
下の3つです。すべてTypeScriptに対応しているモジュールです。
- Node.js標準のhttp/httpsモジュールを使った例。
- requestモジュールを使った例.
- gotモジュールを使った例
Nodeの標準に含まれているhttp, httpsモジュールを使った例
Node標準のhttp/httpsモジュールimport jsonDataImported from './data.json'; const ACCESS_TOKEN = `<<アクセストークンと置き換えます>>`; const ENDPOINT_HOST = `<<エンドポイントホスト名と置き換えます 例) sample.endpoint.com>>`; const ENDPOINT_PATH = `<<エンドポイントホスト下のパスと置き換えます 例) /sample/path`; const postOptions: https.RequestOptions = { host: ENDPOINT_HOST, path: ENDPOINT_PATH, method: 'POST', headers: { 'Content-Type': "application/json;charset=utf-8", Accept: 'application/json', Authrorization: ACCESS_TOKEN } }; function postDataWithAccessToken(options: https.RequestOptions, postData: string): Promise<any> { return new Promise((resolve, reject)=>{ const req = https.request(basePostOptions, (res)=>{ let queue: Buffer[] = []; res.on('data', (chunk)=>{ queue.push(chunk); }); res.on('end', ()=>{ const data = Buffer.concat(queue); resolve(data.toString()); }); }); req.on('error', (e)=>{ console.log(`request error:${JSON.stringify(e)}`); reject(e); }); req.write(postData); req.end(); }); } (async ()=>{ try { const result = await postDataWithAccessToken(postOptions, JSON.stringify(jsonDataImported)); console.log(`${JSON.stringify(result)}`); } catch(e) { console.log(`ERROR - non-200/202 code returned from the endpoint:\n${JSON.stringify(e)}`); } })();ポピュラーなrequestモジュールを使った例
よく見つかるのはrequestモジュールを使用するコードかと思います。実際に私も今まではrequestを使ってましたが、最近開発がメンテナンスモードに入ってしまったとのことで、代わりを探さなくてはいけないと思ってました。
requestモジュールimport request from 'request'; import _ from 'lodash'; import jsonDataImported from './data.json'; const ACCESS_TOKEN = `<<アクセストークンと置き換えます>>`; const ENDPOINTT_TO_POST = '<<エンドポイント 例)https://sample.com/sample/path >>'; const postOptions: request.Options = { uri: ENDPOINTT_TO_POST, method: 'POST', headers: { 'Content-Type': "application/json;charset=utf-8", Accept: 'application/json', Authorization: `Bearer ${ACCESS_TOKEN}` }, json: true, body: jsonDataImported }; function postDataWithAccessToken(options: request.Options): Promise<any> { return new Promise((resolve, reject)=>{ const req = request.post(options, (err, res, body)=>{ if (err) { console.log(`${JSON.stringify(err)}`); } else if (res.statusCode === 200 || res.statusCode === 202) { resolve(res); } else { console.log(`status code was not 200 or 202`); reject(res); } }); }); } (async ()=>{ try { const result = await postDataWithAccessToken(postOptions); console.log(`${JSON.stringify(result)}`); } catch (e) { console.log(`ERROR - non-200/202 code returned from the endpoint:\n${JSON.stringify(e)}`); } })();gotモジュールを使った例
requestモジュールの代わりを選択肢を持っておこうと考えていて、今のところしばらくはgotを使ってみます。今日使ってみた中では、一番簡潔に書けますし、十分通常の用途をカバーするモジュールだと思います。
gotモジュールimport got from 'got'; import jsonDataImported from './data.json'; const ACCESS_TOKEN = `<<アクセストークンと置き換えます>>`; const ENDPOINTT_TO_POST = '<<エンドポイント 例)https://sample.com/sample/path >>'; (async () => { try { const body = await got.post(ENDPOINTT_TO_POST, { body: jsonDataImported, json: true, headers: { 'Content-Type': "application/json;charset=utf-8", Authorization: `Bearer ${ACCESS_TOKEN}` } }); } catch(e) { console.log(`ERROR:\n${JSON.stringify(e)}`); } })();今後
特にgotについてはこれからも使ってみて、便利な使い方など見つけたらアップデートしていこうと思います。
- 投稿日:2019-11-27T20:41:46+09:00
知ってるとかっこよくなれるJS小技集2019
はじめに
コードレビューでさらっと
「こんな書き方もできますよ」って言ってくれる先輩ってかっこいいですよね。
いつかそんな先輩になれるように、メモ化しておこうという試みです。クリスマスのお供にどうぞ。記法
変数名が同じなら省略できる
const params = { id: id name: name }const params = { id, name }{}で分割代入
似てるものでこういう省略系もあります。分割代入と言うらしいです。
const id = response.id;const {id} = response;複数もOK
const {id, name} = response;実務でよくみる使い方だと、Reactでpropsから値取り出すときとかでしょうか。
const {width, height} = props; return ( <div style={{ width, height }} /> )スプレッド演算子...で展開できる
const hoge = { id: fuga.id, name: fuga.name, type: fuga.type }const hoge = { ...fuga }展開してさらに追加してもOK
const hoge = { ...fuga, date: Date.now() }実例だと、ReduxでStateを一部更新するときなんかに使えますね
[HogeAction.SOMETHING]: (state: IHogeState, action: any): IHogeState => ({ ...state, fuga: action.payload })オブジェクトをコピーするためにも使えますが、Object.assign同様ディープコピーではないので注意です。
const original = { id: 1, obj: { name: "shwan" } }; const copy = { ...original }; console.log(copy.obj.name); // "shwan" original.obj.name = "changed"; console.log(copy.obj.name); // "changed"オブジェクトのディープコピー技だとこんなのもありますが、undefindを扱えない罠があったりするので、できるだけ避ける人生を歩みたいですね。
const copy = JSON.parse(JSON.stringify(original));スプレッド演算子に話をもどすと、引数でも展開できたりします。使う場面はあまりなさそうですが。
doSomething(fuga.id, fuga.name, fuga.type);doSomething(...fuga);条件分岐
論理演算子 || で条件分岐
let name; if (response.name) { name = response.name } else { name = 'Guest'; }const name = response.name || 'Guest';nullかもしれない配列を空配列にするときによく使います
response.names.forEach() // response.namesがnullやundefindだとエラーconst arr = response.names || []; arr.forEach()論理演算子 && で条件分岐
if (isGuest) { doSomething(); }isGuest && doSomething();この記法、
if( A && B )
if( A || B )
なときと違う動きをしてるようにも見えますが
&&
は 左が偽なら左の値を、真なら右の値を返す
||
は 左が真なら左の値を、偽なら右の値を返す
という共通の仕組みです。const name = response.name || 'Guest';の例では
response.name
が'shwan'
などの文字列であれば左が真とみなせるので、左の値が返り、''
やnull
であれば、偽なのでGuest
が返ります。キャスト
!! でのbooleanキャスト
const isSelected = this.state.type ? true : false;const isSelected = !!this.state.type;この記法も!を2つつなげると
if(!isSelected)
なときと違う動きをしているようにみえますが、
!
は 値を真偽値とみなしたうえで真偽を反転する という動きでどちらも共通です。+ でのnumberキャスト
const id = '1' console.log(+id); // 1console.log(new Date()); // Wed Nov 27 2019 21:00:38 GMT+0900 (日本標準時) console.log(+new Date()); // 1574856056863キャストできなければ
NaN
になるので使い所は見きわめましょう。
ちなみにnew DateはDate.now()を使えばキャストせずとも数値で出せます。console.log(Date.now()); // 1574856056863letしない
三項演算子でletの回避
let type = 'a'; if (isB) { type = 'b'; }const type = isB ? 'b' :'a';即時関数でletの回避
複雑な分岐なら即時関数を使って回避することもできますね。このあたりは可読性とトレードオフでしょうか。
const type = ((flag) => { if (flag) { return 'a'; } else { return fukuzatuNaSomething(); } })(isB);その他Tips
関数の引数に初期値を設定する
初期値をつけておけば条件分岐を減らせます
const doSomething = (a, b = 1) => a * b; doSomething(1); // 1 doSomething(1, 2); // 2someで繰り返し処理を途中で抜ける
arr.forEach((obj) => { doSomething if(shouldBreak){ //break; ←できない } })arr.some((obj) => { doSomething if (shouldBreak) { return true; } return false; })someで配列の中を調べる
includes代わりに使えます
const arr = ['a', 'b', 'c']; arr.includes('b') // trueconst arr = [{ name: 'shwan' },{ name: 'taro' }]; arr.some((person) => person.name === 'shwan') // true対象が配列なのか調べる
Array.isArray(target)対象がオブジェクトなのか調べる
Object.prototype.toString.call(target).slice(8, -1).toLowerCase() === 'object';ここでいうオブジェクトは
{id: 1, name:'a'}
こういうのです。配列のようにスッキリは書けないので一工夫必要になります。そろそろネタがなくなって極小ネタになってきたので、また来年に向けて溜め直してきます!
- 投稿日:2019-11-27T12:57:02+09:00
Technology Radar 2019のピックアップ
Technology Radarから気になったものをピックアップし、軽く説明を添えてみました。
社内で共有したところ、反響が良かったのでQiitaにも投稿します。(自分と似た技術スタックの方に刺さるのではないかと考えています)
ピックアップの観点
「自社の技術スタックとマッチしてるか」、「自分の技術スタックとマッチしているか」の観点からピックアップしています。
筆者は現在web系の企業のSREチームに所属しており、業務や趣味で触れる技術/言語としては下記のとおりです。
- Ruby on Rails
- Node.js / Vue.js / Nuxt.js
- AWS + Terraform
- Go/python/Firebase/GCP
一方で下記技術は興味が無い/専門じゃない等の理由でスルーしていますのでご注意ください。
- モバイルアプリ系
- ML系
- JVM系
Technology Radarとは
要は今年のイケてる技術の紹介です。
4段階で導入のおすすめ度合いが評価されているので、毎年重宝しています。TECHNOLOGY RADERとはThoughtWorks社が発表している技術トレンド分析の調査結果になります。 年1-2回発表しており、2016年は4月と11月に発表されました。
ユニークな点は、技術トレンドの分析を
Techniques(開発手法) / Tools(ツール) / Platforms (プラットフォーム) / Languages & Frameworks(言語とフレームワーク)
の4分野に分けているところです。
また、評価結果も ADOPT / TRIAL / ASSESS / HOLDの4つに分けているところです。ADOPT : プロジェクトにマッチするならば、採用を強くおすすめしている。
TRIAL : プロジェクトでリスクを管理できればやる価値はある。
ASSESS: どのような影響をあたえるか理解するために採用するときがある。(今後のために採用するときがある)
HOLD : 採用する場合は慎重に進める必要がある。引用元:https://allabout-tech.hatenablog.com/entry/2017/02/15/093000
気になった技術
それぞれの領域ごとに概要と所感を記載しています。
Techniques
Container security scanning (ADOPT)
もはやコンテナのセキュリティスキャンは必須の時代です。
CI/CDパイプライン内でスキャンを実施しましょう。所感:ECRのscan on pushやtrivyで簡単に実現できそうなのでやっていきたい。
Pipelines for infrastructure as code (ADOPT)
ソフトウェアのCI/CDパイプラインによるデプロイが主流になってきました。
Chef/Puppet/Ansible、Packer、Terraform等の登場により、インフラレイヤーもCI/CDを実現することが可能です。
インフラレイヤーもCI/CD化することで、実行元の一元管理や、実行前のエラー検知ができるようになるので、是非やりましょう。所感:Lint/validationやplan結果の表示もできるのでやりたい。stg/prdのapplyタイミングを踏まえて設計する必要があるのでちょっと大変かも。Dockerfileも現在はCIにかかってないので回すようにしたい。
security policy as code (TRIAL)
セキュリティポリシーをコード化し管理していきましょう。
Open Policy AgentやIstio等であれば、ポリシー定義と実施メカニズムを提供しています。所感:明文化してGit管理を開始したので、適用を強制したり検知する仕組みもあわせて実施していけるといい感じかも。
Tools
Commitizen (ADOPT)
http://commitizen.github.io/cz-cli/
対話形式でGitのコミットメッセージをサポートしてくれるツールです。
コミットの種類とか関連するIssueの有無とかbreaking changeの有無とか聞いてくれていい感じにメッセージを組み立ててくれます。
所感:個人のリポジトリはコミットメッセージ英語なので、これを導入することで良さげなリポジトリに見えるようになりそう。
jib (TRIAL)
https://github.com/GoogleContainerTools/jib
Java用のコンテナイメージ作成ツールです。
MavenやGradleに対応しており、DockerfileやDockerデーモンを必要とせずにイメージをビルドします。所感:使うことはまあ無いだろうけど、デーモン無しにイメージを作成できる技術は気になる。
Trivy (TRIAL)
https://github.com/aquasecurity/trivy
コンテナイメージのセキュリティスキャンツールです。所感:今ではかなり有名なやつ。使っていきたい。
Twistlock (TRIAL)
https://www.twistlock.com/
Twistlockは、コンテナ環境向けセキュリティ製品です。開発環境から実行環境まで、包括的なセキュリティを提供します。
NIST/CISベンチマークなど、業界のベストプラクティスに沿った対策が可能です。
所感:金額次第だが、セキュリティ要件厳しいサービスを運用する際にはいいかも。ただし、融通が利くかどうかは重要。
asdf-vm (ASSESS)
https://asdf-vm.com/#/
複数の言語のバージョンを管理できるコマンドラインツールです。
RVMやnvmのようにバージョンを管理できますが、複数の言語をこのツール1つで管理できるのが特徴です。所感:ruby以外もバージョン固定して利用するプロジェクトでは良さそう。個人の環境は全部これに乗せ替えたい。
AWSume (ASSESS)
https://github.com/trek10inc/awsume
AssumeRoleをいい感じにやってくれるCLIツール
所感:社内のエンジニアには基本的にassum roleして利用するIAMユーザーを配ってるので、これを標準の手順にしてみてもよさそう。(現在、MFAを利用していることもあり、AssumeRoleするユーザーでawscliを使う手順がやや面倒)
Pumba (ASSESS)
https://github.com/alexei-led/pumba
PumbaはDockerのためのchaos testingとネットワークエミュレーションのツールです。
ネットワークをエミュレートし、遅延、パケット損失、帯域幅レート制限などのさまざまなネットワーク障害をシミュレートすることもできます。所感:chaos testingはやったこと無いので挑戦してみたい。
Platforms
Crux (ASSESS)
https://opencrux.com/
bitemporal graph queryを備えたドキュメントデータベースです。
bitemporalとは、履歴を持ったデータのこと不変のトランザクションレコードも保持しながら、ビジネスの真の履歴を記録します。これがバイテンポラリティの本質です。開発者およびアプリケーションユーザーとして、時間をかけて効率的にクエリを実行する機能のロックを解除します。 Cruxを使用すると、遡及修正を作成し、履歴データの移行を簡素化し、異常なイベントデータの統合ビューを構築できます。
所感:特許で見たことあるような。履歴を持ち、かつそれを遡及して修正するシステムは本当に辛いので、これがマッチするなら使うのが良さそう。
Hydra (ASSESS)
https://www.ory.sh/hydra/
OAuth2、OpenID connect providerを簡単にホストすることができるOSSです。所感:micro serviceをk8s上で構築する際に使えそう。認証系の自前メンテは辛いので、こういうものを活用していきたい。
Teleport (ASSESS)
https://gravitational.com/teleport/
『Gravitational Teleportは、SSHまたはKubernetes API経由でLinuxサーバーのクラスタへのアクセスを管理するためのゲートウェイです。従来のOpenSSHの代わりに使用することを目的としています。』
所感:中規模以上のk8sを利用している場合に効果を発揮しそう。自前でteleportのクラスタを構築し、ライセンスも必要なプロダクトなので、導入するのはけっこうな大事。GitHubや任意のSSO連携可能なサービスのアカウントで、ロールに基づいたsshができるのはまさに我々が求めていたものである。
Languages & Frameforks
jest-when (TRIAL)
https://www.npmjs.com/package/jest-when
when(fn).calledWith(args).thenReturn(value)
のような感じでモック関数の引数に対するレスポンスを定義できるプラグインです。所感:地味に便利で記述量を少なくできるので良さそう。
NestJS (ASSESS)
https://nestjs.com/
TypeScript製のserver side Node.jsフレームワークです。
GraphQL、Websocket、ORMライブラリなどのプロトコルをサポートしています。参考記事:Nest.jsは素晴らしい
所感:発想はRailsに近いように思える(レールに乗ることでスタイルが統一され楽に開発できる等)。expressとの2択になりそう。
Paged.js
https://www.pagedmedia.org/paged-js/
HTMLで書籍等の印刷物を作る場合に必要なページカウンターやヘッダー、フッター等を描画できるポリフィルとCSSモジュールを生成してくれるライブラリです。所感:本を作る機会があれば使ってみたいかも。前職であれば仕様書は謎に文書形式である必要があったので、Markdownで書いた場合でもヘッダーやフッターを頑張ってつけてたから、それにも使えそう。
まとめ
個人的に気になった技術をいくつかピックアップして紹介してみました。
よくあるツール紹介でごめんなさい。
でも、元が英語だから許してね。
- 投稿日:2019-11-27T12:37:47+09:00
CircleCIのnode imageでnpm installに失敗する
CircleCI2系で、公式ドキュメントを参照してセットアップしたらnpm installがコケた。
circleci/node:6.17.1のイメージを使用してる環境。https://circleci.com/docs/ja/2.0/language-javascript/
Error: Cannot find module 'strip-ansi'
こういうエラーでnpm installが停止する。
package-lockの中を見るとstrip-ansiは入ってるし……と思ってたがプロジェクトのパッケージが問題ではなくて、原因としては、公式ドキュメントにあるsudo
がだめ。.circleci/config.yml- run: name: update-npm command: 'sudo npm install -g npm@latest'npmがsudoでインストールされるとそのあとのnpmコマンドが通らなくなる(別にinstallに限らずnpmコマンド全部落ちる)。
sudoを外すとパーミッションでコケるので、以下のように変更するとよい.circleci/config.yml- run: name: set-global-prefix command: npm config set prefix '$HOME/.npm-global/' - run: name: update-npm command: npm install -g npm@latestグローバルパッケージのインストール場所をパーミッションのいらないところに変更すると通る。
もしかしたらnodeのバージョンにもよるのかもしれないけど、公式通りにやるとハマるのは困った。
- 投稿日:2019-11-27T12:03:30+09:00
結局Firebaseの無料プランSparkでは何ができるのか
Firebaseの制限
Google Cloud Platform(GCP)の提供するFirebaseでは料金の一切かからないプランsparkが存在する。
諸兄等には十分ご存じのことと思うが、そのプランではいくつか機能に制限がかけられている。
その制限はどのぐらい許容できるのもなのだろうか。はじめに
私は仕事でFirebaseのBlazeを利用して開発を行っているが、
ふと強みの一つである無料プランが存在する利点を享受できていないのではと思い当たった。
そのため、この度Sparkプランで簡単なアプリを作成し、どのようなことが可能なのか、
また、その限界はどこなのかの一端を調べてみることにした。検証した内容
今回はこちらの「100秒当たりの制限」はどのぐらいで使いつくしてしまうかについて調べた。開発環境
Firebase
nodejs(v8.16.2)
typescript(3.7.2)
vuejs(2.6.10)ソース
https://github.com/tecoKodera/firebase_spark_test_othello
書きなぐったコードで申し訳ないが、リポジトリは上記にある動作の様子
結果
複数回呼び出す場合もあるような冗長なつくりにしたが、5秒ごとに1/10の確率で話すBOTと、
オセロ10クリック程度で制限を使い切ってしまった。
やはり複数回呼び出しかねない構造のFunctionsはよろしくないようだ。
今回チャット部の発言時間を自動で記録する処理が特に呼び出し回数を消費してしまっているようだった。
sparkプランで運用するには呼び出し自体を減らすよう設計する必要がある。終わりに
Firebaseには他にも制限があり、思いがけないところでコツが必要になってくる。
慣れるまでは大変だが、やはりこの速さでwebアプリを作れることは大きな魅力に違いない。
これからも皆様におかれましては素晴らしいFirebaseライフを。
- 投稿日:2019-11-27T11:39:35+09:00
Node.jsのfsモジュールの使い方
fsモジュールとは
fsモジュールはファイルを扱うためのモジュールで、ファイルから書き出したり、ファイルに書き込んだりするときに役立ちます。
Node.jsがはじめから提供しているモジュールなので、Node.jsのインストールがしてあれば、fsモジュールのインストールの必要はありません。ファイルの読み込み
const fs = require('fs'); //fs.readFileSync(ファイルのパス, 文字コード, コールバック関数) fs.readFileSync('./text.txt', utf-8, (err, data) => { //dataがファイルの中身、errは読み込み時のエラー if(data) { console.log(data); } else { console.log(err); } });ファイルへの新規書き込み
const fs = require('fs'); //fs.writeFileSync(ファイルのパス, 書き込む文字, 文字コード, コールバック関数) fs.writeFileSync('./text.txt', "こんにちは", utf-8, (err) => { if(err) { console.log(err); } });ファイルへの追加書き込み
const fs = require('fs'); //fs.appendFileSync(ファイルのパス, 書き込む文字, 文字コード, コールバック関数) fs.appendFileSync('./text.txt', "こんにちは", utf-8, (err) => { if(err) { console.log(err); } });ファイルの削除
index.jsconst fs = require('fs'); //fs.unlink(ファイルのパス, コールバック関数) fs.unlink(process.argv[2], (err) => { if (err) { console.error(err); } else { console.log('削除が終わりました'); } });process.arg[2]はコマンドの第三引数を指すので、以下のようにファイルをコマンドの第三引数に書き、ファイルの実行を行います。
console$ node index.js ./text.txt
ファイルの作成
const fs = require('fs'); //fs.open(新規作成ファイルのパス, 書き込む文字, コールバック関数) fs.open('./text.txt', 'こんにちは', (err) => { if(err) { console.log(err); } else { console.log('ファイルが作成されました'); } });ストリーム
当初、ストリームを使う理由が分からなかったのですが、ストリームだとデータを必要な分だけ受け取ることができるようになるため、メモリを多く使わずに済むそうです。
const fs = require('fs') //読み込みストリームを作成 const rs = fs.createReadStream('./text.html'); //dataイベントが発生したら(データを受け取ったら)、chunkに'./text.html'のデータが入ります。 rs.on('data', (chunk) => { res.write(chunk) });普通のファイル読み込みで同じ処理をしてみると、
readFileSyncだと、同期的な読み込みになるため、すごく読み込みが遅いです。
そのため、readFileで非同期的な読み込みをしています。const fs = require('fs'); //fs.readFile(ファイルのパス, コールバック関数) fs.readFile('./text.html', (err, data) => { //dataがファイルの中身、errは読み込み時のエラー if(data) { res.write(data); } else { console.log(err); } });今回は、./text.htmlファイルも大きくなく、この程度のファイルならばスピードに大きな違いはありませんでした。
ですが、これが大規模な開発になると違いが出てくると思われます。
- 投稿日:2019-11-27T11:31:19+09:00
ファイルをセーブしたら、npmスクリプトを走らせる」というライブラリを1行で作る。
「ファイルをセーブしたら、npmスクリプトを走らせる」というライブラリがある日突然欲しくなりました。
onchangeというライブラリが見つかりました。npmライブラリです。
使い方は簡単で、onchangeをグローバルにインストールした後、grobパターンで、監視するファイルとnpmスクリプトを記述するだけです。
npm install -g onchange onchange 'app/**/*.js' 'test/**/*.js' -- npm testしかしです...
globパターンを記述するのが地味に面倒い!
ルートフォルダ以下で変更があれば、npmスクリプトを走らせるだけでいいのに...そこでよりシンプルなライブラリを自作することにしました
作ったのが「save-run」というライブラリ。
名前は、save-runとして、npmに登録してあります。
githubリポジトリはこちら使い方は簡単で、グローバルにインストールしてからrun-saveコマンドの後にnpmスクリプトを渡すだけ。
npm install -g run-save run-save npm test幸せになれました〜〜〜
私は、react-nativeエンジニアなのですが、
run-save npm start
run-save npm test
などに使っています。実はこのライブラリは1行で実装されているので、興味のある方は読んでみてください。
#!/usr/bin/env node const { watch } = require('chokidar') const { execSync } = require('child_process') watch('.').on('change', () => execSync(process.argv.slice(2).join(' '), { stdio: 'inherit' }))完!
- 投稿日:2019-11-27T07:51:54+09:00
Node.js で無限ループしつつ、一定周期で処理をしたい
メモ。
Node.js で無限ループしつつ、一定周期で処理をしたいという要件があった。
(具体的には SIGTERM シグナルを受けてから1秒毎に標準出力に文字列を出力したい)
上記について Node.js のサイトにずばり書いてあった。"Infinite Loop" Execution ~ setInterval()
node.jsfunction intervalFunc() { console.log('Cant stop me now!'); } setInterval(intervalFunc, 1500);この場合、1.5秒毎に
intervalFunc()
が実行される。
必要に応じて時間や処理内容を変えれば良い。Node.js v10.17.0 で動作確認済み。