Wi-Fi接続先アクセスポイントのMACアドレスをcurlでAPIサーバーに送信する

## はじめに
事務所をフリーアドレス化した際に有線LANからWi-Fiの無線LANに移行しました。
100人規模の事務所ですが、誰がどこにいるのか探すのが面倒なので、PCがどのアクセスポイントに繋がっているかで大まかな座席位置がわかるシステムを構築しました。

## 仕様
Windows10の netsh コマンドで取得したMACアドレス情報をcurlコマンドでAPIサーバーに送信し、受信したデータをMySQLデータベースにインサートします。
なお、集めたMACアドレスの利用方法についてはこの記事に記述していません。
PC利用者とWi-FiアダプタのMACアドレスを紐付けるテーブル、および、アクセスポイントのMACアドレスのテーブルが別途必要になります。

## 動作した環境
|項目|内容|
|---|---|
|APサーバー|node.js + Express|
|DBサーバー|MySQL|
|クライアント|Windows10|

## サーバーのディレクトリ構成
.
├── app.js
└── routes
　　　   └── v1
　　　　　　 ├── index.js
　　　　 　　└── api_pcwosagasu.js

## ソースコード
※稼働中のプログラムの一部をコピペしたもので、このサンプルが動作するかの検証は行っていません。

#### Expressアプリ
```javascript:app.js
const express    = require('express');
const app        = express();
const bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(function(req, res, next) {
    res.header('Access-Control-Allow-Origin',  '*');
    res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, X-HTTP-Method-Override, Content-Type, Accept');
    next();
});

const port = process.env.PORT || 3000;
const router1 = require('./routes/v1/');
app.use('/app/v1/', router1);
app.listen(port);
```

#### ルーティング
```javascript:index.js
var express = require('express');
var router = express.Router();
router.use('/pcwosagasu', require('./api_pcwosagasu.js'));
module.exports = router;
```

#### API本体
```javascript:api_pcwosagasu.js
const express = require("express");
const router = express.Router();
const mysql = require("mysql");
const util = require('util');
module.exports = router;

async function execQuery(sql) {
    const pool = mysql.createPool({
        host     : 'localhost',
        port     : 3306,
        user     : 'user',
        password : 'password',
        database : 'pcwosagasu',
        timezone: 'jst',
        multipleStatements: true
    })
    pool.query = util.promisify(pool.query)
    try {
        const records = await pool.query(sql);
        pool.end();
        return records;
    } catch (err) {
        throw new Error(err)
    }
}

router.post("/", async (req, res) => {
    const macs = JSON.stringify(req.body).match(/(?:[0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}/g);
    const results = await execQuery('INSERT INTO macs (mac_client,mac_ap) VALUES ("' + macs[0] + '","' + macs[1] + '")' );
    res.send(results);
});
```
Windowsコマンドの実行結果はShift-JISですがUTF-8の体でPOSTされます。
サーバー側では全角文字が文字化けしていますが欲しいのはMACアドレスだけなので、文字化けを無視して正規表現でMACアドレスを抜き出しています。


## APIサーバーの起動
```batchfile
node ./app.js
```
Google Chromeでデバッグする場合は以下のコマンドで

```batchfile
node --inspect --inspect-brk ./app.js
```

## MySQLデータベース定義

```r
CREATE DATABASE IF NOT EXISTS `pcwosagasu`;
USE `pcwosagasu`;
DROP TABLE IF EXISTS `macs`;
CREATE TABLE IF NOT EXISTS `macs` (
  `mac_client` varchar(17) DEFAULT NULL,
  `mac_ap` varchar(17) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
```

## MACアドレス情報のAPIサーバーへの送信
```batch:postmac.bat
netsh wlan show interfaces | curl -X POST -H "Content-Type: application/x-www-form-urlencoded;charset=UTF-8" --data @- 192.168.123.45:3000/app/v1/pcwosagasu
```
このバッチファイルを「Bat_To_Exe_Converter」で非表示のEXEファイルに変換し、ADサーバーのログオンスクリプトに設定すれば、出社時にPCの電源を入れて接続したWi-Fiアクセスポイントが記録されます。

## まとめ
作ってはみたものの、ひとつのアクセスポイントのカバー範囲が広すぎて大雑把なエリアしか分からず目視で探すのとあまり変わらないという結果になりました。
アクセスポイントの配置を最初に確認して実装に着手すべきでした。