| 
 出社人数掲示板 2020 May 28 
昨今のコロナ禍により、
会社フロアーへの出社人数の制約や把握が必要になる場合があると思います。
そのような時、みんなで共有して使える「出社人数掲示板」を、
Google Compute Engine の試用を兼ねて試作してみました。
ただし、現状では実際の運用が出来るレベルではありません。
本件はその試作メモです。
 
 実際の 出社人数掲示板はこちら  です。実運用していないので自由に触って大丈夫です。
アメリカのオレゴン州にあるGoogle無料サーバーのため、
アクセスに少し時間がかかります。 おさらい 2020 May 18-20 
Google Cloud Shell とは
 
 
 無料のサーバインスタンスを立てる 2020 May 21 
VM を立て OS を入れる
 
 
 
 /etc/apache2/apache2.conf 
ServerName factorylabus
#
# This should be changed to whatever you set DocumentRoot to.
#
<Directory /home/USER-NAME/mnt>
	Options Indexes FollowSymLinks
	AllowOverride None
	Require all granted
	Order allow,deny
	Allow from all
</Directory>
#CGI 設定
LoadModule alias_module /usr/lib/apache2/modules/mod_alias.so
LoadModule cgi_module /usr/lib/apache2/modules/mod_cgi.so
ScriptAlias /cgi-bin/ /home/USER-NAME/cgi-bin/
<Directory home/USER-NAME/cgi-bin>
    Options FollowSymLinks ExecCGI
    AllowOverride None
    Require all granted
    Order allow,deny
    Allow from all
    AddHandler cgi-script .cgi .sh .class .pl
</Directory>
/etc/apache2/sites-available/000-default.confDocumentRoot /home/USER-NAME/mnt Cloud Storage をVMにマウントする 2020 May 22-23 
デフォルトではCloud Storageは、VMからは見えませんが、
VMのファイルシステムとしてマウントするコマンド
Cloud Storage FUSE があります。
「Cloud Storage バケットへの接続」
   、及び
「Cloud Storage FUSE」  を参照。
gcsfuseのインストールはgithubのdocs/installing.mdの
1と2(3は不要)をコピペして実行します。
しかし、任意のディレクトリに対してはうまくマウントできず、
取り合えずホーム直下に作りました。
また、マウントはエンジン起動のたびに行う必要があります。
ちなみに、本エンジンは常時稼働しています。 
  によれば、apache のユーザー名で gcsfuse しないと apache に見えないそう。 
 #export APACHE_RUN_USER=www-data #export APACHE_RUN_GROUP=www-data export APACHE_RUN_USER=USER-NAME export APACHE_RUN_GROUP=USER-NAME Web App を構築する 2020 May 24 
その前に、私は Assembler, C, C++, java, javascript しか使った経験がなく、
今回の超簡単アプリもjavaで書きました。
その為、VMにjava実行環境をインストールします。
headless の方を入れます。
 
 
//
// Usage:
//    $ java count mode [param]
//      mode  0=31日分の情報を返す
//            1=param引数の日を+1し、情報を返す
//            2=param引数の日を-1し、情報を返す
//      param +-する日にち
//
import	java.io.FileInputStream;
import	java.io.InputStreamReader;
import	java.io.BufferedReader;
import	java.io.FileOutputStream;
import	java.io.DataOutputStream;
import	java.io.IOException;
public class count {
    static String FILENAME = "count.string";
    public static void main(String[] args) {
	int mode = 0;
	int param = 0;
        if ( args.length < 1 ) {
	    System.out.println("Usage: java count mode [param]");
	    return;
	}
	mode = Integer.parseInt(args[0]);
	if ( mode != 0 ) {
	    if ( args.length < 2 ) {
		System.out.println("Usage: java count mode [param]");
		return;
	    }
	    param = Integer.parseInt(args[1]);
	}
	String[] lines = new String[40];
	try {
	    FileInputStream fis = new FileInputStream(FILENAME);
	    InputStreamReader isr = new InputStreamReader(fis);
	    BufferedReader br = new BufferedReader(isr);
	    for( int i=0; i < 31 ; i++ ) {
		lines[i] = br.readLine();
	    }
	    br.close();
	} catch(IOException e) {}
	if ( mode == 1 ) {
	    lines[param] = "" + (Integer.parseInt(lines[param])+1);
	} else if ( mode == 2 ) {
	    int value = Integer.parseInt(lines[param]);
	    if ( value > 0 )
		lines[param] = "" + (value - 1);	    
	}
	if ( mode != 0 ) {
	    try {
		FileOutputStream fos = new FileOutputStream(FILENAME);
		DataOutputStream dos = new DataOutputStream(fos);
		for( int i=0; i < 31 ; i++ ) {
		    dos.writeBytes(lines[i] + "\n");
		}
		dos.close();
	    } catch(IOException e) {}
	}
	for( int i=0; i < 31 ; i++ ) {
	    System.out.println(lines[i]);	// std out
	}
    }
}
さて、20年程前に会社のApache Web ServerでSSIを使ったことがあり、 少し考えましたが、SSIはあくまで静的なプリプロセッサ―であり、 静的なWeb Siteには使えますが、 引数や変数を伴った動的なWeb Siteで活躍する仕組みではないようです。 apacheを使う場合は 「ApacheとWebアプリケーションの連携」  などという方法もあるようですが本筋ではない気がします。
ポイントは、サーバー側で出社人数を管理している、
上記count.javaのコマンドラインと、ユーザーのブラウザ側のHTMLコードを、
インターネット越しにどう接続するかです。
Web App のお勉強 
 
 
<script language="JavaScript">
  var ScriptUrl = "http://35.199.148.152/cgi-bin/count.pl";
  var mask;
  let xhr = new XMLHttpRequest();
  function codeGen() {
    mask = true;
    xhr.open("GET", ScriptUrl + "?mode=0", true);
    xhr.send();
    xhr.onerror = function() {
      alert("Request failed");
    };
    xhr.onload = function() {
      if ( xhr.status != 200 ) {
        alert(`Error ${xhr.status}: ${xhr.statusText}`);
      } else {
        update();
      }
    };
    // --
    var date = new Date();
    var month = date.getMonth()+1;
    var today = date.getDate();
    var lastDay = new Date(date.getFullYear(), month, 0).getDate();
    var i = 0;
    document.write("<table cellpadding=4>");
    while( i < 7 ) {
      document.write("<tr><td valign=top>");
      document.write("  <div class='item0'>");
      document.write("    <font class='mon_day'>" + month + "/" +  today + "</font>");
      document.write("  </div>");
      document.write("</td><td>");
      document.write("  <a class='toggle btnNum' name='num'> - </a>");
      document.write("  <div class='item1'>");
      document.write("   <p><a href='' class='btnItem' onClick='return plus("+ today + ")'>出社します</a></p>");
      document.write("   <p><a href='' class='btnItem' onClick='return mimus("+ today + ")'>取消します</a></p>");
      document.write("  </div>");
      document.write("</td></tr>");
      if ( lastDay == today ) {
        month++;
        today = 0;
      }
      today++;
      i++;
    }
    document.write("</table>");
  }
  function update() {
    mask = false;
    var counts_string = xhr.response; // 文字列で返った
    var syussya = counts_string.split("\n");
    var date = new Date();
    var month = date.getMonth()+1;
    var today = date.getDate();
    var lastDay = new Date(date.getFullYear(), month, 0).getDate();
    var i = 0;
    while( i < 7 ) {
      document.getElementsByName("num")[i].innerHTML = syussya[today-1];
      if ( lastDay == today ) {
        today = 0;
      }
      today++;
      i++;
    }
  }
  function inc_dec(day, inc_dec) {
    mask = true;
    xhr.open("GET", ScriptUrl+"?mode="+(inc_dec? '1':'2')+"¶m="+(day-1), true);
    xhr.send();
  }
  function plus(day) {
    if ( mask == false )
      inc_dec(day, true);
    return false;
  }
  function mimus(day) {
    if ( mask == false )
      inc_dec(day, false);
    return false;
  }
</script>
両者をつなぐ引数受け渡し部分CGI 「Webサーバーを作る(アプリを動かす)」の第9回  を参照。今回はperlを使い、引数をjavaアプリに渡しました。 
 
#!/usr/bin/perl -w
use strict;
use warnings;
use CGI;
print "Content-type: text/html\n\n";
# GET パラメータを取得
my $q = new CGI;
 
# パラメータ名を指定して取り出す
my $mode = $q->param('mode');  
my $param = $q->param('param'); 
# コマンドラインを形成しjavaアプリを呼び出す
my $command = 'java count ' . $mode . ' ' . $param;
system($command);
課題 
サーバー側 Web Api と、クライアント側 HTML の URL が異なる場合の
オリジン間リソース共有 (CORS) を行うには?
 | ||||||
| 
 無料VMの変更 2021 Aug 15 
2021年7月21日、Google から、無料のVMエンジンが、
F1-micro から E2-micro に変更されるという連絡があり、
その対応を行った。
 
 |