2021年6月11日 星期五

JavaScript 複製文字

<a class="link" href="http://example.com" target="_blank">http://example.com</a>
<input type="button" name="btnCopy" value="複製">

<script type="text/javascript">
    $(function () {
        $("input[name=btnCopy]").click(function () {
            var node = document.querySelector('.link');
            var range = document.createRange();
            range.selectNode(node);
            window.getSelection().removeAllRanges();
            window.getSelection().addRange(range);
            try {
                var successful = document.execCommand('copy');
                if (successful) {
                    alert("複製成功");
                } else {
                    alert("複製失敗");
                }
            } catch (err) {
                alert("複製失敗!");
            }
            window.getSelection().removeAllRanges();
        });
    });
</script>



參考:

Node.js socket.io

let app = require('express')();
let http = require('http').Server(app);
let io = require('socket.io')(http);
let cookie = require('cookie');
let ws_port = 9999;
//設定監聽IPv4的IP,避免取remote IP連IPv6一起取(::ffff:192.168.96.1)
http.listen(ws_port, '0.0.0.0', function () {
    console.log('listening on *:' + ws_port);
});

const test_io = io.of('/test');

test_io.on('connection', function (socket) {
    //client連線數量
    let client_cnt = io.engine.clientsCount;
    
    //取得 query 參數(GET 參數)
    let aa = socket.handshake.query['aa'];
    
    //取得 cookie
    let cookies = '';
    try {
        cookies = cookie.parse(socket.handshake.headers.cookie);
    } catch (err) {
        console.log('#無效cookie:', socket.handshake.headers.cookie);
        console.log(err);
    }
    
    //取得IP
    let client_ip = socket.request.connection.remoteAddress;
    
    //取得header資訊
    if (undefined !== socket.handshake.headers["x-real-ip"]) {
        client_ip = socket.handshake.headers["x-real-ip"];
    }


    socket.on('disconnect', async function () {
        ......
    });
    
    async function main() {
        ......
    }
    main().catch(err => {
        .....
        socket.disconnect(true);
    });
    
    socket.on('testmsg', function () {
        .......
    });

    ......
});


其它:
  1. socket.handshake 物件內的資料
    {
      headers: /* the headers sent as part of the handshake */,
      time: /* the date of creation (as string) */,
      address: /* the ip of the client */,
      xdomain: /* whether the connection is cross-domain */,
      secure: /* whether the connection is secure */,
      issued: /* the date of creation (as unix timestamp) */,
      url: /* the request URL string */,
      query: /* the query params of the first request */,
      auth: /* the authentication payload */
    }

 

參考:



2021年6月10日 星期四

Cocos Creator 預設入口場景丟失

Cocos Creator 最後編輯的場景(入口場景),
儲存在 local/local.json 裡的 last-edit 設定項。

新建專案時,產生的 .gitignore 排除了 library、temp、local、build 資料夾。
基本上,這些資料夾都可以刪除,
Cocos Creator 開啟專案時,會自動重新產生。

但重新產生的 local/local.json,裡面 last-edit 設定會是 null
需重新選擇入口場景再執行遊戲,
否則會出現「預覽場景中啥都沒有,加點什麼,或在編輯器中打開其它場景吧」的遊戲黑畫面。


參考:



2021年5月11日 星期二

Go、xorm 時區

import (
    "fmt"
    "time"

    _ "github.com/go-sql-driver/mysql"
    "xorm.io/xorm"
)

[Go 時區]
取得目前時區與跟UTC的偏移量
t := time.Now()
zone, offset := t.Zone()
fmt.Println(zone, offset) //CST 28800

轉換成指定時區的時間
now := time.Now()
fmt.Println(now) //2021-05-07 03:05:05.029289 +0800 CST m=+0.002740401

time_zone_1, err1 := time.LoadLocation("") //UTC
if err1 != nil {
    fmt.Println(err1)
}
fmt.Println(now.In(time_zone_1)) //2021-05-06 19:05:05.029289 +0000 UTC

time_zone_2, err2 := time.LoadLocation("Local") //Server環境的時區
if err2 != nil {
    fmt.Println(err2)
}
fmt.Println(now.In(time_zone_2)) //2021-05-07 03:05:05.029289 +0800 CST

time_zone_3, err3 := time.LoadLocation("America/Los_Angeles")
if err3 != nil {
    fmt.Println(err3)
}
fmt.Println(now.In(time_zone_3)) //2021-05-06 12:05:05.029289 -0700 PDT

time_zone_4 := time.FixedZone("test", 60*60*3) //自訂一個時區,名稱test, UTC+3
fmt.Println(now.In(time_zone_4))               //2021-05-06 22:05:05.029289 +0300 test

//time_zone_5, err5 := time.LoadLocation("Asia/Shanghai")
//time_zone_5, err5 := time.LoadLocation("Asia/Taipei")



[xorm 時區]
取得 xorm 的時區設定
fmt.Println(engine.TZLocation) //Local

設定 xorm 時區
engine.TZLocation, _ = time.LoadLocation("America/Los_Angeles")
fmt.Println(engine.TZLocation) //America/Los_Angeles




其他:
  1. time.Time 類型的資料包含時區 
  2. parseTime=true,將 DATE、DATETIME 型態的資料用 time.Time 表示。
    parseTime=false,將 DATE、DATETIME 型態的資料用 []byte/string 表示。
    //engine, err := xorm.NewEngine("....?charset=utf8&parseTime=false", connStr)
    sql := "select STR_TO_DATE('2003-12-31 01:02:03', '%Y-%m-%d %H:%i:%s') AS t"
    results, err := engine.Query(sql)
    fmt.Println("results :", results)
    fmt.Println("results t:", string(results[0]["t"]))
    //parseTime=true
    //results : [map[t:[50 48 48 51 45 49 50 45 51 49 84 48 49 58 48 50 58 48 51 90]]]
    //results t: 2003-12-31T01:02:03Z
    //parseTime=false
    //results : [map[t:[50 48 48 51 45 49 50 45 51 49 32 48 49 58 48 50 58 48 51]]]
    //results t: 2003-12-31 01:02:03
    
    sql = "select STR_TO_DATE('0000-00-00 00:00:00', '%Y-%m-%d %H:%i:%s') AS t"
    results, err = engine.Query(sql)
    fmt.Println("results :", results)
    fmt.Println("results t:", string(results[0]["t"]))
    //parseTime=true
    //results : [map[t:[48 48 48 49 45 48 49 45 48 49 84 48 48 58 48 48 58 48 48 90]]]
    //results t: 0001-01-01T00:00:00Z
    //parseTime=false
    //results : [map[t:[48 48 48 48 45 48 48 45 48 48 32 48 48 58 48 48 58 48 48]]]
    //results t: 0000-00-00 00:00:00



參考:


2021年5月9日 星期日

Golang 安裝 xorm.io/reverse

xorm/reverse 可將資料表結構反轉成程式中給 xorm 使用的struct

 [安裝 xorm.io/reverse 發生錯誤]

> go get xorm.io/reverse  
# github.com/mattn/go-sqlite3
cc1.exe: sorry, unimplemented: 64-bit mode not compiled in
原因:系統的 gcc 需支援 64 bit,而我早期裝的是 32 bit
> gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=c:/mingw/bin/../libexec/gcc/mingw32/4.7.2/lto-wrapper.exe
Target: mingw32
Configured with: ../gcc-4.7.2/configure --enable-languages=c,c++,ada,fortran,objc,obj-c++ --disable-sjlj-exceptions --with-dwarf2 --enable-shared --enable-libgomp --disable-win32-registry --enable-libstdcxx-debug --disable-build-poststage1-with-cxx --enable-version-specific-runtime-libs --build=mingw32 --prefix=/mingw
Thread model: win32
gcc version 4.7.2 (GCC)


[解決辦法:安裝 64 位元的 MinGW-w64]
下載網址









安裝後,將 MinGW-w64 的 bin 目錄,加入使用者環境變數
C:\Program Files\mingw-w64\x86_64-8.1.0-win32-seh-rt_v6-rev0\mingw64\bin
如果暫時不想刪除舊的 C:\MinGW\bin,須將新的路徑,移到上方





重啟命令視窗,即可讀取到新的設定(若是在 VS code Terminal,須將所有 VS code 關閉重啟)
> gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=C:/Program\ Files/mingw-w64/x86_64-8.1.0-win32-seh-rt_v6-rev0/mingw64/bin/../libexec/gcc/x86_64-w64-mingw32/8.1.0/lto-wrapper.exe
Target: x86_64-w64-mingw32
Configured with: ../../../src/gcc-8.1.0/configure --host=x86_64-w64-mingw32 --build=x86_64-w64-mingw32 --target=x86_64-w64-mingw32 --prefix=/mingw64 --with-sysroot=/c/mingw810/x86_64-810-win32-seh-rt_v6-rev0/mingw64 --enable-shared --enable-static --disable-multilib --enable-languages=c,c++,fortran,lto --enable-libstdcxx-time=yes --enable-threads=win32 --enable-libgomp --enable-libatomic --enable-lto --enable-graphite --enable-checking=release --enable-fully-dynamic-string --enable-version-specific-runtime-libs --disable-libstdcxx-pch --disable-libstdcxx-debug --enable-bootstrap --disable-rpath --disable-win32-registry --disable-nls --disable-werror --disable-symvers --with-gnu-as --with-gnu-ld --with-arch=nocona --with-tune=core2 --with-libiconv --with-system-zlib --with-gmp=/c/mingw810/prerequisites/x86_64-w64-mingw32-static --with-mpfr=/c/mingw810/prerequisites/x86_64-w64-mingw32-static --with-mpc=/c/mingw810/prerequisites/x86_64-w64-mingw32-static --with-isl=/c/mingw810/prerequisites/x86_64-w64-mingw32-static --with-pkgversion='x86_64-win32-seh-rev0, Built by MinGW-W64 project' --with-bugurl=https://sourceforge.net/projects/mingw-w64 CFLAGS='-O2 -pipe -fno-ident -I/c/mingw810/x86_64-810-win32-seh-rt_v6-rev0/mingw64/opt/include -I/c/mingw810/prerequisites/x86_64-zlib-static/include -I/c/mingw810/prerequisites/x86_64-w64-mingw32-static/include' CXXFLAGS='-O2 -pipe -fno-ident -I/c/mingw810/x86_64-810-win32-seh-rt_v6-rev0/mingw64/opt/include -I/c/mingw810/prerequisites/x86_64-zlib-static/include -I/c/mingw810/prerequisites/x86_64-w64-mingw32-static/include' CPPFLAGS=' -I/c/mingw810/x86_64-810-win32-seh-rt_v6-rev0/mingw64/opt/include -I/c/mingw810/prerequisites/x86_64-zlib-static/include -I/c/mingw810/prerequisites/x86_64-w64-mingw32-static/include' LDFLAGS='-pipe -fno-ident -L/c/mingw810/x86_64-810-win32-seh-rt_v6-rev0/mingw64/opt/lib -L/c/mingw810/prerequisites/x86_64-zlib-static/lib -L/c/mingw810/prerequisites/x86_64-w64-mingw32-static/lib '
Thread model: win32
gcc version 8.1.0 (x86_64-win32-seh-rev0, Built by MinGW-W64 project)

確定設定生效後,即可正常安裝
安裝後會在 GOPATH 底下的 bin 目錄,產生 reverse.exe 執行檔
> go get xorm.io/reverse  
go get: added xorm.io/reverse v0.1.1


[xorm reverse 用法]
1.新增設定文件,例如檔名為 custom.yml,內容為
kind: reverse
name: aa #資料庫名稱
source:
  database: mysql #哪一種資料庫
  conn_str: 'root:密碼@tcp(127.0.0.1:3306)/aa' #連接資料庫設定
targets:
- type: codes
  language: golang
  output_dir: ./test_model #輸出在哪個目錄底下
2.執行將資料表轉換成程式碼結構的命令
> reverse -f custom.yml
結果會在 output_dir(./test_model)目錄下產生 models.go 檔

aa資料庫底下,有兩個資料表a1、b1
CREATE TABLE `a1` (
  `a_id` int(11) NOT NULL,
  `a_data` varchar(45) DEFAULT NULL,
  `a_dtime` datetime DEFAULT NULL,
  `a_cur_time` timestamp NULL DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='測試1';

CREATE TABLE `b1` (
  `b_id` int(11) NOT NULL,
  `b_num` int(10) UNSIGNED ZEROFILL DEFAULT NULL COMMENT '測試',
  `b_num2` int(11) NOT NULL,
  `b_data` decimal(11,2) NOT NULL,
  `b_add_dtime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


ALTER TABLE `a1`
  ADD PRIMARY KEY (`a_id`),
  ADD UNIQUE KEY `a_data` (`a_data`);

ALTER TABLE `b1`
  ADD PRIMARY KEY (`b_id`);


ALTER TABLE `a1`
  MODIFY `a_id` int(11) NOT NULL AUTO_INCREMENT;

ALTER TABLE `b1`
  MODIFY `b_id` int(11) NOT NULL AUTO_INCREMENT;

產生的 models.go 檔內容如下,轉成 xorm 的Column屬性定義:
package models

import (
	"time"
)

type A1 struct {
	AId      int       `xorm:"not null pk autoincr INT(11)"`
	AData    string    `xorm:"unique VARCHAR(45)"`
	ADtime   time.Time `xorm:"DATETIME"`
	ACurTime time.Time `xorm:"TIMESTAMP"`
}

type B1 struct {
	BId       int       `xorm:"not null pk autoincr INT(11)"`
	BNum      int       `xorm:"comment('測試') INT(10)"`
	BNum2     int       `xorm:"not null INT(11)"`
	BData     string    `xorm:"not null DECIMAL(11,2)"`
	BAddDtime time.Time `xorm:"not null default CURRENT_TIMESTAMP TIMESTAMP"`
}
跟原資料表結構相比,可發現有些細節消失了(資料表COMMENT、欄位UNSIGNED ZEROFILL屬性、...也許還會有其他的)
另外測試將產生的 models.go 內容,用engine.Sync2(new(A1), new(B1)) 自動建立資料表,這些細節也是沒有了。
engine.Sync2()能夠根據程式碼中的資料表結構,部分自動同步建立(修改)資料庫中的資料表,例如:新增欄位可以,但刪除欄位不可以。



參考: