2022年9月11日 星期日

[Linux] apt: error while loading shared libraries: libudev.so.1: cannot open shared object file: No such file or directory @ Ubuntu 18.04

安裝套件時,有碰到 libudev-dev 相關套件太新:

$ sudo apt install libudev-dev
Reading package lists... Done
Building dependency tree       
Reading state information... Done
Some packages could not be installed. This may mean that you have
requested an impossible situation or if you are using the unstable
distribution that some required packages have not yet been created
or been moved out of Incoming.
The following information may help to resolve the situation:

The following packages have unmet dependencies:
 libudev-dev : Depends: libudev1 (= 237-3ubuntu10.53) but 237-3ubuntu10.54 is to be installed
E: Unable to correct problems, you have held broken packages.

$ dpkg -l | grep libudev
ii  libudev1:amd64                            237-3ubuntu10.54                            amd64        libudev shared library

$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 18.04.6 LTS
Release: 18.04
Codename: bionic

然後,就耍蠢把他移掉 XD

$ sudo dpkg --purge --force-all libudev1
dpkg: libudev1:amd64: dependency problems, but removing anyway as you requested:
 util-linux depends on libudev1 (>= 183).
 libpci3:amd64 depends on libudev1 (>= 196).
 initramfs-tools-bin depends on libudev1 (>= 183).
 liblvm2app2.2:amd64 depends on libudev1 (>= 183).
 libplymouth4:amd64 depends on libudev1 (>= 183).
 udev depends on libudev1 (= 237-3ubuntu10.54).
 libusb-1.0-0:amd64 depends on libudev1 (>= 183).
 snapd depends on libudev1 (>= 183).
 liblvm2cmd2.02:amd64 depends on libudev1 (>= 183).
 libdevmapper1.02.1:amd64 depends on libudev1 (>= 183).
 open-vm-tools depends on libudev1 (>= 183).
 lvm2 depends on libudev1 (>= 183).
 dosfstools depends on libudev1 (>= 183).
 libapt-pkg5.0:amd64 depends on libudev1 (>= 183).

(Reading database ... 157028 files and directories currently installed.)
Removing libudev1:amd64 (237-3ubuntu10.54) ...
Processing triggers for libc-bin (2.27-3ubuntu1.6) ...

一堆指令都高度依賴不能跑了 XD

$ sudo apt update
apt: error while loading shared libraries: libudev.so.1: cannot open shared object file: No such file or directory

解法也不難,在用 dpkg 裝回來,在 http://archive.ubuntu.com/ubuntu/pool/main/s/systemd/ 尋找

$ wget http://archive.ubuntu.com/ubuntu/pool/main/s/systemd/libudev1_237-3ubuntu10.54_amd64.deb
$ sudo dpkg -i libudev1_237-3ubuntu10.54_amd64.deb
Selecting previously unselected package libudev1:amd64.
(Reading database ... 157024 files and directories currently installed.)
Preparing to unpack libudev1_237-3ubuntu10.54_amd64.deb ...
Unpacking libudev1:amd64 (237-3ubuntu10.54) ...
Setting up libudev1:amd64 (237-3ubuntu10.54) ...
Processing triggers for libc-bin (2.27-3ubuntu1.6) ... 
$ sudo apt update
Get:1 http://security.ubuntu.com/ubuntu bionic-security InRelease [88.7 kB]
Hit:2 http://ap-tokyo-1-ad-1.clouds.archive.ubuntu.com/ubuntu bionic InRelease
Get:3 http://ap-tokyo-1-ad-1.clouds.archive.ubuntu.com/ubuntu bionic-updates InRelease [88.7 kB]
Get:4 http://ap-tokyo-1-ad-1.clouds.archive.ubuntu.com/ubuntu bionic-backports InRelease [74.6 kB]
Fetched 252 kB in 2s (128 kB/s)   
Reading package lists... Done
Building dependency tree       
Reading state information... Done
All packages are up to date.

記錄一下,而真實的任務還沒解決,推論應該是裝上舊把對應的 so 路徑修一下即可,目前還是走安全一點的路徑,用虛擬環境/docker來執行

ref:

2022年9月1日 星期四

Electron 開發筆記 - 使用 @electron-forge/plugin-webpack

評估 electron 到底要跟哪套網頁開發的流程合在一起用,先研究一下 @electron-forge/plugin-webpack,粗略整合還堪用,但還有一些路徑或程式碼架構要處理。

先規劃了 src 目錄:

  % tree src 
  src
  ├── html
  │   └── mainRenderer
  │       ├── index.html
  │       └── index.js
  ├── main
  │   └── index.js
  ├── preload
  │   └── mainRenderer.js
  └── renderer
      ├── index.js
      └── mainRenederer.js
  
  5 directories, 6 files

其中 html 就是預期每個 renderer 的網頁所在地;而 main/index.js 就是 Electron main process 處理的項目;而 renderer/mainRenederer.js 是預期在 Electron main process 中處理 createWindow 的項目抽取出來重複使用;而 preload/mainRenderer.js 就是 Electron Renderer 展現前的 preload script

如此,想讓純前端網頁的程式碼都可以賴在 html 目錄下,屆時要靠常見工具封裝成 SPA 也方便。

而使用 electron-forge/plugin-webpack 上,只需要留意二件事:

1. 在 package.json 描述要被 webpack 封裝的項目

% cat package.json | jq '.config'
{
  "forge": {
    "plugins": [
      [
        "@electron-forge/plugin-webpack",
        {
          "mainConfig": "./webpack.main.config.js",
          "renderer": {
            "config": "./webpack.renderer.config.js",
            "entryPoints": [
              {
                "name": "main_window",
                "html": "./src/html/mainRenderer/index.html",
                "js": "./src/html/mainRenderer/index.js",
                "preload": {
                  "js": "./src/preload/mainRenderer.js"
                }
              }
            ]
          }
        }
      ]
    ]
  }
}

2. 在 Electron main process 中,使用 createWindow 後要讀取的 index.html 跟 preload.js 要改用變數

MAIN_WINDOW_PRELOAD_WEBPACK_ENTRY, MAIN_WINDOW_WEBPACK_ENTRY

目前還會卡到 webpack dev server 運行時,有些 js code 執行異常,正考慮不要靠 webpack dev server,可能就要正式離開 @electron-forge/plugin-webpack" 用法了

2022年8月30日 星期二

Electron 開發筆記 - 初探 ElectronJS 框架開發 PC app

約莫一年前團隊同事接了個用 ElectronJS 開發的程式,並且依照其框架成果再做出另一個 PC app ,最近播點時間來研究一下 ElectronJS 。幾個月前接觸 Golang 時,也曾想過用 Golang + Electron 練習一下 PC app ,只是整體上運作起來還是太卡了點。

整體上,要認識 ElectronJS 建議都先看一次官方文件 www.electronjs.org/docs/latest/ ,基本上寫的精簡不錯,看完一輪 Processes in Electron 就會學會:
  • Electron 的流程架構 (Process Model),可以分成 main process (node.js / main.js) 和 renderer process (BrowserWindow / renderer.js ),並且透過 preload.js 串起 main process 跟 renderer process 溝通橋樑
  • preload.js 是在 renderer process 執行前運行的,等於進入到 renderer process 前,可以打造一些溝通環境
  • 資安領域上,如何讓 renderer process 的權限不要太大 (Context Isolation)
  • 關於 main process 和 renderer process 溝通時,該怎樣進行 (ipcMain, ipcRenderer),可以分成 Renderer to Main 單向溝通、Renderer to Main 雙向溝通、Main to Renderer 溝通等
  • 看一眼 Process Sandboxing 情況,再多了解一下 MessagePorts 用法 (像 window.postMessage 之 iframe 溝通)
如此,就差不多可以來用 Electron 開發 PC app,然而有更多眉眉角角躲在 package.json 中以及一堆神秘的指令,如 electron-forge 等等。

我想,開發 Electron 的複雜度,源自於整個專案進行會跨非常多領域(指令)吧,每個混再一起就會覺得爆炸大,每個分離看待就會舒適許多。

像我自己也弄了:
  • env_nvm.sh:靠 nvm 切換 node.js 版本
  • env_vim.sh:靠 .vimrc 和 .vimrc_coc.nvim 完成簡易 coding style 和 auto-complete 設置
  • 把上述包裝在 init_env.sh 運行,每次開發就先跑一下 source init_env.sh 就行了
最後,對於 Electron PC app 開發,後續也都還會再做一些程式碼封裝方式(webpack等)和程式碼混淆等,當然,若還有開發框架 vue.js, react 等,也都還有對應的任務,所以連續動作還是很多的,之後繼續筆記一下。

2022年8月27日 星期六

Go 開發筆記 - 台灣身分證檢查器/大量產生器

晚上跟數學系的朋友聊幾句,他用個公式算出合法的帳號數字(滿合理的遠大於台灣人口數),於似乎,來用鳥鳥暴力解試試,並且練一下 golang 的 goroutine 用法。當然最後的資料個數是一樣的,共有 5.2億組。總數公式 = 26 (字母) * 2 (男女) * 10^7 (最後一碼是校正碼,只有七種變化)

只是我用暴力解,偷懶用多層 loop 發一下波動拳 XD 理論上還可以優化最後一碼用算的,而不是用暴力算,在一台老電腦上(3.1 GHz 雙核心Intel Core i7),大概花 1小時產出(包括每百萬筆寫到檔案)

最後的成果:

% go run main.go --verify A123456789
A123456789 : PASS, time cost: 23.449µs

% go run main.go --verify A123456780
A123456780 : FAIL, time cost: 25.528µs

% time go run main.go --cpu 4
...
taskID: 0, taskCount:    1000000, totalCount:  510000000, timeCost: 57m56.195527594s, mem: 336 MB
taskID: 2, taskCount:    1000000, totalCount:  511000000, timeCost: 58m12.348436403s, mem: 286 MB
taskID: 1, taskCount:    1000000, totalCount:  512000000, timeCost: 58m17.794134191s, mem: 360 MB
taskID: 0, taskCount:    1000000, totalCount:  513000000, timeCost: 58m18.106069808s, mem: 380 MB
taskID: 2, taskCount:    1000000, totalCount:  514000000, timeCost: 58m33.170090521s, mem: 247 MB
taskID: 1, taskCount:    1000000, totalCount:  515000000, timeCost: 58m39.34318826s, mem: 308 MB
taskID: 0, taskCount:    1000000, totalCount:  516000000, timeCost: 58m39.902875471s, mem: 370 MB
taskID: 2, taskCount:    1000000, totalCount:  517000000, timeCost: 58m50.616989581s, mem: 133 MB
taskID: 1, taskCount:    1000000, totalCount:  518000000, timeCost: 58m55.655774417s, mem: 67 MB
taskID: 2, taskCount:    1000000, totalCount:  519000000, timeCost: 59m3.85291194s, mem: 111 MB
taskID: 2, taskCount:    1000000, totalCount:  520000000, timeCost: 59m14.91097006s, mem: 111 MB
Total verified IDs count: 520000000 , time cost: 59m18.802491746s
go run main.go --cpu 4  9320.09s user 3332.58s system 355% cpu 59:19.56 total

% ls -lah /tmp/ids*
-rw-------  1 user  wheel   1.4G  8 27 08:41 /tmp/ids-0.txt
-rw-------  1 user  wheel   1.4G  8 27 08:41 /tmp/ids-1.txt
-rw-------  1 user  wheel   1.4G  8 27 08:42 /tmp/ids-2.txt
-rw-------  1 user  wheel   1.0G  8 27 08:28 /tmp/ids-3.txt

% wc -l /tmp/ids-* 
 140000000 /tmp/ids-0.txt
 140000000 /tmp/ids-1.txt
 140000000 /tmp/ids-2.txt
 100000000 /tmp/ids-3.txt
 520000000 total

2022年8月25日 星期四

C 開發筆記 - 使用 libwebsockets 製作簡易的 WebSocket Client

已經有用過 Golang 開發小工具,以及其他現成工具如 websocat 等,做 WebSocket Server 的測試。這次回過頭來再仔細看看 libwebsockets 這套,寫一點 C 語言。

程式架構不會太難,比較難的反而是一些小東西,像是跟 ws.ptt.cc 連線時,PTT 會做 Request Header(Origin欄位) 檢查,當作簡單的管控,然而 libwebsockets 則是要設定  LWS_SERVER_OPTION_JUST_USE_RAW_ORIGIN 才能不加料 XD

#include <include/libwebsockets/lws-context-vhost.h>

For backwards-compatibility reasons, by default lws prepends "http://" to the origin you give in the client connection info struct. If you give this flag when you create the context, only the string you give in the client connect info for .origin (if any) will be used directly.

大概在這種地方耗掉半小時以上。另外,還有做 wss 連線時,也須設定 LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT 等等,以及如果想要略過 wss 的 SSL 憑證檢查,有滿多設定項目可以試試:LCCSCF_USE_SSL | LCCSCF_ALLOW_SELFSIGNED | LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK | LCCSCF_ALLOW_INSECURE;

其他則是依照 libwebsockets 的架構,要設計連線時的 callback 處理機制,算是體驗了一下。未來就多一個 C 語言工具可以做 WebSocket Server 連線測試。


常見的錯誤訊息:
  • E: SSL_new failed: error:00000063:lib(0)::reason(99)
  • W: [wsicli|0|WS/h1/default/ws.ptt.cc]: lws_client_ws_upgrade: got bad HTTP response '403'
  • E: lws_ssl_client_bio_create: Unable to get hostname
執行 logs:

% make
gcc -g -Wall main.c `pkg-config libwebsockets --libs --cflags`

% ./a.out   
Usage> ./a.out url
./a.out ws://localhost:8000/
./a.out wss://ws.ptt.cc/bbs app://cmd
./a.out wss://ws.ptt.cc/bbs https://term.ptt.cc

% ./a.out wss://ws.ptt.cc/bbs https://term.ptt.cc
[2022/08/25 20:45:29:8530] N: lws_create_context: LWS: 4.3.2-no_hash, NET CLI SRV H1 H2 WS ConMon IPV6-on
[2022/08/25 20:45:29:8539] N: __lws_lc_tag:  ++ [wsi|0|pipe] (1)
[2022/08/25 20:45:29:8964] N: __lws_lc_tag:  ++ [vh|0|default||-1] (1)
wsCallback - LWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERTS
[INFO] libwebsockets version: 4.3.2
[INFO] lws_parse_uri - Server: ws.ptt.cc:443
[INFO] lws_parse_uri - URLScheme: wss
[INFO] lws_parse_uri - URLPath: bbs
[INFO] clientConnectInfo.addres: ws.ptt.cc
[INFO] clientConnectInfo.port: 443
[INFO] clientConnectInfo.path: /bbs
[INFO] clientConnectInfo.host: ws.ptt.cc
[INFO] clientConnectInfo.origin: https://term.ptt.cc
[INFO] clientConnectInfo.ssl_connection: 109
[2022/08/25 20:45:29:9789] N: __lws_lc_tag:  ++ [wsicli|0|WS/h1/default/ws.ptt.cc] (1)
call lws_client_connect_via_info done, webSocket is NULL(NO)
noop
[2022/08/25 20:45:30:0229] N: lws_gate_accepts: on = 0
[2022/08/25 20:45:30:0575] N: lws_gate_accepts: on = 0
wsCallback - LWS_CALLBACK_CLIENT_ESTABLISHED
wsCallback - LWS_CALLBACK_CLIENT_WRITEABLE
wsCallback - LWS_CALLBACK_CLIENT_RECEIVE
RECEIVER: HTTP/1.1 200 OK

     ??      PTT                ?P   ??        ?P  ??      ???i?i?i?i?i?i??
             140.112.172.11 ?P     ???i???i??            ???i?i?i?i?i
  ?z?w?{     ?????~?{        ???d?i?i???i??   ?P   ???i?i?i?i?i??  ?P
  ?x?V?|?{   ptt.cc            ???i?i?i?i?i???i??    ???i?i?i?i?i
  ?x?V  ?x                   ???i?i?i???i?i?i????  ???i?i?i?i?i??  ??  ?P
?w?}    ?x?z?w?w?{  ?P       ????      ?i?i?i?i?????i?i?i?i    ?P
        ?|?t  ?V?x      ?P           ???i?i?i?i???i?i?i??            ?P
                ?x?z?w?w?w?{         ?i?i?i?i?i?h?h?g?g?f?f?e?e?d?c?b
            ?z?w?r?}?V?V  ?| ???i?i?i?i?i?h?h?g?g?f?f?e?e?d?d?c?c?b
            ?x?V?V           ???i?i
wsCallback - LWS_CALLBACK_CLIENT_RECEIVE
RECEIVER:       ?i?h?h?g?g?f?f?e?e?d?c?b

wsCallback - LWS_CALLBACK_CLIENT_RECEIVE
RECEIVER:            ?f?d?d?e?g?f?e         ?e?d?g??     ???âg?d?e       ????            
               ?g?h  ?h         ?e?d         ?b      ???c?g?d                   
?п?J?N???A?ΥH guest ???[?A?ΥH new ???U:               
^C   ?b?c?e?f?e?g?h?g?f?d    ?n  ??   ??  ???n?l?? ??  ???? ?l?k  ?h