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

Ubuntu18.04 開発環境作成メモ

$
0
0

how to use

cd ~
chmod +x setup.sh
./setup.sh

setup.sh

setup.sh
sudo apt update
sudo apt -y upgrade
sudo apt -yinstall vim
sudo apt -yinstall git
sudo apt -yinstall guake
sudo apt -yinstall curl
sudo apt-get -yinstall xsel

# pyenv sudo apt -yinstall build-essential libffi-dev libssl-dev zlib1g-dev liblzma-dev libbz2-dev libreadline-dev libsqlite3-dev
git clone https://github.com/pyenv/pyenv.git ~/.pyenv
echo'export PYENV_ROOT="$HOME/.pyenv"'>> ~/.bash_profile
echo'export PATH="$PYENV_ROOT/bin:$PATH"'>> ~/.bash_profile
echo'eval "$(pyenv init -)"'>> ~/.bash_profile
source ~/.bash_profile
pyenv install 3.7.6
pyenv global 3.7.6

# nodebrew
curl -L git.io/nodebrew | perl - setup
echo'export PATH=$HOME/.nodebrew/current/bin:$PATH'>> ~/.bash_profile
source ~/.bash_profile
nodebrew install-binary latest
nodebrew use latest

# dockersudo apt install docker.io
sudo groupadd docker
sudo gpasswd -a$USER docker
sudo systemctl restart docker

# docker-composesudo curl -L"https://github.com/docker/compose/releases/download/1.25.1/docker-compose-$(uname-s)-$(uname-m)"-o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose

# ssh keygen
ssh-keygen -t rsa
cat .ssh/id_rsa.pub | xsel --clipboard--input# english directoryLANG=C xdg-user-dirs-gtk-update

# sudo reboot -h now

Swagger-codegenを使おうと思ったが、エラーで使えなかった件

$
0
0

発生した問題

swagger-codegenでnodejs-serverを選択し、モックサーバーを立てようとしたら以下のエラーが出た。

Error: Cannot find module './middleware/swagger.router'

パッケージの中を確認すると、確かにswagger.routerがない。
issueが立ってた。パッケージに間違いがあるらしい。
https://github.com/bug-hunters/oas3-tools/issues/17

解決策

Swagger-codegenのバージョンを下げて、
swagger-codegen@2で対応した。

$ brew install swagger-codegen@2

学んだこと

パッケージも間違っていることがある。
npmのサイトにissuesが上がっていることがある。
Weekly downloadsとかが多いものは信頼性がちょっと高い。

JSのプログラムでincludeするコンパイラ的な何かをかいたお話

$
0
0

どうも、フミです。
京都の上のほうから市内に向かう電車の中で書いているので、誤字はお許しください...

普段からC系の言語とJavascriptを二刀使いしている皆さん、皆さんはJavascriptをかいていて、あ~、include文使えたらいいのにな...
って思ったことありませんか?

いや、いやいや、シンキングフェイスをしたそこのあなた、あなたの気持ちはよ~くわかりますとも!ええ、ええ、そうでしょうね!importを使えばいいだろう!でしょうね!!

使いこなせるのであればいいのですが、importは少し書き方が特殊になる上に、スコープ的にめんどくさいんです(個人の感想です。)

そこで、JSでもinclude文が使えるようになるためのプログラムを作りました!!
5分くおりてぃなので悪しからず...

やったこと

Nodejsを使って既存のファイルを解析し、include文を適用したjsファイルをa.jsとしてカレントディレクトリに出力します。

多分コード読んだほうがわかるので...

cmp.js
constmain_file=process.argv[2];constfs=require('fs');functioninclude(fname){letcode=String(fs.readFileSync(fname));console.log("include \n\n"+code);constanaly=code.split("#include ");letprogram=analy[0];for(leti=1;i<analy.length;i++){program+="\n"+include(analy[i].split(/\r\n|\n|\r/)[0])+"\n";}program+=analy.pop().split(/\r\n|\n|\r/,2)[1];returnprogram;}fs.writeFileSync("a.js",include(main_file));

以上!!

使い方

コンパイル()したいファイルとincludeしたいファイルの拡張子は何でもいいです。
コマンドラインで

node cmp.js [コンパイルしたいメインファイルのパス]

としてやるとa.jsに結果が出力されます。
includeしたいファイル内でさらにincludeしても大丈夫です。

Slackの特定投稿をメールで自動送信してみた

$
0
0

はじめに

社内コミュツールとしてSlackが導入され、社内のコミュニケーションが多少なりとも活性化してきました。
SlackのAppやワークフロービルダーを使って既存プロセスを楽にしようと考える人も出てきて、ツールが変われば人も変わるなーと実感しています。

そんな中でも依頼は「社内メール」という文化は残っており、最後は誰かがメールを送らないといけません。。。
なのでSlackで簡素化した申請プロセスの申請内容をSlackから社内メールに自動送信するようにしてみました。

環境

今回は以下の環境を利用しました。

Slack(Outgoing Webhook)
Sendgrid
Google Apps Script(Node.js)

順番に設定内容を記載します。

1.Slack

チャンネルで特定のキーワードに対して反応するOutgoing Webhookを設定します。
Outgoing WebhookはSlackのApp管理ページから「App ディレクトリを検索」で検索できます。

1-1.設定内容

チャンネル:Outgoing Webhookを動かすチャンネルを指定します。
プライベートチャンネルは指定できませんでした。

引き金となる言葉:トリガーとなるキーワードを指定します。

URL:あとで作るGoogle Apps ScriptのCurrent web app URL:を指定します。

スクリーンショット 2020-01-17 11.39.50.png

2.Sendgrid

メール配送はSendgridを使いました。
https://sendgrid.kke.co.jp/

詳細は割愛しますが、必要となるのはAPIキーです。
ダッシュボートの「Settings」-「API Keys」でKeyを作成してください。
注意:Keyは作成時しか表示されません。

3.Google Apps Script

Slackの投稿を受け取ってメールを送信するスクリプトはGoogle Apps Scriptに構築しました。

3-1.環境変数

環境変数は以下を設定します。
環境変数の設定はGoogle Apps Scriptの「ファイル」-「プロジェクトのプロパティ」-「スクリプトのプロパティ」から設定できます。

■VERIFY_TOKEN
検証用トークンです。自身で設定したOutgoing WebhookからのPOSTかどうか検証します。
これを設定しないとどこからでもPOSTできるようになってしまいます。
設定値はOutgoing Webhookの設定ページにあるTokenを指定します。

■SEND_GRID_ENDPOINT
SendgridのURLを指定します。
https://api.sendgrid.com/v3/mail/send

■SEND_GRID_API_KEY
Sendgridのダッシュボードで取得したAPIキーを指定します。

3-2.スクリプト

doPost(POST、Verify処理)と、sendMail(メール送信処理)の2つに分けています。
メールのto,subject,from_name,fromはご自身の環境に合わせて設定してください。

PropertiesService.getScriptProperties().getProperty('XXX')で環境変数を取得しています。

code.gs
functiondoPost(e){varverify_token=PropertiesService.getScriptProperties().getProperty('VERIFY_TOKEN');if(verify_token!=e.parameter.token){thrownewError("invalid token.");}varmessage=e.parameter.text;sendEmail(message);}functionsendEmail(message){varsendgrid_endpoint=PropertiesService.getScriptProperties().getProperty('SEND_GRID_ENDPOINT');varsendgrid_apikey=PropertiesService.getScriptProperties().getProperty('SEND_GRID_API_KEY');varto="送信先メールアドレス";varsubject="メールタイトル";varfrom_name="送信者名";varfrom="送信元メールアドレス";varbody={"personalizations":[{"to":[{"email":to}],"subject":subject}],"from":{"email":from,"name":from_name},"content":[{"type":"text/html","value":message}]}varpayload=JSON.stringify(body);UrlFetchApp.fetch(sendgrid_endpoint,{method:'POST',headers:{"Content-Type":'application/json',"Authorization":"Bearer "+sendgrid_apikey},payload:payload});}

3-3.有効化

Google Apps Scriptのメニューの「公開」-「ウェブ アプリケーションを導入…」からスクリプトを有効化します。
Who has access to the app:Anyone, even anonymousを選択してください。

スクリーンショット 2020-01-17 13.31.29.png

こちらに出力されるCurrent web app URL:を 1-1.のURLに指定します。
これで設定は完了です。

4.動作確認

Outgoing Webhookで設定したチャンネルで引き金となる言葉を投稿して、内容がメールで送信されるか確認します。
うまく送信されない場合は各設定値と、Google Apps Scriptのログを確認してみてください。

まとめ

Slack投稿をメールに自動送信してみました。
これで「メールでしか申請を受け付けない!」プロセスをSlackで実行することができるようになりました。

今後はもっとポジティブな使い方がしたいです。笑

Windows 10へNode.jsをインストールする

$
0
0

概要

  • Node.jsをNode.jsのサイトからダウンロードしてインストールします。
  • Node.jsの利用方法を説明します。

Node.jsのインストール

  1. インストーラをNode.jsのダウンロードサイトを開きます。

    1. Node.js - ダウンロード
  2. 「LTS版」の《Windows Installer》をクリックしてダウンロードします。
    image.png

  3. ダウンロードしたインストールファイルをクリックしてインストーラーを開きます。
    image.png

  4. 《Next》ボタンをクリックします。
    image.png

  5. 《I accept the terms in the Licence Agreement》(ライセンス契約の条項に同意します)をチェックして、《Next》をクリックします。
    image.png

  6. 《Next》をクリックします。(必要であればインストールフォルダを指定する)
    image.png

  7. 《Next》をクリックします。(基本的にはデフォルトのまま)
    image.png

  8. 《Next》をクリックします。(ネイティブアドオンのビルドはしないのでデフォルトのまま)
    image.png

    1. チェックボックスをチェックするとNode.jsのネイティブアドオンをビルドするための設定をします。
      ネイティブアドオンについては下部の参考サイトを参照してください。
  9. 《Install》をクリックします。
    image.png

  10. ユーザーアカウント制御の画面が表示されるので《はい》をクリックします。

  11. 《Finish》をクリックし、インストールを完了します。
    image.png

Node.jsの利用とインストール確認

  1. Windowsのスタートボタンを右クリックします。
    image.png

  2. メニューが表示されるので「Windows PowerShell」をクリックします。
    image.png

  3. Windows PowerShellの画面が開くのでコマンドを入力してNode.jsがインストールされているか確認します。
    image.png

    1. node --version Node.jsのバージョン確認コマンド
  4. インストールしたバージョン番号が確認できれば正常にインストールされています。
    image.png

  5. Windows PowerShellやコマンドプロンプトからNode.jsは利用できます。

参考サイト

Node.js で Redis のキーの一覧を取得

$
0
0

ライブラリーのインストール

sudo npm install-g redis
redis_list.js
#! /usr/bin/node
// ---------------------------------------------------------------//  redis_list.js////                  Jan/17/2020//// ---------------------------------------------------------------console.error("*** 開始 ***")//constredis=require("redis")constclient=redis.createClient(6379,'localhost')client.on("error",function(err){console.log("Redis connection error to "+client.host+":"+client.port+" - "+err)})client.keys('*',function(err,reply){if(err){console.log("Get error: "+err)}elseif(reply!=null){constkeys=replyconsole.log(keys)console.log("keys.length = "+keys.length)console.log(keys[0])}client.quit()console.error("*** 終了 ***")})// ---------------------------------------------------------------

実行

$ export NODE_PATH=/usr/lib/node_modules
$ ./redis_list.js
*** 開始 ***
[
  't1853', 't1856',
  't1854', 't1852',
  't1855', 't1857',
  't1851', 't1858',
  't1859'
]
keys.length = 9
t1853
*** 終了 ***

確認したバージョン

$ node --version
v13.6.0

toioとTwitterAPIを合わせて使ってみた!

$
0
0

toio.jsとTwitter APIを合わせて使ってみた

久しぶりの記事投稿。今回はtoioをJavascriptで制御するのとTwitterAPIを合わせて使っていく。

toioとは

toioとはソニーインタラクティブエンタテインメントより発売されているロボットトイである。詳しくは公式サイトを見てほしいが、子供から大人まで楽しめるモノになっている。公式からtoio.jsというNode.js(サーバサイドで動くJavaScript環境)のライブラリが公開されているので今回をそちらを利用していく。

今回やること

toioの最大の特徴は主役であるデバイスのキューブ(下図)の光学センサーを用いて、付属のマットやシールに施されている特殊印刷を読み取り、キューブの絶対座標やIDを取得できる点だ。

今回はその絶対座標や各シールのIDを取得した後、TwitterAPIを介してそれらをTweetするのを目標とする。
なおJavascriptを触るのは初めてなのであしからず。

環境構築

環境構築は以下を行った。今回は手順は省く。
- Node.js及びtoio.jsの環境構築(公式を参照)
- TwitterAPIの導入(参照記事)

なおTwitterのアプリケーション作成方法はアップデート毎に変更されているようだ。3年前に一度Androidアプリ開発で触ったことがあったが、開発者アカウントの作成などは審査などが追加されており少々面倒くさくなっていた。

できたもの

今回はクラフトファイターの技カードのIDを識別してツイートする内容とした。(マットを使った座標が今後考えていく・・・)
以下が機能である。
- キューブはキーボートの矢印キーで走行可能
- プログラム実行中は常にIDを取得し続ける
- スペースキーを押すと現在のIDを利用してツイート文を判定・投稿

以下はオートタックルのカードを認識している。

スペースキーを押すと何やら詳細情報がたくさん吐き出されてTwitterに投稿される。
1.png

以下が投稿結果

2.png
ちゃんと投稿できてる。

投稿が完了するとプログラムは終了するようにした。
toioコンテンツ内の特殊印刷から得られるIDはこちらの技術情報から参照できる。

ちなみにもうひとつも(今度はタイフーン)
 
ツイート!
3.png
結果
4.png

ソースコード

const twitter = require("twitter");
const fs = require("fs");
const client = new twitter(JSON.parse(fs.readFileSync("secret.json", "utf-8")));
const keypress = require('keypress')
const { NearestScanner } = require('@toio/scanner')
const DURATION = 700 // ms
const SPEED = {
    forward: [70, 70],
    backward: [-70, -70],
    left: [30, 70],
    right: [70, 30],
}
const flag = true;

//tweet
function tweet(sentence) {
    client.post('statuses/update', { status:sentence }, function (error, tweet, response) {
        if (!error) {
            console.log(tweet);
            process.exit(0);
        } else {
            console.log('error');
            process.exit(1);
        }
    });
}

//make sentences from data
function make_sentence(value){
    if(value === 3670016){
        out = 'Typhoon!'
    }else{
        if(value === 3670054){
            out = 'Rush!'
        }else{
            if(value === 3670018){
                out = 'Auto Tackle!'
            }else{
                if(value === 3670056){
                    out = 'Random!'
                }else{
                    if(value === 3670020){
                        out = 'Stab Power Up!'
                    }else{
                        if(value === 3670058){
                            out = 'Slapping Power Up!'
                        }else{
                            if(value === 3670022){
                                out = 'Side Attack!'
                            }else{
                                if(value === 3670060){
                                    out ='Easy Mode!'
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

//exit processing
function exit(){
    try{
        if(flag){
            throw new Error('program end');
        }
        console.log('not end');
    }catch(e){
        console.log(e.message);
    }
}

//main
async function main() {
    // start a scanner to find nearest cube
    const cube = await new NearestScanner().start()

    // connect to the cube
    await cube.connect()

    //tweet data initialize
    var id = []

    //get id data
    cube
      .on('id:standard-id', data => {id.unshift(data.standardId)})
    //.on('id:position-id', data => {id.unshift(data.x,data.y)})  //appendix

    //move and tweet
    keypress(process.stdin)
    process.stdin.on('keypress', (ch, key) => {
        // ctrl+c or q -> exit process
        if ((key && key.ctrl && key.name === 'c') || (key && key.name === 'q')) {
            process.exit()
        }

        switch (key.name) {
            case 'space':
                var value = id[0];
                console.log('data : ', value)
                make_sentence(value)
                tweet(out)
                break
            case'':

                break
            case 'up':
                cube.move(...SPEED.forward, DURATION)                
                break
            case 'down':
                cube.move(...SPEED.backward, DURATION)
                break
            case 'left':
                cube.move(...SPEED.left, DURATION)
                break
            case 'right':
                cube.move(...SPEED.right, DURATION)
                break
        }
    })

    process.stdin.setRawMode(true)
    process.stdin.resume()

}

main()

いかにもJavascript初心者っぽいコーディングだがあしからず・・・
IDを判別して文章を決める大量のif else文をなんとかしたいが、何かいい方法はないだろうか・・・

今後

初挑戦のNode.jsもといJavaScriptだったがtoioの整った環境と使いやすいデバイス、仕様のおかげで1つ作成することができた。
今回は利用するID(toio内の利用物)を絞ったが、次回はマットから取得できるX,Y座標やアングル等を利用して発展させたいと考えている。

JSON.Stringifyで循環オブジェクト参照構造体が処理できないのをcycle.jsで処理した

$
0
0

概要

https://qiita.com/saitoeku3/items/9e9a608e53029d541a8f
と同じエラーにあったので、cycle.jsで処理したサンプルコードを紹介するよというお話

cycle.js

https://github.com/douglascrockford/JSON-js/blob/master/cycle.js

インストール

npm install json-cyclic

サンプルコード

//import
const decycle = require('json-decycle').decycle;
const retrocycle = require('json-decycle').retrocycle;
...

...
//文字列に変換
receiveNewAcString = JSON.stringify(receiveNewJson, decycle());

//JSONオブジェクトに変換
receiveNewAc = JSON.parse(receiveNewAcString, retrocycle()).data;

VS CodeでDocker開発コンテナを便利に使おう

$
0
0

はじめに

  • ローカル環境で開発し、Linux環境にデプロイしてテストするのが面倒
  • Dockerを使っていい感じに開発環境を作りたい
  • しかし色々設定や構築が面倒

そんな方のためにDockerコンテナを用いた開発環境をVS Codeから便利に構築、運用できる拡張機能「Remote-Containers」の使い方のご紹介です。

この拡張機能の素晴らしさ

VS Codeの拡張機能「Remote-Containers」はコンテナ内でVS Codeを立ち上げ、ホストマシンのVS Codeと通信させることであたかもローカル環境で開発しているような操作感でコンテナ内開発が行えるというものです。

詳しい構成は公式ドキュメントに図があります。


(https://code.visualstudio.com/assets/docs/remote/containers/)

また、複数の開発環境をVS Code上から管理して、ワンクリックでコンテナを立ち上げることが可能です。


(https://code.visualstudio.com/assets/docs/remote/containers/)

そのために開発を始める際にコンテナをコマンドから立ち上げ、シェルをアタッチしてコンテナ内に入るなどの作業が必要なくなります。

ローカル環境でVS Codeを開いて開発を始めるのとほぼ同じ感覚でコンテナ内での開発が始められるのです。

システム要件は以下になります。

  • Windows: Docker Desktop 2.0+ on Windows 10 Pro/Enterprise. (Docker Toolbox is not supported.)
  • macOS: Docker Desktop 2.0+.
  • Linux: Docker CE/EE 18.06+ and Docker Compose 1.21+. (The Ubuntu snap package is not supported.)

環境構築のための環境構築

Docker

まずDockerをインストールしますが、ここは省略します。

筆者はWindows環境にDocker Desktopをインストールしましたが、想像を絶する艱難辛苦を味わいました。

VS Code 拡張機能

VS Code上でctrl + shift + Xで拡張機能メニューを開き、「Remote-Containers」を検索してインストールします。

Microsoft公式なので安心(?)です。

Remote-Containers / Remote-SSH / Remote-WSLをひとつにしたRemote Developmentという拡張機能もあるのでそちらでも大丈夫です。

git

GithubのMicrosoft公式リポジトリに設定ファイルのサンプルがあるので、それをcloneしてくるとスムーズです。

なのでgitをインストールしましょう(手順省略)。

サンプルのリポジトリは以下です。

vscode-remote-try-python

今回はPythonを使いますが、node.jsやjava、goなどもあります。

必要なのは.devcontainerディレクトリ配下のDockerfileとdevcontainer.jsonなので、そこだけ持ってきても構いません。

Remote-Containersの機能で「Try a Sample」というのがあり、cloneしなくてもこれらのリポジトリを使って試すことができますが突然docker imageのビルドが始まるのでやや面喰います。

開発環境構築

プロジェクト構成

例えばPythonのアプリケーションの開発環境を作るとします。

ディレクトリ構成を以下のようにしてVS Codeからprojectディレクトリを開きます。

project/
    └ .devcontainer/
        ├ Dockerfile
        └ devcontainer.json
    └ .git/
    └ package/
        ├ __init__.py
        ├ __main__.py
        └  module.py
    ├ requirements.txt
    └ .gitignore

f1メニューまたは左下に現れる緑色のアイコンをクリックして「Remote-Containers: Open Folder in Container...」を選択します。


(https://code.visualstudio.com/assets/docs/remote/containers/)

するとVS Codeが.devcontainer配下のDockerfileとdevcontainer.jsonを読み込み、その設定に従ってDockerコンテナを立ち上げてくれるという寸法です。

それでは、Dockerfileとdevcontainer.jsonの中身を見て具体的に何が起こっているのかを理解しましょう。

Dockerfile

ここは普通のDockerfileで、特別なことはありませんがユーザー権限回りの設定をいい感じにやってくれています。

#-------------------------------------------------------------------------------------------------------------# Copyright (c) Microsoft Corporation. All rights reserved.# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information.#-------------------------------------------------------------------------------------------------------------FROM python:3

Docker imageをビルドするための元となるイメージを指定する項目です。

pythonのバージョンを詳しく指定したい場合はここをpython:3.7などにします。

ARG USERNAME=vscodeARG USER_UID=1000ARG USER_GID=$USER_UIDRUN apt-get update \
&& apt-get -yinstall--no-install-recommends apt-utils dialog 2>&1 \
&& apt-get -y install git iproute2 procps lsb-release \

    ~~~

    && groupadd --gid $USER_GID $USERNAME \
    && useradd -s /bin/bash --uid $USER_UID --gid $USER_GID -m $USERNAME \

    && apt-get install -y sudo \
    && echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME\
    && chmod 0440 /etc/sudoers.d/$USERNAME \

ここでapt-getの設定とユーザーの権限回りを設定しています。

要はsudoできる権限を持ったvscodeというユーザーでコンテナを扱えるようにしているようです。

devcontainer.json

こちらがこの拡張機能のミソです。

"name":"Python 3","context":"..","dockerFile":"Dockerfile","settings":{"terminal.integrated.shell.linux":"/bin/bash","python.pythonPath":"/usr/local/bin/python","python.linting.enabled":true,"python.linting.pylintEnabled":true,"python.linting.pylintPath":"/usr/local/bin/pylint"},"appPort":[9000],"postCreateCommand":"sudo pip install -r requirements.txt","remoteUser":"vscode","extensions":["ms-python.python"]}

ここにjson形式で書かれている項目がRemote-Containers拡張機能の設定となります。

  • name
    • Dev Containerの表示名を指定できます(Dockerコンテナ名とは別物です)。
  • context
    • プロジェクトのルートを指定します。
    • この場合devcontainer.jsonがいる.devcontainerディレクトリの一つ上なので".."が指定されています。
  • settings
    • コンテナ側のVS Codeにおける各種設定を行う項目です。シェルやPythonのパスなど。
  • appPort
    • ホストマシンからアクセスできるコンテナのポート番号を指定します。
    • docker runするときの-pオプションで9000:9000と指定するのと同じです。
    • つまりホストマシンのブラウザでlocalhost:9000を叩くとコンテナのlocalhost:9000につながります。
  • postCreateCommand
    • イメージをビルドした後にコンテナ内で実行されるコマンドを書くことができます。
    • この場合はプロジェクトのルートにあるrequirements.txtに書かれたパッケージがインストールされます。
  • extensions
    • コンテナ側のVS Codeにインストールされる拡張機能を指定できます。

公式ドキュメントによると、その他にも色々設定できる項目があります。

デフォルトではプロジェクトのルートディレクトリがコンテナの/workspaceにバインドされますが、

{"workspaceFolder":"/home/vscode","workspaceMount":"type=bind,source=${localWorkspaceFolder},target=/home/vscode/project"}

のようにすれば、/home/vscodeにバインドされてVS Codeで開くデフォルトのディレクトリもそこになります。

{"containerEnv":{"WORKSPACE":"/home/vscode"}}

containerEnv項目を指定すると、コンテナ内で使える環境変数を設定できます。

{"runArgs":["--name=project_dev_container"]}

runArgsの項目で、コンテナ立ち上げ時のオプションを直接指定することもできます。

実際にはVS Codeがこのdevcontainer.jsonを読み込んで各種オプションをつけてdocker runしてコンテナを立ち上げています。

その際にrunArgsの項目で指定した文字列のリストがスペース区切りで追加されるわけです。

さらに詳しくはこちら : Developing inside a Container - devcontainer.json reference

その他個別設定

git

コンテナにバインドするプロジェクトディレクトリに.git/が入っていると、そのままコンテナ内のVS Codeのバージョン管理機能が使えます。

VS Codeのバージョン管理機能は大変便利で、git addやgit commit、git pushなどがGUIで行えます。

しかしながらコンテナ内でモートリポジトリと通信しようとすると、毎回Githubの認証が必要になってしまいます。

ですがそこは我らがVS Code、gitの認証情報をホストマシンと共有できる機能が付いています。

Developing inside a Container - Sharing Git credentials with your container

まずホストマシンとでGithubのユーザー名やメールアドレスを.gitconfigファイルに保存しておきます。

$ git config --global user.name "Your Name"$ git config --global user.email "your.email@address"

ユーザールートにある.gitconfigにこれらの設定が書き込まれていますが、これをVS Codeが自動でコンテナにコピーしてくれるようです。

次にパスワードなどの認証情報ですが、二通り設定方法があります。

https通信を使ってidとパスワードで認証している場合、gitのcredential helperにパスワードを保存しておけばその設定がコンテナと同期されます。

Caching your GitHub password in Git

$ git config --global credential.helper wincred

sshでの認証では、ホストマシンでSSH agentにGithub用の公開鍵を登録しておくとその設定が同期されるようです。

PowerShellで

ssh-add$HOME/.ssh/github_rsa

とするとSSH agentに鍵が登録されます。

しかしながらSSH agentが起動していない場合が多く、そのときは管理者権限でPowerShellに入って

Set-Servicessh-agent-StartupTypeAutomaticStart-Servicessh-agentGet-Servicessh-agent

するか、GUIでサービス > OpenSSH Authentication Agentのプロパティから設定できます。

詳しくはWindows 10のssh-agentをコマンド プロンプト、WSL、Git Bashで使ってみた#ssh-agent-の有効化など。

AWS Access Key

コンテナ内からAWS S3と通信しようとすると、アクセスキーの問題が発生します。

ホストマシンのユーザールートにある.awsディレクトリ内にアクセスキーの情報があり、それをコンテナ内でも読み込みたいものです。

しかしながらgitの場合とは異なりそこは自動的に読み込んではくれないようです。

それゆえに一度コンテナの外からdocker cpを使ってコンテナにコピーしてくる必要があります。

docker cp$HOME/.aws {コンテナ名}:home/vscode

ここで、Remote-Containersで立ち上げるコンテナに名前がついてると便利です。

先ほどのdevcontainer.jsonのrunArgsの項目で、

{"runArgs":["--name=project_dev_container"]}

のようにしてコンテナ名をつけるようにすると良いでしょう。

素晴らしい航海

実際に使ってみると、普通にVS Codeで開発するのとほぼ同じ感覚で開発コンテナを扱うことができます。

また、Pythonで開発する際には仮想環境を用意するのが普通ですがコンテナ内で環境を構築することでその必要がなくなります。

なぜなら、各プロジェクトごとに違うコンテナを使っているのでパッケージをグローバルにインストールしても環境を汚染しないからです。

そして、Pythonのバージョンごとにイメージが用意されているので本番環境に合わせてそれを指定することもできます。

(この辺りはRemote-Containersというよりdockerを使うことのメリットですが)

こうした開発環境をワンクリックで開いたり、切り替えたりできるわけです。

また、この拡張機能はポートのバインドも自動で行ってくれるため、フロントエンド開発でのローカルサーバーもストレスなく使うことができます。

ただし、例えばnode.jsなどは3000番ポート指定でローカルサーバーが立ち上がるのでそのポートをローカルマシンに公開しなければなりません。

その場合はdevcontainer.jsonで

{"appPort":[3000]}

のように設定しておきましょう。

参考

公式ドキュメント、長い

この記事を見てRemote-Containersを使い始めました。感謝!

JSON Serverでオブジェクト以外を返す方法

$
0
0

JSON Serverで文字列を返す方法

公式のGetting startedをもとに、
/profileにリクエストが来た場合、nameの値を文字列として返却する方法を紹介する。
文字列として返したい箇所には、"type": "string"を記載している。

db.json
{"posts":[{"id":1,"title":"json-server","author":"typicode"}],"comments":[{"id":1,"body":"some comment","postId":1}],"profile":{"type":"string","name":"typicode"}}

以下のように、JSON Serverをモジュールとして使用することで、上記内容を返却する前に後処理を行えるようにする。

server.js
constjsonServer=require('json-server')constserver=jsonServer.create()constrouter=jsonServer.router('db.json')constmiddlewares=jsonServer.defaults()// Middleware(前処理)server.use(middlewares)server.use((req,res,next)=>{// 受け取ったリクエストに前処理を行う場合はここに書く// POSTをGETに変換する例if(req.method==='POST'){req.method='GET'}// リクエストURLを書き換える例req.url=req.url.replace(/\./g,"")console.log(req.url)next()})// ルーティングを使用する場合はここに書くserver.use(jsonServer.rewriter({"/api/*":"/$1","/posts\\?id=:id":"/posts/:id",}))server.use(router)// 後処理router.render=function(req,res){// レスポンスに後処理を行う場合はここに書く// db.jsonの返却値に"type":"string"がある場合、nameの値を文字列として返却する例if(res.locals.data.type&&res.locals.data.type==='string'){res.send(res.locals.data.name)}else{// それ以外はdb.jsonに記載したとおり返却するres.send(res.locals.data)}}// モックサーバ起動server.listen(3000,()=>{console.log('JSON Server is running')})

あとは、nodeコマンドで実行する

$ node server.js

参考

https://github.com/typicode/json-server/issues/410

nodenvを使ったNode.jsのインストール手順

$
0
0

はじめに

これまではNode.jsのバージョン管理ツールとして、
nodebrewを使っていたのですが、
ディレクトリごとにNode.jsのバージョンを分けたくなったので、
nodenvのインストール手順を記録として残します。

nodenvはこちらから。
今回参考にしたQiitaの記事はこちらから(ありがとうございます)。

詳しくは調べてませんが、pyenvと同様の管理方法ができるらしいですね。

今回はHomebrewを使ってnodenvを入れていきます。

環境

  • MacBook Air (Retina 13-inch 2018)
    • OS
      • macOS Mojave バージョン 10.14.6
    • メモリ
      • 16GB
    • シェル
      • bash

手順

前提

$はターミナルでの入力を示します。

$ ls

や、

$ cd

などの表記とします。

nodenv のインストール手順

Homebrewからnodenvを入れます。
(コマンドをディレクトリはどこでもいいです...)

$ brew install nodenv

インストールが完了したら.bash_profileexport PATH="$HOME/.nodenv/bin:$PATH"eval "$(nodenv init -)"を追記します。

$ echo 'export PATH="$HOME/.nodenv/bin:$PATH"' >> ~/.bash_profile
$ echo 'eval "$(nodenv init -)" '>> .bash_profile

またはエディタを使って追記します。

 $ vim ~/.bash_profile
 export PATH="$HOME/.nodenv/bin:$PATH"
 eval "$(nodenv init -)"

一応シェルは再起動します。

$ exec $SHELL -l

動作するかテストします。

$ nodenv -v
nodenv [バージョン]
$

とバージョン番号が表示されれば、
インストール完了です。

Node.jsのインストール

バージョンを確認するならnodenv install -lとします。

$ nodenv install -l

インストール自体はnodenv install [バージョン]で完了します。

$ nodenv install [バージョン]

インストールしているNode.jsのバージョンの確認。
$ nodenv versions

全体で使う場合はglobalでバージョンを指定します。
特定のディレクトリで使う場合はlocalでバージョンを指定します。

$ nodenv global [バージョン]

$ node local [バージョン]

最後にnode -vでバージョンを確認します。

$ node -v
v[バージョン番号]
$

もしバージョンがインストールしたものと違った場合は補足を確認してください。

補足

$ nodenvが使えない場合や、
nodeのバージョンがインストールしたものにならない場合は、
node-buildを入れたほうがいいのかもしれません。

$ git clone git:://github.com/nodenv/node-build.git ~/.nodenv/plugins/node-build

終わりに

nodeenvと打ち間違いが無いようお気をつけください。

初めての Azure Bot Service - Sample code と local test 編 -

$
0
0

はじめに

今回は Azure Bot Service を使用して連続した対話に対応できる Bot を作成します.
Azure Bot Service を初めて使用する人を(できる限り)想定してます.
(熟練の方々からしたら退屈するかと思います.)

また,今回は Bot の sample を local test するところまでで
Azure への Deploy については次回行います.

(訂正や指摘などあれば,温かく教えていただけると助かります.)

私の開発環境

  • PC : surface laptop2 (windows 10)
  • Editor : VS Code

PC に関しては何でも大丈夫です.
Editor に関しては 本記事を参考にされる場合は VS Code をご使用ください.
(後程お話しますが, Azure への deploy 時に VS Code の Extension を使用しています)

Azure Bot Service の概要

Azure Bot Service とは,Microsoft 社のクラウドサービスである Azure のサービスの1つです.
公式の document は以下をご参考ください.

Azure Bot Service のリソースを作成すると,セットで Azure App Service のリソースが作成されます.App Service とは同じく Azure のサービスの 1 つで,Web Application を作成することの出来るサービスです.

Bot の基本

まずは,Bot が初めての方,Auzre Bot Service に初めて触れる方のためにいくつかの用語や実装法の紹介をします.

専門用語

Azure Bot Service を使用する上で参考になる用語をいくつか先にご紹介しておきます.

  • channel
    • Bot への通話手段.窓口のようなイメージ.
    • User は channel を通じて Bot App と会話をします.
    • Teams や LINE, Slack,Web chat などがあります.
    • channel によって仕様が異なるため,実際の Bot 開発では channel が何かも大事.
  • connecter
    • channel と Bot アプリを繋ぐ.
    • 実は Azure Bot Service の実態はこの部分(だと思われる)
  • Bot App
    • 実際に処理を行う部分.
    • 実態としては,一般的な Web App と変わらない
    • Azure Bot Service の場合は App Service に相当します

bot archtecture.png

ご存知の方もいらっしゃるかもしれませんが,Azure Bot Service 自体は Bot Application ではありません.channel を通してきたメッセージを Bot へと伝える connecterの役割を担っています.

Bot の実装方法

Bot アプリを作成する場合,Line や Slack などの channel ではなく,実装の観点で話すと2つの実装方法があります.

  • function 型
    • AWS lambda や Azure Function などの Serverless Function を活用した場合
    • 非常にシンプルな作り
    • Function を使用した回数だけ課金対象になるので使用頻度によっては非常に安価
  • Server 型
    • 今回のAzure Bot Service(厳密には Web App Service)のような場合
    • serverを起動している間機能する
    • State(変数の値など)を保持することができる

Azure Bot Service を使用した場合は,下の server 型になります.

function 型では リクエスト(Bot の場合は Bot への呼びかけ)が発生する度に function が実行されます.一方,server 型では server が起動している間のみ応答を返します. これらの特性の大きな違い(の 1 つ)は server側で変数の値などを保持してステートフルな会話が可能なことです.

ステートフルな会話とは簡単に言うと一連の流れを記憶した状態で会話ができるということです.
Serverless Function であれば,基本的には 「1 Question : 1 Answer」 であるのに対して,ステートフルな実装であれば「 n Question : m Answer」と複数の情報から返答を返すことができます.
とりあえずここでは,ざっくりと下図のようなイメージだけで大丈夫です.
(私も厳密な定義は微妙です(笑))

state-full bot.png

sample の実行

それでは実際に sample を動かしつつ確認していきます.

sample コードの取得

以下の Github から sample コードを取得します.

Azure Bot Service の sample Code (Github)

今回は連続した会話フローのsample (Node.js版) を使用します.
先ほど取得したコードのうち,以下の directory を開いてください.

/BotBuilder-Samples/samples/javascript_nodejs/05.multi-turn-prompt/

少しコードを見てみましょう.
プログラムを実行すると index.js が実行されます.
まずは index.js をみてみます.一部抜粋したものを記載しておきます.

index.js
// Copyright (c) Microsoft Corporation. All rights reserved.// Licensed under the MIT License.constrestify=require('restify');constpath=require('path');// Import required bot services.// See https://aka.ms/bot-services to learn more about the different parts of a bot.const{BotFrameworkAdapter,ConversationState,MemoryStorage,UserState}=require('botbuilder');// Import our custom bot class that provides a turn handling function.const{DialogBot}=require('./bots/dialogBot');const{UserProfileDialog}=require('./dialogs/userProfileDialog');// Read environment variables from .env fileconstENV_FILE=path.join(__dirname,'.env');require('dotenv').config({path:ENV_FILE});/**********
  中略
**********/// Define the state store for your bot.// See https://aka.ms/about-bot-state to learn more about using MemoryStorage.// A bot requires a state storage system to persist the dialog and user state between messages.constmemoryStorage=newMemoryStorage();// Create conversation state with in-memory storage provider.constconversationState=newConversationState(memoryStorage);constuserState=newUserState(memoryStorage);// Create the main dialog.constdialog=newUserProfileDialog(userState);constbot=newDialogBot(conversationState,userState,dialog);// Create HTTP server.constserver=restify.createServer();server.listen(process.env.port||process.env.PORT||3978,function(){console.log(`\n${server.name} listening to ${server.url}.`);console.log('\nGet Bot Framework Emulator: https://aka.ms/botframework-emulator');console.log('\nTo talk to your bot, open the emulator select "Open Bot"');});// Listen for incoming requests.server.post('/api/messages',(req,res)=>{adapter.processActivity(req,res,async(context)=>{// Route the message to the bot's main handler.awaitbot.run(context);});});

前半部分では必要な module を import したり,
sample プログラムの別の js ファイルでインスタンスを作成しています.

HTTP server を create しているところでは,PORT の設定なんかもしていますね.

また,最後の部分で post する際のエンドポイントを設定しています.
今回はしませんが,Proactive なメッセージ(push 通知など)を実装する際には,
同様の方法で Proactive 用のエンドポイントを用意することもあります.

続いて,実際の会話フローの制御をしているプログラムを確認しましょう.
/dialogs/userProfileDialog.jsを開いてください.一部抜粋したものを記載しておきます.

userProfileDialog.js
constructor(userState){super('userProfileDialog');this.userProfile=userState.createProperty(USER_PROFILE);// 典型的な会話のパターンを用意してくれているthis.addDialog(newTextPrompt(NAME_PROMPT));this.addDialog(newChoicePrompt(CHOICE_PROMPT));this.addDialog(newConfirmPrompt(CONFIRM_PROMPT));this.addDialog(newNumberPrompt(NUMBER_PROMPT,this.agePromptValidator));// ここで連続する会話を追加しているthis.addDialog(newWaterfallDialog(WATERFALL_DIALOG,[this.transportStep.bind(this),this.nameStep.bind(this),this.nameConfirmStep.bind(this),this.ageStep.bind(this),this.confirmStep.bind(this),this.summaryStep.bind(this)]));this.initialDialogId=WATERFALL_DIALOG;}

TextPromptNumberPromptはその名の通り,テキストや数値入力などの典型的な会話のパターンを実装するために用意されています.

そして,抜粋した code の後半部分にあるWatarfallDialogに様々な dialo を add することで,add した dialog が一連の会話として扱われます.ここで add されている dialog は抜粋部分より後ろの sample code で上記の Prompt を継承して実装されたものです.

local test

まずは Azure に deploy(ざっくり言うとプログラムを Azure 上で動作させる) せずに,local で動作テストできるようにします.以下のリンクより Bot Framework Emulator の exe ファイルを取得して実行します.

Bot Framework Emulator

ちょっと分かりにくいですが,ページ中頃にある以下の画像ようなファイル群から自分に適したものを入手してください.

BotEmulator_download.png

上 4 つのどれかで大丈夫なはずです.

Bot Framework Emulator が起動できること(アプリが実行できて window が開くこと)を確認したら,sample program のある場所で command prompt やら Power Shell やらのコマンドツールを開きましょう.何かしらのコマンドツールを開けたら,npm installnpm startを実行してください.

すると,以下のような画面になります.

npm start.jpg

この画面になり,Bot App が Listen 状態になったことを確認したら,
先ほどの Bot Framework Emulator を実行してOpen Botを押してください.
そして,URL の欄にhttp://lovalhost:3978/api/messagesと入力します.
これは sample code で index.js の最後に書かれている server.postのエンドポイントです.
このポイントに http post リクエストを送ることで Bot と会話します.

Bot Emulator OpenURL.png

こんな感じですね!入力したら Connect してください.

無事にsample を実行できたら,何か話しかけてみましょう.
下の gif のように会話ができると思います.

Bot-Framework-Emulator-2020-01-17-11-37-53_Trim.gif

ちなみに,Bot を停止させたい時は shell の画面で ctr+cを押してください.

次の内容

少し長くなりそうなので今回はここまでで終了とします.
もう1回くらいは書こうと思うので,予定している内容を書いておきます.

  • Dialog の分岐
    • 今回は決まった会話内容でしたが,次回はもう少し複雑に会話を分岐させます.
  • Azure への Deploy
    • 今回は localtest で終わりましたが,次回は実際に Azure に Deploy します.
  • channel の設定
    • とりあえず Teams との連携でも目指します.

(よくよく考えたら今回まだ Azure Bot Service 使ってない説)

Node.js の基礎とそのフレームワーク Express

$
0
0

Node.js とは何なのか

Node.js とは、簡単にいうと JavaScript をサーバーサイドで実行させてくれる存在です。フロントエンドも、バックエンドも1つの言語で実行でき、WEBサービス、スマートフォンアプリ、IoT関連の開発にも使用することができるみたいです。

インストール

まず Node.jsをインストールしていない人は、[Node.js公式サイト](https://nodejs.org/en/) から、LTS版をダウンロードしてインストール。

『node』 でJavaScriptを実行させる

コマンドラインでindex.jsが格納されているフォルダにpwdで移動し、そのフォルダ内のindex.jsを実行する。

node index.js

nodeだけでEnter押すと、JavaScriptコンソールで色々なコードを試せるようになるみたい。やめるときは .exit と入力するか、control + C を2回押すと終了します。

Node.js のいろんなAPI

Node.jsには様々な機能があり、その一覧が公式サイトのdocumentationで見れます。
https://nodejs.org/dist/latest-v12.x/docs/api/

APIの1つ。 『File System』

FileSystemは、ローカルファイルとかにアクセスすることができるAPI。

今回は、Node.js の File System を使用して、ローカルファイルのコピーを使用します。

FileSystemを読み込む

qiita.js
//jshint esversion:6constfs=require("fs");

※ const とは、var のようなもの。しかし、var が後から変更できるのに対して、constは後から変更できることができず、一度データを格納(代入?)するとずっとそのまま。

※コメントがないと、"const" is available in ES6 というエラーメッセージが出てきますが、コメントで//jshint esversion:6と記載することでエラーメッセージを回避することができます。

ファイルのコピーを作成する

qiita.js
//jshint esversion:6constfs=require("fs");fs.copyFileSync("file.txt","copyfile.txt");//fs.copyFileSync("コピーするファイル","コピーされたもののファイル名");

※ file.txtのコピーを作成して、copyfile.txtを作成します。って意味。 ちなみに、すでにcopyfile.txtという名前のファイルが存在していた場合、上書き保存されるので注意。

コマンドラインで、実行する

node qiita.js

※今回は、qiita.js というファイルにJavaScriptコードを記載していたので、そのファイルをコマンドライン上で実行する。

Expressフレームワーク

node.js をより使いやすくしたのがExpress フレームワークらしい。めっちゃざっくりだけど。

Expressのインストール

スクリーンショット 2020-01-17 21.49.43.png

retrieved from Express.jp 公式サイト
https://expressjs.com/ja/starter/installing.html

最後のところは『 npm install express 』だけでOKみたい。

Express をjsファイルで使用できるようにする

requireでExpressをロードし使用できるようにします。ついでにexpress()もappに格納します。

qiita.js
constexpress=require("express");constapp=express();

Expressでサーバーを作成する

ここが割と理解に苦しんだところ。

手順

========================
(JavaScript上)
1.まずExpressをロード
2.アクセスされた時のRespondを考える(ページ別)
3.listenでサーバーを指定
(コマンドラインにて)
4.node server.js で実行
(ブラウザ上にて)
5.http://localhost:3000/と入力し、サーバーに接続
6.respondの処理が実行される
(コマンドラインにて)
7.control + C で終了する

========================

これが一応の流れで、下記が実際のコード。

server.js
// jshint esversion:6// expressをロードconstexpress=require("express");constapp=express();// localhost:3000 にアクセスされた時のRespondapp.get("/",function(request,respond){//ここでconsole.log(request);とするとrequestの内容みれるrespond.send("Hello World");});// localhost:3000/profile にアクセスされた時のRespondapp.get("/profile",function(request,respond){respond.send("My name is Kibinag0. I'm from Japan.");});//listenで待ち受け状態にするapp.listen(3000,function(){console.log("Server started on port 3000");});

・Request

ブラウザ?からサーバーにリクエストされる情報。

・Respond

 サーバーにリクエストが来た時に、反応して実行する処理。

ちなみにサーバーにはスレッドモデル(Apache等)とイベントループ(Node.js等 シングルスレッドともいう)という種類があり、それぞれの違いはこちらが分かりやすかったため、参照。
https://dotinstall.com/lessons/basic_nodejs/26202

・listen()

listenで待ち受け状態にする。このlistenがあることによってrequestを受け取ることができるようになる。

『res.sendFile』を使用してHTMLファイルでRespondする

今までは、"Hello world"とかいう文字列でRespondしていましたが、今回はres.sendFileを使用してHTMLファイルでRespondします。

server.js
// リクエストがあったら、index.htmlファイルをrespondするapp.get("/",function(req,res){res.sendFile(__dirname+"/index.html");});

(__dirname + "/index.html")は、dirnameをちゃんと取得して、そのindex.htmlがどのディレクトリに格納されているのかを教えてあげる必要があるんですね。

body-parserを使用してformデータを取得する

HTMLファイルでFormを使用して、ユーザーにデータを入力してもらう。そして、そのデータを使用して何か処理を行う場合の方法です。

事前にbody-parserをインストール

npm install body-parser

HTMLでフォームを作成

index.html
<h1>Calculator</h1><formclass=""action="/"method="post"><inputtype="text"name="num1"placeholder="First Number"><inputtype="text"name="num2"placeholder="Second Number"><buttontype="submit"name="submit">Calculate</button></form>

このフォームをサーバー側で

calculator.js
// jshint esversion:6// ロードするconstexpress=require("express");constbodyParser=require("body-parser");constapp=express();// body-parserの使用app.use(bodyParser.urlencoded({extended:true}));// index.html でrespondするapp.get("/",function(req,res){res.sendFile(__dirname+"/index.html");});// index.htmlのフォームでpostされた部分app.post("/",function(req,res){// bodyの中のnum1, num2を取得するvarnum1=Number(req.body.num1);varnum2=Number(req.body.num2);varresult=num1+num2;res.send("The result of the calculation is "+result);});app.listen(3000);

Udemy AngelaさんのWEB DEVELOPMENT COURSE『206. Processing Post requests with body-parser』より

サーバー更新自動化『nodemon』のすすめ

ちなみに、上記だとserver.jsファイルを更新するたびにコマンドラインでサーバー終了して、もう一回立ち上げることになります。それって結構めんどくさいですよね。

そんな人のために、Udemy講師のAngelaさんが役立つツールnodemonを教えてくれました。
Angelaさんの講義はこちら→ Udemy Bootcamp web development

nodemonを使うと、server.jsファイルを上書き保存するたびに検知してくれて、自動でサーバーを更新し、反映させてくれる優れものです。

https://nodemon.io/

インストール

インストールの仕方はコマンドラインで

npm install -g nodemon

と記載するだけ。

※permission error が出たら

sudo npm install nodemon -g

で対応。

使い方

nodemon server.js

とコマンドラインで記載すると、server.jsファイルの更新を自動反映してくれます。

以上 Node.jsとExpress。
結構難しいかったので、追加、修正を随時していきます。。

Nuxt を winser でサービス化する

$
0
0

Nuxt で作成したアプリケーションを WinSer でWindowsサービス化しようとしたらいろいろはまったので備忘録として対処を残しておく。

背景

nodejs で作成したアプリケーションを Windows環境でサービス化するためのツールとして、 WinSerがある。
start コマンドとして「node index.js」のように node.exe を直接叩く場合は特に設定をする必要はないが、 NuxtJS のような専用の起動コマンドが存在するような場合に、npm や yarn からは起動できてもWindowsサービスとして起動できないということが発生する。

対策

WinSer (で使用される nssm)は絶対パスか、パスが通ったコマンド出なければ実行できない(ように見える)。また「.cmd」拡張子のファイルは拡張子込みで記述する必要がある。

1. WinSer をインストールする

npm に上がっている WinSer はバグっているので修正されたものを拾う。

yarn add winser "git+https://github.com/LiberisLabs/winser.git"   

2. パスを通す

yarn へのパスを通す。
以下がもしないなら、サービスを実行するユーザーの環境変数の Path に追加する。そのユーザーで yarn をグローバルインストールしてあることが前提。

C:\Users\<username>\AppData\Roaming\npm

Local System アカウントで実行するなら、システム環境変数に追加する。

3. package.json に winser 要のタスクを追記する

package.json
"scripts":{"dev":"nuxt","build":"nuxt build","start":"nuxt start","generate":"nuxt generate","install-service":"winser -i -a --startcmd \"yarn.cmd nuxt start\" --set \"ObjectName .\\appuser password\"","uninstall-service":"winser -r -x"}

WinSer は標準では start をもとにサービスを作成するが、それでは動かないため --startcmd で start の代わりの実行コマンドを記述する。さらに、 --set で実行ユーザーとパスワードを指定する(Local System で実行するなら不要)。
やっていることは nuxt.cmd を叩いているだけだが、直接見つけられないため、yarn を叩くことで
nuxt.cmd を見つけている。

サービス化した場合、サービスの起動停止を自動化したくなる。UACを無効化したくなるが、その必要はなく、特定ユーザーにサービスに係る権限を与える方法はこの辺りを参照する。

参考

WinserでNode.jsのサーバーをサービス化してみる
NSSM
WinSer

Express で簡単な WebAPI を作成

$
0
0

フォルダー構造

$ tree
.
├── app.js
└── routes
    └── index.js
app.js
//-------------------------------------------------------------------------//  app.js////                  Jan/18/2020//-------------------------------------------------------------------------varexpress=require('express')varroutes=require('./routes')varbodyParser=require("body-parser")varcfenv=require('cfenv')varapp=express()app.use(bodyParser.urlencoded({extended:true}))app.use(bodyParser.json())app.use(express.static(__dirname+'/public'))varappEnv=cfenv.getAppEnv()app.post('/post_test',routes.post_test)app.listen(appEnv.port,'0.0.0.0',function(){console.log("server starting on "+appEnv.url)})//-------------------------------------------------------------------------
routes/index.js
// -----------------------------------------------------------------------/*
    routes/index.js

                        Jan/18/2020
*/// -----------------------------------------------------------------------exports.post_test=function(req,res){varaa=0varbb=0if(req.body.aa){aa=parseInt(req.body.aa,10)}if(req.body.bb){bb=parseInt(req.body.bb,10)}vardict_aa={}dict_aa["aa"]=aadict_aa["bb"]=bbdict_aa["sum"]=aa+bbdict_aa["diff"]=aa-bbvarstr_out=JSON.stringify(dict_aa)res.send(str_out)}// -----------------------------------------------------------------------

サーバーの起動

$ node app.js 
server starting on http://localhost:3000

テストスクリプト

#URL=http://localhost:3000/post_test
#
curl -X POST -daa="12"-dbb="45"$URL#echo#
curl -X POST -H"Content-Type: application/json"\-d'{"aa":"32", "bb":"41"}'$URL#echo#
curl -X POST -H"Content-Type: application/json"\-d@in01.json $URL#echo#
in01.json
{"aa":"52","bb":"84"}

実行結果

$ ./go_test.sh 
{"aa":12,"bb":45,"sum":57,"diff":-33}
{"aa":32,"bb":41,"sum":73,"diff":-9}
{"aa":52,"bb":84,"sum":136,"diff":-32}

CentOS 8にNode.js 12をインストール(AppStream)

$
0
0

はじめに

Application Stream(AppStream)を利用してCentOS8にNode.js 12をインストール
参考:RHEL8のパッケージ構成 - BaseOSとApplication Stream - 赤帽エンジニアブログ

サポート

本手法で導入した場合、Red Hat Enterprise Linux 8 Application Streams Life Cycle - Red Hat Customer Portalより、2021-11がEOLだと思われる。
それ以降に報告された脆弱性や不具合への対応は実施されない可能性がある。

LOG

インストール

#cat /etc/redhat-release
CentOS Linux release 8.1.1911 (Core)

#yum install-y @nodejs:12/common
... 略

各種確認

#which node
/usr/bin/node

#node -vv12.4.0

#yum module info nodejs:12
Failed to set locale, defaulting to C.UTF-8
Last metadata expiration check: 0:09:35 ago on Sat Jan 18 07:24:40 2020.
Name         : nodejs
Stream       : 12 [e] [a]
Version      : 8010020191122190621
Context      : cdc1202b
Architecture : x86_64
Profiles     : common [i], development, minimal, s2i
Repo         : AppStream
Summary      : Javascript runtime
Description  : Node.js is a platform built on Chrome's JavaScript runtime for easily building fast, scalable network applications. Node.js uses an event-driven, non-blocking I/O model that makes it lightweight and efficient, perfect for data-intensive real-time applications that run across distributed devices.
Artifacts    : nodejs-1:12.4.0-2.module_el8.1.0+251+8afea200.src
             : nodejs-1:12.4.0-2.module_el8.1.0+251+8afea200.x86_64
             : nodejs-debuginfo-1:12.4.0-2.module_el8.1.0+251+8afea200.x86_64
             : nodejs-debugsource-1:12.4.0-2.module_el8.1.0+251+8afea200.x86_64
             : nodejs-devel-1:12.4.0-2.module_el8.1.0+251+8afea200.x86_64
             : nodejs-devel-debuginfo-1:12.4.0-2.module_el8.1.0+251+8afea200.x86_64
             : nodejs-docs-1:12.4.0-2.module_el8.1.0+251+8afea200.noarch
             : nodejs-nodemon-0:1.18.3-1.module_el8.1.0+251+8afea200.noarch
             : nodejs-nodemon-0:1.18.3-1.module_el8.1.0+251+8afea200.src
             : nodejs-packaging-0:17-3.module_el8.1.0+251+8afea200.noarch
             : nodejs-packaging-0:17-3.module_el8.1.0+251+8afea200.src
             : npm-1:6.9.0-1.12.4.0.2.module_el8.1.0+251+8afea200.x86_64

Hint: [d]efault, [e]nabled, [x]disabled, [i]nstalled, [a]ctive

CentOS 8にNode.js 10をインストール(AppStream)

$
0
0

はじめに

Application Stream(AppStream)を利用してCentOS8にNode.js 10をインストール
参考:RHEL8のパッケージ構成 - BaseOSとApplication Stream - 赤帽エンジニアブログ

サポート

本手法で導入した場合、Red Hat Enterprise Linux 8 Application Streams Life Cycle - Red Hat Customer Portalより、2021-04がEOLだと思われる。
それ以降に報告された脆弱性や不具合への対応は実施されない可能性がある。

LOG

インストール

#cat /etc/redhat-release
CentOS Linux release 8.1.1911 (Core)

#yum install-y @nodejs:10
... 略

各種確認

#which node
/usr/bin/node

#node -vv10.16.3

#yum module info nodejs:10
Failed to set locale, defaulting to C.UTF-8
Last metadata expiration check: 0:01:24 ago on Sat Jan 18 08:05:14 2020.
Name             : nodejs
Stream           : 10 [d][e][a]
Version          : 8000020191007212731
Context          : 55190bc5
Architecture     : x86_64
Profiles         : common [d] [i], development, minimal, s2i
Default profiles : common
Repo             : AppStream
Summary          : Javascript runtime
Description      : Node.js is a platform built on Chrome's JavaScript runtime for easily building fast, scalable network applications. Node.js uses an event-driven, non-blocking I/O model that makes it lightweight and efficient, perfect for data-intensive real-time applications that run across distributed devices.
Artifacts        : nodejs-1:10.16.3-2.module_el8.0.0+186+542b25fc.src
                 : nodejs-1:10.16.3-2.module_el8.0.0+186+542b25fc.x86_64
                 : nodejs-debuginfo-1:10.16.3-2.module_el8.0.0+186+542b25fc.x86_64
                 : nodejs-debugsource-1:10.16.3-2.module_el8.0.0+186+542b25fc.x86_64
                 : nodejs-devel-1:10.16.3-2.module_el8.0.0+186+542b25fc.x86_64
                 : nodejs-devel-debuginfo-1:10.16.3-2.module_el8.0.0+186+542b25fc.x86_64
                 : nodejs-docs-1:10.16.3-2.module_el8.0.0+186+542b25fc.noarch
                 : nodejs-nodemon-0:1.18.3-1.module_el8.0.0+14+a5a48e73.noarch
                 : nodejs-nodemon-0:1.18.3-1.module_el8.0.0+14+a5a48e73.src
                 : nodejs-packaging-0:17-3.module_el8.0.0+186+542b25fc.noarch
                 : nodejs-packaging-0:17-3.module_el8.0.0+186+542b25fc.src
                 : npm-1:6.9.0-1.10.16.3.2.module_el8.0.0+186+542b25fc.x86_64

Hint: [d]efault, [e]nabled, [x]disabled, [i]nstalled, [a]ctive

node.js製のlambdaアプリをコマンド一発でアップロードする方法

$
0
0

node.jsでlambdaのアプリを作っているのですが、コードやパッケージが増えてくるとインライン編集出来なくなったり、zipでアップロードする必要が出てきます。ちょっとした変更でもわざわざawsのサイトに行ってアップロードするのは面倒ですし、複数のlambdaアプリを作っていたら間違えて別の関数にアップロードしてしまった、といった事故も起きるかもしれません。そこで、コンソールからコマンドでアップロードできるようにする方法を書きます。

※動作確認環境: macOS 10.14.6

aws CLIの設定

まずawsのCLIをインストールします。バージョンが出ればOKです。

$ brew install python3
$ pip3 install aws
$ aws --version

次にawsのユーザー情報を設定する必要がありますが、アクセスキーが必要になります。IAMでAdministratorAccessポリシーを持ったユーザーを作成しておきます。
https://blog-asnpce.com/technology/313

アクセスキー、シークレットアクセスキー、リージョンをaws configureで設定します。

$ aws configure
AWS Access Key ID [None]: xxxxxxxxxxxxxxx
AWS Secret Access Key [None]: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Default region name [None]: ap-northeast-1
Default output format [None]: // 設定せずそのままEnter

これでコンソールからawsのcliを使用するときに自分のアカウントを操作することができるようになりました。

package.jsonの編集

package.jsonを編集し、lambdaアプリのディレクトリでnpm run deployを実行するとアップロード出来るようにします。
package.jsonのscripts内にdeployというプロパティ名でコマンドをセットします。セットするコマンドは以下です。このコマンドを実行することにより、package.jsonが入っているディレクトリをzipに圧縮してからCLIでアップロード出来ます。
{}内はご自身のlambdaアプリに合わせてください。zipのファイル名はなんでもいいです。

zip -r {zipファイルの名前}.zip ./ -x \"*.zip\" && aws lambda update-function-code --function-name {lambda関数の名前} --zip-file fileb://{zipファイルの名前}.zip
package.json
{"name":"prodfunc","version":"1.0.0","engines":{"node":">=12.0.0"},"description":"","main":"index.js","scripts":{//ここに追加"deploy":"zip -r prodfunc.zip ./ -x \"*.zip\"&& aws lambda update-function-code --function-name prodfunc --zip-file fileb://prodfunc.zip"},"author":"","license":"ISC","dependencies":{//}}

コンソールで以下を実行し、エラーが出なければ成功です。

$ npm run deploy

参考
https://docs.aws.amazon.com/lambda/latest/dg/nodejs-create-deployment-pkg.html

ejsのとの違い

$
0
0

htmlの要素として出力したいか、文字として出力したいかで使い分ける
→基本的には<%= %>で、子要素の出力を一緒に使いたいときには<%- %>を使用す

そもそもEJSとは

ejsとはテンプレート機能を実現するNode.jsのパッケージです。

1,<%= >

ejsに用意されている独自機能です。
このタグは、指定した変数の値を出力するものです。

<%=変数 >

2,<%- >

ejsに用意されている独自機能です。
HTMLをエスケープ処理しないでそのまま出力する為のものです。

Promiseとasync/awaitを使った同期処理

$
0
0

Node.jsを使ったプログラムを書いていて、同期的に処理してほしいところを全て非同期でやっちゃう可愛いnodeのおかげでいくつか勉強になったことをまとめる。

同期処理を考える手順

1.まずはコールバック関数を使う

まず最初に思いつくのはこれ。コールバックを使えば、処理1の値を使った処理2みたいなことができる。
が、簡単な処理に関してはこれで十分だが、処理が複雑になってくるといわゆる「コールバック地獄」と言われる見た目も処理も地獄のようなプログラムができてしまう。要はネストが深くなって何がなんだかよくわからなくなる。

sample.js
function処理2{callback(処理1)}

2. Promiseを使う

そこで登場するのがPromise。こいつは結構優れもので、書き方を覚えてしまえばコールバック地獄を回避できる。
そもそもPromiseは何をしているかを簡単に説明すると、オブジェクト(引換券的なもの)を先に渡しておいて、resoleが返ってきた、つまり処理が終わればそのオブジェクトと結果を交換するよって感じ。
もっと砕いて言うと、電子レンジがPromiseで、人は何かを温めるとき電子レンジに食べ物を入れる。これが自分のものだよって言うことを示す引換券をもらうとして、温めが終わったら取りにいくイメージ。その間は何をしててもokだから要はPromise単体だと非同期処理を行なっている。

sample.js
varresult_1=newPromise(function(resolve){resolve("result_1成功");});result_1.then(function(){//処理}).then(fucntion(){})・・・

同期処理にしたければPromiseのthenを使う。これは次々に処理を記述しているが、結局処理が終わらない(resoleが返ってこない)と次に進まないので同期的な処理になる。thenを使えば、コールバックを綺麗に記述でき、メンテナンス性も向上する。

async/awaitを使った方がもっと綺麗

これに関してはいろんなサイトでごちゃごちゃ書いているが、要は使えたらいいので簡潔に言うと、asyncな関数で待ちたい処理をawaitにするだけ。

sample.js
// await式を使いたいので、async関数を宣言するconstmain=async()=>{// 処理1のPromiseを宣言するconstroutine1=newPromise(resolve=>{//略resolve('end')})constresult1=awaitroutine1;// 処理1の完了を待ち結果を受け取る// 処理2以下を記述……}}// 関数を実行main();

async/awaitが最も綺麗にかけるのでおすすめ。

注意事項 Promiseを変数に入れるか関数のreturnにするか

sample.js
constroutine1=newPromise(resolve=>{//略resolve('end')})functionroutine1(){returnnewPromise(resolve=>{//略});}

この違いは結構大事。変数のroutine1を呼び出す場合は、呼び出す前にこの代入式を記述するとその時点で処理が実行される。一方で関数の場合は、呼び出した時点で初めてPromiseの処理が始まるという違い。
また、ループでなんどもPromise処理を使いたい時には、functionで毎回呼び出さす必要がある。変数だと一回resolveを返してしまえばそのPromiseは御役御免となり一生使えない。

Viewing all 8868 articles
Browse latest View live