2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

NodeJSで遠隔操作してみた

Posted at

暇だったので、nodeで簡単な遠隔操作をしてみることにしました
環境:
OS: MacOS
editor: vscode

同じWiFiにつながってないと他のパソコンや端末からアクセスできません!


デレクトリ:

.
├── test.mp3 <= 3
├── index.html <= 2
└── server.js <= 1

1 directory, 5 files

ソースコード:

index.htmlserver.jsを作成してください

main.js
const http = require("http");
const fs = require("fs");
const PORT = 8000;
const html = fs.readFileSync("./index.html", "utf8");
const player = require("play-sound")((opts = {}));
const filePath = "test.mp3";
const { styleText } = require('node:util')

// ユーザー名とパスワードを設定
const USERNAME = "admin";
const PASSWORD = "password";

// isSelectedの状態を保持する
let isRunning = false; // 処理が起動しているかどうかを示すフラグ
let intervalId = null; // 処理を継続するためのID

// HTTP Basic Authenticationをチェック
const authenticate = (req) => {
  const auth = req.headers["authorization"];
  if (!auth) {
    return false; // 認証がない
  }
  const [username, password] = Buffer.from(auth.split(" ")[1], "base64")
    .toString()
    .split(":");
  return username === USERNAME && password === PASSWORD;
};

// サーバーを作成
const server = http.createServer((req, res) => {
  if (!authenticate(req)) {
    res.writeHead(401, { "WWW-Authenticate": "Basic" });
    res.end("Authorization required");
    return;
  }

  // 認証成功時の処理
  if (req.method === "GET") {
    const errorMessage = styleText('green', 'GET :');
    console.log(errorMessage);
    res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
    res.end(html);
  } else if (req.method === "POST" && req.url === "/toggle") {
    const errorMessage = styleText('green', 'POST :');
    console.log(errorMessage);
    let body = "";
    req.on("data", (chunk) => {
      body += chunk;
    });
    req.on("end", () => {
      try {
        const { isSelected } = JSON.parse(body);
        handleToggle(isSelected, res);
      } catch (error) {
        console.error("JSON parsing error:", error);
        res.writeHead(400, { "Content-Type": "application/json; charset=utf-8" });
        res.end(JSON.stringify({ error: "Invalid JSON" }));
      }
    });
  } else {
    res.writeHead(404, { "Content-Type": "text/plain; charset=utf-8" });
    res.end("Not Found");
  }
});

// 処理の開始または停止
const handleToggle = (isSelected, res) => {
  if (isSelected && !isRunning) {
    isRunning = true;
    const errorMessage = styleText('blue', '開始します');
    console.log(errorMessage);
    intervalId = setInterval(() => {
      const errorMessage = styleText('red', 'StartMp3');
      console.log(errorMessage);
      player.play(filePath, (err) => {
        if (err) {
          console.log(`エラーが発生しました: ${err}`);
        }
      });
    }, 1000); // 1秒ごとにログを出力
  } else if (!isSelected && isRunning) {
    isRunning = false;
    const errorMessage = styleText('blue', '停止します');
    console.log(errorMessage);
    clearInterval(intervalId);
    intervalId = null;
  }

  res.writeHead(200, { "Content-Type": "application/json; charset=utf-8" });
  res.end(JSON.stringify({ message: "State received" }));
};

// サーバーを起動
server.listen(PORT, () => {
  console.log(`Server running on http://localhost:${PORT}`);
});

index.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>遠隔操作ボタン</title>
    <style>
        body {
            background-color: #1a1a1a;
            color: #fff;
            font-family: 'Arial', sans-serif;
            overflow: hidden;
        }

        .center {
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
            margin: 0;
            position: relative;
        }

        .toggle-btn {
            background-color: #007bff;
            color: #fff;
            padding: 15px 30px;
            border: none;
            border-radius: 10px;
            cursor: pointer;
            font-size: 1.5em;
            position: relative;
            outline: none;
            box-shadow: 0 0 10px rgba(0, 0, 0, 0.8);
            transition: transform 0.3s;
            z-index: 1;
        }

        .selected {
            background-color: #26ff00;
            animation: glow 1s infinite alternate;
        }

        @keyframes glow {
            from {
                box-shadow: 0 0 20px rgba(47, 255, 0, 0.5);
            }
            to {
                box-shadow: 0 0 40px rgb(94, 255, 0);
            }
        }

        .error-message {
            color: rgb(115, 255, 0);
            font-weight: bold;
            position: absolute;
            top: 0; /* ボタンの上に表示 */
            left: 50%;
            transform: translateX(-50%);
            display: none; /* 初期は非表示 */
            z-index: 2;
        }
        .server-message {
            color: blue;
            font-weight: bold;
            position: absolute;
            top: 0; /* ボタンの上に表示 */
            left: 50%;
            transform: translateX(-50%);
            display: none; /* 初期は非表示 */
            z-index: 2;
        }

        .server_err {
            background-color: rgb(251, 59, 59);
            color: #fff;
            padding: 15px 30px;
            border: none;
            border-radius: 10px;
            /*cursor: pointer;*/
            font-size: 1.5em;
            position: relative;
            outline: none;
            /*box-shadow: 0 0 10px rgba(0, 0, 0, 0.8);*/
            transition: transform 0.3s;
            z-index: 1;
        }
        .server_sf {
            background-color: rgb(78, 99, 255);
            color: #fff;
            padding: 15px 30px;
            border: none;
            border-radius: 10px;
            /*cursor: pointer;*/
            font-size: 1.5em;
            position: relative;
            outline: none;
            /*box-shadow: 0 0 10px rgba(0, 0, 0, 0.8);*/
            transition: transform 0.3s;
            z-index: 1;
        }
    </style>
</head>
<body>
    <div class="center">
        <div class="server_sf" id="serverMessage">安全</div>
        <div class="server_err" id="errorMessage">エラー</div>
        <button class="toggle-btn" id="toggleButton">実行</button>
    </div>

    <script>
        const button = document.getElementById('toggleButton');
        const errorMessage = document.getElementById('errorMessage');
        const serverMassage = document.getElementById('serverMessage');
        let isSelected = false;

        errorMessage.style.display = 'none'; // 正常な応答時にエラーメッセージを非表示
        serverMassage.style.display = 'block'; // 正常な応答時にエラーメッセージを非表示

        button.addEventListener('click', () => {
            isSelected = !isSelected;
            button.classList.toggle('selected', isSelected);
            button.textContent = isSelected ? "運転中..." : "実行";

            fetch('/toggle', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify({ isSelected })
            })
            .then(response => {
                console.log('サーバーの応答:', response); // サーバー応答のデバッグ
                if (!response.ok) {
                    throw new Error("サーバーの応答が不正です");
                }
                return response.json();
            })
            .then(data => {
                console.log('サーバーからの応答:', data);
                errorMessage.style.display = 'none'; // 正常な応答時にエラーメッセージを非表示
                serverMassage.style.display = 'block'; // 正常な応答時にエラーメッセージを非表示
            })
            .catch(error => {
                console.error('エラー:', error);
                console.error('サーバーからの応答')
                errorMessage.style.display = 'block'; // エラー時にエラーメッセージを表示
                serverMassage.style.display = 'none'; // 正常な応答時にエラーメッセージを非表示
            });
        });
    </script>
</body>
</html>

mp3のフリー音源を探してきて、作業デレクトリにもっていってtest.mp3と名前を変えればOK

npm install play-sound
node main.js

そしたらhttp://localhost:8000に移動して
あと一応パスワードをつけといたんで、admin passwordログインできますが

server.jsの一部分
// ユーザー名とパスワードを設定
const USERNAME = "admin";
const PASSWORD = "password";

ここの部分で設定できます

最後に

他のパソコンや端末でやてみたいと思うかもしれませんが、http://localhost:8000このURLを打ち込んでもうまくいきません!
ターミナルで

ifconfig

でわかります

% ifconfig   
lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> mtu 16384
	options=1203<RXCSUM,TXCSUM,TXSTATUS,SW_TIMESTAMP>
	inet 127.0.0.1 netmask 0xff000000 <= この行!
	inet6 ::1 prefixlen 128 
	inet6 fe80::1%lo0 prefixlen 64 scopeid 0x1 
	nd6 options=201<PERFORMNUD,DAD> ...

つまり他のパソコンや端末で動かすためには、
調べたやつ:127.0.0.1 :8000ということなのでhttp://127.0.0.1:8000に行けばうまくいきます

よくわからない時はGeminiChatGPTに聞くとわかったりします

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?