本文探討區塊鏈技術在無伺服器架構中的應用,並以智慧合約的實作案例說明整合流程。首先,我們會以 Solidity 語言撰寫一個用於管理手機號碼註冊資訊的智慧合約,並使用 Truffle 框架將其佈署至以太坊區塊鏈網路。接著,示範如何使用 WebHook 與已佈署的智慧合約進行互動,以查詢手機號碼的註冊資訊。此外,本文也介紹如何使用 Chromeless 自動化瀏覽器操作,將舊有的 UI 系統包裝成 OpenFaaS 函式,並與 WebHook 整合,實作更完整的應用場景。最後,我們將探討如何使用 Go 語言實作 Glue 功能,串接不同服務,並利用 Dockerfile 多階段建置最佳化佈署流程。

區塊鏈技術在無伺服器架構中的應用:以智慧合約為例

隨著區塊鏈技術的不斷發展,其在無伺服器架構中的應用也日益受到關注。本文將以智慧合約為例,探討區塊鏈技術在無伺服器架構中的應用,並深入分析相關技術細節。

智慧合約的基本概念

智慧合約是一種執行在區塊鏈上的程式碼,它能夠自動執行特定的任務。智慧合約的執行結果會被記錄在區塊鏈上,因此具有不可篡改的特性。

註冊智慧合約的實作

pragma solidity ^0.5.0;

contract RegistrationRepository {
    event RegistrationFound(string telNo, string bank, string accNo);
    event RegistrationNotFound(string telNo);

    mapping(string => Registration) public registrations;

    struct Registration {
        string bank;
        string accNo;
        address owner;
    }

    function register(string memory telNo, string memory bank, string memory accNo) public {
        registrations[telNo] = Registration(bank, accNo, msg.sender);
        emit Registered(telNo, msg.sender);
    }

    function findByTelNo(string memory telNo) public view returns (address) {
        Registration memory r = registrations[telNo];
        require(r.owner != address(0), "Registration not found");
        emit RegistrationFound(telNo, r.bank, r.accNo);
        return r.owner;
    }
}

內容解密:

此智慧合約用於管理手機號碼的註冊資訊。主要功能包括:

  1. register 函式:將手機號碼與銀行帳戶資訊進行繫結,並記錄擁有者地址。
  2. findByTelNo 函式:根據手機號碼查詢相關的銀行和帳戶資訊。
  3. 事件機制:當查詢到註冊資訊時觸發 RegistrationFound 事件,否則觸發 RegistrationNotFound 事件。

使用 Truffle 框架佈署智慧合約

Truffle 是一個流行的以太坊開發框架,用於編譯、佈署和測試智慧合約。

佈署指令碼範例

var RegistrationRepository = artifacts.require("./RegistrationRepository.sol");

module.exports = function(deployer) {
    deployer.deploy(RegistrationRepository).then(function() {
        RegistrationRepository.deployed().then(function(repo) {
            repo.register("+661234567", "faas", "55700").then();
            repo.register("+661111111", "whisk", "A1234").then();
        });
    });
};

內容解密:

此指令碼用於佈署 RegistrationRepository 智慧合約,並註冊兩個手機號碼,分別對應不同的銀行和帳戶。

區塊鏈網路的設定

本文使用 Parity 客戶端建立以太坊區塊鏈網路。

Parity 客戶端啟動命令

docker run --rm --name=parity_dev -d -p 8545:8545 -p 8180:8180 \
    --network=parse_net \
    --network-alias=blockchain \
    parity/parity:stable-release \
    --geth --chain dev --force-ui \
    --reseal-min-period 0 \
    --jsonrpc-cors http://localhost \
    --jsonrpc-apis all \
    --jsonrpc-interface 0.0.0.0 \
    --jsonrpc-hosts all

內容解密:

此命令啟動一個 Parity 客戶端容器,並組態相關引數以便與其他服務進行互動。

WebHook 如何與區塊鏈互動

WebHook 函式透過呼叫智慧合約來查詢手機號碼的註冊資訊。

Java 程式碼範例

public RegistrationResult lookup(String telNo) throws Exception {
    val repo = ContractRegistry.registrationRepository();
    val receipt = repo.findByTelNo(telNo).send();

    val foundEvents = repo.getRegistrationFoundEvents(receipt);
    if (!foundEvents.isEmpty()) {
        val reg = foundEvents.get(0);
        return new RegistrationResult(reg.bank, reg.accNo);
    } else {
        val notFoundEvents = repo.getRegistrationNotFoundEvents(receipt);
        if (!notFoundEvents.isEmpty()) {
            return null;
        }
    }
    throw new Exception("Lookup does not find any event in receipt.");
}

內容解密:

此函式呼叫 findByTelNo 方法查詢手機號碼的註冊資訊,並根據事件結果傳回相關資訊或丟擲異常。

最佳化建議

  1. 最佳化事件處理:目前的實作中,智慧合約會觸發多個事件。可以考慮最佳化為只觸發一個事件,以提高效率。
  2. 錯誤處理:在 WebHook 函式中,可以增加更完善的錯誤處理機制,以應對各種可能的異常情況。

使用 Chromeless 包裝舊系統

Chromeless 是一個 Node.js 函式庫,用於實作瀏覽器自動化。

建立 hivectl 函式

$ faas new hivectl --lang node

內容解密:

此命令使用 FaaS CLI 建立一個名為 hivectl 的新函式,用於包裝舊有的 UI 系統。

隨著區塊鏈技術和無伺服器架構的不斷成熟,我們可以預見更多的企業將採用這些技術來構建更安全、更高效的應用系統。同時,開發者需要不斷學習和掌握相關技術,以應對日益複雜的技術挑戰。

附錄

系統架構圖

  graph LR
    A[WebHook] -->|呼叫智慧合約|> B[區塊鏈網路]
    B -->|傳回結果|> A
    C[舊系統] -->|被Chromeless包裝|> D[hivectl函式]
    D -->|與WebHook互動|> A

圖表翻譯: 此圖表展示了系統的整體架構,包括 WebHook 如何與區塊鏈網路互動,以及如何使用 Chromeless 包裝舊系統並與 WebHook 進行互動。

程式碼最佳實踐

在開發過程中,應遵循最佳實踐來確保程式碼的品質和可維護性。例如,使用清晰的命名規則、新增必要的註解、以及進行充分的測試等。這些做法有助於提高程式碼的可讀性和可靠性。

使用 OpenFaaS 和 Chromeless 自動化頭部 Chrome 瀏覽器操作

簡介

本文將介紹如何利用 OpenFaaS 和 Chromeless 實作自動化頭部 Chrome 瀏覽器操作。我們將建立一個名為 hivectl 的 OpenFaaS 函式,該函式透過 Chromeless 控制頭部 Chrome 瀏覽器,以自動化 HiveMind ERP 系統中的財務帳戶調整操作。

建立 OpenFaaS 函式

首先,我們需要建立一個名為 hivectl 的 OpenFaaS 函式。執行以下命令:

$ faas new hivectl --lang node

該命令將在當前目錄下建立一個名為 hivectl 的資料夾,並包含 OpenFaaS 函式的描述檔案 hivectl.yml

組態 OpenFaaS 函式

以下是 hivectl.yml 的內容:

provider:
  name: faas
  gateway: http://localhost:8080
functions:
  hivectl:
    lang: node
    handler: ./hivectl
    image: chanwit/hivectl:0.4

該組態檔案定義了一個名為 hivectl 的 OpenFaaS 函式,使用 Node.js 語言,處理器為 ./hivectl,並使用 chanwit/hivectl:0.4 映象。

編寫 Chromeless 指令碼

以下是 hivectl/handler.js 的內容:

const { Chromeless } = require('chromeless')

const url = 'http://hivemind/vapps/hmadmin/Accounting/FinancialAccount/FinancialAccountTrans?finAccountId='

module.exports = (content, callback) => {
  async function run(accountId, amount) {
    const chromeless = new Chromeless({
      launchChrome: false,
      cdp: { host: 'chrome', port: 9222, secure: false, closeTab: true }
    })

    const screenshot = await chromeless
      .goto('http://hivemind/Login/logout')
      .click('#TestLoginLink_button')
      .wait('.btn-danger')
      .goto(url + accountId)
      .wait('#AdjustDialog-button')
      .click('#AdjustDialog-button')
      .type(amount, '#AdjustFinancialAccount_amount')
      .mousedown('#select2-AdjustFinancialAccount_reasonEnumId-container')
      .mouseup('#select2-AdjustFinancialAccount_reasonEnumId-container')
      .press(40, 5)
      .press(13)
      .click('#AdjustFinancialAccount_submitButton')
      .screenshot()
      .catch(e => {
        console.log('{"error":"' + e.message + '"}')
        process.exit(1);
      })

    console.log('{"success": "ok", "screenshot":"' + screenshot + '"}')
    await chromeless.end()
  }

  const opt = JSON.parse(content)
  run(opt.accountId, opt.amount).catch(console.error.bind(console))
};

內容解密:

此指令碼使用 Chromeless 控制頭部 Chrome 瀏覽器,以自動化 HiveMind ERP 系統中的財務帳戶調整操作。首先,它導航到登出頁面並點選測試登入連結。然後,它導航到指定的財務帳戶頁面,點選調整按鈕,輸入調整金額,選擇調整原因,並點選提交按鈕。最後,它擷取螢幕並輸出結果。

建置和佈署 OpenFaaS 函式

執行以下命令建置 OpenFaaS 函式:

$ faas build -f ./hivectl.yml

建置完成後,將映象推播到 Docker Hub。

啟動頭部 Chrome 瀏覽器和 HiveMind ERP 系統

執行以下命令啟動頭部 Chrome 瀏覽器:

$ docker run -d --network=parse_net \
  --network-alias=chrome \
  --cap-add=SYS_ADMIN \
  justinribeiro/chrome-headless

執行以下命令啟動 HiveMind ERP 系統:

$ docker run -p 10000:80 \
  -d --network=parse_net \
  --network-alias=hivemind \
  moqui/hivemind

呼叫 OpenFaaS 函式

以下是 WebHook 程式碼,呼叫 hivectl 函式:

public boolean faasAdjust(String txId, String accountId, Double amount) throws Exception {
  val env = System.getenv("FAAS_GATEWAY_SERVICE");
  val faasGatewayService = (env == null ? "http://gateway:8080" : env);
  val JSON = MediaType.parse("application/json; charset=utf-8");
  val client = new OkHttpClient();
  val json = new ObjectMapper().writeValueAsString(new HashMap<String, String>() {{
    put("accountId", accountId);
    put("amount", String.valueOf(amount));
  }});
  val body = RequestBody.create(JSON, json);
  val request = new Request.Builder()
    .url(faasGatewayService + "/function/hivectl")
    .post(body)
    .build();
  val response = client.newCall(request).execute();
  System.out.println(response);
  if (response.code() == 200) {
    val str = response.body().string();
    return true;
  }
  throw new Exception(response.toString());
}

圖表翻譯:

此圖表呈現了整個系統的架構,包括 OpenFaaS、Chromeless、頭部 Chrome 瀏覽器和 HiveMind ERP 系統之間的互動流程。

  graph LR;
    A[OpenFaaS] -->|呼叫|> B(hivectl);
    B -->|控制|> C(頭部 Chrome 瀏覽器);
    C -->|操作|> D(HiveMind ERP 系統);
    D -->|傳回|> C;
    C -->|傳回|> B;
    B -->|傳回|> A;

圖表翻譯: 此圖表呈現了 OpenFaaS 呼叫 hivectl 函式,hivectl 函式控制頭部 Chrome 瀏覽器,瀏覽器操作 HiveMind ERP 系統,並傳回結果的整個流程。

使用 Go 語言實作 Glue 功能

以下是使用 Go 語言實作的 Glue 功能程式碼:

func main() {
  input := os.Args[1]
  // OpenWhisk params are key/value pairs
  params := map[string]interface{}{}
  err := json.Unmarshal([]byte(input), &params)
  if err != nil {
    fmt.Printf(`{"error":"%s", "input": "%s"}`, err.Error(), string(input))
    os.Exit(-1)
  }
  
  entry := Entry{
    Account: Account{
      Id: params["accountId"].(string),
    },
    Amount: params["amount"].(float64),
  }
  
  jsonValue, err := json.Marshal(entry)
  if err != nil {
    fmt.Printf(`{"error":"%s"}`, err.Error())
    os.Exit(-1)
  }
  
  accountService := os.Getenv("ACCOUNT_SERVICE")
  
  if accountService == "" {
    accountService = "http://accounting:8080/entries"
  }
  
  resp, err := http.Post(accountService, "application/json", bytes.NewBuffer(jsonValue))
  if err != nil {
    fmt.Printf(`{"error":"%s"}`, err.Error())
    os.Exit(-1)
  }
  
  if resp.StatusCode >= 200 && resp.StatusCode <= 299 {
    fmt.Println(`{"success": "ok"}`)
    os.Exit(0)
  }
  
  fmt.Printf(`{"error": "%s"}`, resp.Status)
}

Dockerfile 多階段建置

以下是 Dockerfile 的內容:

# Stage 0
FROM golang:1.8.5-alpine3.6
WORKDIR /go/src/app
COPY account_ctl.go .
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -tags netgo -ldflags '-extldflags "-static"' -o exec account_ctl.go

# Stage 1
FROM openwhisk/dockerskeleton
ENV FLASK_PROXY_PORT 8080
COPY --from=0 /go/src/app/exec /action/
RUN chmod +x /action/exec
CMD ["/bin/bash", "-c", "cd actionProxy python -u actionproxy.py"]

多階段建置流程

  graph LR;
    A[原始碼] -->|複製|> B(Stage 0);
    B -->|建置|> C(靜態二進位制檔案);
    C -->|複製|> D(Stage 1);
    D -->|設定環境|> E(最終映象);

圖表翻譯: 此圖表呈現了多階段建置的流程,包括原始碼複製、靜態二進位制檔案建置、以及最終映象的建立。