20190425のNode.jsに関する記事は8件です。

Alexa Lambda関数を「一から作成」する方法

Alexa SkillのLambda関数の作成は、「設計図」のテンプレートから作成する方法が、Alexa道場では紹介されています。
でも、この場合、もともとの設計図のサンプルコードが入っており、それを編集していくのは面倒だったり、何より、関数名の一部は変更できず、関数名が長く気持ちが悪いです。
そこで、「一から作成」を使って、ローカル環境で作成したプロジェクトをアップロードする方法を紹介します。
どちらかというと備忘録です。

Node.jsプロジェクトの作成とindex.jsの作成

まず、ローカルドライブで、プロジェクトを作成し、package.jsonを作成します。

$ mkdir SKILL_DIRECTORY
$ cd SKILL_DIRECTORY
$ npm init

npm initでは、package nameなどを聞かれますが、とりあえずそのまま[Enter]します。

続いて、Alexaのモジュールを追加します。

$ npm install ask-sdk

すると、npm_modulesというフォルダが作成され、ここにask-sdkのモジュールが以下のように追加されます。

フォルダ
.bin
ask-sdk
ask-sdk-core
ask-sdk-dynamodb-persistence-adapter
ask-sdk-model
ask-sdk-runtime
aws-sdk
base64-js
buffer
...

ここで、不要と思われるモジュールのフォルダは削除します。必要なモジュールのフォルダのみにします。
aws-sdkは、Lamdba上に存在するため削除します。
その他base64-jsなどaskで始まらないモジュールのフォルダを削除します。
askで始まるモジュールは、そのフォルダにpackage.jsonファイルが存在します。
このファイルを開いて_whererを探すとそこには、ローカルフォルダの位置が記載されています。リポジトリで使用するようですが、ローカルフォルダがわかるのが嫌なら削除してしまいましょう。

続いて、基本となるindex.jsを作成します。このファイルが呼び出しファイルになります。自分でなんらか記載します。

その後、このindex.jsnode_modulesフォルダをzipで圧縮します。

zipファイルのLamdbaへのアップロード

AWSのLambdaの関数から「関数の作成」の「一から作成」を選び、関数名を自由につけて、「関数の作成」ボタンを押下します。
一から作成.jpg

続いて、関数コードのコードエントリタイプを「.zipファイルをアップロード」を選択し、zipファイルをアップロードします。

これであとは、エンドポイントなどを設定すれば、Alexa developer consoleから作成した関数を呼び出すことができます。

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

【Angularアプリ開発】Angularアプリの基本構造を説明します

モジュール

プロジェクトを構成するコンポーネントを束ねる要件はモジュールと呼びます。Angular自体にも複数のモジュールから構成されております。プロジェクトの要件に応じて必要なモジュールをインポートして利用することになります。

App.module

/src/app/に含まれているapp.module.tsファイルは、アプリを起動する際に最初に読み取りにして行くモジュールです。
下図で、app.module.tsファイルを例としてモジュールの役割を見てみましょう。
スクリーンショット 2019-04-25 22.00.13.png

importコマンド
構文: import{ name1, …, nameN } from module
    ・name: インポートする要素名(複数指定可)
    ・module: モジュール
意味: Angularアプリを動作させるのに必要となるモジュール/コンポーネントをインポートします。
Angular標準モジュール
上図の「1.」の@angular/~はAngularが提供する標準モジュールです。最低限、モジュールを定義するためのNgModule、ブラウザー上でアプリを動作させるためのBrowserModuleが導入必要です。
本格的なアプリでは、フォームを扱うためのFormsModule、ルーティング機能を提供するRouterModuleなどを導入する必要があります。
AppRoutingModule
上図の[2.]のAppRoutingModule、 ルートのAppModuleからインポートされるルーティング専用のトップレベルモジュールで、 ルーターをロードして管理することです。
?実装は、下記の「AppRoutingModuleの実装」に行われます。
AppComponent
上図の[3.]のAppComponentは、アプリの本体を表すコンポーネントです。
?実装は、下記の「AppComponentの実装」に行われます。
モジュールクラス
上図の「4.」のAppModuleモジュールクラスは、他のモジュールから呼び出す際などには、ここで宣言した名前(AppModule)を利用します。
@NgModuleデコレーター
上図の「5.」の@NgModuleデコレータは、他者が本モジュールを見れるために、本モジュールとしての情報を宣言しておきましょう。
デコレーターは、モジュールやクラスなどの要素に対してメタ情報を付与するための仕組みです。Javaのアノテーションに相当する仕組みです。
デコレーターには「パラメーター名: 値」のハッシュ形式で、あらかじめ決められたパラメーター情報を指定できます。

@NgModuleデコレーターには、主に以下ようなパラメーターが利用できます。

パラメーター 概要
declarations              モジュール配下のコンポーネント
imports 現在のモジュールで利用する他のモジュール/コンポーネント
exports 現在のモジュールで外部に公開するコンポーネント
providers サービス
bootstrap 最初に起動すべき最上位のコンポーネント(=ルートコンポーネント)

AppConponentの実装

上記の「App.module」の「3.」のAppConponentを実装します。
AppConponent(もしくはメインコンポーネント)とは、アプリで最初に呼び出される、いわゆるエントリーポイントです。
スクリーンショット 2019-04-25 22.01.27.png

「1.」は、コンポーネントを定義するために必要となるオブジェクトをインポートしています。
「2.」は、コンポーネントの本体で、先ほどAppModuleモジュールで指定したAppComponentという名前でコンポーネントクラスを作成しています。モジュールから参照できます
?exportキーワードで外部に公開していることに注意してください。
「3.」@Componentデコレーターでは、さまざまなパラメーターを指定できます。

パラメーター 概要
selector コンポーネントの適用先を表すセレクター式
template コンポーネントに適用するビュー(テンプレート)

テンプレートの中の変数nameは、Interpolation(補間)と呼ばれる構文で、「4.」の場所に定義されております。

AppRoutingModuleの実装

上記の「App.module」の「3.」のルートモジュールを実装します。ルートモジュールは、ユーザーがリンクをクリックしたとき、またはURLをブラウザのアドレスバーに貼り付けた時に、 どのビューを表示したらよいかをルーターに伝えます。
スクリーンショット 2019-04-25 22.34.27.png
「2.」のRoutesは、「パラメーター名: 値」のハッシュプロパティを持っています:

パラメーター 概要
path ブラウザのアドレスバーにある URL にマッチする文字列
component              そのルートに遷移するときにルーターが作成すべきコンポーネント

errorページ追加

VSCodeのターミナルを開き、以下ようにerrorページを追加してみましょう。

$ ng g component error
# 以下表示
  CREATE src/app/error/error.component.css (0 bytes)
  CREATE src/app/error/error.component.html (24 bytes)
  CREATE src/app/error/error.component.spec.ts (621 bytes)
  CREATE src/app/error/error.component.ts (265 bytes)
  UPDATE src/app/app.module.ts (734 bytes)

下図のように、ルートモジュールを編集しErrorページをルーターに伝えます。
スクリーンショット 2019-04-25 23.05.49.png

Errorページを試すために、サーバを起動して、URLに「localhost:4200/error」を打つでErrorComponentを表示しましょう。

$ ng serve

スクリーンショット 2019-04-25 23.05.02.png

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

もう npm ls でイラッとしない

みなさんは npm ls で依存モジュールがずらずらと表示されて、イラッとしたことはありませんか。私はあります。

npm ls --depth=0

とすれば、トップレベルのモジュールのみに制限できますが、いちいち --depth=0 をつけるのは面倒です。

そこで、次のコマンドを実行してみましょう。

npm config set depth 0

これ以降、--depth=0 をつけなくても、npm ls でトップレベルのモジュールのみが表示されるようになります。設定は ~/.npmrc に保存されます。

依存ツリーが見たい場合は、

npm ls --depth=9999

のように、depth を適当に大きな値で上書きすれば OK です。

参考

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

slackにdynamoDBから情報を取得して、整形まで。[投稿は、ご自身で。]

ことの発端

  • POSを開発しているチーム所属なので導入店舗が増えれば管理も増えてくる。
  • クレジット決済端末を交換したい時とかに、いちいちCLIでDynamoDBをみていた。
    • めんどくさい of the day。

どうでもいいこと

  • Node: 知りません。
  • TypeScript: 美味しいの?
  • lambda: チョットワカル
  • Qiita: 通勤してる時にちょっと見る。
  • 某パズルゲーム: ランク994(2019/04/24)
    • 昨年ランク1000行けなかったのが悔しい。

では、参る。

  • slackのスラッシュコマンドで作りました。
    • すでにあるものに付け加えたので、slackから値を受け取りたい等はお調べください。
  • 今回slackから渡ってくるサブコマンドは、3つあります。

    • [1]: どのコマンド使うか。 <- 必須。
    • [2]: dynamoDBの primary key となるもの(今回は文字列4桁) <- 必須。
    • [3]: dynamoDBの sort key となるもの(こちらも文字列4桁) <- なくてもいい。 Pasted_Image_2019_04_24_19_02.png
  • エラーハンドリングは社内でしか使いわないので、しません。

  • TypeScriptです。

  • 男は黙ってconst

post to slack #1

sample.ts
import * as AWS from "aws-sdk"
import * as url from "url"

const docClient = new AWS.DynamoDB.DocumentClient();

import * as url from "url" は呼ばれたチャンネルに返却するためです。

参考資料: AWS JavaScript SDK DynamoDB - 公式ドキュメント

post to slack #2

main functionの内部です。

sample.ts
const resURL = url.parse(query.response_url)
const partitionKey = query.text.split(" ")[1];
let params

if (query.text.split(" ")[2] && query.text.split(" ")[2] !== "") {
    const sortKey = query.text.split(" ")[2]
    params = {
      TableName: TABLE_NAME,
      ProjectionExpression: '#pk, row2, row3, row4, row5, row6',
      KeyConditionExpression: '#pk = :partKey AND row1 = :sortKey',
      ExpressionAttributeNames: { '#pk': PRIMARY_KEY },
      ExpressionAttributeValues: {
        ':partKey': partitionKey,
        ':sortKey': sortKey
      },
    }
} else {
    params = {
      TableName: 'TABLE_NAME',
      ProjectionExpression: '#pk, row2, row3, row4, row5, row6',
      KeyConditionExpression: '#pk = :partKey',
      ExpressionAttributeNames: { '#pk': PRIMARY_KEY },
      ExpressionAttributeValues: { ':partKey': partitionKey },
      Limit: 10,
    }
}
  • TableName: DynamoDBの使用するテーブル名
  • ProjectionExpression: DynamoDBから取ってきたい列。 <- なくてもいい。
  • KeyConditionExpression: クエリ部分
  • ExpressionAttributeNames: クエリする際のprimaryKeyと思えばいいはず。
  • ExpressionAttributeValues: ExpressionAttributeNamesの値
  • Limit: DynamoDBから取得する最大数。

if内はslackからくる引数が2つの場合。(1つだけ抽出)
else内は引数が1つの場合。(PRIMARY_KEYの列を抽出)

post to slack #3

sample.ts
docClient.query(params, (err, data: any) => {
    if (err) {
      console.error("Unable to query. Error:", JSON.stringify(err, null, 2));
    } else {
      const array = data.Items.map(i => {
        const output = {
          item1: i.row2
          item2: i.row3,
          item3: i.row4,
          item4: i.row5,
          item5: i.row6,
        }
        return output
      });

      let fields = [{
        title: String,
        value: ``,
        short: true
      }];

      fields.splice(0, 1) // 空の連想配列を取り除く
      for (const i of array) {
        const text = ` item1: ${i.item1}\n item2: ${i.item2}\n item3: ${i.item3}\n item4: ${i.item4}\n`
        fields.push({
          title: i.item5,
          value: "```" + text + "```",
          short: true
        })
      }
post to slack #4に続く

:warning:TypeScriptなのにany使ってます。ごめんなさい。

  • 必要な物だけを使いたかったので ProjectionExpression を記述しました。
  • Slack Attachments ドキュメント
  • Pasted_Image_2019_04_25_15_27.png 仕上がりはこんな感じにしました。
  • fieldsを使用することで、slackのスペースを有効に使えます。
  • fields部分の処理をforですることで複数に対応しています。
    • 1回の処理で枠1つのfieldsを作り、arrayの要素分作成します。
  • 複数にする際はfor文でできます。

post to slack #4

sample.ts
const attachments = [
        {
          fallback: "通知:tada:",
          color: "#439FE0",
          title: "タイトル + partitionKey",
          fields: fields,
          mrkdwn_in: ["text"],
        }];
      postSlackBot(resURL, attachments) //自前の関数です。
    }
  });
  • fallback: 通知。シュココのところです。
  • color: 色
  • title: タイトル
  • fields: #3で作ったfields

自前の関数はありますが、slackに表示する記事はたくさんあると思うので、検索してみてください。

おわり。

以上で、DynamoDBから取得し、整形までのフローです。

もっとよくできるとかあれば、コメントいただければと思います。

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

Node.js v12をyumでインストールしてみた。(CentOS 7)

Node.js v12がリリース

node.js v12 (LTS予定)がリリースされました。
v8エンジンがアップグレードされたり、TLS1.3がサポートされたりと、色々変わっているようです。
詳しくは、リリースノート(英語)をみましょう。
https://github.com/nodejs/node/blob/master/doc/changelogs/CHANGELOG_V12.md#12.0.0

Node.js v12 をインストール

取り敢えず、リポジトリを追加。

# yum install https://rpm.nodesource.com/pub_12.x/el/7/x86_64/nodesource-release-el7-1.noarch.rpm

念のため、yum でnodejsのどのバージョンが対象になっているか確認。

# yum info nodejs

Installed Packages
Name        : nodejs
Arch        : x86_64
Epoch       : 2
Version     : 12.0.0 <-ココが重要
Release     : 1nodesource
Size        : 58 M
Repo        : installed
From repo   : nodesource
Summary     : JavaScript runtime
URL         : http://nodejs.org
License     : MIT and ASL 2.0 and ISC and BSD
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.

問題なさそうなので、インストールする。

# yum -y install nodejs

最後に、バージョンを確認しておしまい。

# node --version
v12.0.0

enjoy!

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

Node.jsとPHP APIを使用して複合機が受信するFAXをアプリで見れるようにしてみた。

はじめに

・複合機でFAXを受信したときに、そのデータをスマホアプリに転送してほしいとお願いされた。Node.jsとPHP APIを使用して機能の実現を試みました。

開発環境

・サーバー構成
 WindowsServr2012R2
 Apache + SQLServer2012 + PHP
 Node.js(シェルスクリプト)

・複合機機種
 Canon iR-ADV C5235F

実装コード

・Node.jsからPHP APIの呼び出し

 参考にしたページ:https://qiita.com/zaburo/items/0280807fe5e59026e41b

fax_tenso.js
var kyotenHand001EmailAdress = "【手動転送用のメールアドレス】";
var kyotenAuto001EmailAdress = "【自動転送用のメールアドレス】";
var request = require('request');
// HTTP header
var headers = {
  'Content-Type': 'application/json',
  'Content-type': 'application/x-www-form-urlencoded'
};
//require
var chokidar = require("chokidar");
funcWatcher(
  "【会社番号】/【拠点番号】/hand/",
  "【会社ごとの転送用メールアドレス】",
  kyotenHand001EmailAdress
);
//-----------------------------------
// 2018/05/26
// shinichi yamazaki
// node.jsでファイルの変更を検出して何かする
// ファイル監視のための処理を関数化しました
// 引数1:監視するディレクトリパス
// 引数2:会社を特定するためのメールアドレス(メールアドレスである必要はあまりない)
// 引数3:拠点とFAXモードを特定するためのメールアドレス(全社共通)
//-----------------------------------
function funcWatcher(
    pass, 
    companyEmailAdress, 
    kyotenEmailAdress)
{
  // chokidarの初期化
  var watcher = chokidar.watch(
      "【サーバーの監視先フォルダパス】" + pass, {
      ignored:/[\/\\]\./,
      persistent:true
  });
  // イベント定義
  watcher.on('ready',function(){
      // 準備完了
      console.log("ready watching...");
      // ファイルの追加
      watcher.on('add',function(path){
        var options = {
          url : '【FAX転送用のPHP API】',
          method: 'POST',
          headers: headers,
          form: {
            'companyEmailAdress': companyEmailAdress,
            'kyotenEmailAdress': kyotenEmailAdress,
            'mailTitle': "hello"
          }  
        };
        // FAX転送用のPHP APIの呼び出し
        request.post(options, function (error, response, body) {
          if (body) {
            var options = {
              url : '【通知用のPHP API】',
              method: 'POST',
              headers: headers,
              form: {
                  'idm': "",
                  'registerID': "-1",
                  'companyID': "",
                  'staffID': "",
                  'msg': "新しいFAXを受信しました",
                  'mode': "mode=6",
                  'groupID': "",
                  'smartPhoneName': body
              }  
            };
            // 通知用のPHP APIの呼び出し
            request.post(options, function (error, response, body) {
              if (body) {
              }
              if (error) {
              }
            });
            console.log(body);
          }
          if (error) {
            console.log(error);
          }
        });
        console.log(path + " added.");
      });
  });
}

サーバー側
 FAX転送用のPHP API

fax_tenso.php
<?php
  date_default_timezone_set('Asia/Tokyo');
  // 現在日時をUNIXタイムスタンプを秒単位で取得する
  $now = time();
  // 現在日時を YYYY/MM/DD hh:mm:ss の書式の文字列で取得する
  $now = date('Y/m/d H:i:s');
  $companyEmailAdress = $_POST["companyEmailAdress"];
  $kyotenEmailAdress  = $_POST["kyotenEmailAdress"];
  $subject  = $_POST["mailTitle"];
  $bodystructure  = $_POST["bodystructure"];
  // 変数宣言
  $companyID = "";
  $faxKyoten = "";
  $faxMode   = "";
  $sendFlag  = "";
  $maxFaxID  = "";
  // FAX受信者リスト
  $faxPushList = NULL;
  $pushJsonArray = array();
  require('common.php');
  //-----------------------------------------
  // マッピング
  // 会社番号の取得
  // 2018/05/03 yamazaki
  //-----------------------------------------
  $companyData = databaseGet(
    "SELECT".
    "    companyID".
    " FROM MK_company".
    " WHERE".
    "    faxEmail=N'".$companyEmailAdress."'"
  );
  // 存在していないときの処理
  if ($companyData == NULL) {
    echo "会社番号の取得に失敗しました。";
    die('MSSQL Serer Connect Error');
  }
  else {
    $companyID = $companyData[0]["companyID"];
  }
  //-----------------------------------------
  // マッピング
  // 拠点情報の取得
  // 2018/05/03 yamazaki
  //-----------------------------------------
  $kyotenData = databaseGet(
    "SELECT".
    "    faxKyoten,".
    "    sendFlag".
    " FROM MK_kyoten".
    " WHERE".
    "    kyotenEmail=N'".$kyotenEmailAdress."'"
  );
  // 存在していないときの処理
  if ($kyotenData == NULL) {
    echo "拠点情報の取得に失敗しました。";
    die('MSSQL Serer Connect Error');
  }
  else {
    $faxKyoten = $kyotenData[0]["faxKyoten"];
    $sendFlag  = $kyotenData[0]["sendFlag"];
  }
  if ($sendFlag == "0") {
    $faxMode = "auto";
  } else {
    $faxMode = "hand";
  }
  //-----------------------------------------
  // マッピング
  // FaxID最大値の取得
  // 2018/05/06 yamazaki
  //-----------------------------------------
  $faxIDData = databaseGet(
    "SELECT".
    "    MAX(faxID)+1 AS maxFaxID".
    " FROM MK_faxSend".
    " WHERE".
    "    companyID=N'".$companyID."'"
  );
  // 存在していないときの処理
  if ($faxIDData == NULL) {
    echo "FaxID最大値の取得に失敗しました。";
    die('MSSQL Serer Connect Error');
  }
  else {
    $maxFaxID = $faxIDData[0]["maxFaxID"];
  }
  //-----------------------------------------
  // マッピング
  // FAX受信者リストの取得
  // 2018/05/06 yamazaki
  //-----------------------------------------
  $faxPushDate = databaseGet(
    "SELECT".
    "    staffID".
    " FROM MK_staff".
    " WHERE".
    "    companyID = N'". $companyID. "' AND".
    "    faxRec = N'000'"
  );
  // 存在していないときの処理
  if ($faxPushDate == NULL) {
    echo "FAX受信者リストの取得に失敗しました。";
    die('MSSQL Serer Connect Error');
  }
  else {
    $faxPushList = $faxPushDate;
  }
  // 保存先のFAX受信リストを取得する。
  $files = glob("../../../fax_data/get/dev/".$companyID."/".$faxKyoten."/".$faxMode."/*");
  $list = array();
  foreach ($files as $file) {
    if (is_file($file)) {
      $fileNamePath = explode("/", $file);
      $fileName = $fileNamePath[9];
      $fileExte = explode(".", $fileName);
      error_log("ファイルの拡張子:".$fileExte[1], 0);
      // 拡張子がTIFの時にJPEGに変換する処理
      if ($fileExte[1] == "tif" || $fileExte[1] == "tiff") {
        $dest = "./dst/";
        $type = "jpg";
        $image = new Imagick();
        $image->readImage("【サーバーのFAX受信フォルダ ← ここに複合機からFAXが転送されるようにしてください】".$companyID."/".$faxKyoten."/".$faxMode."/".$fileName);
        $image->setImageFormat('jpg');
        $image->writeImage("【サーバーのFAX転送先フォルダ ← Webアプリはここに参照しに行く】".$companyID."/".$faxKyoten."/".$fileExte[0].".jpg");
        // 後処理
        $image->clear();
        $image->destroy();
        // 変換前のファイルを削除する
        unlink("【サーバーのFAX受信フォルダ】".$companyID."/".$faxKyoten."/".$faxMode."/".$fileName);
      }
      else {
        //-----------------------------------------
        // 該当ファイルの移動
        // 1つずつ
        //-----------------------------------------
        if (FALSE == rename(
          "../../../fax_data/get/dev/".$companyID."/".$faxKyoten."/".$faxMode."/".$fileName,
          "../../../fax_data/send/dev/".$companyID."/".$faxKyoten."/".$fileName
        )) {
          die('File Move Error');
        }
      }
      //-----------------------------------------
      // マッピング
      // FAX送信情報の登録
      // 2018/05/06 yamazaki
      //-----------------------------------------
      databaseSet(
        "INSERT INTO".
        " MK_faxSend(".
        "    faxDateTime,".
        "    companyID,".
        "    faxFlag,".
        "    subject,".
        "    imagePass,".
        "    faxID,".
        "    faxKyoten".
        " ) VALUES(".
        "    '".$now."',".
        "    N'".$companyID.  "',".
        "    '" .$sendFlag.   "',".
        "    N'".$subject.    "',".
        "    N'".$fileExte[0].".jpg".   "',".
        "    '" .$maxFaxID.   "',".
        "    N'".$faxKyoten.  "'".
        ")"
      );
      foreach ($faxPushList as $faxPush) {
        //-----------------------------------------
        // マッピング
        // FAX送信情報履歴の登録
        // 2018/05/06 yamazaki
        //-----------------------------------------
        databaseSet(
          "INSERT INTO".
          " MK_historyOption(".
          "    companyID,".
          "    category,".
          "    ymdTime,".
          "    staffID,".
          "    flag,".
          "    externNo,".
          "    okiniFlag".
          " )".
          " VALUES(".
          "    N'".$companyID.  "',".
          "    '6',".
          "    '".$now."',".
          "    N'".$faxPush["staffID"]."',".
          "    '0',".
          "    '" .$maxFaxID.   "',".
          "    '" .$sendFlag.   "'".
          " )"
        );
        //-----------------------------------------
        // マッピング
        // スタッフIDから通知先の情報の取得
        // 2018/05/07 yamazaki
        //-----------------------------------------
        $pushData = databaseGet(
          "SELECT".
          "    registerID,".
          "    name".
          " FROM MK_smartPhone".
          " WHERE".
          "    staffID = N'".$faxPush["staffID"]."' AND".
          "    companyID = N'".$companyID."' AND".
          "    name <> N'card'"
        );
        //-----------------------------------------
        // 2018/05/15 yamazaki
        // 通知先の情報が取得できないときは何もしない
        //-----------------------------------------
        foreach ($pushData as $pushInfo) {
          $pushJsonArray[] = array(
            'registerID' =>$pushInfo["registerID"],
            'name' =>$pushInfo["name"]
          );
        }
      }
      $maxFaxID++;
    }
  }
  // commonPushFuncメソッドで、対象者全員に通知を送る。
  //(※FAXデータが複数存在するときに複数回通知が飛ぶこともありえる)
  header('Content-type: application/json');
  // 指定されたデータタイプに応じたヘッダーを出力する
  print(json_encode($pushJsonArray));
  exit();
?>

クライアント側
アプリ(iPhone, Android ガワネイティブ)

運用時の問題点

①機能自体は実装できている。ただ、運用面でサーバーを再起動するとそのたびにシェルスクリプトを実行する必要がある。
②Node.jsのソースバージョン管理が出来ていない。

対策案

①ひとまずは、Windows Serverのタスクスケジューラにログオン時にShell Scriptを自動起動で実行出来るようになればいいかな。他にもっと良い方法がありそうだが...
②Gitを使ってバージョン管理ができるといいな。

まとめ

・Node.jsでフォルダの更新を監視し、トリガーからPHP APIの呼び出しができた。
・現状、実行ファイルsをPowerShellから手動でしか呼び出せていないので、なんとか他のやり方でスマートにやりたい。
・将来的には他の会社、複数の拠点で運用出来る様にしたい。(今後拡張が出来るように設計段階で盛り込み済み)

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

Raspberryに特定バージョンのNode.jsをインストールする

Raspberryに普通にNode.jsをインストールすると、Ver8.xがインストールされます(2019年4月時点)
例えば、Ver10.15.3をインストールしたいってことありませんか?
今回は、そんなお話です。

Node.jsのインストール

Node.jsをインストールします。
Raspberry Pi Zeroは、Armv6なので通常の手順でインストールすると8.xがインストールされます。
10.15.3をインストールするには、以下の手順になります。

sudo apt remove nodejs
sudo apt autoremove
VERSION=v10.15.3
DISTRO=linux-armv6l
cd /usr/src
sudo wget https://nodejs.org/dist/$VERSION/node-$VERSION-$DISTRO.tar.xz
sudo mkdir -p /usr/local/lib/nodejs
sudo tar -xJvf node-$VERSION-$DISTRO.tar.xz -C /usr/local/lib/nodejs

ホームディレクトリの.profileを開いて以下の行を追加します。

.profile
# Nodejs
VERSION=v11.13.0
DISTRO=linux-armv6l
export PATH=/usr/local/lib/nodejs/node-$VERSION-$DISTRO/bin:$PATH

.profileを有効にし、リンクを張ります。

. ~/.profile
sudo ln -s /usr/local/lib/nodejs/node-$VERSION-$DISTRO/bin/node /usr/bin/node
sudo ln -s /usr/local/lib/nodejs/node-$VERSION-$DISTRO/bin/npm /usr/bin/npm
sudo ln -s /usr/local/lib/nodejs/node-$VERSION-$DISTRO/bin/npx /usr/bin/npx

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

node -v
v10.15.3
npm -v
6.4.1
npx -v
6.4.1
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

anyenv から入れた nodenv で Node.js を入れたときのメモ

本記事について

「りあクト!」1を読みはじめ、本のように「anyenv 経由で ndenv をインストールして、ndenv で Node.js をインストール」しようと思ったら、anyenv で ndenv をインストールできないなど、状況が変わっていてハマったため残したメモです。

環境

  • OS:macOS Mojave
  • シェル:zsh
  • homebrew インストール済み
  • これまで nvm を使用

概要

結局今回は以下でインストールが完了しました:

  1. anyenv をインストール
  2. anyenv 経由で nodenv をインストール
  3. nodenv で Node.js をインストール
  4. これまで使っていた nvm のアンインストール

anyenv のインストール方法

GitHub - anyenv/anyenv: All in one for **env

README にはまず homebrew でのインストールが紹介されているが、ブログや Qiita を見ると多くが git clone でインストールしている。homebrew 版はかなり最近なんだろうか。

こちらでは両方の方法が紹介されている。
https://qiita.com/rinpa/items/81766cd6a7b23dea9f3c

anyenv のインストール

今回は homebrew でインストールしてみる。
README に従う。

$ brew install anyenv

$ anyenv init
# Load anyenv automatically by adding
# the following to ~/.zshrc:

eval "$(anyenv init -)"

$ anyenv init を打ったら指示が出てきた。指示の通りに ~/.zshrc に追記。
そしてターミナル再起動。すると(README の通り)次の warning が出る。

ANYENV_DEFINITION_ROOT(/Users/xxx/.config/anyenv/anyenv-install) doesn't exist. You can initialize it by:
> anyenv install --init

warning の通り実行。

$ anyenv install --init
Manifest directory doesn't exist: /Users/xxx/.config/anyenv/anyenv-install
Do you want to checkout ? [y/N]: y
Cloning https://github.com/anyenv/anyenv-install.git master to /Users/xxx/.config/anyenv/anyenv-install...
Cloning into '/Users/xxx/.config/anyenv/anyenv-install'...
remote: Enumerating objects: 44, done.
remote: Counting objects: 100% (44/44), done.
remote: Compressing objects: 100% (39/39), done.
remote: Total 44 (delta 1), reused 43 (delta 1), pack-reused 0
Unpacking objects: 100% (44/44), done.

Completed!

ndenv のインストール(できない)

anyenv で ndenv が入れられない。

$ anyenv install ndenv
anyenv-install: definition not found: ndenv

ndenv は非推奨になっていた

nodenv のインストール

ndenv の代わりに nodenv が推奨になっていたため、こちらをインストール。

$ anyenv install nodenv
$ exec $SHELL -l

Node.js のインストール

$ nodenv install -l
$ nodenv install 12.0.0
$ node -v
v7.6.0
$ npm -v
4.1.2
$ nodenv global 12.0.0
$ node -v
v7.6.0
$ npm -v
4.1.2

インストールしたはずの node v12.0.0 が呼び出せない。
(nvm など使ってない方はここで呼び出せるはず?)

nvm のアンインストール(必要な人のみ)

ここで、これまで nvm を使っていたことを思い出し、nvm をアンインストールすることに。
アンインストール方法は GitHub の README を参照

➜  ~rm -rf "$NVM_DIR"

(つまり ~/.nvm の削除)

そして ~/.zshrc の下記を削除:

export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"  # This loads nvm

確認:

$ node -v
v12.0.0
$ npm -v
6.9.0

呼び出せた :tada:

やっと本の続きが読める

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