20200604のNode.jsに関する記事は14件です。

自動売買のbitflyer.comでHTTP API使ってみたよ?

自動売買のbitflyer.comでHTTP API使ってみたよ。?
使ってみて思ったことはリアルタイム処理とHTTP APIを混合で
使うべしだと・・・。ただ・・ビットコインの価格高いよね。
私には買えない。

http_api.js
//板情報
var F = require('./api-bitflyer.com.js');
F.Fapi.init.key = "APIKEY";
F.Fapi.init.secret = "secretkey";
F.Fapi.init.method = "GET";
F.Fapi.init.path = "/v1/getboard";
F.Fapi.init.data =  { "product_code": "ETH_JPY" };
F.Fapi.run();
api-bitflyer.com.js
exports.Fapi = {
    init: {
        key: "",
        secret: "",
        method: "",
        path: "",
        data: ""
    },
    run: function () {
        var request = require('request');
        var crypto = require('crypto');

        var timestamp = Date.now().toString();
        var method = this.init.method;
        var path = this.init.path;
        var body = JSON.stringify(
            this.init.data
        );

        var text = timestamp + method + path + body;
        var sign = crypto.createHmac('sha256', this.init.secret).update(text).digest('hex');
        var pra = function(data){
            let str = [];
            for (const key in data) {
                if (data.hasOwnProperty(key)) {
                    str.push(key + "=" + data[key]);
                }
            }
            return "?" + str.join('&');
        };
        var options = {
            url: 'https://api.bitflyer.com' + path + (method.toUpperCase()==="POST"?"":pra(this.init.data)),
            method: method,
            body: body,
            headers: {
                'ACCESS-KEY': this.init.key,
                'ACCESS-TIMESTAMP': timestamp,
                'ACCESS-SIGN': sign,
                'Content-Type': 'application/json'
            }
        };
        request(options, function (err, response, retload) {
            console.log(retload);
        });

    }
};
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

自動売買☓bitflyer.comでHTTP API使ってみたよ?

自動売買☓bitflyer.comでHTTP API使ってみたよ。?
使ってみて思ったことはリアルタイム処理とHTTP APIを混合で
使うべしだと・・・。ただ・・ビットコインの価格高いよね。
私には買えない。

http_api.js
//板情報
var F = require('./api-bitflyer.com.js');
F.Fapi.init = {
    key:"apikey",
    secret:"secretkey",
    method:"GET",
    path:"/v1/getticker",
    data:{product_code:"ETH_JPY"}
};
F.Fapi.run();
api-bitflyer.com.js
exports.Fapi = {
    init: {
        key: "",
        secret: "",
        method: "",
        path: "",
        data: ""
    },
    run: function () {
        var request = require('request');
        var crypto = require('crypto');

        var timestamp = Date.now().toString();
        var method = this.init.method;
        var path = this.init.path;
        var body = JSON.stringify(
            this.init.data
        );

        var text = timestamp + method + path + body;
        var sign = crypto.createHmac('sha256', this.init.secret).update(text).digest('hex');
        var pra = function(data){
            let str = [];
            for (const key in data) {
                if (data.hasOwnProperty(key)) {
                    str.push(key + "=" + data[key]);
                }
            }
            return "?" + str.join('&');
        };
        var options = {
            url: 'https://api.bitflyer.com' + path + (method.toUpperCase()==="POST"?"":pra(this.init.data)),
            method: method,
            body: body,
            headers: {
                'ACCESS-KEY': this.init.key,
                'ACCESS-TIMESTAMP': timestamp,
                'ACCESS-SIGN': sign,
                'Content-Type': 'application/json'
            }
        };
        request(options, function (err, response, retload) {
            console.log(retload);
        });

    }
};
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

bitflyer.comでHTTP API使ってみたよ?

bitflyer.comでHTTP API使ってみたよ。?
使ってみて思ったことはリアルタイム処理とHTTP APIを混合で
使うべしだと・・・。ただ・・ビットコインの価格高いよね。
私には買えない。

http_api.js
//板情報
var F = require('./api-bitflyer.com.js');
F.Fapi.init.key = "APIKEY";
F.Fapi.init.secret = "secretkey";
F.Fapi.init.method = "GET";
F.Fapi.init.path = "/v1/getboard";
F.Fapi.init.data =  { "product_code": "ETH_JPY" };
F.Fapi.run();
api-bitflyer.com.js
exports.Fapi = {
    init: {
        key: "",
        secret: "",
        method: "",
        path: "",
        data: ""
    },
    run: function () {
        var request = require('request');
        var crypto = require('crypto');

        var timestamp = Date.now().toString();
        var method = this.init.method;
        var path = this.init.path;
        var body = JSON.stringify(
            this.init.data
        );

        var text = timestamp + method + path + body;
        var sign = crypto.createHmac('sha256', this.init.secret).update(text).digest('hex');
        var pra = function(data){
            let str = [];
            for (const key in data) {
                if (data.hasOwnProperty(key)) {
                    str.push(key + "=" + data[key]);
                }
            }
            return "?" + str.join('&');
        };
        var options = {
            url: 'https://api.bitflyer.com' + path + (method.toUpperCase()==="POST"?"":pra(this.init.data)),
            method: method,
            body: body,
            headers: {
                'ACCESS-KEY': this.init.key,
                'ACCESS-TIMESTAMP': timestamp,
                'ACCESS-SIGN': sign,
                'Content-Type': 'application/json'
            }
        };
        request(options, function (err, response, retload) {
            console.log(retload);
        });

    }
};
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[JS1日クッキング]APIサーバーをCircleCIで自動テスト

何かを簡単に作って、ちょっとした勉強になる。そんなシリーズになる予定のものの第3回です。

今回は、シンプルなAPIサーバーをCircleCIで自動テストをします。テストは前回にしてあるものを使います。

完成品はこちら -> sequelize-todo-api-server

JS1日クッキング まとめページ - Qiita

材料

作り方

1. テストメタデータの設定

テストの結果をテストメタデータとしてファイルへ保存できるようにします。CircleCIでテストした後、テストメタデータをCircleCIへアップロードすると、テスト結果がCircleCIのダッシュボードで確認できるようになります。

Jestのテストメタデータを作成するために、jest-junitをインストールします。

npm install -D jest-junit

jest.config.js というファイルを作り、設定を書いていきます。

jest.config.js
module.exports = {
  reporters: ["default", ["jest-junit", { outputDirectory: "reports/jest" }]],
};

ここまでできたら、npm run testでテストを実行すると、reports/jestディレクトリ内にjunit.xmlが生成されるようになります。この中にテストメタデータが入っています。

2. CircleCIの設定ファイルの用意

npm-scriptに

"test:ci": "export NODE_ENV=test && npx jest --ci --runInBand"

を加えます。--ci--runInBandがCIでJestを使うときに必要になります。

CircleCIで使用する設定ファイルを用意します。設定ファイルは、.circleciディレクトリ内のconfig.ymlに書きます。

.circleci/config.yml
version: 2.1

jobs:
  build:
    docker:
      - image: circleci/node:lts
      - image: circleci/mysql:8-ram
        environment:
          MYSQL_USER: sequelize
          MYSQL_PASSWORD: sequepass
          MYSQL_DATABASE: database_test
    steps:
      - checkout
      - restore_cache:
          name: キャッシュの読み込み
          key: dependency-cache-{{ checksum "package-lock.json" }}
      - run:
          name: パッケージをインストール
          command: npm install
      - save_cache:
          name: キャッシュを保存
          key: dependency-cache-{{ checksum "package-lock.json" }}
          paths:
            - node_modules
      - run:
          name: db を待機
          command: dockerize -wait tcp://localhost:3306 -timeout 1m
      - run:
          name: JUnit をレポーターとしてテストを実行
          command: npm run test:ci
      - store_test_results:
          name: テスト結果を保存
          path: reports

jobsのbuild内に、使うコンテナと作業を記述していきます。

dockerキーに使用するコンテナを指定します。最初に使うイメージがコマンドを実行するコンテナになります。なので、Node.jsのコンテナを最初に書き、続いてDBのイメージを書きます。DBの設定は環境変数を使用して設定します。circleci/mysqlの環境変数は、MySQLの公式イメージと同じです。

mysql - Docker Hub

ここでは、sequelizeで設定したユーザー名とパスワードだけでなく、使用するデータベースも設定します。使用するデータベースを設定しないとアクセスが拒否されます。

stepsキーに処理を順番に書いていきます。主に、

  • checkoutでリポジトリからデータをダウンロード
  • npm installでライブラリのインストール
  • dockerize -wait tcp://localhost:3306 -timeout 1mでDBが準備できるまで待つ
  • npm run test:ciでCI用のテストを実行
  • store_test_resultsでテストメタデータをCircleCIへアップロード

ということをしています。

3. CircleCIへリポジトリの登録

CircleCIで自動テストができるようにします。CircleCIに登録をした後、「Projects」のページに移動します。

1-project-add.png

「Set Up Project」をクリックします。

2-start-building.png

「Start Building」をクリックします。

3-add-config.png

新しいブランチ作って、そこにデフォルトの設定ファイルを加えるか尋ねられますが、今回は自分で用意したものを使うので、「Add Manually」をクリックします。

4-start-building.png

「Start Building」をクリックします。これで、CircleCIで使用するリポジトリの設定ができました。

4. 自動テストをする

では、実際に自動テストをしましょう。Githubにプッシュすると、自動的にCircleCIが処理を始めます。

「Piplines」で、CircleCIの処理中の様子や結果をみることができます。

5-piplines.png

処理が終わった後、「build」をクリックすると、以下のように処理結果をみることができます。

6-ci-result.png

「TESTS」をクリックすると、テストメタデータからテスト結果を表示してくれます。

7-ci-tests-display.png

テストが失敗しているときは、以下のようにテストメッセージが表示されます。

test-failure.png

5. ステータスバッヂの表示

CircleCIのステータスバッヂをGithubに表示することができます。CircleCIのステータスバッヂは、以下のようなものです。

8-ci-badge.png

これは、

[![CircleCI](https://circleci.com/gh/[Githubアカウント]/[リポジトリ]/tree/[ブランチ].svg?style=svg)]([画像のリンク先(大抵はGithubのブランチ)])

の中の[]を全部埋めると、MDファイルにステータスバッヂを表示できます。例えば、今回使ったブランチだと、

[![CircleCI](https://circleci.com/gh/kei-lb6/sequelize-todo-api-server/tree/ci-test.svg?style=shield)](https://circleci.com/gh/kei-lb6/sequelize-todo-api-server/tree/ci-test)

のようになります。これをREADME.mdに含めて、Githubでステータスバッヂを表示しています。

詳しくは下のページを参考にしてください。

Adding Status Badges - CircleCI

おわりに

CircleCIで自動テストをしました。workflowを使ってテスト成功後にデプロイをすることもできるので、使いこなせれば楽ができそうです。Netlifyもそうですけど、設定すればGithubにプッシュすれば自動に何かやってくれます系のサービスはとても便利ですね。

コード -> sequelize-todo-api-server

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【array-foreach-async】forEach()でasync/awaitを使おうとして失敗した皆へ

AWS Lambda関数でNode.jsを使用し、forEach()でasync/awaitしたい状況に陥ったのですが、コードを書いて実行してもawaitの文が実行されていませんでした。色々調べたところ、Node.jsのarray-foreach-asyncというライブラリを利用することで簡単に解決することができたので、まとめていきます。

環境

  • macOS
  • AWS Cloud9
  • Node.js 12

修正前の実行コード

今回の説明において不要なコードは省略しています。

const env = process.env
const requestPromise = require('request-promise');
const AWS = require('aws-sdk');
const DB = new AWS.DynamoDB.DocumentClient();

exports.handler = async(event, context) => {

    // (省略)

    event.Records.forEach(async(record) => { // ここでasync  

        // (省略)

        const data = await DB.put(dbParams).promise(); // 1つ目のawait
        console.log(data);

        // (省略)

        const req = await requestPromise.post(options); // 2つ目のawait
        console.log(req);
    });
    return "success!"
};

実行すると、出力にはsuccess!のみが表示され、console.logは無視されます。forEach()がawaitの処理完了を待たずに終了し、Lambda関数が閉じてしまったためです。どちらか一方のawaitをコメントアウトしても結果は変わらず。forEach()ではasync/awaitが効いていないことが分かります。
そもそもArray.prototype.forEach()自体がasync関数ではないため、引数のcallback関数にasync/awaitを付けたところで無意味ということです。

修正後の実行コード

Node.jsのarray-foreach-asyncというライブラリをインストールすることで、forEach()をasync関数にしたforEachAsync()を使用できるようになります。
これを使えば、forEach()と同じ動作でasync/awaitを実現できます(参考:array-foreach-async - npm)。

まずはライブラリをインストールします。

npm install array-foreach-async

ソースコードは次のようになります。

const env = process.env
const requestPromise = require('request-promise');
const AWS = require('aws-sdk');
const DB = new AWS.DynamoDB.DocumentClient();
require('array-foreach-async'); // ライブラリの読み込み

exports.handler = async(event, context) => {

    // (省略)

    await event.Records.forEachAsync(async(record) => { // 変更箇所

        // (省略)

        const data = await DB.put(dbParams).promise(); 
        console.log(data);

        // (省略)

        const req = await requestPromise.post(options);
        console.log(req);

    });
    return "success!"
};

forEachforEachAsyncに変更し、文の先頭にawaitを付けます。
実行すると、awaitの文が両方ともきちんと実行され、ログの出力を確認できました。

補足

ずっとforEach()を使うことしか考えていなかったため後から気が付いたのですが、そもそもforEach()の代わりにfor〜ofを使用すれば解決できました。JavaScriptに慣れていなさすぎる...
修正前の実行コードを次のように変更すればOKです。

const env = process.env
const requestPromise = require('request-promise');
const AWS = require('aws-sdk');
const DB = new AWS.DynamoDB.DocumentClient();

exports.handler = async(event, context) => {

    // (省略)

    for(const record of event.Records) {

        // (省略)

        const data = await DB.put(dbParams).promise(); // 1つ目のawait
        console.log(data);

        // (省略)

        const req = await requestPromise.post(options); // 2つ目のawait
        console.log(req);
    }
    return "success!"
};

コードも簡潔であり、わざわざarray-foreach-asyncをインストールする必要がないので、どうしてもforEach()を使わなければならない状況以外では、素直にfor〜ofを使う方が良いかもしれませんね。

ご参考までに。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

forEach()でasync/awaitを使おうとして失敗した皆へ【array-foreach-async】

AWS Lambda関数でNode.jsを使用し、forEach()でasync/awaitしたい状況に陥ったのですが、コードを書いて実行してもawaitの文が実行されていませんでした。色々調べたところ、Node.jsのarray-foreach-asyncというライブラリを利用することで簡単に解決することができたので、まとめていきます。

環境

  • macOS
  • AWS Cloud9
  • Node.js 12

修正前の実行コード

今回の説明において不要なコードは省略しています。

const env = process.env
const requestPromise = require('request-promise');
const AWS = require('aws-sdk');
const DB = new AWS.DynamoDB.DocumentClient();

exports.handler = async(event, context) => {

    // (省略)

    event.Records.forEach(async(record) => { // ここでasync  

        // (省略)

        const data = await DB.put(dbParams).promise(); // 1つ目のawait
        console.log(data);

        // (省略)

        const req = await requestPromise.post(options); // 2つ目のawait
        console.log(req);
    });
    return "success!"
};

実行すると、出力にはsuccess!のみが表示され、console.logは無視されます。forEach()がawaitの処理完了を待たずに終了し、Lambda関数が閉じてしまっているためです。どちらか一方のawaitをコメントアウトしても結果は変わらず。forEach()ではasync/awaitが効いていないことが分かります。
そもそもArray.prototype.forEach()自体がasync関数ではないため、引数のcallback関数にasync/awaitを付けたところで無意味ということです。

修正後の実行コード

Node.jsのarray-foreach-asyncというライブラリをインストールすることで、forEach()をasync関数にしたforEachAsync()を使用できるようになります。
これを使えば、forEach()と同じ動作でasync/awaitを実現できます(参考:array-foreach-async - npm)。

まずはライブラリをインストールします。

npm install array-foreach-async

ソースコードは次のようになります。

const env = process.env
const requestPromise = require('request-promise');
const AWS = require('aws-sdk');
const DB = new AWS.DynamoDB.DocumentClient();
require('array-foreach-async'); // ライブラリの読み込み

exports.handler = async(event, context) => {

    // (省略)

    await event.Records.forEachAsync(async(record) => { // 変更箇所

        // (省略)

        const data = await DB.put(dbParams).promise(); 
        console.log(data);

        // (省略)

        const req = await requestPromise.post(options);
        console.log(req);

    });
    return "success!"
};

forEachforEachAsyncに変更し、文の先頭にawaitを付けます。
実行すると、awaitの文が両方ともきちんと実行され、ログの出力を確認できました。

補足

ずっとforEach()を使うことしか考えていなかったため後から気が付いたのですが、そもそもforEach()の代わりにfor〜ofを使用すれば解決できました。JavaScriptに慣れていなさすぎる...
修正前の実行コードを次のように変更すればOKです。

const env = process.env
const requestPromise = require('request-promise');
const AWS = require('aws-sdk');
const DB = new AWS.DynamoDB.DocumentClient();

exports.handler = async(event, context) => {

    // (省略)

    for(const record of event.Records) {

        // (省略)

        const data = await DB.put(dbParams).promise(); // 1つ目のawait
        console.log(data);

        // (省略)

        const req = await requestPromise.post(options); // 2つ目のawait
        console.log(req);
    });
    return "success!"
};

コードも簡潔であり、わざわざarray-foreach-asyncをインストールする必要がないので、どうしてもforEach()を使わなければならない状況以外では、素直にfor〜ofを使う方が良いかもしれませんね。

ご参考までに。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Node.jsをPHPで書き換えてみた

N予備校のプログラミング入門コース3章で作成した「秘密の匿名掲示板」をPHPで書き換えてみたので,その記録です。

きっかけ

スラスラわかるPHP(志田 仁美 著 翔泳社 刊)をやってみて,
「この間作った匿名掲示板,書き換えられるのでは?」
と思ったので。
スラスラわかるPHPをやってみた所感はこちら

早速書き換える

仕様を変更したところ

  • 認証の方式
    おそらくN予備校ではBasic認証(alartみたいに上に出てくるやつ)を使っていたと思いますが, 書き換えの際にはスラスラわかるPHPのように,DBを使用する方式としました。
  • TrackingID
    N予備校で作成した際はCookieを利用してTrackingIDを実装していたと思いますが,セッションを利用する方式としました。

その他細かい変更点はあると思うのですが,大きく変更したのはこちら2点です。

書き換えで苦労したところ

記事とユーザーの情報をどう関連付けるか

Laravelでは
userテーブル->id = articleテーブル->userid
としておけば情報を結びつけてくれていましたが,
今回はそれができない…ということで,とても苦労しました。
結局,セッションに該当するユーザー情報をもたせることで実現しました。
今回の場合,ユーザーのidとユーザー名が該当しました。

TrackingIDをどう実現するか

Cookieを使うべきか?それともセッションを使うべきか?…という,なんとも根本的なところから悩みました。
こればかりは一人で解決できず,友人にも意見を求めたところ,セッションで実現でいいのでは?という意見をもらったので,結局セッションを使うということで,決着。
ざっくりとした実装方法は下記の通りです。

ログイン時にランダムな文字列を予めセッションにセットしておく(仮にsecretidとします)
→書き込み時にpostテーブルに格納
→IDとして表示するのはsecretidの値

所感

思ったよりも難しかった気がする

これはただ単に私の実力不足に起因するものだと思いますが,思ったよりも難しかった気がします。

勉強になった

セッションか?Cookieか?を考えたり,どうやってuserテーブルの情報をpostテーブルに入れるか…?を考えたり。
今まではmigrationに頼っていた部分がSQLになるので,SQLの勉強をしてみたり。
どうやって実現していたか?のロジックを一から考え直してみたり…
簡単に実現することはできませんでしたが,自分の実力不足を痛感するとともに,勉強になったことは多かったように思います。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

nodebrew入れるときにnodeのPATHが遠らない話(マカー向け)

nodeのPATHが通らない

・.bashrcにはPATHをとおす記述を書く
・.bash_profileには毎回起動時にbashrcを読み込む記述を書く
上記二点は済なのに
.bashrcをコマンド叩いて毎回読み込ませないといけない地獄から抜け出せなかったので何かと思ったら
bashではなくzshを使っていたらしい。。

http://pixelbeat.jp/bash_profile_not_working/ を参考に
~/.zprofile に ~/.bash_profile と同じ内容を追記したら直りました。

ありがとうございました!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

GoogleAPI for Node.js で Authorize までを共通化する

はじめに

Node.js を使用して GoogleAPI にアクセスする場合、SheetAPI であろうと DriveAPI であろうと認可の部分までは実は大体一緒です。

https://developers.google.com/docs/api/quickstart/nodejs
https://developers.google.com/sheets/api/quickstart/nodejs
https://developers.google.com/drive/api/v3/quickstart/nodejs

あまりプロジェクト内で各サービスを行き来する事は無いのですが、どうせ共通なら一つのファイルにまとめて使いまわしたい、と思ってクラスを作りました。サンプルの内容をts化、クラス化して、Promise 対応しています。
誰でも思いつく事だと思いますが、今後の自分のため + 同じような結論に行きついた方のためにまとめておきます。

認可までを行うクラス

GoogleAuthorizer という名称のクラスにしました。
適当な名前で、以下のファイルを保存します。ここでは authorize.ts にしました。

import fs from "fs";
import readline from "readline";
import { google } from "googleapis";
import { OAuth2Client } from "googleapis-common";

export class GoogleAuthorizer {

  private credentialsBuffer: string | null = null;
  private tokenBuffer: string | null = null;

  constructor(
    private scopes: string[],
    private tokenPath: string,
    private credentialsPath: string
  ) { }

  public async getOAuth2Client(): Promise<OAuth2Client> {
    if (this.credentialsBuffer) {
      return await this.authorize(JSON.parse(this.credentialsBuffer));
    } else {
      return new Promise<OAuth2Client>((res, rej) => {
        fs.readFile(this.credentialsPath, async (err, content) => {
          if (err) {
            rej('Error loading client secret file:' + err);
            return;
          }
          // Authorize a client with credentials, then call the Google Drive API.
          this.credentialsBuffer = content.toString();
          try {
            const o = await this.authorize(JSON.parse(content.toString()));
            res(o);
          } catch (e) {
            rej(e);
          }
        });
      });
    }
  }

  private async authorize(credentials: any): Promise<OAuth2Client> {
    return new Promise<OAuth2Client>((res, rej) => {
      const { client_secret, client_id, redirect_uris } = credentials.installed;
      const oAuth2Client = new google.auth.OAuth2(
        client_id, client_secret, redirect_uris[0]);
      if (this.tokenBuffer) {
        oAuth2Client.setCredentials(JSON.parse(this.tokenBuffer));
        res(oAuth2Client);
        return;
      }
      // Check if we have previously stored a token.
      fs.readFile(this.tokenPath, async (err, token) => {
        if (err) {
          try {
            await this.getAccessToken(oAuth2Client);
            res(oAuth2Client);
          } catch (e) {
            rej(e)
          }
          return;
        }
        this.tokenBuffer = token.toString();
        oAuth2Client.setCredentials(JSON.parse(token.toString()));
        res(oAuth2Client);
      });
    });
  }

  private getAccessToken(oAuth2Client: OAuth2Client): Promise<OAuth2Client> {
    return new Promise<OAuth2Client>((res, rej) => {
      const authUrl = oAuth2Client.generateAuthUrl({
        access_type: 'offline',
        scope: this.scopes,
      });
      console.log('Authorize this app by visiting this url:', authUrl);
      const rl = readline.createInterface({
        input: process.stdin,
        output: process.stdout,
      });
      rl.question('Enter the code from that page here: ', (code) => {
        rl.close();
        oAuth2Client.getToken(code, (err, token) => {
          if (err || !token) {
            rej('Error retrieving access token' + err);
            return;
          }
          oAuth2Client.setCredentials(token);
          // Store the token to disk for later program executions
          fs.writeFile(this.tokenPath, JSON.stringify(token), (err) => {
            if (err) {
              rej(err);
              return;
            }
            console.log('Token stored to', this.tokenPath);
          });
          res(oAuth2Client);
        });
      });
    });
  }
}

あまり気にしなくても良いかもしれませんが、ファイルIOがあまり発生するのもアレかなと思って、一度ファイルから読んだ情報はバッファに入れて再利用しています。

使用方法

先程保存した authorize.ts を読み込み、コンストラクタに以下の引数を指定して、まずはインスタンスを作成します。
その後、getOAuth2Clientawait 付きで呼び出せば、必要な OAuth2Client が取得できます。

引数 内容
1 使用するスコープ(配列)
2 トークンファイルのパス
2 認証ファイルのパス
import { GoogleAuthorizer } from "./authorize";

class Main {

  constructor() {
    this.init();
  }

  async init() {
    const SCOPES = ['https://www.googleapis.com/auth/drive.metadata.readonly'];
    const TOKEN_PATH = "token.json";
    const CREDENTIALS_PATH = "credentials.json";

    const a = new GoogleAuthorizer(SCOPES, TOKEN_PATH, CREDENTIALS_PATH);
    try {
      const auth = await a.getOAuth2Client();
      console.log(auth);
    } catch(e) {
      console.error(e);
    }
  }

}
new Main();

おまけ

冒頭で紹介した Google の Node.js サンプルページでは、とりあえず認証情報作るボタンがありますが、これをクリックすると QuickStart というプロジェクトが作成され、その中に適切な権限が与えられた認証情報が作成されて、認証ファイルがDLされます。
既存のプロジェクトに手動で追加する場合に困ったのですが、以下に方法が書いてありました。

https://cloud.google.com/bigquery/docs/authentication/end-user-installed?hl=ja#bigquery-enduser-installed-packages-nodejs

manual.png

BigQueryのページですが、ここはサービス間で共通です。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

�CircleCIに新しいDockerイメージ cimg が使えるようになったらしい!

cimgとは

CircleCIの次世代convenience imageとして新しいDockerイメージが登場しておりました。
より安定性とキャッシュ効率について考えられています。

詳細はこちらのリンクを確認ください。
https://circleci.com/blog/announcing-our-next-generation-convenience-images-smaller-faster-more-deterministic/

登場したわけ

「circleci/node」はnodeのDockerfile+CircleCIのライブラリ?で構成されています。
そのため、nodeに破壊的な変更が加わると「circleci/node」がうまく起動しないことが発生しました。
それを防ぐために登場したものがcimgのイメージです。
※間違っていましたらご指摘お願いします

検証

どれくらいキャッシュ効率がいいのか試してみました。
各Nodeのイメージを使用するまでのpull時間を計測します。
(circleci側でキャッシュしているだろうという前提)

  • build-node
    • Dockerイメージ:Node
  • build-circleci_node
    • Dockerイメージ:circleci/node
  • build-cimg_node
    • Dockerイメージ:cimg/node

検証結果

数回実施しましたが平均的に以下のような結果になりました。

スクリーンショット 2020-06-04 9.08.34.png

まとめ

「circleci/node」,「cimg/node」ともに早すぎてこれ以上差がつかないのかもしれない!?
登場したわけを聞いた時、今後の利用はcimg系の利用が必須ではないかなと思い、この記事を書きました。
こちらの情報(cimg)はCircleCIのユーザーコミュニティイベントで初めて聞きましたので、機会があればまた参加して色々聞いてみようかなー
皆さんもぜひこちらに参加してみてください。

では、よいCI/CDライフを!!

検証に利用したソース

ちなみに、検証に使用したソースはこちらです。

config.yml
version: 2
jobs:
  build-cimg_node:
    docker:
      - image: cimg/node:12.16
    steps:
      - checkout
      - run: node --version
  build-circleci_node:
    docker:
      - image: circleci/node:12.16
    steps:
      - checkout
      - run: node --version
  build-node:
    docker:
      - image: node:12.16
    steps:
      - checkout
      - run: node --version
workflows:
  version: 2
  build_and_test:
    jobs:
      - build-cimg_node
      - build-circleci_node
      - build-node
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Node.js の mysql2 で MariaDB のデータを削除 (Delete)

Async/Await を使います。

maria_delete.js
#! /usr/bin/node
// ---------------------------------------------------------------
//  maria_delete.js
//
//                  Jun/04/2020
//
// ---------------------------------------------------------------
var mysql = require('mysql2')

// ---------------------------------------------------------------
async function main(id_in)
{
    const dotenv = require('dotenv')
    dotenv.config()
    const user = `${process.env.user}`
    const password = `${process.env.password}`
    const data_base = `${process.env.data_base}`

    var conn = await mysql.createConnection ({
        host: 'localhost',
        user: user,
        password: password,
        database: data_base
        })

    const command = "delete from cities where id = '" + id_in + "'"

    await conn.execute(command)
    conn.end()
    console.error ("*** 終了 ***")
}

// ---------------------------------------------------------------
console.error ("*** 開始 ***")
const id_in = process.argv[2]
console.log (id_in)
main(id_in)
// ---------------------------------------------------------------

実行コマンド

export NODE_PATH=/usr/lib/node_modules
./maria_delete.js t3327
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Node.js の mysql2 で MariaDB のデータを更新 (Update)

Async/Await を使います。

maria_update.js
#! /usr/bin/node
// ---------------------------------------------------------------
//  maria_update.js
//
//                  Jun/04/2020
//
// ---------------------------------------------------------------
var mysql = require('mysql2')

// ---------------------------------------------------------------
function get_current_date_proc ()
{
    const today = new Date ()
    var ddx = (1900 + today.getYear ()) + "-" + (today.getMonth () +1)
    ddx += "-" + today.getDate ()

    return ddx
}

// ---------------------------------------------------------------
function update_command_gen (id_in,population_in)
{
    const today = get_current_date_proc()
    var command = "update cities set population = " + population_in
    command += " , date_mod = '" + today + "'"
    command += " where id = '" + id_in + "'"
    console.log (command)

    return  command
}

// ---------------------------------------------------------------
async function main(id_in,population_in)
{
    const dotenv = require('dotenv')

    dotenv.config()

    const user = `${process.env.user}`
    const password = `${process.env.password}`
    const data_base = `${process.env.data_base}`

    var conn = await mysql.createConnection ({
        host: 'localhost',
        user: user,
        password: password,
        database: data_base
        })

    const command = update_command_gen (id_in,population_in)

    await conn.execute(command)
    conn.end()
    console.error ("*** 終了 ***")
}

// ---------------------------------------------------------------
console.error ("*** 開始 ***")

const id_in = process.argv[2]
const population_in = process.argv[3]

console.log (id_in + "\t" + population_in)

main(id_in,population_in)
// ---------------------------------------------------------------

実行コマンド

export NODE_PATH=/usr/lib/node_modules
./maria_update.js t3326 721539800
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Node.js の mysql2 で MariaDB のデータを読む (Read)

Async/Await を使います。

maria_read.js
#! /usr/bin/node
// ---------------------------------------------------------------
//  maria_read.js
//
//                  Jun/04/2020
//
// ---------------------------------------------------------------
function compare_by_key_proc (left,right)
{
    var aa = left.key
    var bb = right.key

    var rvalue = 0

    if (aa < bb)
        {
        rvalue = -1
        }
    else if (aa > bb)
        {
        rvalue = 1
        }

    return  rvalue
}

// ---------------------------------------------------------------
function sort_key_proc (dict_aa)
{
    var array = new Array()

    for(var it in dict_aa)
        {
        array.push({'key':String (it), 'value':dict_aa[it]})
        }

    array.sort (compare_by_key_proc)

    return array
}

// ---------------------------------------------------------------
function dict_display_proc (dict_aa)
{
    const array_aa = sort_key_proc (dict_aa)

    array_aa.forEach (function(unit_aa,index)
        {
        const key = unit_aa.key
        const value = unit_aa.value

        var out_str = key + "\t"
        out_str += value["name"] + "\t"
        out_str += value["population"] + "\t"
        out_str += value["date_mod"]
        console.log (out_str)
        })  
}

// ---------------------------------------------------------------
async function read01 (mysql,user,password,data_base)
{
    try {
    var conn = await mysql.createConnection({
        host: 'localhost',
        user: user,
        password: password,
        database: data_base
        })
    const sql_str = 'select * from cities'
    const [rows, fields] = await conn.execute(sql_str)

    return rows
    } catch (ee) {
        console.log(ee)
        return ''
    } finally {
        if (conn && conn.connection) {
        conn.end()
    }
}

}

// ---------------------------------------------------------------
async function main()
{
    var mysql = require('mysql2/promise')
    const dotenv = require('dotenv')

    dotenv.config()

    const user = `${process.env.user}`
    const password = `${process.env.password}`
    const data_base = `${process.env.data_base}`

    const rows = await read01 (mysql,user,password,data_base)

    var dict_aa = new Object ()

    rows.forEach(function(row)
        {
        dict_aa[row.id] = {"name": row.name,
            "population": row.population,
            "date_mod": row.date_mod}
        })

    dict_display_proc (dict_aa)

    console.error ("*** 終了 ***")
}

// ---------------------------------------------------------------
console.error ("*** 開始 ***")
main()
// ---------------------------------------------------------------

実行コマンド

export NODE_PATH=/usr/lib/node_modules
./maria_read.js
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Node.js の mysql2 で MariaDB のデータを作成 (Create)

Async/Await を使います。

maria_create.js
#! /usr/bin/node
// ---------------------------------------------------------------
//  maria_create.js
//
//                  Jun/04/2020
//
// ---------------------------------------------------------------
var mysql = require('mysql2/promise')
// ---------------------------------------------------------------
function dict_append_proc (dict_aa,id_in,name_in,population_in,date_mod_in)
{
    var unit_aa = {}
    unit_aa['name'] = name_in
    unit_aa['population'] = population_in
    unit_aa['date_mod'] = date_mod_in

    dict_aa[id_in] = unit_aa

    return  dict_aa
}

// ---------------------------------------------------------------
function data_prepare_proc ()
{
    var dict_aa = new Object ()

    dict_aa = dict_append_proc (dict_aa,'t3321','岡山',812763,'1950-10-23')
    dict_aa = dict_append_proc (dict_aa,'t3322','倉敷',783257,'1950-7-15')
    dict_aa = dict_append_proc (dict_aa,'t3323','津山',975241,'1950-1-2')
    dict_aa = dict_append_proc (dict_aa,'t3324','玉野',231864,'1950-6-22')
    dict_aa = dict_append_proc (dict_aa,'t3325','笠岡',769358,'1950-8-14')
    dict_aa = dict_append_proc (dict_aa,'t3326','井原',865792,'1950-9-12')
    dict_aa = dict_append_proc (dict_aa,'t3327','総社',438251,'1950-3-21')
    dict_aa = dict_append_proc (dict_aa,'t3328','高梁',352486,'1950-7-26')
    dict_aa = dict_append_proc (dict_aa,'t3329','新見',276951,'1950-10-2')


    return  dict_aa
}

// ---------------------------------------------------------------
async function main()
{
    const dict_aa = data_prepare_proc ()

    const dotenv = require('dotenv')

    dotenv.config()

    const user = `${process.env.user}`
    const password = `${process.env.password}`
    const data_base = `${process.env.data_base}`

    try {
    var conn = await mysql.createConnection ({
        host: 'localhost',
        user: user,
        password: password,
        database: data_base
        })

    const sql_str_drop = 'drop table if exists cities'
    await conn.execute(sql_str_drop)

    var sql_str_create = 'create table cities '
    sql_str_create += '(id varchar(10), name varchar(20),'
    sql_str_create += ' population int, date_mod date)'
    await conn.execute(sql_str_create)

    for (var key in dict_aa)
    {
    console.log(key)
    var sql_str = "insert into cities "
    sql_str += "(id,name,population,date_mod) values ("

    const str_data = "'" + key + "','" + dict_aa[key].name + "',"
        + dict_aa[key].population + ",'" + dict_aa[key].date_mod + "')"

    sql_str += str_data
    await conn.execute(sql_str)
    }

    } catch (ee) {
        console.log(ee)
        return ''
    } finally {
        if (conn && conn.connection) {
        conn.end()
        }
    }

    console.log ("*** 終了 ***")
}

// ---------------------------------------------------------------
console.log ("*** 開始 ***")
main ()
// ---------------------------------------------------------------

実行コマンド

export NODE_PATH=/usr/lib/node_modules
./maria_create.js
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む