複数のクライアント環境が、サーバに接続する機構をつくってみた

## はじめに

複数のクライアント環境が、特定のサーバに接続する機構がよくあります。
例えば、WordPressやGit(GitHub)などがあります。
もっと言ってしまえば、そこらじゅうにあるWebアプリケーションが該当しますが、今挙げた２つは、クライアントがファイル構造を日頃から意識している特徴があります。

まず、WordPressはこんな仕組みになってます。
現在無数に存在するWordPressクライアントに対して、テーマとプラグインは（広義では）ひとつのサーバであり、クライアントへ同じ情報を提供しています。
![スクリーンショット 2021-07-24 17.32.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520045/7d51e671-73d5-e509-5a1e-79ac46d39cc2.png)

次に、GitとGitHubの関係も簡単に表すとこんな感じになります。
Gitは無数のクライアントが存在しますが、WordPress同様、GitHubはサーバがひとつとなります。
![スクリーンショット 2021-07-24 17.32.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520045/4540ca40-2599-9696-59f8-107a9c7f6cb1.png)

くどいようですが、
これをモデルとして書き直すとこんな感じになります。
![スクリーンショット 2021-07-24 17.33.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520045/2637d02c-0fe1-8a43-ed30-748c4d911333.png)

今回は、これをLaravelで再現します。
これをLaravelで再現するとこうなります。
![スクリーンショット 2021-07-24 17.35.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520045/46702a46-95e3-47de-2820-22b75202747a.png)

## 今回の目的

複数のクライアント環境が、ある一つのサーバにアクセスする仕組みを作ります。
ありきたりな単純なサーバ-クライアントの関係です。

## 下準備

今回は、以下の設定で進めていきます。
ローカルIPアドレスの環境構築になります。

| 種別         | IP Address      | データの格納場所 | 
| ------------ | --------------- | ---------------- | 
| サーバ       | 192.168.189.200 | /show            | 
| クライアント | 192.168.189.101 | /get             | 
| クライアント | 192.168.189.102 | /get             | 

DockerとLaravelの環境を整えます。

```bash
# Dockerのインストール
curl -fsSL https://get.docker.com/ | sh

# Laravelのインストール
curl -s "https://laravel.build/client" | bash

cd client
./vendor/bin/sail up -d
```

## クライアントの作成

```bash
# コントローラの作成
./vendor/bin/sail artisan make:controller GetServerController
```

`./app/Http/Controllers/GetServerController.php`が作成されたので、編集します。

```GetServerController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;

class GetServerController extends Controller
{
    public function index () 
    {
        /* ここでは試しにyuzukichi.jpのHTMLファイルを読み出しています */
        //$server_name = "https://yuzukichi.jp/get-docker.sh";
        $server_name = "192.168.189.200/show";
        return view('get_server', ['server'=> $server_name, 'data'=>$this->curl_test($server_name)]);
    }

    private function curl_test($url)
    {
        $conn = curl_init(); // cURLセッションの初期化
        curl_setopt($conn, CURLOPT_URL, $url); //　取得するURLを指定
        curl_setopt($conn, CURLOPT_RETURNTRANSFER, true); // 実行結果を文字列で返す。
        $res =  curl_exec($conn);
        curl_close($conn); //セッションの終了
        return htmlspecialchars($res);
    }
}
```

cURL関数を使って、外部サイトのファイルにアクセスして値を取得する形にします。

`./public/resources/views/get_server.blade.php`を作成し、HTMLの雛形だけ作っておきます。
VSCodeとかだと`!`を入力してからタブキーを押すと、勝手に雛形を生成してくれるので便利です。

```get_server.blade.php
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <p>GET SERVER: <?= $server ?> </p>
    <p>GET VALUE: <?= $data ?> </p>
</body>
</html>
```

`./public/routes/web.php`に以下を追記します。

```web.php
<?php

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\GetServerController;

/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/

Route::get('/', function () {
    return view('welcome');
});

Route::get('/get', [GetServerController::class, 'index']);
```

今回はコントローラにてcURL関数で外部サイトのファイルを読み出す動きをさせました。
これを応用して認証処理やAPIを作成することによって、外部のデータを操作したり取得したりすることができるようになります。

`http://IPアドレス/get`にアクセスした結果
（https://yuzukichi.jp/get-docker.sh にアクセスした例）
![スクリーンショット 2021-07-24 18.59.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520045/61de4840-bb2e-c8ca-4e4f-24c635c07956.png)

この構成のまま、ファイルをパッケージングすることで、複数のクライアントがサーバに接続する仕組みを作ることができます。
とても単純な構成でした。

## サーバ側の作成
サーバ側でも下準備を行い、Laravelを動かしていきます。

```bash
# コントローラの作成
./vendor/bin/sail artisan make:controller ShowDataController
```
```ShowDataController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;

class ShowDataController extends Controller
{
    public function index () 
    {
        $value = "successfully!";
        return view('show', ['data'=> $value]);
    }
} 
```

クライアントと同様のやり方で、`./public/resources/views/show.blade.php`を作成します。

```show.blade.php 
<?php
echo $data;
```

`./public/routes/web.php`を追記します。

```web.php
<?php

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\ShowDataController;

/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/

Route::get('/', function () {
    return view('welcome');
});

Route::get('/show', [ShowDataController::class, 'index']);
```

これで基本形は完成になります。
クライアント側を再パッケージし、他の環境で複数個デプロイすることで、複数クライアントからアクセスされるクライアント-サーバモデルを実現することができます。

実際には、コントローラ部分に認証の処理や、データベース操作などの処理を行うことになると思います。
サーバ側のデータベースを活用すれば、WordPressやGitHubのような仕組みを再現することができます。
（あくまでも単純なモデルとしての再現で、実際のWPやGitHubはよりハイレベルな処理が行われています）