Quantcast
Channel: Node.jsタグが付けられた新着記事 - Qiita
Viewing all 9100 articles
Browse latest View live

FXトレーダーコミュニティをslackワークスペースで作った話(前編)

$
0
0

作ろうと思ったきっかけ

去年リリースされたLINEオープンチャット
他の興味も含め興味があるジャンルのオプチャにあちこち入った
そのうちの一つがFXのオプチャで
たまーに覗いていた程度だった。2月3月ごろコロナの影響で為替が大きく動いた時にちょっと
真剣に覗いてみたところトレンドの解説などをかなり詳しくやってくれている人が何人かいて
参考にトレードをしたりしていた。
しかし毎日オプチャを見ていると
いくつかの不自由さに気づく。

一つのタイムライン

まず一つはさまざまな話題が一個のタイムラインに溢れかえっていること
超初心者の自分でググれよみたいな質問だったり
だれかれ構わず粗探しをしたいクレーマー気質な人とそれと戦い続ける人の無駄なやりとりだったり
ロングしました、ショートしました!と張り切って伝えてくれている人がいるのはいいものの
ぱっと見でドル円の話をしているのかユーロポンドの話をしているのかが伝わりにくいかった。
職業柄かもしれないがこの情報が整理されていない状態がすごくストレスだった。

人間しか投稿できない煩わしさ

本業ではもちろんslackをバリバリ使うので当然アプリ連携なんか普通のことで
全部人間がPOSTしなければならないオプチャがすごく不便だった。

そこで
これslackに移行できればすごく有意義な場所となるのでは?
という結論にいたり、作ってみました。

  • 通貨ペアごとの部屋
  • 話題ごとの部屋
  • 簡単な通知bot

などを用意し
そこでオプチャで知り合った何人かに声をかけたのが始まり。

vue.jsで作った公式サイト
https://fx-labo.web.app/
FX研究所公式オープンチャット
https://line.me/ti/g2/o1ChnqwNK5JtsE9FmAfvpg

ぶち当たる壁4つの壁

壁その1 slackって何?

おそらく既存の大多数のslackユーザーは
ITリテラシーが高めでslack以外のチャットツール(チャットワークなど)
を経験しており、さらには気兼ねなく不明点を聞ける会社の同僚といろいろ試しながら
slackに触れていったと思われる。

ここの読者には信じられないかもしれないが
世間一般的にはslackの認知度なんて1割にも満たないと思われる
(コロナの影響で少しは上昇したかもだが)
その上、見ず知らずの相手に一からテキスト情報のみで
それを教えなければならないのだ
しかも、ITリテラシーが高いとはお世辞にも言えない人たちが大半だったため
グーグルで検索したり、とりあえず試してみたりという選択肢はなく
容赦無くどんどんチャット上で聞いてくる。しかもだいたい毎日同じ質問
(メンションはどうやってつけるの?スレッドって何?チャンネルって何?)

FXの上手な人たちを集めて質の高いトレードのための情報を得ようと思ったのに
最初の二週間はほとんどCS(カスタマーサポート)のようなことばかりをしていた。
そして驚いたことに大半(感覚値8割強)がスマホのみでトレードもチャットも完結しているのだ.
筆者はプロジェクトでPCでslackを使うがスマホ版では確認と緊急の返信くらいしでしか使わないので
そこにズレが生じる。FXのトレーダーだーからみんなパソコンいっぱい持っていると思ってたが
パソコンの方が圧倒的少数派だった。

壁その2 そこに性善説(優しい世界)はなかった

会社やプロジェクトでslackを使う時、最初にルールが共有されるだろう
general で雑談ばかりしていたり、チャンネル違いの投稿をするときっと誰かが指摘するだろう。
なぜなら会社プロジェクトを成功させるために効率化が必要という認識を
いつのまにか全員で共有できているからだ

しかしオンラインで集まった匿名コミュニティだと
FXで儲けたい人たちという共通項はあれど自分が損をしていなければ、
隣の人が100万円溶かしていようが関係ない話をしてようが全く関係ないのである
なので、他人のslack使い方がおかしかろうが、それを正さなければという意識が働かないのだ
慣れてきたらユーザー同士が優しく教えあう世界はそこにはなかった。

今でこそ古参メンバーが管理人の苦労を汲み取っていろいろとサポートしてくれて(ほんと助かってる)
機能するようになったが開設当初はせっかく用意したチャンネルはほとんど機能せずほとんど雑談とチャンネル違いの話題で埋め尽くされていた。

壁その3 自然流入がない

オプチャで勧誘してみたところ
開設一週間で50人以上の人が参加してくれた
しかし、そのうちアクティブに会話してくれたのは10人にも満たなかった。
オプチャだと1日に何十人もの人が検索経由で人が流入してくるが
Slackという閉ざされたコミュニティだとそれは皆無で
自分たちで外部で宣伝せざるを得ないのだが
なにせ、slackの認知度が低いため
よく分からん怪しいサイトに誘導してる奴がいるくらいの認識で終わってしまうのだ。
どうせ有料のサイトでしょ?なんか情報商材売りつけてくるんでしょ?と身構えてしまうのだ。
それに加えオプチャのルームにはそういった勧誘をを禁しているとこが大半なのだ
みんなであの手この手で勧誘していたら一番大きなFXのオプチャルームから締め出されてしまった。
その後twitterなどを駆使し別のユーザー獲得方法を確立(次回以降執筆予定)

壁その4 Slackの無料枠の件

ユーザーの大半を雑談が多いオープンチャットから獲得していたのこともあるかもしれないが
FXは土日に相場は動かないので、土日には雑談チャンネルでみんなワイワイと話している。
(顔も名前もどこに住んでるのか年齢も分からない人たちとずっと為替の話をしているのが楽しい)

一ヶ月半くらい経った時にslackのメッセージ数上限の通知がきた
(無料プランだと10000件を越えると古いものから表示されなくなる)
それは最初から知っていたし
そもそもFXの相場分析なので一週間も前の分析は必要ない、せいぜい2,3日分あれば十分なのだ
しかし10000件の容量のうち 通知系の垂れ流しbotと雑談でその大半を占めていることに気づいたのだ。
実況や即時性の情報ではなくナレッジを貯めていく系のチャンネルも用意していたのでこちらはいずれ消えるにせよ
できれば長く保存しておきたい。これらを少しでも延命させるために。
削除botを自作した。(詳しくは次回執筆予定)
雑談は300件以上増えると古いものから自動で削除
通知系垂れ流しは古い情報が不要なので10件
ドル円部屋は200件、テクニカルを教えあう部屋は500件
といった具合だ。
これにより10000件の枠をどのように分配するかある程度制御できるようになった。

三ヶ月たった現在

上記のような紆余曲折があったが、
運用開始から三ヶ月経った今は ドル円やポンド円などメジャーな通貨ペアには常に誰かがいて
あーでもないこーでもないと相場を見守っているし、
類は友を呼ぶではないがエンジニアが多数集まってきており
最強のEA(自動トレードソフト)を開発しようという流れができてきたり。
上級者が初心者に優しく教えてあげるチャンネルが立ち上がったり。
土日には常連同士でくだらない雑談で盛り上がったりしている。

当初想定していたコミュニティに少しずつ近づきつつある印象です。

最後に

次回以降、私が様々な便利ツールも並行して開発していますのでそのツールのご紹介もしますが

現時点で興味のある方
バリバリのトレーダーさんや
FXの初心者さん
自動トレードや機械学習トレードに興味があるエンジニアの方も
どなたでも無料で利用できますので参加希望の方は
オープンチャットかTwitterにて連絡いただければ招待URLをお知らせいたします。

vue.jsで作った公式サイト
https://fx-labo.web.app/

集客用twitter
https://twitter.com/FxSlack


MAC:node.jsでmysqlへ接続する

$
0
0

node.js から mysqlに接続するのに苦労しましたので覚書をします。

環境

macOS : 10.15.5 (Catalina)
node.js : v14.3.0
mysql : ver 8.0.19

mysqlインストール

shell
$ brew install mysql

でインストールされました。
(他の情報でmpnを使用するやり方が書いてありましたが、私の環境では起動ができませんでした)

コネクションを実行するコード

mysqlconnection.js
//------------------------------------------------------------//      my sql connection//------------------------------------------------------------varmysql=require('mysql');//DBの定義vardbConfig={host:'localhost',//接続先ホストuser:'root',//ユーザー名password:'******',//パスワードdatabase:'******'//DB名};varconnection;functionhandleDisconnect(){console.log('create mysql connection');connection=mysql.createConnection(dbConfig);//接続する準備//接続connection.connect(function(err){if(err){console.log('error when connecting to db:',err);setTimeout(handleDisconnect,2000);//2秒待ってから処理}});//error時の処理connection.on('error',function(err){console.log('db error',err);if(err.code==='PROTOCOL_CONNECTION_LOST'){handleDisconnect();}else{throwerr;}});module.exports=connection;//connectionを(他のファイルから)requireで呼び出せるようにする}handleDisconnect();

実行するにはシェル(ターミナル)に以下を入力します

shell
$ node mysqlconnection.js

エラー発生

私の環境では上記を実行してもエラーが出ました。

  1. mysqlが起動していない場合のエラー
 errno: -61,
  code: 'ECONNREFUSED',
  syscall: 'connect',
  address: '127.0.0.1',
  port: 3306,
  fatal: true

このエラーの対処は

shell
$ mysql.server start

とします。

2.認証方法エラー
新しいmysqlで認証方法が変更になっていてnode.jsからは古い認証方法でアクセスするためにそれに合わせる必要があるようです。

ER_NOT_SUPPORTED_AUTH_MODE: Client does not support authentication protocol requested by server; consider upgrading MySQL client

この対処は以下を参照しました。

Node.jsでMySQL 8.0へ接続しようとする時に発生するエラー

ですがこれをこのままやってもうまくいかず

mysqlの初期パスワードをクリアする必要がありました。
他のサイトではvar/log/mysqld.log に初期パスワードが残っているとの情報があったのですが、私の環境ではありませんでした。
それで以下の記事

Mac ローカル環境の MySQL 8.0 のrootパスワードを忘れた時のリセット方法

を参考にて、
1.サーバーを停止
$ mysql.server stop
2.MySQLをセーフモードで起動する。
$ mysqld_safe --skip-grant-tables &
3.rootユーザのパスワード無し状態でログインする。(同じターミナルで大丈夫でした)
$ mysql -u root
4.rootユーザーのパスワードを空に設定する。
mysql> UPDATE mysql.user SET authentication_string=null WHERE User='root';
5.セーフモードで開いたMySQLを閉じる
mysql> exit
6.セーフモードで動作しているMySQLをkillする。
$ mysql.server status
SUCCESS! MySQL running (XXXXX)
$ kill XXXXX

7.通常モードでMySQLを起動する。
$ mysql.server restart
8.rootでmysqlを起動する。(パスワード要求されるがENTERをおす。)
$ mysql -u root -p
9.パスワードを再設定する。
mysql> USE mysql;
10.ここで先ほどの
Mac ローカル環境の MySQL 8.0 のrootパスワードを忘れた時のリセット方法
に書いてあるSQLを実行します

mysql>ALTERUSER'root'@'localhost'IDENTIFIEDWITHmysql_native_passwordBY'password'

passwordの部分はrootでログインを行う際の任意のパスワードです。

ここまで実行するとこのエラーはなくなります。

その他注意

・node.jsからmysqlへアクセスするにはmysqlにdbを作成する必要があります。

mysql
mysql>createdb_test

・mysqlconnection.jsは作成したdbと、設定パスワードを記述する必要があります

mysqlconnection.js
vardbConfig={host:'localhost',//接続先ホストuser:'root',//ユーザー名password:'******',//パスワードdatabase:'******'//DB名};

browser-syncのport番号をランダムにする

$
0
0

複数の案件を同時に進めている都合上、複数個のbrowser-syncを同時に走らせたいときportが衝突してイライラしちゃうので、そもそもportをランダムにしとけばいいんじゃないか説。

他にいい方法があれば教えてください。。。

// browser-sync.jsmodule.exports=()=>{constpath=require('path');constbrowser=require('browser-sync').create();browser.init({files:[// 監視したいファイルのパターンリスト],// 動的・プライベート ポート番号からランダムでport:Math.floor(Math.random()*(65535-49152))+49152,startPath:'/',server:{baseDir:path.join(__dirname,'public')}});};
// 呼び出し側のjsrequire('./browser-sync')();

参考

【アプリ編】textlintではじめる自動文章校正

$
0
0

textlintとは

textlint(テキストリント)は、設定した校正ルールに基づいたミスの指摘・修正を自動化するツールです。

本来はコマンドプロンプト等の『黒い画面』からインストールして使うのですが、作者の方(@azu_reさん)がより使いやすいデスクトップアプリ版をリリースしてくださっています。
こちらで十分な方にとっては圧倒的におすすめです。

アプリのダウンロード

https://github.com/textlint/textlint-app/releases/tag/v1.4.1

↑こちらのページからインストーラをダウンロード、実行します。

アプリを開くとこのような画面が出ます。▼
スクリーンショット 2020-07-07 11.47.51.png

基本的にはメモ帳やテキストエディットのような「エディタアプリ」と同じだということがわかと思います。

しかしこのアプリを使うためには、以下の2点を用意する必要があります。

・ワーキングディレクトリ(作業用フォルダ)
・校正ルールプリセット

順番に説明します。

ワーキングディレクトリの設定

”ディレクトリ”というのは、つまりフォルダのことです。
筆者も最初わからなかったんですが、プログラミングの工程でコマンド操作をする際には、フォルダのことをディレクトリと呼ぶみたいです。

textlintを使う上では、どこのディレクトリで校正作業するのか?という設定が必要になります。

その設定をするのは、左カラムの『Settings』画面。▼
スクリーンショット 2020-07-07 11.48.02.png

上の方にあるWorking directoryの部分に、作業するフォルダのパスを入力します。
何も設定をしないとデフォルトでtextlint-appのフォルダが使われますが、実際に使う際にはデスクトップ等の見やすい場所に置いておく方が何かとスムーズかと思います。お好みでフォルダをご用意ください。
スクリーンショット 2020-07-07 12.00.18.png
↑今回はこのフォルダを使います。

作業用のフォルダを決めたら『.textlintrc』というファイルを用意します。
『.』から始まるこのファイルは”隠しファイル”といって、フォルダを開いても表示されません。

ファイルを作る時はエディタを使いましょう。
サクラエディタやAtomで空のファイルを作成し、名前をつけてフォルダへ保存します。
スクリーンショット 2020-07-07 12.24.42.png
(Macの場合「command」 + 「shift」 + 「.」でこのように隠しファイルを表示できます)

ファイルを用意できたら、同じフォルダ内に『rule』というフォルダを作ります。
スクリーンショット 2020-07-07 12.34.49.png

ここまでできたら、次はルールの設定をしていきます。

校正ルールの設定

現状では、textlintは何の校正ルールも持っていません。
実際に校正を行うには、ルールを自分で設定するか、誰かの作ったルールプリセットをインストールする必要があります。

今回やりたいのは『表記揺れを統一させること』(『是非』は『ぜひ』の表記に統一したいなど)なので、textlint-rule-prhというプリセットを使ってみます。

prhを使うためには、間違い表現と正しい表現をまとめたymlファイルが必要です。
エディタで『jisho』フォルダを開いて、『rule』フォルダ内にファイルを作成しましょう。
スクリーンショット 2020-07-07 12.44.52.png
今回は『jisho.yml』というファイル名にしました。
(画像で使っているVSCodeでは、ymlファイルを開くと紫の!マークがつきます。特にエラーではないのでご心配なく)

ymlファイルにルールを記述する

https://github.com/textlint-rule/textlint-rule-prh
▲こちらのページに詳しい記述方法が書いてありますが、基本的にはこんな感じです。

jisho.yml
version:1rules:-expected:正しい表現です。pattern:間違った表現です。-expected:正しい書き方。patterns:-こんなパターン-どんなパターン-あんなパターン

このように『patternに該当する表記があったらexpectedが正しいですよ』という指示を書きます。
「是非」→「ぜひ」のような統一の場合はこの書き方。

もし書き間違いなど、正解パターンに対して間違いパターンをいくつも指定したいときは、下にあるようにpatternsと書いたあと間違いパターンを書き連ねていきます。

.textlintrcの中身を書く

最初に作った隠しファイルは、使うルールを指定するための設定ファイルです。
その中にymlファイルのパスを引いて、「これを使います」と指示しましょう。

{
  "rules": {
    "prh": {
      "rulePaths": ["rule/jisho.yml"]
    }
  }
}

(コピペでOKです)

アプリ側での設定

ここまで、作業用フォルダとその中身を用意しました。

jisho
 └ rule - jisho.yml
 └ .textlintrc

このようなファイル構成になっているかと思います。
このjishoフォルダを、textlintアプリで開いてみます。
スクリーンショット 2020-07-07 13.13.58.png
Working directoryの入力欄に、jishoフォルダのパスを書きます。
Windowsだと、フォルダを開けば上の方にパスが表示されるので、それをコピーして貼り付ければOKです。
スクリーンショット 2020-07-07 13.16.35.png
パスを書いてLoadを押すと、中に入っている.textlintrcの中身が下に出てきます。この状態で下の方にあるinstallsaveを押しましょう。

すると、アプリに内蔵されているnpmによってプリセットがインストールされ、アプリでprhが使えるようになります。

試しにエディタに戻って、間違い表現を入力してみましょう。
(最初に書いてあるガイド文は消して大丈夫です)
スクリーンショット 2020-07-07 13.28.51.png
右のカラムに『正規表現はこっちですよ?』という指摘が出ました。
間違いの数だけこの指摘が表示されます。

Fix all errorsと書かれた白いところを押せば、一括で正しい方に修正されます。
スクリーンショット 2020-07-07 13.29.02.png
何個あってもワンクリックです。とても便利!
ただ逆にいうと一括での修正しかできないので、「ここだけは例外的に直さない」という使い方はできません。
日本語的に変な箇所がないかどうか注意しましょう。

(アプリ版ではなくCLIで導入してVSCode上で使う場合なら、そういう融通も利かせられます。環境構築が難しいですがよろしければそちらも挑戦してみてください。)

その他のルール

prhは表記揺れを直すだけですが、他のルールを使えば

・一文で「、」は4つまで
・「かもしれない」などの弱い表現は禁止する

などの校正ルールを追加することもできます!

ルールの自作・カスタマイズができるのもtextlintの魅力ですが、そちらはプログラミング初学者にはけっこうハードルが高いようなので、筆者はまだチャレンジしていません。
おもしろそうなのでJavaScriptに慣れてきたらいずれ…

他にもいろんな方のルールがGitHub上で公開されているので、是非探してみてください。

typeScriptにWebpackを使用する

$
0
0

※あくまで個人の学習ノートなので参考程度に

1.package.jsonを追加

npm init -y

package.jsonが作成される

2.webpackインストール

npm install --save-dev webpack webpack-cli

node_moduleのフォルダとpackage-lock.jsonが作成される。

※作成されるnode_moduleはgitにpushしない

3.webpack.config.jsをディレクトリに追加

webpack.config.jsはwebpackの設定ファイル

webpack.config.js
constpath=require('path');//requireimportと同じ扱いでpathnodejsがもっているモジュールmodule.exports={entry: './dist/main.js',//一番最初に読み込ませるjsファイルoutput: {//生成したファイルをどこに格納するかを指定filename: 'bundle.js',//生成されるファイル名path: path.resolve(__dirname,dist),//生成されるファイルの格納ディレクトリ}}

4.bundle.jsを作成

npm run build

bundle.jsが作成される。

5.HTMLファイルの記述変更

jsファイルの読み込み先を先ほど作成したbundle.jsに変更
(bundle.jsに全てのjsファイルのコードがまとまっているため)

index.html
<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width, initial-scale=1.0"><metahttp-equiv="X-UA-Compatible"content="ie=edge"><title>Document</title>
  <link rel="stylesheet" href="style.css">
  <script src="dist/bundle.js" defer></script>
</head>

以上で終了。

-----------ここからはやってもやらなくても良い-------------

・sourceマップにjsファイルを表示したい場合

1.現在の状態だと以下のように検証ツール上にはbundle.jsしか表示されていない。
スクリーンショット 2020-07-07 14.32.57.png

2.webpackの設定ファイルにdevtool: 'inline-source-map'と追加する

webpack.config.js
constpath=require('path');module.exports={entry: './dist/main.js',output: {filename: 'bundle.js',path: path.resolve(__dirname,dist),},devtool: 'inline-source-map'//この行を追加
}

3.再度buildすると以下のように変わる
スクリーンショット 2020-07-07 14.39.24.png

typescriptから直接bundle.jsを作成する方法

$
0
0

本記事ではtypescriptから直接bundle.jsを作成する方法について書いていきます。

<今までのbundle.jsの作成方法>
1.tsファイルをコンパイルしてjsファイルを作成
2.jsファイルをbundleしbundle.jsを作成

この流れが面倒なので直接やってしまおう。

1.ts-loaderをインストールする

npm install --save-dev ts-loader typescript

2.webpackの設定ファイルに記述

webpack.config.jsにどのファイルにts-loaderを実行するかを記述する。

webpack.config.js
constpath=require('path');module.exports={entry: './src/main.ts',//最初に読み込ませるファイルもtsファイルに変更output: {filename: 'bundle.js',path: path.resolve(__dirname,'dist'),},devtool: 'inline-source-map',module: {rules: [{test: /\.ts$/,  //どういうファイルに対して
      use: 'ts-loader',  //何をするかexclude: /node_modules/  //このファイルは例外
    }]
  }
}

3.buildしてみる

1.以下のコマンド実行。
npm run build

あれ、エラーだけど、、、、
ERROR in ./src/main.ts
Module not found: Error: Can't resolve './foods.js' in '/Users/*****/*****/******/src'
@ ./src/main.ts 1:0-35 2:0-5

ここでのエラーで原因は、main.tsの中でjsファイルをインポートしようとしているため。

main.ts
import{Foods}from"./foods.js";Foods.getInstance();

そしたらfoods.tsに書き換えればいいんじゃない?
スクリーンショット 2020-07-07 15.23.58.png

それでもエラーが出てしまいます。

しかし、Webpackを使用する場合は拡張子は.tsで正解なんです!

でもエラーが出ているままって気持ち悪いですよね。。。

こうすることで解決できます!

1.importもとの拡張子を消しちゃいます。
スクリーンショット 2020-07-07 15.28.53.png
※このままだとbuild時にエラーになります

2.webpackの設定ファイルに以下を記述します。

webpack.config.js
constpath=require('path');module.exports={entry: './src/main.ts',output: {filename: 'bundle.js',path: path.resolve(__dirname,'dist'),},devtool: 'inline-source-map',module: {rules: [{test: /\.ts$/,use: 'ts-loader',exclude: /node_modules/}]}--------ここから--------------------resolve: {extensions: ['.ts','.js']}}

これを書くことで拡張子がなくてもOK。

この記述でインポートしようとした時に拡張子がなかったら左から調べてくれるようになります。

Webpackって本当に便利ですね。。。

3.再度buildしてみる

以下のコマンド実行。
npm run build

今回は無事にエラーなくbundle.jsが作成されましたね!!!

以上になります。

SiriっぽいTeamsアプリを作ってみる

$
0
0

はじめに

仕事にしても何にしても使えるものは使っておくに限る。
最近はリモートワークの影響でteamsを使い始めたので、これも使っておきたい。
どうせなら勤怠とかの自動化に使おうとも思ったが、敷居が高そうなので途中から計画変更してSiriにした。
だって、Siriっぽいもの作った事ありますって言っておけば何かしら仕事もらえるんじゃなかろうか。

結果

image.png
何も分からない俺のSiri

Teams API

TeamsにはTeamsに蓄えられた情報を扱うためのRest APIが用意されている。

これらのRestAPIを使ってタブやボットなどのアプリを作成する。
尚、APIで使用可能なリソースは下記種類がある。

リソースメソッド
team各自のチームの一覧表示、すべてのチームの一覧表示、作成、読み取り、更新、削除、複製、アーカイブ、アーカイブ解除
groupメンバーの追加、 メンバーの削除、所有者の追加、 所有者の削除、ファイルの取得、ノートブックの取得、プランの取得、予定表の取得
channel一覧表示、作成、読み取り、更新、削除
teamsTab一覧表示、作成、読み取り、更新、削除
teamsApp一覧表示、公開、更新、削除
teamsAppInstallation一覧表示、インストール、アップグレード、削除
chatMessage送信
call応答、拒否、リダイレクト、ミュート、ミュート解除、画面共有ロールの変更、参加者の一覧表示、参加者の招待
schedule作成または置換、取得、共有
schedulingGroup作成、一覧表示、取得、置換、削除
shift作成、一覧表示、取得、置換、削除
timeOff作成、一覧表示、取得、置換、削除
timeOffReason作成、一覧表示、取得、置換、削除

2020-06-27現在では.NET, JS, Pythonでサンプルが用意されている。

参考になるサンプルを探す

サンプルを眺めていると、nodejs配下に50.teams-messaging-extensions-searchなるジャストなものがある。
このサンプルはなにをするものかと言うと、アプリケーションコマンドにnodeのパッケージ名を入力すると詳細を教えてくれる。と言うもの。
アプリケーションコマンドが何かと言うと、

image.png
ココ

これを元にsiriを作っていきたい。まずはREADMEに沿って環境を整える。

必要なパッケージを入れる。

nodejsのサンプルなので、必要なのはnodejs。特にバージョンの指定がないのでstableで良いと思う。
自分の端末にはもともと入っていたので特に変えてない。

image.png

nodejs入れたらinstall

npm install

ngrokの導入

READMEを読むとngrokを利用するらしいので、早速本家から落としてインストールする。尚ngrokに関しては有志の強い方が記事を書いてくださっているので、そちらを参照してほしい。
この記事でngrokに関する有用な情報はない。だって今回初めて触った。

インストール方法はngrokに登録してソフトをダウンロードして展開するだけ。
展開したらexeが出てくるのでパス通す。特に困る事はないハズ。

公式サイトの指示通りngrokをアカウントに接続させたら完了。

image.png
とりあえずヘルプ出してみた

あとは実行するだけ

ngrok http -host-header=rewrite 3978

Azureの準備

teamsを使う以上、Azureを使う。で、Azureの準備。

Bot Framework registration resourceの手順通りに進める。
Azure Portalを開き、リソースを作成する。

image.png

botと打つとBot Channel Registrationの候補が現れるのでこれを選ぶ。(公式手順ではWeb App Botでもできるらしい)

image.png

一礼して作成

image.png

下記設定で作成ボタンをクリック。するとデプロイまで進んでくれる。Azure賢い。

項目設定値
ボットハンドルmiyatama-worksheet-hater
サブスクリプション従量課金(デフォルト)
リソースmiyatama-teams-learning(新規作成)
場所米国西部(かっこいいから)
価格レベルS1
メッセージングエンドポイント
ApplicationInsightオン
ApplicationInsightの場所East US
MicrosoftアプリIDとパスワード自動生成

で、しばらく放っておくと完了の通知が来る。

image.png
や っ た ぜ

すべてのリソースを開くと2つリソースが追加されている(botとApplication Insight)。Botの方をクリック。

image.png

image.png

設定をクリック

image.png

右側ペインを下にスクロースるとMicrosoft App IDの項目があるので、管理のリンクをクリック

image.png

新しいクライアントシークレットをクリック

image.png

説明を入力して追加をクリック

image.png

ちゃんと追加される。この時にキーをコピーしてファイルに保存しておく。大事な事なのでもう一回書いておく。
シークレットをコピーしてファイルに保存しておく

image.png
ちゃんと追加出来ててえらい。

Azureでteams使える様にする。

Azure Portalで発行したAppIDとパスワードを.envファイルに追記する。

項目設定値
MicrosoftAppId後述
MicrosoftAppPassword前述のシークレット発行時にコピーした文字列 

AppIDはbotの設定に記載されている

image.png

これで準備ができたので早速動かす。

npm start

teams用の設定を行う

teamsAppManifest/manifest.jsonを編集する。

  • idへMicrosoft App IDを設定
  • composeExtensions.botIdへMicrosoft App IDを設定

その後、teamsAppManifest内のファイルをZipに固める(ファイル名はmanifest.zip)。
大事な事なのでもう一度書こう。
teamsAppManifest内のファイルをZipに固める

image.png

teamsからカスタムアプリのアップロードを行う。アプリのアイコンをクリックし、ペインをスクロールするとカスタムアプリをアップロードの項目が出てくるのでクリック。

image.png

アップロードで先ほど作成したzipファイルを選択する。成功した場合はアプリが画面上に表示される。

image.png
アイコン変だけど気にしない

アプリをクリックして追加を行う

image.png

早速よびだす

image.png
だめでした。

これはなぜかと言うと下記図で言う所のAzureとngrokが連携できていないから。

flow.png

と言うわけでngrokで用意したendpointをAzureに教えてあげないといけない。
まずはココを参考にchannelを作成する。
次に、ngrokeのendpointをAzureに教える。ngrokのendpointはngrok http -host-header-rewrite 3978で実行した時の結果を参照してほしい。
万が一gitbashで実行してしまった場合はwinptyを使うなりコマンドプロンプトで実行するなりなんなりで対処してほしい。

image.png
上記例だとhttps://0a3496160a1a.ngrok.io/api/messages

Azure PortalからBotのリソースを開き、設定を表示する。すると、メッセージングのエンドポイントなる項目があるので、ここにngrokのendpointを張り付ける。

image.png

もう一回試す

image.png
や っ た ぜ

Siriっぽくする

サンプル実行できただけでもかなりお腹いっぱいなのだが、元来の目的であるSiriの作成に入る。
Siriと言えば、すみません。よくわかりません。だ。異論もあるだろうか、私のイメージではそうだ。

botのコードを見てもらうと分かる通り、検索した結果を返すだけだ。これをSiri化するのは簡単だ。
固定ですみません。よくわかりません。を返せばよいだけだ。

中の仕様がよく分からない方はここを見てほしい。めちゃくちゃ親切に書いてある。
書き変えた(?)後のコードは以下の通り。

constaxios=require('axios');const{TeamsActivityHandler,CardFactory}=require('botbuilder');classTeamsMessagingExtensionsSearchBotextendsTeamsActivityHandler{asynchandleTeamsMessagingExtensionQuery(context,query){constattachments=[];constheroCard=CardFactory.heroCard("result");constpreview=CardFactory.heroCard("すみません。よくわかりませんでした。");constattachment={...heroCard,preview};attachments.push(attachment);return{composeExtension:{type:'result',attachmentLayout:'list',attachments:attachments}};}}module.exports.TeamsMessagingExtensionsSearchBot=TeamsMessagingExtensionsSearchBot;

早速試す

image.png
や っ た ぜ

ふりかえり

冒頭にも記載した通り、最初は勤怠の自動化をやろうかと思って色んなサンプルを眺めたりしていた。
が、途中でめんどくさくなって、何でもいいからアウトプットしておく運びとなった。
まぁ、ここまでやっておけば後は自然言語処理でも賢さ演出するぐらい誰でもできるし、何とかなるだろう。
teamsの記事を何個か書く予定なので無駄にはならないハズだ。

何よりも、勉強の方法を議論する位なら勉強した方が早い。

SendGridでいい感じにメールの配信停止グループを管理する

$
0
0

個人で開発しているサービスにメールの配信基盤を整えようと思って色々調べていたので、その結果わかったことを備忘録としてまとめておきます。

メールの配信停止設定で最低限やっておきたいこと

メールの配信設定を行うにあたって、以下の項目が守られていることが個人的に望ましかったです。

  1. 簡単にメールを配信停止できること
  2. 自分のサービスとメール配信サービスでメールの配信停止設定を共有できること

1. 簡単にメールを配信停止できること

まず、送られるメールは簡単に配信停止できるようにすべきです。配信停止のベストプラクティスと、SendGrid の便利な機能にも以下のように書かれています。

  1. 簡単に配信停止できるようにする

配信停止の手順が簡単であればあるほど、受信者と送信者、双方にとってメリットがあります。配信停止のボタンやリンクをどこに置くか決める時、隠すように配置してはいけません。また、リンクがきちんと機能するか複数回チェックしましょう。リンクをフッタに配置するケースをよく見かけますが、どこに配置したとしても、見つけやすくわかりやすくする必要があります。

サービス運営側としては宣伝のためメールを送りたいと思うので、できればメールの配信を続けたいかと思いますが、そのあまり配信停止の設定が不便だとユーザーからの信用を損ないますし、UX も悪いです。

2. 自分のサービスとメール配信サービスでメールの配信停止設定を共有できること

SendGrid にて、メールの配信停止を行う手順は メールの種類ごとに配信停止を管理する - ドキュメント | SendGridにもあるように、わりと簡単に行えそうでした。

しかし、実際にメールの配信設定を管理する際は、自分で作っているサービス側でもメールの配信設定ができる必要があります。

例えば、SendGrid 側でメールの配信を停止した場合、自分で作っているサービス側のメール配信設定もオフになっているべきです。この実装をどのようにすればよいか、あまりメール配信に慣れていない自分は調べるのに苦労しました。

メールの配信停止設定を管理する方法

いろいろ試した結果、SendGrid の Suppressionsの API を利用すると、やりたいことが実現できそうでした。

SendGrid ではメールの配信停止グループを設定できるのですが、こちらの API を使うことで特定のメールアドレスと配信停止グループに対して

  • メールの配信設定の取得
  • メールの配信停止
  • メールの配信停止の取り消し

ができます。

あとは、自分のサービス上でこの API を呼び出してあげれば良いです。自分は Node.js を使っていたので、sendgrid/sendgrid-nodejsでのコードを参考までに載せておきます。

メールの配信設定の取得
importclientfrom"@sendgrid/client";importRequestOptionsfrom"@sendgrid/helpers/classes/request";client.setApiKey("SG.xxxxx.yyyyy");(async()=>{constrequest={}asRequestOptions;constemail="example@gmail.com";request.method="GET";request.url=`/v3/asm/suppressions/${email}`;const[response]=awaitclient.request(request);console.log(response.body);})();
メールの配信停止
importclientfrom"@sendgrid/client";importRequestOptionsfrom"@sendgrid/helpers/classes/request";client.setApiKey("SG.xxxxx.yyyyy");(async()=>{constrequest={}asRequestOptions;constemail="example@gmail.com";constgroupId=12345;constdata={recipient_emails:[email]};request.body=data;request.method="POST";request.url=`/v3/asm/groups/${groupId}/suppressions`;const[response]=awaitclient.request(request);console.log(response.body);})();
メールの配信停止の取り消し
importclientfrom"@sendgrid/client";importRequestOptionsfrom"@sendgrid/helpers/classes/request";client.setApiKey("SG.xxxxx.yyyyy");(async()=>{constrequest={}asRequestOptions;constemail="example@gmail.com";constgroupId=12345;request.method="DELETE";request.url=`/v3/asm/groups/${groupId}/suppressions/${email}`;const[response]=awaitclient.request(request);console.log(response.body);})();

ちなみに、余談ですがメールの送信も以下のような感じでできます。

importsendgridfrom"@sendgrid/mail";sendgrid.setApiKey("SG.xxxxx.yyyyy");constmsg={to:"example@gmail.com",from:"no-reply@example.com",subject:"Sending with Twilio SendGrid is Fun",html:`
    <html>
        <body>
            ここが本文です<br />
            <a href="<%asm_preferences_raw_url%>">配信停止を管理する</a><br />
        </body>
    </html>`,asm:{groupId:12345}};(async()=>{try{awaitsendgrid.send(msg);}catch(error){console.error(error);if(error.response){console.error(error.response.body);}}})();

これにより、自分のサービスの設定画面からメールの受信・停止設定を行うことができますし、送信したメールの「メール配信停止」リンクからメールの配信を停止した際も、自分のサービス側で設定を同期できます。

おわりに

今回は SendGrid を利用しましたが、似たような API があるサービスであれば今回実現したかったことは実装できるかと思います。

ただ自分はあまりこの手のサービスを知らないので、もしおすすめのサービスをご存じの方がいらっしゃれば、ぜひコメント欄にて教えていただけますと嬉しいです!😄


というわけで、この記事で書いた内容をもとにメールの配信機能を実装してみました!

メール通知機能を追加しました!|AnyMake|note

もしよろしければ、AnyMakeもチェックしてみてください👍


csv-parser モジュールでCSV文字列を処理したい場合の方法

$
0
0

csv-parser で CSV文字列をパースする。

https://www.npmjs.com/package/csv-parser

上のモジュールで単純なCSV文字列をパースしたい場合はリーダブルストリームを
一旦生成することで csv-parserのインターフェイスを合わせる事ができる。
(もっと簡単な方法がありそう

importcsvParserfrom"csv-parser"import{Readable}from"stream"//CSVが格納された文字列constcsvString=`col1,col2,col3
row1,row2,row3
row1,row2,row3`// Readable Stream を作成constreadable=newReadable({read:(size)=>{//この処理の記述の必要性が実は良く分からないreturntrue}})readable.on("data",(chunk)=>{//parse されたデータconsole.log(chunk)}).on("err",(err)=>{//error 時の処理}).on("end",()=>{//終了時の処理}).write(csvString,(err)=>{//CSV文字列をストリームに書き込む//close イベントを emit するreadable.emit("end")})

Promiseが必要であれば end コールバックでResolveすれば多分OK。

GitHub Pagesを使った自前無料ブログの作り方(Hexo)

$
0
0

本文の前に

この記事はまどれーぬさんの公開された記事ゼロからわかる!GitHub Pagesを使った自前無料ブログの作り方(Jekyll)からインスパイアを受けています。ぜひ読んでみてください。とてもわかり易くまとまっています。

※今回の記事はLinux(Ubuntu)で操作を行っています。それ以外のOSをお使いの方は少しやり方が異なる場合があります。ご了承ください。

この記事でわかること

  • HexoというNode.js.製の静的サイトジェネレーターを使ったサイトの制作方法

  • Github Pagesでの公開方法

余談と事前準備

余談ですがなぜJekyllではなくHexoを使うのかについてです。理由は唯一つ

私がRubyを使ったことがなくJSのほうが使いやすかったから

これだけです(笑)

はい、では事前に準備するものです

  • PC(今回はLinuxを使用しています)
  • GitHubアカウント
  • テキストエディタ(今回はVSCodeを使用しています。)

環境構築

ではまずNode.jsとHexoの環境構築をしていきましょう。

まずはNode.jsです。こちらの記事を参考にしてみてください。

そして次はYarnというパッケージ管理システムをインストールしていきます。
コンソールに

curl -o- -L https://yarnpkg.com/install.sh | bash

と入力してください。

最後の方に export PATH~という文字列があるのでそれをコピーして実行してください。そうするとPATHが通り、yarnを使用することができるようになります。

次に今回の目的であるHexoをインストールしていきます。

コンソールに

yarn global add hexo-cli

と打ち込んでください。

ディレクトリを作成します。

hexo init {ファイル名}

作成されたディレクトリに移動して、モジュールをインストールします

cd {ファイル名}
yarn install

サーバーを起動します。

hexo server

http://localhost:4000/にアクセスするとページが表示されます。

ここまでできれば環境構築は完了です。

初期設定

ブログの詳細な設定は_config.ymlで行います。
yaml_hexo.jpg
ここではブログタイトルや言語、URLの設定などを行います。テーマ設定やGitへのデプロイ設定などもここで行います。

テーマ選びと設定

では、今度は好きなテーマを設定してみましょう。今回はicarusというテーマを設定していきます。テーマに関してはこちらにまとまっています。

ほとんどのテーマには独自の設定項目が存在するためHexoと別に管理する必要があります。そのためにgitsubmoduleという機能を使用します。

まずは既存のテーマをForkしていきましょう。

icarus-fork.jpg

icarusテーマのGithubページです。こちらの右上にForkというボタンがあるのでクリックしてください。そうするとリポジトリをForkすることができます。Forkが完了するとページが切り替わると思います。自身のForkができたら再びLinuxのコンソールに戻り、作成したディレクトリに移動します。そして

git submodule add {フォークしたリポジトリのURL} themes/{テーマ名}

を入力します。そうするとtheme/{テーマ名}にフォークしたリポジトリが追加されます。

Hexoのテーマ設定を行う

作成したディレクトリの_config.ymlに設定を行っていきます。私の場合テーマ名をtheme-icarusにしたので

theme:theme-icarus

と設定をしました。

テーマの詳細設定

では今度はテーマの詳細設定を行っていきます。theme/{テーマ名}の_config.ymlに設定を書いていきます。
少し長いのでGithubのURLを貼っておきます_config.yml

記事を書く

さぁではお待ちかね記事を書いていきましょう!と、その前に少し設定をしなければなりません。
Hexoのルートディレクトリの_config.ymlpost_asset_folderという設定をtrueにします。
これをしないと記事内に画像を埋め込むのが面倒になります。
次に記事を管理するフォルダを作っていきます。

hexo new {記事の名前}

これで記事の画像などの管理フォルダと記事のmarkdownファイルが作成されます。

markdownファイルはこんな感じです。
md_hexo.jpg
では細かいところを説明していきます。
一番上の部分

---
title: タイマーアプリを作ってみた
date: 2020-03-26
tags:
---

この部分は記事のタイトル、更新日時、タグなどの概要を設定する部分です。
この部分はレイアウトとしてhexo newを打ったときに同時に生成されます。
そして重要なポイント<!--more-->というタグについて説明します。
このタグはHexo独自のタグであり、これを設定しないと記事一覧ページで全文が表示されてしまいます。
moreタグあり
timer-more.png

moreタグなし
timer-no-more.png

このようになってしまうのでmoreタグはとりあえず付けておきましょう。(中にはmoreタグに対応していないテーマもあるのでmoreタグに対応しているかもテーマを選ぶ基準にするといいと思います。)

GitHub Pagesを使って全世界に公開

Gitへのデプロイ設定

こちらの記事にとても良くまとまっているのでご覧ください。

終わりに

お疲れさまでした!これでブログを作って公開する環境を整えることができましたね!
これからは記事を書いたら

hexo deploy

で公開することができます。

AWS Lambda、API Gateway、SESを使用し、S3静的ウェブサイトの動的な連絡フォームを作りましょう!💪

$
0
0

AWS S3にサイトを安くて簡単にホスティングできますが、S3は静的なサイトしかホスティングできないですので、従来ならバックエンド処理が必要となるフォーム送信の実装などは難しそうですね。しかし、クラウド時代ではそんな心配はありません!ソリューションはサーバーレスアーキテクチャです!AWSはすでに色々なサーバーレス構築のツールを提供しています。

今回はユーザからお問い合わせやフィードバックを送信するたびに、任意な宛先に通知メールを送信するシンプルなサーバーレスメールサービスを一緒に作ります。AWS LambdaとAPI Gatewayを利用し、簡単なAWSサーバーレス構築を紹介します。

構成図はこんな感じです。
diagram.PNG

処理の流れとしては、ユーザーから連絡フォームより入力した情報を収集し、クライアント側のブラウザからAmazon API Gateway RESTfulサービスに投稿します。Amazon API Gatewayは、収集されたユーザー情報をAWS lambda関数に渡します。AWS Lambda関数は、Eメールを自動生成し、Amazon SESを使用してメールサーバーに転送します。

1.フォームを作成

  • index.htmlファイルを作成し、下記のコードを貼り付けます。
index.html
<!DOCTYPE html><htmllang="en"><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width, initial-scale=1.0"><title>連絡フォーム</title><script src="script.js"></script><linkrel="stylesheet "href="style.css "><script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js "></script></head><body><h1>連絡フォーム</h1><formid="contact-form"method="post"><h4>名前:</h4><inputtype="text"id="name-input"placeholder="お名前を入力してください。"class="form-control"/><br/><h4>件名:</h4><inputtype="subject "id="subject ""placeholder="お名前を入力してください。 "class="form-control "/><br/><h4>メール:</h4><inputtype="email "id="email-input "placeholder="メールを入力してください。 "class="form-control "/><br/><h4>メッセージ:</h4><textareaid="description-input "rows="3 "placeholder="メッセージを入力してください。 "class="form-control "></textarea><br/><divclass="button-wrapper "><buttontype="button "onClick="submitToAPI(event) "class="btn btn-lg ">送信</button></div></form></body></html>

ブラウザでプレビューを確認できます。こんな感じです。
basic-html-form.PNG

  • 見た目はあまり良くないですので、改善しましょう。style.cssを同じフォルダ内で作成し、下記のコードを貼り付けます。
style.css
*{box-sizing:border-box;}body{text-align:center;color:rgb(255,255,255);background-color:#194680;padding-top:20px;}#contact-form{margin:auto;text-align:left;padding:20px;max-width:430px;border:whitesolid2px;border-radius:10px;}button{text-align:center;margin-top:20px;font-size:18px;border:whitesolid2px;background-color:white;border-radius:5px;}.button-wrapper{text-align:center;}input,textarea{width:380px;}textarea{height:200px;padding:10px;}input{height:35px;}

ブラウザではこんな感じになります。
styled-form.PNG

2. AWS Lambda関数の定義

  • AWS Lambda画面で新規関数を作成し、hello-worldのnodejsテンプレを選択します。
    lambda2.PNG

  • 基本的な情報の画面では関数を任意に名付けて、実行ロールは最初選択のままで進みます。
    lambda3.PNG

  • 次の画面の関数コードに下記のコードを切り替えます。

index.js
varAWS=require('aws-sdk');varses=newAWS.SES();//宛先のメールアドレスを入力してください。varRECEIVER='example-receiver@gmail.com';//送信先のメールアドレスを入力してください。//送信先のメールはAWSに認証登録する必要があります。varSENDER='example-sender@gmail.com';//クライアントへのレスポンスヘッダーを設定varresponse={"isBase64Encoded":false,"headers":{"Content-Type":'application/json',"Access-Control-Allow-Headers":"Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token,Accept","Access-Control-Allow-Methods":"POST,GET,OPTIONS","Access-Control-Allow-Origin":"*",},"statusCode":200,"body":"{\"result\": \"テスト成功です!\"}"};exports.handler=function(event,context,callback){console.log('受理したイベント:',event);sendEmail(event,function(err,data){context.done(err,null);});callback(null,response);};//メール送信処理functionsendEmail(event,done){varparams={Destination:{ToAddresses:[RECEIVER]},Message:{Body:{Text:{Data:'● お名前: '+event.name+'\n● 件名: '+event.subject+'\n● メール: \n'+event.email+'\n● 内容: \n'+event.desc,Charset:'UTF-8'}},Subject:{Data:event.name+'からの連絡フォームが来ました!',Charset:'UTF-8'}},Source:SENDER};ses.sendEmail(params,done);return{response,body:JSON.stringify(params),statusCode:200}}
  • 同じLambda管理画面で、上にスクロールし、アクセス権限のタブに切り替え、ロール名のリンクをクリックします。

lambda-policy.PNG

  • 当関数のIAMポリシーをSES権限を追加します。IAM画面で該当ポリシーをクリックしポリシーを編集 ->JSONのフォーマットに切り替えし、下記のコードを追加します。

lambda-policy3.PNG

{
  "Sid": "FormPolicy",
  "Effect": "Allow",
  "Action": "ses:SendEmail",
  "Resource": "*"
}

こんな感じです。
lambda-policy2.PNG

3. APIゲートウェイでAPI構築

  • AWSメインコンソールよりAPI Gateway管理画面にアクセスし、APIを作成をクリックします。
    api.PNG

  • 次の画面ではREST API構築をクリックします。

api2.PNG

  • 次の画面はREST APIの選択のままで、API名前を任意に付けます。

api2a.PNG

  • 次の画面は上にあるアクションをクリックし、メッソド作成をクリック、POSTを選択します。

api3.PNG

  • 右側の設定画面では、統合タイプLambdaで、Lambda関数は先ほど作成したものを選択します。

api4b.PNG

  • CORSエラーにならないように、CORS機能も有効にします。アクションのドロップダウンをCORS有効化をクリックし、設定はそのままで保存します。

api4c.PNG

  • API Gatewayの最新アップデートでは、ゲートウェイのレスポンスも設定しないと、CORSエラーが発生するため、設定しましょう。右のゲートウェイレスポンス→ DEFAULT 4XX編集の順番にナビゲートします

api5a.PNG

  • レスポンスヘッダーに下記の値を追加し、保存します。
  Access-Control-Allow-Origin: '*'

こんな感じです。
api5b.PNG

これでAPIの構築は完了です。

4. SES送信用のメール検証登録

mail.PNG

verifiedの状態になったら、OKです!

5.全コンポーネントを連携する

  • 最後のステップではすべてを繋ぎます!index.htmlと同じいフォルダでscript.jsを作成し、下記のコードを貼り付け、var URLurlの2ヶ所に先ほど設定したAPI GatewayのエンドポイントURLを差し替えます。
script.js
functionsubmitToAPI(e){e.preventDefault();//設定したAPI GatewayのエンドポイントURLをここに入れます。varURL="API-GATEWAY-ENDPOINT-URL";//フォームの入力値をチェックvarname=/[A-Za-z]{1}[A-Za-z]/;if(!name.test($("#name-input").val())){alert("2文字以上記入してください。");return;}varsubject=/[A-Za-z]{1}[A-Za-z]/;if(!subject.test($("#subject").val())){alert("2文字以上記入してください。");return;}if($("#email-input").val()==""){alert("メールを入力してください。");return;}varemail=/^([\w-\.]+@([\w-]+\.)+[\w-]{2,6})?$/;if(!email.test($("#email-input").val())){alert("メールアドレスは正しくありません。");return;}varname=$("#name-input").val();varsubject=$("#subject").val();varemail=$("#email-input").val();vardesc=$("#description-input").val();vardata={name:name,subject:subject,email:email,desc:desc};$.ajax({type:"POST",//設定したAPI GatewayのエンドポイントURLをここに入れます。url:"API-GATEWAY-ENDPOINT-URL",dataType:"json",crossDomain:"true",contentType:"application/json; charset=utf-8",data:JSON.stringify(data),success:function(){// フォームをクリアし、送信成功のメッセージを表示するalert("メッセージが送信されました!");document.getElementById("contact-form").reset();location.reload();},error:function(){// 送信エラーのメッセージを表示するalert("メッセージ送信失敗!");}});}

6. 結論

フォームより受信するメールはこんな感じです。
demo.PNG

これでAmazon S3で静的Webサイトをホストしても、AWSアーキテクチャを利用し、ユーザよりサイト管理者へフォーム送信機能を実装できました!

初投稿です、、いかがでしょうか(´・ω・`)
コメント、フィードバックなど是非よろしくお願いいたします!
それでは、また今度! (`・∀・´)ノ

Node.jsで動くオンライン対戦リバーシを作ってみた

$
0
0

ソース

https://github.com/inari2019/osero
正直かなり醜いコードだと思ってます。

実際に作ったもの

http://pocketmikan.ml:3000/
※予期なくリンクが変わったり、封鎖している可能性があります。

環境

バックエンド:Node.js(Express.js)
ソケット通信:socket.io
フロントエンド:javascript
描画:HTML5 Canvas

構成

無題の図形描画 (1).jpg

コードの解説

大体のことはgithubのコードに書いてるので割愛

実行の流れとしては
プレイヤーから駒を置く場所を受け取る(index,js)

駒を置けるか確認したのち駒を置く(modules/gameclass.jsのput関数)

置いた後の盤面データなどをプレイヤーに送信(index.js)

リバーシのアルゴリズム

https://techacademy.jp/magazine/22767
まんまこれですすみませんでした

終わりに

自分でもわかるぐらいひどいコードです。改善の余地しかありませんが、テストがあるので改善出来てません。

$ npm run watch しようとしたら Sorry, there's a problem with nodist. Couldn't resolve node version ~~~と出たときの対処法

$
0
0

課題

$ npm run watch

しようとしたら
Sorry, there's a problem with nodist. Couldn't resolve node version spec %s: %s 4.5.0 Couldn't find any matching version
と怒られた。

なんでだろうと調べたりいろいろ試したりしましたが小1時間ほどハマり心優しい同僚に助けてもらったので覚書しておきます。

対処法

1. nodeのバージョンを確認する

node -v
v0.0.0

2. .node-version(node-dev-env.node-version)を開いて記載されているバージョンを確認する

私の場合「v11.13.0」と記載されていました。
このバージョンとnode-v したときのバージョンを合わせてやります。

3. 今適用されているnode.jsのバージョンを確認

$ nodist
  (x64)
> 4.5.0  (C:\xampp\htdocs\hogehoge.jp\node-dev-env\.node-version: v4.5.0)
  10.15.1  (global: 10.15.1)
  11.0.0
  11.13.0

つまり現在のnode.jsのバージョンが4.5.0になってしまっている。(私の場合11.13.0も一応存在はしました)

4. v11.13.0がなければインストール

$ nodist + v11.13.0

5. v11.13.0がインストール済になったので切り替える

$ nodist v11.13.0
v11.13.0
v11.13.0 (global)

6. node.jsのバージョンが切り替わったか確認しましょ

$ node -v
v11.13.0

これで切り替え完了!

7. 頼む、動いてくれ!

$ npm run watch

8. それでも動かなかったとき

魔法の呪文
(使用中の node にあったバージョンの npm をインストールしてくれます)

$ nodist npm match

9. それでもまだ動かなかったとき

おまじない
(npm config スクリプトの設定でパスを先頭に追加)

$ npm config set scripts-prepend-node-path true

からの

npm config list

; userconfig C:\Users\minami-inayama\.npmrc
scripts-prepend-node-path = true

が追加されていることを確認します。
そして

nmp run watch

終わり

ここまでの手順でわたしは動きました。

参考:

nodist 環境下で npm script 使用時にエラー – blog
https://www.namu-ws.com/blog/dev/nodist-npm-script-error

npm がどうしてもエラーになってしまったら - Qiita
https://qiita.com/tana08/items/d50212a1919308cc1480

Laravel-Mixコンパイル時のcode ELIFECYCLEエラーに対応する - Qiita
https://qiita.com/ishizukih/items/9673e709832dacaa5155

nodistでnode.jsのバージョン管理をする | IT王子の技術ブログ
https://www.it-ouji.com/2019/10/26/nodist%E3%81%A7node-js%E3%81%AE%E3%83%90%E3%83%BC%E3%82%B8%E3%83%A7%E3%83%B3%E7%AE%A1%E7%90%86%E3%82%92%E3%81%99%E3%82%8B/

Macにnodebrewでnodeをインストールするまでにしたこと

$
0
0

Macにnodebrewnodeをインストールしようとおもったところ、nodebrewでインストールしたnodeのバージョンとnode -vのバージョンが合っていなかったので、解決した方法を備忘録として残します。

npm、node、nodebrewをアンインストールする

まずはnpmnodenodebrewをインストールしているかを確認します。

ターミナル
$ npm -v
$ node -v
$ nodebrew -v

コマンドでバージョンが確認できない場合はインストールの段階に進みましょう。

バージョンが確認できた場合はアンインストールします。

npmをアンインストールする

まずnpmをアンインストールします。

次のコマンドを順番に実行してください。

ターミナル
$ npm uninstall -f npm
$ rm -rf .npm \
> node_modules

npm -vで確認してバージョンが表示されなければ成功です。

nodeをアンインストールする

nodeをアンインストールします。
nodeをインストールした方法でアンインストールの方法が違います。

よくわからない場合は全て実行してください。

パッケージ版

homebrewでインストールした場合のアンインストール方法

ターミナル
$ brew uninstall node

その他でインストールした場合のアンインストール方法

次のコマンドを順番に実行してください。

ターミナル
$ lsbom -f -l -s -pf /var/db/receipts/org.nodejs.node.pkg.bom \
> | while read i; do
> sudo rm /usr/local/${i}
> done
$ sudo rm -rf /usr/local/lib/node \
>     /usr/local/lib/node_modules \
>     /var/db/receipts/org.nodejs.*

ソース版

which nodeで確認したコードをrm -rfで削除してください。
必ずしも/usr/local/bin/nodeとは限りません。

ターミナル
$ which node
/usr/local/bin/node
$ rm -rf /usr/local/bin/node \
> node_modules

アンインストール後

アンインストール後にnode -vで確認して、バージョンが表示されなければ成功です。

nodebrewをアンインストールする

nodebrewをアンインストールする方法は二つあります。
最初の方法でアンインストールできると思いますが、できなかった場合は次の方法も実行してみてください。

以下がnodebrewをアンインストールするコマンドです。

ターミナル
$ brew uninstall nodebrew

このコマンドを実行した後nodebrew -vでバージョン確認をしましょう。
バージョンが表示されなければ成功です。

この方法でアンインストールができなかった場合は次の方法を試してみてください。

ターミナル
$ brew search nodebrew

このコマンドでnodebrewというディレクトリがあるかを確認します。
あった場合は次を実行してnodebrewのある場所を確認します。

ターミナル
$ brew info nodebrew

場所が確認できた場合はFinderからそこの場所に移動して、nodebrewを直接ゴミ箱に捨ててください。

これでnpmnodenodebrewのアンインストールが終了しました。

nodeのインストール

アンインストールが終了したら、nodeをインストールしていきます。

nodebrewのインストール、環境変数の設定

次のコマンドを順番に実行してください。

ターミナル
$ curl -L git.io/nodebrew | perl - setup
$ export PATH=$HOME/.nodebrew/current/bin:$PATH

nodeのインストール

次にnodeのインストールをします。
インストールするバージョンは最新版にします。

ターミナル
$ nodebrew install-binary latest

インストールしたバージョンの確認

インストールしたバージョンを確認します。

ターミナル
$ nodebrew ls
v14.5.0

current: node

current: nodeとありますが、ここには現在使用しているバージョンが表示されます。
この状態だとまだ使用することができないのでバージョンを設定します。

バージョンの設定

使用するバージョンを設定します。
今回はv14.5.0というバージョンを設定します。

ターミナル
$ nodebrew use v14.5.0

これでバージョンが設定できました。

ターミナル
$ nodebrew ls
v14.5.0

current: v14.5.0

確認すると設定できています。

動作確認

最後にnodeが動作しているか確認しましょう。

ターミナル
$ node -v
v14.5.0

設定したバージョンが表示されれば成功です。

参考サイト

外部サイト

Qiita

Macにnode.js,npmのインストール

$
0
0

node.js,npmのインストールの流れ

① Homebrewのインストール
② nodebrewのインストール
③ node.jsのインストール
上記の手順で行います。
node.jsがインストールされれば、同時にnpmもインストールされます。

Homebrewのインストール

terminalコマンド
$/usr/bin/ruby-e"$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

nodebrewのインストール

terminalコマンド
$brewinstallnodebrew

nodebrewのバージョンの確認

バージョンを確認することで、インストールがうまく行っているのかを確認できる。

terminalコマンド
$nodebrew-v

node.jsのインストール

terminalコマンド
$nodebrewinstall-binarylatest

インストールされたnode.jsのバージョンを確認する。

terminalコマンド
$nodebrewlist

上記を入力すると、下記のようなログが出力される。

出力ログ
v12.14.1current: v12.14.1

currentの部分が、現在動いているnode.jsです。
次のように出力された場合には、node.jsが有効になっていません。

出力ログ
current: none

有効化するためには、インストール済みのバージョンをuseコマンドで有効化します。

terminalコマンド
$nodebrewusev12.14.

node.jsがインストールされれば、npmも同時にインストールされます。


Node.jsで複数ファイルを送るには

$
0
0

こんにちは、wattak777です。

一つだけファイルを送信する、というサンプルは幾つかあるのですが、複数ファイルの場合のサンプルをちょっと作ってみました。

サーバー側はmulterを使った以下のサンプル。

server.js
varexpress=require('express');varapp=express();varmulter=require('multer');app.post('/file_upload',multer({dest:ファイルを置くパス}).single('my_file'),function(req,res){console.log(req.file.path,req.file.originalname);res.sendStatus(200);});varserver=app.listen(12345,function(){console.log("listening at port %s",server.address().port);});

で、本題のクライアント側は以下の実装。
request-promiseを使って同期的に送るようにしました。

client.js
constfs=require('fs');constrequest=require('request-promise');constFileNameList=['test1.bin','test2.bin','test3.bin'];varFileNameIndex=0;varreturnCode=httpPost();functionhttpPost(){constFormData={my_file:{value:fs.createReadStream(ファイルのパス+FileNameList[FileNameIndex]),options:{filename:FileNameList[FileNameIndex],contentType:'application/octet-stream'}}}constoptions={uri:"http://サーバーのIPアドレス:12345/file_upload",formData:FormData,method:'post',headers:{'Content-Type':'multipart/form-data'}}varresponse=request(options).then(function(body){console.log('then :'+body);onEnd();}).catch(function(err){console.log('catch error :'+err);});returnresponse.statusCode;}functiononEnd(){console.log('Index '+FileNameIndex+' is finish.');FileNameIndex=FileNameIndex+1;if(FileNameIndex>=FileNameList.length){console.log('End Operation.');}else{varres=httpPost();}}console.log('Start Operation.');

とやると、クライアント側の表示は以下のようになります。

$ node client.js
Start Operation.
then :OK
Index 0 is finish.
then :OK
Index 1 is finish.
then :OK
Index 2 is finish.
End Operation.

nodemailerでGmailのエイリアスのアドレスから送信できるようにする

$
0
0

以下ページの転載になります。ご了承ください。

nodemailerでGmailのエイリアスのアドレスから送信できるようにする - Yuto Hongo Portfolio


2020/07 時点での記事となります。

G Suite前提での手順となってしまいますが、参考になればと思います。


[ひとことでいうとこんな記事]

nodemailerからメール送信する際、自分の所持しているメルアドを利用せずにエイリアス(Info@, sales@ 等)のアドレスからの送信が可能です!


[こんな人におすすめ]

  • メディアを作ることになったが、お問い合わせの自動返信機能で個人アドレスを使うわけにはいかない人

[目次]

  • 参考記事
  • 手順1. Google OAuth 2.0 設定
  • 手順2. G Suite で エイリアスアドレスの追加
  • 手順3. Gmail で エイリアスアドレスの追加・デフォルト設定
  • 手順4. nodemailerでメール送信スクリプトを作成
  • まとめ

参考記事

参考にさせていただいた記事です。ありがとうございます。

node.js 上の nodemailer で OAuth 2.0 を使って gmail からメールを送る

そして、nodemailerでのエイリアスアドレスでの送信に関してはstackoverflowのコメント欄を参考に設定をいたしました

Nodemailer send emails using original user account instead of alias

手順1. Google OAuth 2.0 設定

1-1 Google APIs でプロジェクト作成

  1. Google APIsページで、「プロジェクトを作成」をクリック。(もしくは、プロジェクト選択タブをクリックし「新しいプロジェクト」をクリック)
  2. 「プロジェクト名」を入力し、「作成」をクリック。

nodemailer-send-emails-using-alias-address-for-gmail.001

1-2 OAuth 同意画面 の設定

  1. 「OAuth 同意画面」をクリック
  2. 「アプリケーション名」を入力
  3. 「保存」をクリック

nodemailer-send-emails-using-alias-address-for-gmail.002

1-3 OAuth 2.0 クライアントIDの作成

  1. 「認証情報」をクリック
  2. 「認証情報を作成」をクリックし、「OAuth クライアント ID」を選択
  3. 「アプリケーションの種類」で「Webアプリケーション」を選択し、「名前」を入力

nodemailer-send-emails-using-alias-address-for-gmail.003

クライアントIDクライアントシークレットが表示されるので、保存しておく。

nodemailer-send-emails-using-alias-address-for-gmail.004

1-4 Gogle Developers OAuth 2.0 Playground で Reflesh Token の取得

  1. Google Developers OAuth 2.0 Playgroundページを開く
  2. 右上の「⚙歯車ボタン」をクリックする
  3. 以下のような情報を入力する

nodemailer-send-emails-using-alias-address-for-gmail.005

項目
OAuth flowServer-side
OAuth endpointsGoogle
Authorization endpointそのまま (https://accounts.google.com/o/oauth2/v2/auth)
Token endpointそのまま (https://oauth2.googleapis.com/token)
Access token locationAuthorization header w/ Bearer prefix
Access typeOffline
Force approval promptNo
Use your own OAuth credentialsチェックボックスをクリック
OAuth Client IDさきほど取得した クライアントID
OAuth Client secretさきほど取得した クライアントシークレット
  1. 「Step 1」を選択
  2. 「Input your own scopes」に「 https://mail.google.com/」を入力し「Authorize APIs」を押す
  3. 「Google OAuth 2.0 Playground に移動」と表示されるので、対象のGoogleアカウントを選択
  4. 「Google OAuth 2.0 Playground が Google アカウントへのアクセスをリクエストしています」と表示されるので「許可」を選択
    nodemailer-send-emails-using-alias-address-for-gmail.006

  5. 「Step 2」に進んだら「Exchange authorization code for tokens」を押す

  6. Reflesh tokenが表示されるので、保存しておく
    nodemailer-send-emails-using-alias-address-for-gmail.007

手順2. G Suite で エイリアスアドレスの追加

2-1 Google管理コンソール

  1. Google Adminにアクセスし、「ユーザー」をクリック

2-2 ユーザーに紐づくエイリアスアドレスを作成

  1. 先程手順1を行ったGmailアカウントをクリック
  2. 「ユーザー情報」をクリック
  3. 「メールエイリアス」をクリックし、エイリアス名を入力したら「保存」を押す

nodemailer-send-emails-using-alias-address-for-gmail.008

手順3. Gmail で エイリアスアドレスの追加・デフォルト設定

3-1 エイリアスアドレスの追加・認証

  1. Gmail右上の「歯車ボタン」を押し、「すべての設定を表示」を押す
  2. 「アカウント」タブをクリックする
  3. 「名前」の欄に「他のメールアドレスを追加」とあるのでクリック
  4. 「エイリアスとして扱います」にチェックをつけ、「名前」と手順2で準備したエイリアスのアドレスを入力
  5. 確認メールでの認証が必要といわれるので、「確認メールの送信」をクリック
  6. 届いた確認メールのリンクをクリックするか、確認コードを入力し「確認」をクリック

nodemailer-send-emails-using-alias-address-for-gmail.009

3-2 エイリアスアドレスを送信メールのデフォルトに設定

  1. Gmailの設定画面に戻ると3-1で設定されたエイリアスアドレスが追加されています
  2. エイリアスアドレスのほうを「デフォルトに設定」をクリックする

(※これがないと、nodemailerで送信した際に、エイリアスのアドレスから送信されたことにならず、元のアドレスからの送付となってしまいます。)

手順4. nodemailerでメール送信スクリプトを作成

4-0 手順1で準備したものの確認

  • Client ID
  • Client Secret
  • Reflesh Tken

4-1 nodemailerのpackageをインストール

  1. npmでも yarnでも

4-2 OAuthの情報をnodemailerに準備

constnodemailer=require('nodemailer')constauth={type:'OAuth2',user:'alias@adress',// エイリアスのアドレスclientId:'clientId',// Client IDclientSecret:'clientSecret',// Client SecretrefreshToken:'refleshToken',// Reflesh Token}consttransporter=nodemailer.createTransport({service:'gmail',auth})

4-3 メール情報を準備・メール送信

constmailOptions={from:`エイリアス <alias@mail.com>`,// エイリアスのアドレスと名前to:`send_to@mail.com`,// TObcc:`blind@mail.com`,// BCCsubject:`Subject`,// タイトルtext:`text`// 本文}transporter.sendMail(mailOptions)

まとめ

以上の方法で、エイリアスのメールアドレスを用いたnodemailerの送信が可能になりました。

ガッツリとシステムを組む場合にはこのような手法をとらないような気もしますが、スモールビジネスで小さくはじめたい方などは、Googleのようなプラットフォームにのっかるのも手ではないでしょうか?

最終的に Firebase Functions にメール送信は任せたいと思います。

サーバーレス開発プラットフォーム Firebase入門 (日本語) 単行本

Kabanero を使ったクラウド・ネイティブなアプリ開発(VSCode + Codewind)を体験 - その後

$
0
0

2020年7月8日に実施された 初夏のIBM Dojo #9 Kabaneroを使ったクラウド・ネイティブなアプリ開発を体験ワークショップに参加してきました。講師 @osonoiさんです。

以前に翻訳した Kabaneroと、それと関連する Developer Experienceにある「VS Code を使用して Kabanero を試す」を体験できるオンラインセッションでした。セッション資料がわかりやすいので、ぜひ参照してください。

VSCode + codewind の環境、とっても手軽で便利。監視、ビルド、実行など全て Docker 環境で実行され、処理系のインストール無しでさくさく試せる。いろんな言語/環境を試してみたい。

と、Twitter で呟きましたが、すごく参考になったので、ちょっと自分でも中身を確認してみました。自分なりに迷いつつのメモなので、間違えていたり、意味不明だったらスミマセン。

お手軽に開発環境をセットアップ

セッション資料に従い、アプリケーション開発環境をセットアップしてみます。前提となるソフトウェアは以下の2つだけ。

  • Docker : 仮想マシン実行環境
  • VSCode : テキストエディタ

VSCode の 拡張機能 (Extension) で Codewindを探してインストールします。
image.png
新規プロジェクト作成で、Kabanero リポジトリにある Kabanero Node.js Express scaffold templateを選択します。
image.png
後は開発環境などが自動でセットアップされます。ビルド環境も実行環境も Docker コンテナ化されているため、Node.js など開発に必要なツールがインストールされていなくても問題ありません。今回のセットアップも Docker 上にコンテナが追加されるだけで、ローカルにインストールされないため、気軽に試すことができます。

アプリを起動すると Node.js Express が動作し、シンプルな Webページが表示されます。
image.png
さあ、後はサンプルコードを修正して、いろいろ試すだけ。ソースコードに修正を保存すれば、ビルドが実施され、すぐにWebページに反映されます。

以上、ここまでの手順の詳細は IBM Dojo の セッション資料をご参照ください。IBM Developer Dojoのどれかに参加すると、Dojo サポート用の Slack チャネルに招待して貰えるので、そこで質問もできます。

生成された環境を眺めてみる

さてこのまま、環境はブラックボックスとして、Node.js + Express のアプリ開発を開始してもいいのですが… せっかくですから、自動生成された環境を少し眺めてみましょう。

VSCode のワークスペース

まず VSCode のワークスペースを見てみると、以下のような構成になっています。
image.png
ページを表示しているのは routes/index.jsですね。
image.png
表示に利用されている Pug 形式のテンプレート views/index.pugは以下のように非常にシンプルでした。
image.png
これらなのですが、探してみると GitHub の appsody アカウントにある stacks リポジトリ配下にある /incubator/nodejs-express/templates/scaffoldフォルダが元になっているようです。

Docker で動作するコンテナについて

さて、上記の Web ページを表示中、Docker は以下のように3つのコンテナを実行していました。
image.png

最初のコンテナ (イメージは kabanero/nodejs-express:0.4) がアプリを実行している環境のようですので、コンテナに sh アクセスして、動作しているプロセスの状態を見てみます。
image.png
アクセスのための sh と ps コマンド以外のプロセスは以下のような感じ。

USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
default      1  1.8  0.3 105308  7492 pts/0    Ssl+ 09:43   7:34 /.appsody/appsody-controller --mode=run
default     42  0.0  2.2 743756 45576 ?        Ssl  09:43   0:00 npm
default     58  0.2  4.2 1268880 86480 ?       Sl   09:43   1:08 node server.js

ついでに真ん中のコンテナ(イメージは eclipse/codewind-performance-amd64:0.13.0) のプロセスはこちらで、ちょっと何やっているか不明なのですが、実行しているイメージ名から Codewind 本体のような気がします。アプリのビルド前から居ましたし。

USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
1000         1  0.0  1.5 741756 30936 ?        Ssl  07:20   0:00 npm
1000        16  0.0  2.5 680096 52572 ?        Sl   07:20   0:00 node server.js

三番目のコンテナ (イメージは eclipse/codewind-pfe-amd64:0.13.0) のプロセスはこちらで、こちらはソースコードの更新をチェックしたり、最初のコンテナを起動してたり、いろいろ働いているようです。

USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.1  11892  2652 ?        Ss   07:20   0:00 sh -c  /file-watcher/scripts/root-watcher.sh ${HOST_WORKSPACE_DIRECTORY} ${CONTAINER_WORKSPACE_DIRECTORY}
root        33  0.0  2.1 676736 43460 ?        Sl   07:20   0:00 npm
root        61  0.0  0.1  11896  2916 ?        S    07:20   0:00 /bin/bash ./npm-start.sh
root        62  0.0  2.1 676368 44708 ?        Sl   07:20   0:00 npm
root        73  0.0  5.6 972028 115352 ?       Sl   07:20   0:16 node server.js
root       535  0.0  0.1  11896  2760 ?        S    09:43   0:00 /bin/bash /codewind-workspace/.extensions/codewind-appsody-extension/appsody run --name cw-dojoyamacha
root       536  0.0  0.0  23032  1408 ?        S    09:43   0:00 /usr/bin/coreutils --coreutils-prog-shebang=tee /usr/bin/tee -a /codewind-workspace/.logs/dojo-yamacha
root       542  0.0  0.5 116632 11840 ?        Sl   09:43   0:00 /codewind-workspace/.extensions/codewind-appsody-extension/bin/appsody run --name cw-dojoyamachan-df39
root       603  0.0  1.4  45688 29636 ?        Sl   09:43   0:00 docker run --rm -P --name cw-dojoyamachan-df39b4d0-c0eb-11ea-97e7-d775ccf52e96 --network codewind_netw
root       620  0.0  0.0  23032  1320 ?        S    16:11   0:00 /usr/bin/coreutils --coreutils-prog-shebang=tail /usr/bin/tail -q -F -c +0 /codewind-workspace/.logs/d

三番目のコンテナ内の環境変数に、幾つか興味深い値がありましたので、転記します。

CODEWIND_VERSION=0.13.0
CONTAINER_WORKSPACE_DIRECTORY=/codewind-workspace
ENABLE_CODE_COVERAGE=false
HELM_HOME=/root/.helm
HOSTNAME=72958642fbc6
HOST_HOME=C:\Users\z
HOST_MAVEN_OPTS=
HOST_OS=windows
HOST_WORKSPACE_DIRECTORY=C:\codewind-data
IMAGE_BUILD_TIME=20200612-133352
JAVA_HOME=/opt/java/jre
LOG_LEVEL=info
NODE_ENV=production
PATH=/opt/java/jre/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
PERFORMANCE_CONTAINER=codewind-performance-amd64:0.13.0

そして気がついていませんでしたが、ローカルPCに C:\codewind-dataなんてフォルダが生成されていました… 作業ディレクトリとほぼ同じ構成ですが、.vscodeフォルダが無いかわりに空の node_modulesフォルダが存在します。
image.png
試しに c:\ ドライブ全体を対象に appsodyでファイル名検索した結果がこちら。c:\work\codewind\dojo-yamachanがプロジェクト作成時に自身で指定した作業フォルダです。
image.png
ふーむ、なかなか興味深いですね。

実際の起動プロセス

さて、作成したアプリがどう起動されるか追ってみましょう。実行用コンテナで node server.jsとあるので、sh でコンテナの中に入り、server.jsファイルの中でそれっぽい部分を探してみます。

// Register the user's app.constbasePath=__dirname+'/user-app/';functiongetEntryPoint(){letrawPackage=fs.readFileSync(basePath+'package.json');letpackage=JSON.parse(rawPackage);if(!package.main){console.error("Please define a primary entrypoint of your application by adding 'main: <entrypoint>' to package.json.")process.exit(1)}returnpackage.main;}constuserApp=require(basePath+getEntryPoint());app.use('/',userApp({server:server,app:app,log:pino,}));

まずわかるのが、作成した自身のアプリが /project/user-app/ディレクトリに配置されているということです。
image.png

そしてこのディレクトリですが、Docker ランタイムにより、さきほど発見したローカルPCの C:\codewind-data配下のフォルダがマウントされ、永続化されていることがわかります。

image.png

たぶんですが、作業フォルダの内容をビルドした結果 (今回は Node.js で webpack など前処理もないので単にファイルコピーのみ?) がこのローカルPC上のフォルダに配置され、それを実行環境の Docker コンテナの /project/user-app/ディレクトリにマウントすることで、即時反映できている、という仕組みのようです。

で、さきほどの server.jsファイルのコードにある getEntryPoint()関数の中を見ると、package.jsonのなかの mainエントリがアプリの本体を指定しているようで、今回だと app.jsが指定されています。

package.json
"main":"app.js",

そしてこの app.jsを見ると、これが Express アプリの本体で、これでようやく最初に出てきた routes/index.jsviews/index.pugファイルに繋がります。

app.js
module.exports=(/*options*/)=>{// Use options.server to access http.Server. Example of socket.io://     const io = require('socket.io')(options.server)constapp=require('express')()app.set('views',__dirname+"/views");app.set('view engine','pug');app.use('/',require('./routes'));returnapp;};

起動順としては、以下のような感じですかね。

  1. Appsody が用意した実行用コンテナの /project/user-appにローカルPCの c\codewind-data配下のプロジェクト用フォルダがマウントされる 【Appsody共通】
  2. Appsody が用意した実行用コンテナ内の /project/server.js/project/user-app/package.jsonファイルの main エントリを参照する【Appsody Node.js 系共通】
  3. main エントリに指定された /project/user-app/app.jsが実行される【Appsody Node.js Express 系共通?】
  4. app.js によって Pug テンプレートエンジンがセットされ、views/index.pugをテンプレートとして route/index.jsが表示される。【今回の Stack 固有】

うん、これでやっとスッキリしました。

というわけで

Appsody (VSCode + Codewind) で作成した Node.js + Express サンプルアプリの起動の仕組みをざっくり調べてみました。なかなか良く出来た仕組みだなー、と感心してみたり。

ただ、時間の関係もあり、ソースコードの変更をウォッチしているところ、ビルドしているところ、などはまだ調べていません。また時間を作って、コンパイルする Java などの環境(変化がわかりやすいので)を対象に調べてみたいな、などと思っています。なにかわかったら、メモ公開するかもしれません。

それではまた!

プログラムの怖いところ ライブラリのバージョンアップ

$
0
0

はじめに

本記事はライブラリのバージョンアップが原因でプログラムが動かなくなり、どの様に原因を調査して解決まで行き着いたかについて、システム開発の一助となるストーリーをご紹介します。

概要

とあるtoCのシステムにおけるバックエンドのプログラム(API)で軽微な修正を行い、デプロイしたときの話になります。

本番環境と開発環境が存在し、開発環境でテストした上で本番環境でリリース作業を実施。本番環境でデプロイ後、システムの一部機能で正常性が確認できない事態が発生しました。

バックエンドはDockerで開発を行っているため、デプロイ時にdocker compose buildでビルドを毎回行っています。デプロイ自体は成功しているため、ライブラリのバージョンアップが関係しているのではないかと予想していましたが、のちに調査が難航することになるとは、このときは予想していませんでした。。

当該事象発生時は原因究明に至らなかったため、切り戻しを実施し、リリース作業は中断。翌日に原因調査を行いました。

question_head_gakuzen_boy.png

原因調査

前提として本番環境と開発環境で使用していたソースは、一部機能をマージしてないなど環境差異は発生していましたが今回発生した事象に関係はありません。

調査を開始し、開発環境で事象を再現させるために確認を行いましたが、同様の事象は発生しませんでした。その後、本番環境で使用したソースを開発環境でデプロイすると事象が再現しました。

開発環境で事象再現後、デバッグするために本番環境で使用したソースの不具合が発生している箇所にconsole.log(e)でログ出力する様にしてデバッグを行いました。

不具合が発生している箇所に対するAPIのリクエストを実行し、サーバ側のログを確認すると、データベースのあるテーブルのカラムが見つからないと言うエラーメッセージが出力されていました。

仮説としてプログラムで利用していたORMライブラリのバージョンが上がったため、今まで許容していたデータベースに対する接続がエラーになっているのではないかという考えに辿りつきました。

animal_chara_computer_azarashi.png

解決方法

本番環境で稼働中のコンテナで生成されたyarn.lockファイルと、開発環境でデプロイしたコンテナのyarn.lockファイルのORMライブラリのバージョンを比較すると、開発環境のコンテナのマイナーバージョンが1桁だけ上がっていることを確認しました。

検証としてpackage-lock.jsonのORMライブラリのバージョンを、本番環境で稼働中のコンテナで生成されたバージョンと同じバージョンに固定すると、事象が再現しないことが確認できました。

よって暫定対応としては、ORMのライブラリのバージョンを固定しないことで一旦は解決しましたが、今後の運用として色々と課題を認識しました。

shinpai_man.png

DevOps

DevOps観点で感じた課題について以下に記載します。

※本記事の内容は、あくまで考え方の一例であり、必ずしも全ての考え方がシステムに適合したり、ここに書いている内容で満たされている訳ではありません。

  • ライブラリのバージョン固定
    保守性を高める場合はライブラリのバージョンを上げないように固定することが望ましいですが、セキュリティとトレードオフになります。また、バージョンアップする場合は確認の工数もかかります。npm outdatedコマンドを実行すると、現在インストールされているバージョン、現在のバージョン指定でインストールされる最新バージョン、リリースされている最新バージョンが表示されます。

  • テストの再現性
    当たり前ですが極力環境差異をなくしたテスト方法の考案及びテスト環境を構築し、テストを実施することが望ましいです。※参考:3.6 本番環境とテスト環境の差異に関する教訓(T6)

  • 本質的なアプローチ
    今回の様な事象は技術的な手段で解決する以前に、開発や運用ポリシー等を定義していればこの様なリスクを軽減する可能性は上がります。

おわりに

本事象を通して改めて学んだのは、プログラムは数字1桁が変わるだけで動かなくなるという恐ろしさと、DevOpsの重要性です。

DevOpsは文化です。DevOpsは人が作る必要があるため、言うだけは簡単ですがシステムのあるべき姿を計画し、実行して継続することは大変です。

この失敗を次に生かしてシステム開発のライフサイクルを短縮し、ソフトウェア品質の高い継続的デリバリーを実現していきたいと思いました。

【自分用メモ】JavaScript

Viewing all 9100 articles
Browse latest View live