2020/11,江端さんの技術メモ

2年前のコードをAWS Lightsailに乗せられないか、docker compose up -d  を試してみたところ、変なところでエラーが出てきた。

go build cmd/server/main.go

と打ち込んでみたら

というところで、引掛っていることが分かった。

原因をググってみた「メモリ不足」。

最低でも1G用意しろ、って書いてあった。

Amazon Lightsailの一番安いやつは、512MBだった。

まあ、今時、ノートPCだって、4G搭載しているからなー、これはないかなー 。

しかし、搭載を断念するのも残念だしなー、安全を考えると2GBは欲しいしなー ・・・でも、10ドル/月かぁ。

ちょっと考えよう。

Lightsail のインスタンスのスケールアップ

(後日談) 1MBのメモリを持つ、5$/月 の インスタンスにスケールアップして、docker compose up -d を通しました。

# いや、実装に成功していたラズパイのメモリが1GBだったので、多分大丈夫だろうと踏みました。

―― が、コンテナが起動していないので、ここからが勝負です。

 

2020/11,江端さんの技術メモ

地図データの入った PostgreSQL + postGIS サーバ を関係者に配るために、Docker containerのイメージを公開する(サーバ構築手順書を作成するのが面倒だから)

1.コンテナイメージの確認

C:\Users\ebata>docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
6432e639f678 postgis-pgrouting:latest "docker-entrypoint.s…" 3 months ago Up 6 hours 0.0.0.0:15432->5432/tcp toyosu_db_1

2.コンテナイメージのパッキング(commit)

C:\Users\ebata>docker commit 6432e639f678 tommurphy/toyosu_db_1
sha256:c7a1a0537fbe24d0c1371264cbd83e620a09e2ec5c328b5fbb42efb0e9454f8e

3. dockerへのログイン

C:\Users\ebata>docker login -u tommurphy
Password:
Login Succeeded

4. 外部への公開

C:\Users\ebata>docker push tommurphy/toyosu_db_1
The push refers to repository [docker.io/tommurphy/toyosu_db_1]
fcc5c725337c: Layer already exists             

fcc5c725337c: Layer already exists
a3994f456ccb: Layer already exists
.....
latest: digest: sha256:27a46f90aa1c7c9f9b5fa92877d22156144b882ba15ba4e04fe0e4fe2cb4af24 size: 4497

5. 確認

https://hub.docker.com/にアクセス

5. 相手側への連絡

「dockerをインストールしたマシンで、"docker pull tommurphy/toyosu_db_1" とコマンド投入しろ」

「で、そのあと、$ docker run -it tommurphy/toyosu_db_1 bash とコマンド投入しろ」

 

と連絡する。

(とりあえず、Windows10で作ったイメージを、Amazon Lightsailの ubuntu20.04に入れることまでは成功した。動くかどうかは不明)

→ ダメ。データベースすっからかんのコンテナができた。もうちょっと嵌る必要があるなぁ

というか、そもそもDockerコンテナとはそういうものらしい("docker" "postgresql" "永続化"、あたりでググってみる)

現在、PostgreSQLをデータごとDockerコンテナ化するを読んでいる。

 

 

2020/11,江端さんの技術メモ

私が使っているQGIS3の地図と地物情報を、先方に送りたいのですが、先方に「DB構築してくれ」とは言えない場合があります(というか、殆どの場合がそうだろう)。

# で、今、実際にそんな状況になっている。

最初、qgzファイルを送付すれば足る、とか思っていたのですが、甘かったようです(qgzファイルはプロジェクト情報しか送付できない)

で、QGIS3を色々触っているうちに、なんかファイルができたような気がするので、自分用のメモとして残しておきます。

以上(現在、先方の成否報告待ち)。

キーワード:gpkg QGIS3 地物情報 先方にメールで送付

 

2020/11,未分類,江端さんの技術メモ

以下、自分用のメモのみ

AWS  Lightsailにdockerのインストールまで成功

PostgreSQLのインストールも成功したと思う

が、ここから嵌り始める。

ca_sim=# create extension postgis;

^C^CCancel request sent
Cancel request sent
ERROR: canceling statement due to user request
server closed the connection unexpectedly
This probably means the server terminated abnormally
before or while processing the request.
The connection to the server was lost. Attempting reset: Failed.
!>

が出てきて、

サーバ側に
2020-11-04 12:52:16.858 UTC [51] ERROR: canceling statement due to user request
2020-11-04 12:52:16.858 UTC [51] STATEMENT: create extension postgis;
2020-11-04 12:53:53.365 UTC [1] LOG: server process (PID 51) was terminated by signal 9: Killed
2020-11-04 12:53:53.365 UTC [1] DETAIL: Failed process was running: create extension postgis;
2020-11-04 12:53:53.365 UTC [1] LOG: terminating any other active server processes
2020-11-04 12:53:53.367 UTC [25] WARNING: terminating connection because of crash of another server process
2020-11-04 12:53:53.367 UTC [25] DETAIL: The postmaster has commanded this server process to roll back the current transaction and exit, because another server process exited abnormally and possibly corrupted shared memory.
2020-11-04 12:53:53.367 UTC [25] HINT: In a moment you should be able to reconnect to the database and repeat your command.
2020-11-04 12:53:53.371 UTC [53] WARNING: terminating connection because of crash of another server process
2020-11-04 12:53:53.371 UTC [53] DETAIL: The postmaster has commanded this server process to roll back the current transaction and exit, because another server process exited abnormally and possibly corrupted shared memory.
2020-11-04 12:53:53.371 UTC [53] HINT: In a moment you should be able to reconnect to the database and repeat your command.
2020-11-04 12:53:53.372 UTC [56] WARNING: terminating connection because of crash of another server process
2020-11-04 12:53:53.372 UTC [56] DETAIL: The postmaster has commanded this server process to roll back the current transaction and exit, because another server process exited abnormally and possibly corrupted shared memory.
2020-11-04 12:53:53.372 UTC [56] HINT: In a moment you should be able to reconnect to the database and repeat your command.
2020-11-04 12:53:53.516 UTC [1] LOG: all server processes terminated; reinitializing
2020-11-04 12:53:53.535 UTC [58] FATAL: the database system is in recovery mode
2020-11-04 12:53:53.538 UTC [57] LOG: database system was interrupted; last known up at 2020-11-04 12:47:18 UTC
2020-11-04 12:53:53.607 UTC [57] LOG: database system was not properly shut down; automatic recovery in progress
2020-11-04 12:53:53.613 UTC [57] LOG: redo starts at 0/216DCD0
2020-11-04 12:53:53.712 UTC [57] LOG: invalid record length at 0/24F2310: wanted 24, got 0
2020-11-04 12:53:53.712 UTC [57] LOG: redo done at 0/24F22D8
2020-11-04 12:53:53.741 UTC [1] LOG: database system is ready to accept connections

そこで、

コンテナの外に出て、

sudo apt-get clean
sudo apt-get install postgis
sudo apt-get update

■全部のDockerを止める
C:\Users\ebata>docker ps -aq | xargs docker stop
C:\Users\ebata>docker ps -aq | xargs docker rm (これやると、これまでの設定も全滅するので注意)

もう一度、imageから作り直して ・・(30分経過)・・ううむ、それでもダメか。

今日はここで一旦引き上げ

2020/11,江端さんの技術メモ

正直手続忘れてしまったけど、一応historyからメモを作成しておきます。
https://docs.docker.com/engine/install/ubuntu/

$ sudo apt-get remove docker docker-engine docker.io containerd runc
$ sudo apt-get update
$ sudo apt-get install \
apt-transport-https \
ca-certificates \
curl \
gnupg-agent \
software-properties-common
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
$ sudo apt-key fingerprint 0EBFCD88
$ sudo apt-get update
$ sudo apt-get install docker-ce docker-ce-cli containerd.io

ここからコケ始めました。

$ apt-cache madison docker-ce

の後、

$ sudo apt-get install docker-ce=<VERSION_STRING> docker-ce-cli=<VERSION_STRING> containerd.io

を入力したら、予想通り失敗しました。

(ちょっと一息)

$ apt-cache madison docker-ce

を入力した時、一番最初に表示された"5:19.03.13~3-0~ubuntu-focal" を訳も分からずに、置き換えしました。

$sudo apt-get install docker-ce=5:19.03.13~3-0~ubuntu-focal docker-ce-cli=5:19.03.13~3-0~ubuntu-focal containerd.io

でもって、

$ sudo docker run hello-world

をして、コメントに出てくる通りに、

$ docker run -it ubuntu bash

を実施しても"Got permission denied....." とか言われて、dockerのコンテナの中に入ることができませんでした。

$ docker ps

Got permission denied while trying to connect to the Docker daemon
socket at unix:///var/run/docker.sock:
Get http://%2Fvar%2Frun%2Fdocker.sock/v1.39/containers/json:
dial unix /var/run/docker.sock: connect: permission denied

てなエラーが出てくるので、このエラーメッセージで検索したところ、

# dockerグループへユーザを追加
$ sudo gpasswd -a ubuntu docker

# グループの追加ができたことを確認
$ id ubuntu

と入力して、(ここ大事)

# 一回ログアウトして再ログインする
$ exit

して、再度

$ sudo docker run hello-world
$ docker run -it ubuntu bash

をしたら、今度はコンテナの中に入ることができました。

ubuntu@ip-172-26-13-137:~$ docker run -it ubuntu bash
Unable to find image 'ubuntu:latest' locally
latest: Pulling from library/ubuntu
6a5697faee43: Pull complete
ba13d3bc422b: Pull complete
a254829d9e55: Pull complete
Digest: sha256:fff16eea1a8ae92867721d90c59a75652ea66d29c05294e6e2f898704bdb8cf1
Status: Downloaded newer image for ubuntu:latest
root@e9ff5fa891d0:/# ;s
bash: syntax error near unexpected token `;'
root@e9ff5fa891d0:/# ls
bin   dev  home  lib32  libx32  mnt  proc  run   srv  tmp  var
boot  etc  lib   lib64  media   opt  root  sbin  sys  usr

よく分からんけど、これで、Amazon Lightsailの中にDockerをインストールすることができたんだろう・・・と思っています。

2020/11,江端さんの技術メモ

イプシムのSIM(IPアドレス付きで、一番安いやつ)が、ラズパイに差さったままで使っていなかったので、iPadで使えるようにした。必要に応じて、またラズパイに戻せばいいし。

  1. SIM取り出し用の機具の準備

  2. イプシムのSIMカード情報の確認(画像は偽造しています)

  3. SIMカード番号の確認 (上記のICCIDと同じであるかを確認(画像は偽造しています))

3. iPadのスロットに挿入する

4. iPadから、https://ipsim.net/support.html にアクセスし、APN構成プロファイルをダウンロードする

これをダウンロードするのだが、これがインストールできているどうかが、確認できずに困った(インストールボタンが見あたらなかったから)。この場合は、「設定」で調べる。

ちなみに、以下の情報が必要なのかは分からないが一応セットしておいた。

 

5. iPadから、https://ipsim.net/support.html にアクセスし、APN構成プロファイルをダウンロードする(画像は偽造しています)

上記の赤い囲みに数字が出てくれば、インストールできている(と思う)。

7.右上にこの表示が出てくれば、SIMカードは稼動している(最初のうち、ブラウザが表示されなかったりするが時間が経過すると見えるようになる(ことがあるみたい)。表示されずに、なんども、手順をやりなおしていたが、"放置"が正解だったような気がする)

以上

2020/10,江端さんの技術メモ

昨夜、らくがきのように綴った

Let’s encrypt を試してみた件(整理は明日)

を、まとめておきます。

昨日の実験で、Amazon lightsail でも、自前の公開暗号鍵(Let’s encrypt)を使えることが分かって、昨夜から気分の良い私です ―― これで、3.5ドル/月の、個人AWS練習用サーバの目処が立った。

どうも、私、"Let’s encrypt"を含めて、どうも私は公開暗号鍵の取扱いを、色々勘違いしていたようです。

たとえば、こちら、とか、こちら、で、AWSのロードバランサー(ELB: Amazon Elastic Load Balancing)に、"Let’s encrypt"で作った公開暗号鍵を関連付ける作業について記載しています。

しかし、AWSの供与をして頂いた部署が、IAMの設定を理解しておらず(もちろん、私も理解していませんでしたが)、 公開暗号鍵がロードバランサに紐付かずに、この時は、地獄を見ました

"Let’s encrypt"を使った認証鍵と暗号鍵を生成する時に、引数に、httpサーバの起動状態やら、鍵の置き場所などを指定するものだから、私は上位の認証局が、下々(私)の認証鍵と暗号鍵を見張っていると思っていました。

しかし、昨夜のGolandのコーディングで、認証鍵と暗号鍵は、有効期限付きのただのファイルである、ということを理解しました。

公開鍵証明書の認証局(CA: Certificate Authority)は、「下々のもの(私)に頼まれて、上位認証局(お上)が、鍵(ファイル)を作っているだけ」 ―― とりあえずは、この理解で十分であることが分かりました。

# というか ―― 巷(ちまた)の説明、難しすぎる。

まあ、それはさておき。

今回試みた、Let’s encryptでの鍵作りについて説明します(前提は、こちらを読んでおいて下さい)。

Let’s encryptでの鍵作りのパラメータは、省略することができるようです

$sudo certbot certonly --webroot -w /var/www/html -d sea-anemone.tech -d www.sea-anemone.tech

$sudo certbot certonly  -w /home/ubuntu/go_template/server_test -d sea-anemone.tech

  • "--webroot"は、webサーバの稼動している状況で扱う(しかもhttp://(×https://)が通らないとダメだめらしい)
  • "-w"以下は、golangのサーバを動かしている(サーバプログラムのある)ディレクトリを記載するらしい
  • "-d"以下は、SSLで使うドメイン名を入力("www.sea-anemone.tech"は、なんか知らんけど拒否された。理由は不明だけど、まあ、今は使っていないので無視する)

てな感じで、「とにかく鍵作ってくれ!」と頼むと、

How would you like to authenticate with the ACME CA? 
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
1: Spin up a temporary webserver(standalone)  (一時的なWebサーバを単独で起動する) 
2: Place files in webroot directory (webroot)ファイルを webroot ディレクトリに配置 する(webroot) 
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

となっていて、少なくとも、nginxなどのwebサーバ上げていない状態だから、少くとも"2"ではなく、"1"でを押下したら、

IMPORTANT NOTES: - Congratulations! Your certificate and chain have been saved at:
 /etc/letsencrypt/live/sea-anemone.tech/fullchain.pem 
Your key file has been saved at: 
/etc/letsencrypt/live/sea-anemone.tech/privkey.pem

という場所に鍵を作ってくれた様子。

ところが、この鍵、普通のmoreやlessでは見えずに、sudo more などとしないと見えないし、privkey.pemについては、それすらも見えない、という慎重さです。

とにかく、golangのサーバを動かしている(サーバプログラムのある)ディレクトリにコピーしました。

ubuntu@ip-172-26-13-137:~/go_template/server_test$ sudo cp /etc/letsencrypt/live/sea-anemone.tech/fullchain.pem . 
ubuntu@ip-172-26-13-137:~/go_template/server_test$ sudo cp /etc/letsencrypt/live/sea-anemone.tech/privkey.pem .

そんでもって、privkey.pemの権限が厳しいので、危ないけど >chmod +777 privkey.pem をやって、golangからアクセスして貰えるようにしておきました(権限のモードを忘れた)。こうしないと、go run serverXX.goをやると「privkey.pemが読めん」と文句を言われます。

で、serverXX.goの中を書き換え

/*
                log.Fatal(http.ListenAndServe(*addr, nil)) // localhost:8080で起動をセット
        */

        /*
        var httpErr error
        if _, err := os.Stat("./algo.crt"); err == nil {
                fmt.Println("file ", "algo.crt found switching to https")
                if httpErr = http.ListenAndServeTLS(*addr, "./algo.crt", "./algo.key", nil); httpErr != nil {
                        log.Fatal("The process exited with https error: ", httpErr.Error())
                }
        } else {
                httpErr = http.ListenAndServe(*addr, nil)
                if httpErr != nil {
                        log.Fatal("The process exited with http error: ", httpErr.Error())
                }
        }
        */

        var httpErr error
        if _, err := os.Stat("./fullchain.pem"); err == nil {
                fmt.Println("file ", "fullchain.pem found switching to https")
                if httpErr = http.ListenAndServeTLS(*addr, "./fullchain.pem", "./privkey.pem", nil); httpErr != nil {
                        log.Fatal("The process exited with https error: ", httpErr.Error())
                }
        } else {
                httpErr = http.ListenAndServe(*addr, nil)
                if httpErr != nil {
                        log.Fatal("The process exited with http error: ", httpErr.Error())
                }
        }

としたら、iPadで

https://sea-anemone.tech:8080
https://sea-anemone.tech:8080/smartphone

も、問題なく出力されるようになりました。

とりあえず、PruneMobileを雲の上に上げるメドが付き、ようやく一安心です。

 

2020/10,江端さんの技術メモ

ubuntu@ip-172-26-13-137:~/go_template/server_test$ sudo certbot certonly  -w /home/ubuntu/go_template/server_test -d sea-anemone.tech
Saving debug log to /var/log/letsencrypt/letsencrypt.log

How would you like to authenticate with the ACME CA?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1: Spin up a temporary webserver (standalone)
2: Place files in webroot directory (webroot)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Select the appropriate number [1-2] then [enter] (press 'c' to cancel): 1
Plugins selected: Authenticator standalone, Installer None
Obtaining a new certificate

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at:
   /etc/letsencrypt/live/sea-anemone.tech/fullchain.pem
   Your key file has been saved at:
   /etc/letsencrypt/live/sea-anemone.tech/privkey.pem
   Your cert will expire on 2021-01-28. To obtain a new or tweaked
   version of this certificate in the future, simply run certbot
   again. To non-interactively renew *all* of your certificates, run
   "certbot renew"
 - If you like Certbot, please consider supporting our work by:

   Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
   Donating to EFF:                    https://eff.org/donate-le

--webroot などをガン無視。www.sea-anemone.tech が作れなかったけど、こっちも無視。

でもって、

ubuntu@ip-172-26-13-137:~/go_template/server_test$ sudo cp /etc/letsencrypt/live/sea-anemone.tech/fullchain.pem .
ubuntu@ip-172-26-13-137:~/go_template/server_test$ sudo cp /etc/letsencrypt/live/sea-anemone.tech/privkey.pem .

を強行。

privkey.pemの権限が厳しいので、危ないけど >chmod +777 privkey.pem をやって、golangからアクセスして貰えるようにしておいた(権限のモードを忘れた)

で、serverXX.goの中を書き換え

/*
                log.Fatal(http.ListenAndServe(*addr, nil)) // localhost:8080で起動をセット
        */

        /*
        var httpErr error
        if _, err := os.Stat("./algo.crt"); err == nil {
                fmt.Println("file ", "algo.crt found switching to https")
                if httpErr = http.ListenAndServeTLS(*addr, "./algo.crt", "./algo.key", nil); httpErr != nil {
                        log.Fatal("The process exited with https error: ", httpErr.Error())
                }
        } else {
                httpErr = http.ListenAndServe(*addr, nil)
                if httpErr != nil {
                        log.Fatal("The process exited with http error: ", httpErr.Error())
                }
        }
        */

        var httpErr error
        if _, err := os.Stat("./fullchain.pem"); err == nil {
                fmt.Println("file ", "fullchain.pem found switching to https")
                if httpErr = http.ListenAndServeTLS(*addr, "./fullchain.pem", "./privkey.pem", nil); httpErr != nil {
                        log.Fatal("The process exited with https error: ", httpErr.Error())
                }
        } else {
                httpErr = http.ListenAndServe(*addr, nil)
                if httpErr != nil {
                        log.Fatal("The process exited with http error: ", httpErr.Error())
                }
        }

としたら、とりあえず

https://sea-anemone.tech:8080

で、iPadに地図が表示されるのは確認できた。

今日はここまで。

 

 

2020/10,江端さんの技術メモ

PruneMobile  を Amazon Lightsail に乗せています。

https://が上手く起動しなかったので、色々考えていました。

まず、serverXX.goを、

//var addr = flag.String("addr", "0.0.0.0:8080", "http service address") // ローカルテスト
var addr = flag.String("addr", ":8080", "http service address") // AWS上で動かす時

と変更して、さらに、これまで使ってきた「オレオレ証明書」の内容に問題があると気がついて、mkcert を使って、AWS Lighsail対応に作り直してみました。

C:\Users\ebata\Downloads>mkcert-v1.4.1-windows-amd64.exe sea-anemone.tech 43.53.5.81 137.172.25.12 localhost 127.0.0.1
Using the local CA at "C:\Users\ebata\AppData\Local\mkcert" ✨

Created a new certificate valid for the following names 📜
 - "sea-anemone.tech"
 - "43.53.5.81"
 - "137.172.25.12"
 - "localhost"
 - "127.0.0.1"

The certificate is at "./sea-anemone.tech+4.pem" and the key at "./sea-anemone.tech+4-key.pem" ✅

で、"sea-anemone.tech+4.pem"を"algo.crt"と、"./sea-anemone.tech+4-key.pem" を"algo.key"とリネームして、serverXX.goの入っているディレクトリに放り込みました。

WindowsPCの方は、上手く表示できるのですが、iPhoneやiPadの方は、

ERROR:undefined
onclise:CLOSE

が表示されて、JavaScriptが走りません。

分からないのですが『さすがに、iPhoneは「オレオレ証明書」では騙せないのかな』などと考えています。

Amazonの証明書は無料なのですが、なぜかAmazonの証明書はロードバランサがないと使えず、そんでもってロードバランサは$18/monthも金を取られるんです。本体が$3.5/monthなのに、なんか理不尽です。

とすると、アレかなぁ・・・できるだけ手を出したくないんだけどなぁ。

ともあれ、今日は疲れましたので、終了です。

2020/10,江端さんの技術メモ

document.getElementById("open").onclick = function(evt) と、ws.onopen = function(evt) が、混乱して、上手く動かなかったけど、ようやく分かりました(ような気ががしています)。

■document.getElementById("open").onclick = function(evt) { 処理内容}は、
"open"ボタンを押した時に行う処理を行い、
■ws.onopen = function(evt){処理内容}は、
websocketのopenのイベントが飛んできた時に行う

つまり、"ボタン"と"websocket"という、全く別物を取り扱っている、ということに、やっと気がつきました ―― 同じ"open"という言葉を使うので、混同していました。

なので、

ws.close()処理は、当然に、document.getElementById("open").onclick = function(evt) { 処理内容} の中で実施しなけばなりません。

ws.onopen = function(evt){処理内容}は、すでにwebsocketのclose処理が行われた後の処理を記載するので、ここでws.close()を記載したら、変なことになります(二重にwebsocketのclose処理をすることになる)


 

それと、位置情報をコールバックで取得する関数を、
const successCallback = (position) => { 処理内容 }

エラーイベントを検知する関数を、
const errorCallback = (err) => { 処理内容 }
と記載した場合、

このコールバックを登録する関数は、
watchPositionID = navigator.geolocation.watchPosition(successCallback, errorCallback, options);
であり、

このコールバックを停止する関数は、navigator.geolocation.clearWatch(watchPositionID);

となります。

という訳で、server26.goの"smartphoneTemplate"で登録している、htmlファイル(javascriptを含む)の部分だけ切り出したものを記載しておきます。

var smartphoneTemplate = template.Must(template.New("").Parse(`
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<script> 

let watchPositionID;  // グローバル変数として出しておく
let ws; // グローバル変数として出しておく

window.onload = () => {
	// これは、Web起動時に最初に読まれる部分であるが、今回、これらの関数は、全部
	// 	document.getElementById("open").onclick = function(evt) {  // openボタンを押した時 
	// 中に放り込んだ。 openボタンを押した後に起動するようにする為である

	// navigator.geolocation.watchPositionについては次のURLにかかれています。
	// https://developer.mozilla.org/ja/docs/Web/API/Geolocation/watchPosition

	// これが位置情報コールバックの起動コマンド
	//watchPositionID = navigator.geolocation.watchPosition(successCallback, errorCallback, options);

	// ここで(もう)webソケットを開く
	//ws = new WebSocket("{{.}}");

};

// ブラウザーを閉じる前に位置の監視を止めます
window.onbeforeunload = () => {
	// こちらの内容も
	// document.getElementById("close").onclick = function(evt) { // closeボタンを押した時
	// の中に放り込んだ  closeボタンを押した時に起動するようにする為である	

	// これが位置情報コールバック停止のコマンド	
	//navigator.geolocation.clearWatch(watchPositionID);
	
	//ws.close();
}


// 引数にはミリ秒を指定。(例:5秒の場合は5000)
function sleep(a){
	  var dt1 = new Date().getTime();
	  var dt2 = new Date().getTime();
	  while (dt2 < dt1 + a){
		dt2 = new Date().getTime();
	}
	  return;
}

// 以下の3つはグローバル変数として取り扱う
var personal_id =0;  
var lat;
var lng;  

//var ws;

// 位置情報を構造体として格納する為のファンクション(jsでは、こういう風に使うらしい)
function obj(id, lat, lng){
	this.id = id;
	this.lat = lat;
	this.lng = lng;
}

// 乱数生成装置 (minとmaxの間の乱数を作る)
function random(min, max){
	return  Math.random()*(max-min) + min;
}


window.addEventListener("load", function(evt) {
	// メッセージ表示部
    var output = document.getElementById("output");
    var input = document.getElementById("input");

    var print = function(message) {
        var d = document.createElement("div");
        d.textContent = message;
        output.appendChild(d);
	};

	///// 起動時のボタン設定(アクティブにしたり非アクティブにしたりする)
	// disabled属性を削除
	document.getElementById("open").removeAttribute("disabled");
	document.getElementById("open").style.color = "black";

	// disabled属性を設定 (closeボタンを非活性化)
	document.getElementById("close").setAttribute("disabled", true);
	document.getElementById("close").style.color = "White";			

	document.getElementById("open").onclick = function(evt) {  // openボタンを押した時
		console.log("document.getElementById open");

		// disabled属性を設定 (openボタンを非活性化)
		document.getElementById("open").setAttribute("disabled", true);
		document.getElementById("open").style.color = "White";		

		// disabled属性を削除(closeボタンを非活性化)
		document.getElementById("close").removeAttribute("disabled");
		document.getElementById("close").style.color = "black";	

        //if (ws) {
        //    return false;
        //}
	

		// ここでコールバック関数を起動
		watchPositionID = navigator.geolocation.watchPosition(successCallback, errorCallback, options);
		// websocket オープン
		ws = new WebSocket("{{.}}");
		// 最初はidを0にする
		personal_id = 0;   
			
		ws.onopen = function(evt) {  // 通信openイベントを検知した時(通信がopen状態になった後)
			print("OPEN");
		
			var send_obj = new obj(0, lat, lng);  // 最初はpersonal_idを"0"としてエントリ
	
			console.log("open:send_obj");	
			console.log(send_obj.id);	
			console.log(send_obj.lat);
			console.log(send_obj.lng);		
	
			var json_obj = JSON.stringify(send_obj);
			ws.send(json_obj);

		}

		ws.onclose = function(evt) {  // 通信closeイベント(×ボタン)を検知した時 (通信がclose状態になった後)
			print("onclose:CLOSE");
            ws = null;
        }

		ws.onmessage = function(evt) {  // 通信メッセージを受信した時(受信した後)
			print("RESPONSE: " + evt.data);  // jsonメッセージの内容を表示
			// データをJSON形式に変更
			var obj = JSON.parse(evt.data);

			personal_id = obj.id; // IDの取得(何回も取る必要はないが)
			console.log("personal_id");			
			console.log(personal_id);
			
			if ((Math.abs(obj.lat) > 90.0) || (Math.abs(obj.lng) > 180.0)){ // 異常な座標が入った場合は、マーカーを消去する
				console.log("before ws.close()");
				ws.close();
				console.log("after ws.close()");
			}
		}
		
        ws.onerror = function(evt) { //  エラーイベントを検知した時(検知した後)
            print("ERROR: " + evt.data);
        }
        return false;
    };
	
	document.getElementById("close").onclick = function(evt) { // closeボタンを押した時
		console.log(" document.getElementById close");

		// disabled属性を削除
		document.getElementById("open").removeAttribute("disabled");
		document.getElementById("open").style.color = "black";

		// disabled属性を設定 (closeボタンを非活性化)
		document.getElementById("close").setAttribute("disabled", true);
		document.getElementById("close").style.color = "White";	

        if (!ws) {
            return false;
		}
		
		var send_obj = new obj(personal_id, 999.9, 999.9); //  意図的に異常な位置情報を入れて正常終了させる処理

		console.log("close:send_obj");
		console.log(send_obj.id);		
		console.log(send_obj.lat);
		console.log(send_obj.lng);		

		var json_obj = JSON.stringify(send_obj);
		ws.send(json_obj);

		ws.close();  // これはws.closeの方で実施すると変なことになる  closeが実施された後で、close()することになる

		navigator.geolocation.clearWatch(watchPositionID); //コールバック関数の停止?

		personal_id = 0;   // 最後もidを0にする		
	
        return false;
    };
});

// 位置情報の取得に成功した際のコールバック

const successCallback = (position) => {
	console.log("successCallback:position");

	lat = position.coords.latitude;
	lng = position.coords.longitude;

	console.log(personal_id);
	console.log(lat);
	console.log(lng);

	//コールバックが発生するタイミングでサーバに位置情報を送付する

	if (personal_id != 0){
		var send_obj = new obj(personal_id, lat, lng);  // 最初は"0"でエントリ

		console.log("open:send_obj");	
		console.log(send_obj.id);	
		console.log(send_obj.lat);
		console.log(send_obj.lng);		

		var json_obj = JSON.stringify(send_obj);
		ws.send(json_obj);
	}

	// sleep(1000); // 1秒待つ	

}

// 位置情報の取得に失敗した際のコールバック
const errorCallback = (err) => {
	console.log(err);
};

// 位置を監視する構成オプション
// オプションの内容は次のリンクに書かれています。
// https://developer.mozilla.org/ja/docs/Web/API/PositionOptions
const options = {
	enableHighAccuracy: true,
	//timeout: 5000,
	timeout: 500000,
	maximumAge: 0
};

</script>
</head>
<body>
<table>
<tr><td valign="top" width="50%">
<p>Click "Open" to create a connection to the server, 
"Send" to send a message to the server and "Close" to close the connection. 
You can change the message and send multiple times.
<p>
<form>
<button id="open">Open</button>
<!-- <p><input id="input" type="text" value="Hello world!"> -->
<!-- <button id="send">Send</button> -->
<button id="close">Close</button>
</form>
</td><td valign="top" width="50%">
<div id="output"></div>
</td></tr></table>
</body>
</html>
`))