Node.jsフレームワーク(Express-Generator)でのページ遷移

ラズパイにはExpress-Generatorをインストールしていましたが、MacBookにもインストールして久しぶりに触っています。Express-Generatorはwebアプリ雛形作成のためのツールの一つです。webアプリ作成のためには理解すべき点がいくつかありますが、動的なページを作成するためのデータの与え方はその一つです。

以下は関連するディレクトリを表示していますが、index.jsでviews配下のindex.pugのコンテンツを作るようになっています。

index.jsソースの一部(dbName())は記載していませんが、データベースからの読み出しを行なっています。本タイトルと直接の関係はないので省略。

var express = require('express');
var router = express.Router();

var nameList = "";

/* GET home page. */
router.get('/', function(req, res, next) {
  var response = Math.floor(Math.random() * (100 - 1)) + 1;
  
  dbName();

  const wait = () => {
  res.render('index', { title: 'Express', data: response, db: nameList});
  }
  setTimeout(wait, 3);
});

res.render()の第二引数以下がindex.pugに渡されてhtmlのコンテンツを構成しています。雛形ではtitle一個しかありませんが、カンマ区切りで任意の個数を追加できます。ここでは1~100までの範囲の乱数をdataとして、データベースから読み出したデータを変数名dbでindex.pugに渡しています。

index.pug

extends layout

block content
  h1= title
  p Welcome to #{title}

  p #{data} 

  p #{db}

SQLite3のデータベースアクセスも非同期で実行されるので、ページ作成が先行して実行されてdbデータの供給が間に合わないので、仮に時間待ち3msを入れていますが、あくまでデバッグ専用でいずれ修正の予定。

 

admin

 

 

Node.js(JavaScript)で経過日(時間)を求める

GolangにはtimeパッケージにYearDay()という年初からの連続で今日が何日目かを返してくれる関数があってそれをファイル名(tbl + 西暦年 + 連続何日目)に使っています。1日に2個以上テーブル作る可能性がないから、これで一意にファイル名を決定できます。

https://pkg.go.dev/time

でもNode.jsで同じファイル名を指定しようとするとこのような関数はないので、計算が必要になります。なぜNode.jsで必要かというとGolangで作成したSQLiteのテーブルにNode.jsからアクセスしたいからですが。

Golangでのテーブル作成、年号と年初からの経過日でファイル名を作成しています。以下のコードの一番下の行でターブル作成。

date := strconv.Itoa(t.Year()) + strconv.Itoa(t.YearDay())

	if del {
		cmd := "drop table if exists tbl" + date

		_, err := db.Exec(cmd)
		if err != nil {
			fmt.Println("db table drop error")
		}
	}

	// table exist check
	cmd := "select*from tbl" + date
	_, table_check := db.Query(cmd) // checked by using return code

	if table_check != nil {

		cmd = "create table if not exists tbl" + date + "(id string primary key, name, time int, stat int)"

JavaScriptでのテーブル名の作成スクリプト

// calc file name
let d = new Date();
let year = d.getFullYear();
let month = d.getMonth();
let day = d.getDate();

let date1 = new Date(year, 0, 0);
let date2 = new Date(year, month, day)
let behind = Math.floor((date2 - date1) / (24*3600*1000));      // convert milisec to day


db.serialize(() => {
    db.each("select * from tbl" + year + behind + " where stat=0", (err, row) => {
    console.log(`${row.id} ${row.name} ${row.time} ${row.stat}`);
    })
});

Math.fllor():端数切り捨てはなくても大丈夫のようですが、入れておいて実害はないだろうから。

 

admin

Node.jsでSQLiteにアクセス

Golangで作成したSQLiteのテーブルをnode.jsからアクセスしてみようと思ったが、前提になるnpmが起動できないし、nodeも起動できない。

% node   

dyld[71646]: Library not loaded: /opt/homebrew/opt/icu4c/lib/libicui18n.71.dylib

  Referenced from: <66A3E1EC-93E2-36D1-889D-02EE5C192FCC> /opt/homebrew/Cellar/node/18.11.0/bin/node

Reason: tried: ‘/opt/homebrew/opt/icu4c~~~~以下省略

解決方法は、

https://stackoverflow.com/questions/53828891/dyld-library-not-loaded-usr-local-opt-icu4c-lib-libicui18n-62-dylib-error-run

から、

% brew reinstall icu4c

で解決。

・Node.jsからSQLiteへアクセスするドライバーをインストール

% npm install sqlite3

・すでに存在しているテーブルにアクセスしてみる、

//

// DB handler

//

'use strict';

const sqlite3 = require("sqlite3");

const db = new sqlite3.Database("./myfare.db");

db.serialize(() => {

    db.each("select * from tbl202382 where stat=0", (err, row) => {

    console.log(`${row.id} ${row.name}`);

    })

});

db.close();

do.run()が非同期実行なのでsierialize()が必要とのことですが、データ更新してなくて読んでるだけで並行処理されるものがないから実はserialize()はこのケースでは不要。

しかし実行すると、

Error: Cannot find module ‘sqlite3’

対策はパスを通すことらしいので、

% export NODE_PATH=`npm root -g`

で、

% echo $NODE_PATH

/opt/homebrew/lib/node_modules

にsqlite3は存在していますが、

% which sqlite3

とは違うディレクトリなので実はシンボリックリンクを使っているのかもしれない。

ともかくもSQLite3のテーブルアクセスはできた。

SQLiteでテーブル存在有無を確認(Golang)

GolangでDBドライバー使ってコードからテーブルの存在有無を確認する方法です。SQLコマンド打てば簡単ですが、コードでチェックするというのはどうやるかしばらく悩みました。以下のstackoverflowから引用しました。

https://stackoverflow.com/questions/56915022/check-if-database-table-exists-using-golang

動作環境でimportしているライブラリ(DBアクセスで必要なのはsqlとsqlite3の2個)、go-sqlite3は使わないけどインポートだけはしないとコンパイルできません。

go-sqlite3のブランクインポートが必要な理由は、

https://maku77.github.io/p/kgzfwdt/

になります。

import (
	"bufio"
	"database/sql"
	"encoding/json"
	"errors"
	"fmt"
	_ "github.com/mattn/go-sqlite3"
	"log"
	"os"
	"strconv"
	"time"

	"go.bug.st/serial"
	"go.bug.st/serial/enumerator"
)

以下がテーブル存在をチェックしているコードになりますが、dateはフィアル名の一部ですね。戻りのerrorコードがnilならテーブル存在、それ以外ならテーブルが存在しないことになります。

	// table exist check
	cmd := "select*from tbl" + date
	_, table_check := db.Query(cmd)			// checked by using return code

	if table_check != nil {

方法は別にSQLite限定ではなくて他のDBでも同じだろうと思います。

 

admin

ioutilもdeprecated(Golang)

タイトルの通りですが、1.20以降ではそうなります。実は1.16でそういう風に宣言されていたらしい。以下のリンクを参照、

bytes, err := ioutil.ReadFile("sample.json")

bytes, err := os.ReadFile("sample.json")

おそらくファイル全体を読み込むのは、メモリ効率が良くないし、Goの美学とも相入れないのでos.ReadFileを使えということなんだろうと思います。

https://future-architect.github.io/articles/20210210/

 

admin

M5StackC plusとGolangでシリアル通信する

M5StackC plusからのMyfareカードのUID情報をUSBシリアル使ってGoで受信してみます。

参考は、

https://zenn.dev/nnabeyang/articles/d54f18cc39dc4a654c7a

USBシリアルのVID/PIDをMacBook Airからシステム情報/USBで引くと、以下のように見える。USB経由でファイル(USBストレージ)とシリアルインターフェースが見えるようになっています。

0x403と0x6001を使うが、これでは該当するポートが見つからないと言われる。

VID/PIDを調べるために取得スクリプトを、

https://pkg.go.dev/go.bug.st/serial/enumerator

のexampleから引っ張ってくる。参考までにPortDetails構造体の中身見ると、型が数値ではなく文字列だから16進表記じゃだめです。まあ、元々が文字列じゃないか、

if port.IsUSB {
fmt.Printf("   USB ID     %s:%s\n", port.VID, port.PID)
fmt.Printf("   USB serial %s\n", port.SerialNumber)


-->
   USB ID     0403:6001
   USB serial AD5232ED16
type PortDetails struct {
	Name         string
	IsUSB        bool
	VID          string
	PID          string
	SerialNumber string

	// Product is an OS-dependent string that describes the serial port, it may
	// be not always available and it may be different across OS.
	Product string
}

VID/PIDの文字列をそのまま使って、

package main

import (
	"bufio"
	"errors"
	"fmt"
	"log"
	"os"

	"go.bug.st/serial"
	"go.bug.st/serial/enumerator"
)

func getPortName() (string, error) {
	ports, error := enumerator.GetDetailedPortsList()
	if error != nil {
		return "", error
	}
	for _, port := range ports {
		/*
			if port.IsUSB {
				fmt.Printf("   USB ID     %s:%s\n", port.VID, port.PID)
				fmt.Printf("   USB serial %s\n", port.SerialNumber)
		*/

		if port.IsUSB && port.VID == "0403" && port.PID == "6001" {
			return port.Name, nil
		}
	}
	return "", errors.New("M5Stack cplus is not conntected")
}

func main() {
	portName, err := getPortName()
	if err != nil {
		log.Fatal(err)
		os.Exit(1)
	}
	mode := &serial.Mode{
		BaudRate: 115200,
	}
	port, err := serial.Open(portName, mode)
	if err != nil {
		log.Fatal(err)
		os.Exit(1)
	}
	scanner := bufio.NewScanner(port)
	for scanner.Scan() {
		fmt.Println(scanner.Text())
	}
}

これでちゃんと読めた。

 

admin

M1 MacBook AirのUbuntu版数

Ubuntuの18.04系が5月にサポート終了するというニュース見て、今の版数を改めて確認。

Intel MacBookは20.04系(VMWare)で、

$ lsb_release -a
No LSB modules are available.
Distributor ID:	Ubuntu
Description:	Ubuntu 22.04.2 LTS
Release:	22.04
Codename:	jammy

M1 Mac(UTM)に入れたのは最新版の22.04、まあインストール時期からすれば当然ですが。

 

admin

 

MacBook Airのゴミ箱がワンクリックで消せない

まあMacOSではありがちな現象ではありますが、ゴミ箱がワンクリックで消せなくて、わざわざゴミ箱の中に入ってファイルを全選択して消去。

週一のリフレッシュブートで回復しているから、何らかのOS問題。回避が簡単な問題なら最近気にならなくなった。

 

admin

rand.Seed()はdeprecated(Go lang)

VScodeでGo 1.20以降の環境では、rand.Seed()は使うなというwarningが出ます。

代わりに推奨されているのは、rand.NewSource()になります。

	rand.Seed(time.Now().UnixNano())
	rand.NewSource(time.Now().UnixNano())

理由は以下のポップアップメッセージですが、a dependency changes how much it consumes from …..の意味は理解できません。最後の一行を読むと、他のパッケージからもglobal random resourceにアクセスがあると期待したシーケンスで出力されなくなると読めるのでリソース(global random resource)を共有時の問題のようで、他のパッケージからアクセスできないrand.NewSource()を使えということなのでしょう。

stackoverflowのQAを見るとこの件がアップされていますね。

https://stackoverflow.com/questions/75597325/rand-seedseed-is-deprecated-how-to-use-newrandnewseed

 

admin

 

ChatGPT

公開されてからいくつかの質問をしていますが、無回答というのはなくてとりあえずハズレでも良いから回答するという特性があります。

ネットの記事にあった、円周率は3.05以上であることを証明しなさいというのを入力すると、円周率は3.14…だから3.05以上だという無意味な回答が出てきます。

内接する正多角形で考えると正六角形で3以上、正八角形でおよそ3.06、正十二角形でおよそ3.1というのが最大平方根の計算だけで求まるからというのがおそらく正しい回答で今の設問ならば正八角形で回答すれば良い。

下の手書きの絵は正十二角形での計算過程ですが、角度が60/45/30度ならば最大でも平方根の計算だけで求まります。

多分人間の思考とは違うので、こういう問題は苦手だろうと思います、簡単なアルゴリズムのコード化などはそれらしい結果が出てくるので。

だんだん賢くはなるだろうけれども、少なくとも創造はできないだろうから人間の思考の補助としての使い道でしょう。

 

admin