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

Nodeのプロミスって??

はじめに

Nodeのプロミスについて、自分なりにまとめてみることにしました。

プロミスとは

プロミスを簡単に説明するなら、「非同期処理の結果の値(失敗も含む)を表現するオブジェクト」です。

プロミスの動作

  1. 非同期処理をする、ある関数(Function A)があった時、このFunction Aを呼び出すとPromiseを返します。
  2. このPromiseは、非同期処理が完了(fulfilled) or 非同期処理が失敗(rejected)のどっちかが起きることは保証されています。
  3. このPromiseがfulfilled/rejectedが起きていない場合は、非同期処理が完了していない(pending)の状態となります。

プロミスの状態まとめ

つまり、プロミスは3つの状態があります。

  1. 非同期処理が完了(fulfilled)
  2. 非同期処理が失敗(rejected)
  3. 非同期処理が完了していない(pending)

プロミス使用パターン

Promise.then([ハンドラ関数A],[ハンドラ関数B])

・ パターンとして、成功の場合に呼び出す関数をハンドラ関数A、失敗したときに呼び出す関数をハンドラ関数Bを呼ぶようにすると、非同期処理が完了し、プロミスが成功した時はハンドラ関数Aが実行され、失敗したときはハンドラ関数Bが実行されます。

.then() は処理結果を受け取り、新しいプロミスオブジェクトを作成して戻り値として返却するメソッドです。

・ 図は、はじめのPromise Xが解決された後、ハンドラ関数の戻り値によりPromise Yが解決される流れをイメージしています。[結構この図、力作ですw]

Promise説明図.png

参考文献

Mozilla - Promise

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

非同期パターン(プロミスって??)

はじめに

非同期パターンのプロミスについて、自分なりにまとめてみることにしました。

プロミスとは

プロミスを簡単に説明するなら、「非同期処理の結果の値(失敗も含む)を表現するオブジェクト」です。

プロミスの動作

  1. 非同期処理をする、ある関数(Function A)があった時、このFunction Aを呼び出すとPromiseを返します。
  2. このPromiseは、非同期処理が完了(fulfilled) or 非同期処理が失敗(rejected)のどっちかが起きることは保証されています。
  3. このPromiseがfulfilled/rejectedが起きていない場合は、非同期処理が完了していない(pending)の状態となります。

プロミスの状態まとめ

つまり、プロミスは3つの状態があります。

  1. 非同期処理が完了(fulfilled)
  2. 非同期処理が失敗(rejected)
  3. 非同期処理が完了していない(pending)

プロミス使用パターン

Promise.then([ハンドラ関数A],[ハンドラ関数B])

・ パターンとして、成功の場合に呼び出す関数をハンドラ関数A、失敗したときに呼び出す関数をハンドラ関数Bを呼ぶようにすると、非同期処理が完了し、プロミスが成功した時はハンドラ関数Aが実行され、失敗したときはハンドラ関数Bが実行されます。

.then() は処理結果を受け取り、新しいプロミスオブジェクトを作成して戻り値として返却するメソッドです。

・ 図は、はじめのPromise Xが解決された後、ハンドラ関数の戻り値によりPromise Yが解決される流れをイメージしています。[結構この図、力作ですw]

Promise説明図.png

参考文献

Mozilla - Promise

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

非同期のパターン(プロミスって??)

はじめに

非同期パターンのプロミスについて、自分なりにまとめてみることにしました。

プロミスとは

プロミスを簡単に説明するなら、「非同期処理の結果の値(失敗も含む)を表現するオブジェクト」です。

プロミスの動作

  1. 非同期処理をする、ある関数(Function A)があった時、このFunction Aを呼び出すとPromiseを返します。
  2. このPromiseは、非同期処理が完了(fulfilled) or 非同期処理が失敗(rejected)のどっちかが起きることは保証されています。
  3. このPromiseがfulfilled/rejectedが起きていない場合は、非同期処理が完了していない(pending)の状態となります。

プロミスの状態まとめ

つまり、プロミスは3つの状態があります。

  1. 非同期処理が完了(fulfilled)
  2. 非同期処理が失敗(rejected)
  3. 非同期処理が完了していない(pending)

プロミス使用パターン

Promise.then([ハンドラ関数A],[ハンドラ関数B])

・ パターンとして、成功の場合に呼び出す関数をハンドラ関数A、失敗したときに呼び出す関数をハンドラ関数Bを呼ぶようにすると、非同期処理が完了し、プロミスが成功した時はハンドラ関数Aが実行され、失敗したときはハンドラ関数Bが実行されます。

.then() は処理結果を受け取り、新しいプロミスオブジェクトを作成して戻り値として返却するメソッドです。

・ 図は、はじめのPromise Xが解決された後、ハンドラ関数の戻り値によりPromise Yが解決される流れをイメージしています。[結構この図、力作ですw]

Promise説明図.png

参考文献

Mozilla - Promise

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

【React + TypeScript】プロジェクト開始時tsconfig.jsonに追記しておくべき設定2点

はじめに

TypeScriptでReactアプリを作成する際、TypeScript設定ファイルの「tsconfig.json」に追記しておくと良い設定について記録しておきます。

アプリはnodeインストール済みの環境で以下コマンドを発行して作成したものとします。

npx create-react-app hello-world --template typescript

追記後のtsconfig.json

"baseUrl": "src"」と「"downlevelIteration": true」を追記しています。

hello-world/tsconfig.json
{
  "compilerOptions": {
    "target": "es5",
    "lib": [
      "dom",
      "dom.iterable",
      "esnext"
    ],
    "allowJs": true,
    "skipLibCheck": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "react",
    "baseUrl": "src",
    "downlevelIteration": true,
  },
  "include": [
    "src"
  ]
}

"baseUrl": "src"

追記しておくと、node-modules/にインストールされていないモジュールをインポートする時(src配下に自分で作成したモジュールなど)、src/を起点としたパスで指定することができます。

例としてsrc/components/pages/home.tsxからsrc/components/atoms/button.tsxを参照する際、この設定が無い場合相対パスをつなげて書かなければならないですが

src/components/pages/home.tsx
import * from '../../atoms/button'

この設定を追記することで

src/components/pages/home.tsx
import * from 'components/atoms/button'

このように書くことができます。

"downlevelIteration": true

コンパイルターゲットをES5以前に設定している場合(「"target": "es5"」)でも、ES2015から導入された便利な記述をES5以下で実行できるようよしなに書き下してくれます。
この設定が無ければ新機能を使用した記述によるコンパイルエラーが発生してしまう可能性も有るので、最初から有効にしておくと良いです。
 
 
 

以上です。お疲れ様でした:cat2:

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

nginx + expressをfargate 4coreで動かす

  • nginx + expressをfargateに詰め込む
  • unix socket を使って繋ぐ
  • expressは4プロセス立ち上げる
  • node clusterは使わないパターン、socketが競合してしまったので。
  • 共通ボリュームにapi1.sock - api4.sockを設定して、nginxからupstreamする

api

共通ボリュームをVolumeにしておく

VOLUME /usr/src/tmp

sockのパスを環境変数で指定させる

main.js
const sock = process.env.SOCK_PATH;
app.listen(sock, () => {
  fs.chmodSync(sock, '666');
  console.log(`Server running on ${sock} with pid ` + process.pid);
});

nginx

api1.sock - api4.sockへupstreamする

nginx.conf
upstream api {
    server unix:///usr/src/tmp/api_1.sock;
    server unix:///usr/src/tmp/api_2.sock;
    server unix:///usr/src/tmp/api_3.sock;
    server unix:///usr/src/tmp/api_4.sock;
}
server {
    listen       80 default;
    listen  [::]:80;

    location / {
        proxy_pass http://api;       
        break;
    }
}

タスク定義

ECSタスク定義で、繋ぐ

task-define.json
{
"containerDefinitions": [
  {
    "name": "nginx",
    "portMappings": [
      { "hostPort": 80, "protocol": "tcp", "containerPort": 80 }
    ],
    "mountPoints": [
      {
        "readOnly": true,
        "containerPath": "/usr/src/tmp",
        "sourceVolume": "etc"
      }
    ]
  },
  {
    "name": "api1",
    "mountPoints": [
      { "containerPath": "/usr/src/tmp", "sourceVolume": "etc" }
    ],
    "environment": [
      { "name": "SOCK_PATH", "value": "/usr/src/tmp/api_1.sock" }
    ]
  },
  {
    "name": "api2",
    "mountPoints": [
      { "containerPath": "/usr/src/tmp", "sourceVolume": "etc" }
    ],
    "environment": [
      { "name": "SOCK_PATH", "value": "/usr/src/tmp/api_2.sock" }
    ]
  },
  {
    "name": "api3",
    "mountPoints": [
      { "containerPath": "/usr/src/tmp", "sourceVolume": "etc" }
    ],
    "environment": [
      { "name": "SOCK_PATH", "value": "/usr/src/tmp/api_3.sock" }
    ]
  },
  {
    "name": "api4",
    "mountPoints": [
      { "containerPath": "/usr/src/tmp", "sourceVolume": "etc" }
    ],
    "environment": [
      { "name": "SOCK_PATH", "value": "/usr/src/tmp/api_4.sock" }
    ]
  }
],
"volumes": [{ "name": "etc" }],
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

React開発時の汎用的なGitpod環境設定

  • 開発時に、オンラインエディタであるGitpodを利用する機会があります。
  • 同様の技術利用が多いため、環境テンプレートを作成する必要があります。
  • 今回はReactを利用した開発においてのGitpod設定を記述します。
  • ※Gitpodの概要や利用方法に関しては、こちら

前提

  • Reactプロジェクトの準備
    • 試用の場合、create-react-app等で準備
    • ※npmプロジェクトであれば基本可

結果

  • 先にGitpod設定ファイルである、.gifpod.ymlの記述を示します。
tasks:
  - init: npm ci
    command: npm start

ports:
  - port: 3000
    onOpen: open-preview

github:
  prebuilds:
    addComment: true
    addBadge: true

vscode:
  extensions:
    - dbaeumer.vscode-eslint@2.1.8:02aHhbJ0Q4aGdjHXlTdVKg==
    - esbenp.prettier-vscode@5.7.1:GDba64T6G+TUi1qmc6BE3A==
    - dsznajder.es7-react-js-snippets@3.0.0:9YEGn/57fW8lJt7cVxJQDQ==
  • 以下、実際のGitpodでの開発画面。

pen.png

内容

  • 上記の結果は、主に以下を設定した開発環境を用意するための記述です。
    • 環境構築時の自動コマンド指定
    • 自動プレビュー
    • 起動速度の短縮
    • vscode拡張機能の自動追加

起動コマンド指定

  • .gitpod.ymlでは、tasksで環境構築時の自動コマンド指定が可能です。
  • そのため、React開発時に必要な以下を設定します。
    • 依存関係インストール
      • init(新規作成時のみ実行)プロパティで設定
        • ※再起動やスナップショット時は行われない
    • 開発サーバー起動
      • command(開始時に毎回実行)プロパティで設定

自動プレビュー

  • .gitpod.ymlでは、portsサーバー動作設定が可能です。
  • タブ抑止のため、open-previewでエディタ画面内にプレビューの表示を行います。

起動速度の短縮

  • オンラインエディタでは、起動速度が遅い場合があります。
  • Gitpodでは、Githubアプリ連携によるプレビルド機能により大幅な解消が可能です。
    • ※基本デフォルトで十分のため、githubで連携するのみで記述は必須では無い。
    • ※拡張の場合のみ、prebuildsプロパティを記述

vscode拡張機能の自動追加

  • .gitpod.ymlでは、VSCode拡張機能も管理・共有することが可能です。
  • extensionsプロパティで、React開発に最低限必要な以下を設定します。

まとめ

  • 上記のことから、オンライン開発環境における最低限の定型化と良質な開発性の重要性を実感。

参考

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

[作り方] discord.js グローバルVC(グローバルボイスチャット)

グローバルVCを作ってみた。

NeoXBotというdiscordのbotを作ったときに、
グローバルボイスチャットのリクエストがあったので、
先月ごろ作りました。

準備
"discord.js" をnpmからインストール

npm install discord.js

・音声用に "discordjs/opus" を同じくnpmからインストール

npm install @discordjs/opus
/**
DiscordID:696600519283572766
©X / KOU00000
orichalcum.gom@gmail.com
*/
//グローバルボイスチャットの名前
const gvcName = "グローバルボイスチャット";
const token = "あなたのbotのtoken"

const discord = require("discord.js");
const client = new discord.Client();
client.login(token);

//音データ作成用
const {Readable}=require('stream');

//音の流れない音データを作る。
class Silence extends Readable{
  _read(){this.push(Buffer.from([0xF8,0xFF,0xFE]))}
};
/**
 * discord の client が ready 状態になってないと、
 * client.channels..... を行えない。
*/
client.on("ready",()=>{
console.info("ready...")
client.channels.cache.filter
//グローバルボイスチャットが変数gvcNameと同じチャンネルを抽出
(ch=>ch.type === "voice" && ch.name === gvcName)
.forEach(ch=>
{
ch.join()//vcに参加
.then(conn => {//connに参加したvcのデータが含まれる。

      //音の流れない音データを配信 
      //(最初にbotがVCで音データを流さないと音の取得ができないため。)
      conn.play(new Silence,{ type: 'opus' });
      let receiver = conn.receiver;
      //だれかがVCで発言したら。
      conn.on('speaking', (user, speaking) => {
        //botだったら放送しない。
        if(user.bot)return; 
        //音を取得
        const UserVoice = receiver.createStream(user);
        const broadcast = client.voice.createBroadcast();
        //流す音
        broadcast.play(UserVoice,{ type: 'opus' });
    //一斉にbotが接続中のVCに取得した音声を配信。
    for (const connection of client.voice.connections.values()) {
         connection.play(broadcast);
    };
        });
    });
});
});

※ ※ ※
ここにのせたコードは、
NeoXBotに搭載してるものとは別に、
公開用にシンプルにしたバージョンのコードなのですが、
ちゃんとしたテストなどを行っていないので、
もしかしたらちゃんと動かないかもしれないです。
答えられる限り答えるので、何かあればコメントでお願いします。

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

吉報報告アプリをつくってみた!っていう話

コロナ渦の中、皆様いかがお過ごしですか?
少しでも元気になるシステム開発できないかな〜と思いまして、
吉報を全社で喜ぶためのアプリを開発しました。

プログラムの詳細は、書かないですが、どんな構成で作ったかを紹介します!
開発リミットが2日しかなかったので、作り込んではいないです。?
(そのうちの1日はどんな音楽がテンション上がるかで費やしました。)

吉報を報告するアプリってどんなの?

チャットワークに、メッセージを送るとMacをつないでいるモニターにテンションが上がる音楽とともに吉報が報告されます。

fanfare.mov.gif
※本来であれば、テンションが上がる音楽が流れます。

アーキテクチャ

この構成はなんとサーバー代もかからず、「完全無料」です!
image.png

①チャットワークの特定のスレッドに報告をする
image.png

※あつまるBotに対してToをつけた場合だけ全社への報告になるようにしています?

②チャットワークAPIを受け取り、データを加工

③FirebaseのRealtime Databaseを更新

④Electronで作成したMacアプリ側で、データを受け取る

⑤Cloud StorageからBGMをダウンロードして音楽を流し、メッセージを画面に流す
※報告内容によって、ダウンロードする音楽を切り分けています。

どこにつまづいたか

ブラウザに依存させず、Mac本体に制御を加えたかったので、Macアプリ作ろうと思い立ちました。
いろいろ方法はあるものの、久々に"Electron"を触ってみました。

《つまづきポイント①》

Electron側のウィンドウの制御

イメージは下の図のようになっています。
透明な全画面ブラウザを上にマスクさせて、CSSでメッセージが流れる表現をしています。
image.png

Electronの画面の表現には慣れていなかったので、いろいろ苦戦しました。?

  • mainWindow.setIgnoreMouseEvents(true); ウィンドウをクリックできない状態にする
  • mainWindow.setAlwaysOnTop(true, 'floating'); ウィンドウを最前面表示
ウィンドウ制御周りのコード
  // メインウィンドウを作成します
  let size = screen.getPrimaryDisplay().size; // ディスプレイのサイズを取得する
  mainWindow = new BrowserWindow({
    webPreferences: {
      nodeIntegration: true,
    },
    left: 0,
    top: 0,
    frame: false,       // フレームを非表示にする
    resizable: false,   // ウィンドウリサイズ禁止
    transparent: true,
    width: size.width,
    height: size.height,
    skipTaskbar: true,
    alwaysOnTop: true // 一番手前に表示する
  });

  // 全てのウィンドウに表示(フルスクリーン対応)
  app.dock.hide();
  mainWindow.setAlwaysOnTop(true, 'floating');
  mainWindow.setVisibleOnAllWorkspaces(true);
  mainWindow.setFullScreenable(false);
  app.dock.show();

  // マウスイベント無効化
  mainWindow.setIgnoreMouseEvents(true);

app.dock.hide();して、app.dock.show();する一連の流れについては、謎挙動。。。
しかし、この流れでなければ、最前面&フルスクリーンは実装できませんでした。

《つまづきポイント②》

つまづきポイントを書こうと思ったのですが、つまづきポイント①で書いたところ以外は、
特につまづきませんでした。。。とにかくFirebaseが便利すぎて、助けられました。

作ってみてどうだったか

このアプリを会社に導入してから、1日に8回くらい吉報が流れます。?
多い時は、15回以上流れることもありました?

《社内と気持ちの変化》

  • 喜びを部署超えて、全社に共有できる(他の部署のことを知ったり、話すきっかけにもなる)
  • テンションがあがり、早く吉報を報告したい気分になる

何より、使ってもらえることが作った側からすると一番嬉しいです☺️

今後の展望

吉報を報告した人、内容によって、BGMを分けたり、画面のギミックを変えたりできるともっともっとテンションが上がって、吉報を報告したい気持ちが高まりそう。
あとは、社内だけでなく、他の会社でもこのアプリを使ってもらえると嬉しいなと思います。
ぜひ、興味ある方、声かけてください〜?

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