精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

利用 Vely 在 Linux 構建你自己的 SaaS

系統(tǒng) Linux
Vely 可讓你在網絡應用程序中利用 C 語言的強大功能。

Vely 將 C 語言的高性能和低內存占用與 PHP 等語言的易用性和安全性相結合。作為自由開源軟件,它以 GPLv3 和 LGPL 3 授權,所以你甚至可以用它來構建商業(yè)軟件。

利用 Vely 構建 SaaS

你可以使用 Vely 創(chuàng)建一個多租戶網絡應用程序,它可以作為軟件即服務模式(SaaS)在互聯(lián)網上運行。每個用戶都有一個完全獨立的數(shù)據(jù)空間。

在這個網絡應用程序示例中,用戶可以注冊一個筆記本服務來創(chuàng)建筆記,然后查看和刪除它們。它僅用了 7 個源文件,310 行代碼,就展示了如何集成多項技術:

  • MariaDB
  • 網絡瀏覽器
  • Apache
  • Unix 套接字

運作原理

以下是從用戶的角度來看應用程序是如何工作的。下圖是代碼演示。

該應用允許用戶通過指定電子郵件地址和密碼創(chuàng)建新的登錄名。你可以用任何你喜歡的方式設置它們,例如運用 CSS:

創(chuàng)建一個用戶賬戶創(chuàng)建一個用戶賬戶

驗證用戶的電子郵件:

驗證用戶的電子郵件地址驗證用戶的電子郵件地址

每個用戶使用自己獨有的用戶名和密碼登錄:

用戶登錄用戶登錄

一旦登錄,用戶就可以添加筆記:

用戶可以添加筆記用戶可以添加筆記

用戶可以獲取筆記列表:

用戶列舉筆記用戶列舉筆記

刪除筆記之前,應用會申請確認信息:

刪除筆記之前,應用會申請確認信息刪除筆記之前,應用會申請確認信息

用戶確認后,筆記被刪除:

用戶確認后,筆記被刪除用戶確認后,筆記被刪除

設置先決條件

遵照 Vely.dev 上的安裝指示。這是一個使用 DNF、APT、Pacman 或者 Zypper 等標準工具包的快速流程。

由于它們都是這個范例的一部分,你必須安裝 Apache 作為網絡服務器,安裝 MariaDB 作為數(shù)據(jù)庫。

安裝 Vely 后,如使用 Vim,打開里面的“語法高亮顯示”:

vv -m

獲取源代碼

這個演示 SaaS 應用程序的源代碼是 Vely 安裝的一部分。為每個應用程序創(chuàng)建一個單獨的源代碼目錄不失為一個好主意(而且你可以按自己喜好命名)。在這種情況下,解包源代碼會幫你完成這些工作:

$ tar xvf $(vv -o)/examples/multitenant_SaaS.tar.gz
$ cd multitenant_SaaS

默認情況下,該應用程序以 multitenant_SaaS 命名,但你可以將其命名為任何內容(如果這么做,其他每個地方你都需要改一下)。

創(chuàng)建應用程序

第一步是創(chuàng)建一個應用程序。使用 Vely 的 vf 工具就可以輕松完成:

$ sudo vf -i-u $(whoami) multitenant_SaaS

這個命令創(chuàng)建了一個新的應用程序主目錄(/var/lib/vv/multitenant_SaaS),并幫你執(zhí)行應用程序設置。通常,這意味著在該主目錄中創(chuàng)建各種子目錄并分配權限。在這種情況下,只有當前用戶(whoami 的結果)擁有目錄,具有 0700 權限,這確保了其他人沒有訪問文件的權限。

創(chuàng)建數(shù)據(jù)庫

在你鍵入任何代碼之前,你需要一個能夠存儲該應用程序所用信息的空間。首先,創(chuàng)建一個名為 db_multitenant_SaaS 的 MariaDB 數(shù)據(jù)庫,由用戶名為 vely 的用戶所有,密碼為 your_password 。你可以修改剛才提到的任何值,但得記住,在這個示例里,你需要將包含這些內容的每個地方都得修改一遍。

在 MySQL 中以 root 身份登錄:

create database if not exists db_multitenant_SaaS;
create user if not exists vely identified by 'your_password';
grant create,alter,drop,select,insert,delete,update on db_multitenant_SaaS.* to vely;

然后在數(shù)據(jù)庫內創(chuàng)建數(shù)據(jù)庫對象(表,記錄等等):

use db_multitenant_SaaS;
source setup.sql;
exit

將 Vely 連接至數(shù)據(jù)庫

為了讓 Vely 知曉你數(shù)據(jù)庫的位置以及如何登錄進去,創(chuàng)建一個名為 db_multitenant_SaaS 的數(shù)據(jù)庫配置文件。(該名稱用于在源代碼中的數(shù)據(jù)庫聲明,所以如果你改了它,確保在它存在的每個地方都改一遍。)

Vely 使用原生的 MariaDB 數(shù)據(jù)庫連接,因此你可以指定給定的數(shù)據(jù)庫所能允許的任何選項:

$ echo '[client]
user=vely
password=your_password
database=db_multitenant_SaaS
protocol=TCP
host=127.0.0.1
port=3306' > db_multitenant_SaaS

構建應用程序

使用 vv 工具構建應用程序,利用 --db 選項指定 MariaDB 數(shù)據(jù)庫和數(shù)據(jù)庫配置文件:

$ vv -q--db=mariadb:db_multitenant_SaaS

啟用應用服務器

啟動你的網絡應用程序的服務器,需要使用 vf FastCGI 進程管理器。應用程序服務器使用 Unix 套接字與網絡服務器(創(chuàng)建反向代理)通信:

$ vf -w3 multitenant_SaaS

這么做會啟用三個守護進程,為接收到的請求提供服務。你也可以啟動一個自適應服務器,它會增加進程的數(shù)量從而服務更多的請求,并在不需要他們時減少進程的數(shù)量:

$ vf multitenant_SaaS

請參閱 vf 了解更多選項,以幫助你實現(xiàn)最佳性能。

當你需要停止你的應用程序服務器,使用 -m quit 選項:

$ vf -m quit multitenant_SaaS

創(chuàng)建網絡服務器

這是一個網絡應用程序,那么應用程序就得需要一個網絡服務器。該示例通過一個 Unix 套接字監(jiān)聽器使用 Apache。

1、設置 Apache

將 Apache 配置為一個反向代理,并將你的應用程序與之連接,你需要啟用 FastCGI 代理支持,這通常使用 proxy 和 proxy_fcgi 模塊。

對于 Fedora 系統(tǒng)(或者其它的,比如 Arch)來說,通過在 Apache 配置文件 /etc/httpd/conf/httpd.conf 中添加(或取消注釋)適當?shù)?nbsp;LoadModule 指令,就可啟用 proxy 和 proxy_fcgi 模塊。

以下指令適用于 Debian,Ubuntu 以及類似的系統(tǒng),啟用 proxy 和 proxy_fcgi 模塊:

$ sudo a2enmod proxy
$ sudo a2enmod proxy_fcgi

以下指令適用于 OpenSUSE,將這幾行添加在 /etc/apache2/httpd.conf 結尾處:

LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_fcgi_module modules/mod_proxy_fcgi.so

2、配置 Apache

現(xiàn)在你必須將代理信息添加在 Apache 的配置文件中:

ProxyPass "/multitenant_SaaS" unix:///var/lib/vv/multitenant_SaaS/sock/sock|fcgi://localhost/multitenant_SaaS

你的配置文件的位置可能會有所不同,這取決于不同的 Linux 發(fā)行版:

  • Fedora、CentOS、Mageia 和 Arch: /etc/httpd/conf/httpd.conf
  • Debian、Ubuntu、Mint: /etc/apache2/apache2.conf
  • OpenSUSE:/etc/apache2/httpd.conf

3、重新啟動

最后,重啟 Apache。在 Fedora 和類似系統(tǒng),還有 Arch Linux 是如下指令:

$ sudo systemctl restart httpd

在 Debian 和基于 Debian 的系統(tǒng),還有 OpenSUSE 是如下指令:

$ sudo systemctl restart apache2

設置本地郵箱

這個示例中,電子郵件是其功能的一部分。如果你的服務器已經可以發(fā)送電子郵件了,你可以跳過這一條。此外,你可以使用本地郵箱(myuser@localhost)來測試它。要做到這一點,需安裝 Sendmail。

在 Fedora 和類似系統(tǒng)中是如下指令:

$ sudo dnf installsendmail
$ sudo systemctl start sendmail

而在 Debian 和類似系統(tǒng)(如 Ubuntu):

$ sudo apt installsendmail
$ sudo systemctl start sendmail

當應用程序向本地用戶發(fā)送電子郵件,比如說 OS_user@localhost,你就可以通過查看 /var/mail/ 處(即所謂“郵件池”)來確認電子郵件是否被發(fā)送。

從瀏覽器訪問應用服務器

假設你在本地運行該應用,可以通過使用 http://127.0.0.1/multitenant_SaaS?req=notes&action=begin 域名從你的網絡服務器訪問你的應用服務器。如果你在互聯(lián)網上的在線服務器運行該程序,你可能就需要調整防火墻設置以允許 HTTP 通信。

源代碼

該應用程序示例包含 7 個源文件。你可以自行回顧代碼(記住,這些文件只有 310 行代碼),下面是每個文件的概述。

SQL 設置(setup.sql)

創(chuàng)建的兩個表:

  • users:每個用戶的信息。在 users 表中,每個用戶都有自己唯一的 ID (userId 列),以及其他信息,如電子郵件地址和該地址是否通過了驗證。還有一個哈希密碼。實際的密碼永遠不會存儲在純文本(或其他形式)中,單向哈希用于檢查密碼。
  • notes:用戶輸入的筆記。notes 表包含了所有的筆記,每個筆記都有一個 userId 列,表示哪個用戶擁有它們。userId 列的值與 users 表中的同名列匹配。這樣,每個筆記顯然都屬于單個用戶。

該文件內容如下:

create table if not exists notes (dateOf datetime, noteId bigint auto_increment primary key, userId bigint, note varchar(1000));
create table if not exists users (userId bigint auto_increment primary key, email varchar(100), hashed_pwd varchar(100), verified smallint, verify_token varchar(30), session varchar(100));
create unique index if not exists users1 on users (email);

運行時數(shù)據(jù)(login.h)

為了正確地顯示登錄、注冊和注銷鏈接,你需要一些在應用程序中任何地方都可以使用的標志。此外,應用程序使用 cookie 來維護會話,因此它需要在任何地方都可用,例如,驗證會話是否有效。發(fā)送到應用程序的每個請求都以這種方式進行確認。只有帶有可驗證 cookie 的請求是允許的。

所以要做到這種效果,你需要有一個 global_request_data 類型的 reqdata(請求數(shù)據(jù)),其中包含 sess_userId(用戶的 ID)以及 sess_id(用戶目前的會話 ID)。此外,還有一些不言自明的標志,可以幫助渲染頁面:

#ifndef _VV_LOGIN
#define _VV_LOGIN
typedef struct s_reqdata {
    bool displayed_logout; // true 則顯示登出連接
    bool is_logged_in; // true 則會話已驗證登錄
    char *sess_userId; // 目前會話的用戶 ID
    char *sess_id; // 會話 ID
} reqdata;
void login_or_signup ();
#endif

會話檢查和會話數(shù)據(jù)(_before.vely)

Vely 里有一個 請求前處理程序before_request handler 的概念。你寫的代碼會在其它處理請求的代碼之前執(zhí)行的。要達到這個目的,你只需要將這樣的代碼寫在名為 _before.vely 的文件中,然后剩余的部分將會自動處理。

SaaS 應用程序所作的任何事情,例如處理發(fā)送至應用程序的請求,必須驗證其安全性。這樣,應用程序就能知曉調用方是否有執(zhí)行操作所需要的權限。

在這里,通過請求前處理程序進行權限檢查。這樣,無論其他代碼如何處理請求,都已經掌握了會話信息。

為保持會話數(shù)據(jù)(比如會話 ID 和用戶 ID)在你代碼中的任何地方都可用,你可以使用 global_request_data。它只是一個指向內存的通用指針(void*),任何處理請求的代碼都可以訪問它。這非常適合處理會話,如下所示:

#include "vely.h"
#include "login.h"
// _before() 是一個請求前處理程序。
// 它總是在處理請求的其他代碼之前執(zhí)行。
// 對于任何類型的請求范圍設置或數(shù)據(jù)初始化,它都是一個很好的位置。
void _before() {
    // 輸出 HTTP 請求頭
    out-header default
    reqdata *rd; // 這是全局請求數(shù)據(jù),見 login.h
    // 為全局請求數(shù)據(jù)分配內存,
    // 將在請求結束時自動釋放
    new-mem rd size sizeof(reqdata)
    // 初始化標志
    rd->displayed_logout = false;
    rd->is_logged_in = false;
    // 將我們創(chuàng)建的數(shù)據(jù)設置為全局請求數(shù)據(jù),
    // 可以從任何處理請求的代碼中訪問
    set-req data rd
    // 檢查會話是否存在(基于來自客戶端的 cookie)
    // 這在任何其他請求處理代碼之前執(zhí)行,
    // 使其更容易準備好會話信息
    _check_session ();
}

檢查會話是否有效(_check_session.vely)

多租戶 SaaS 應用程序中最重要的任務之一就是通過檢查用戶是否登錄來(盡快)檢查會話是否有效。這是通過從客戶端(例如網絡瀏覽器)獲取會話 ID 和用戶 ID 的 cookie,并將它們與存儲會話的數(shù)據(jù)庫進行比較來實現(xiàn)的:

#include "vely.h"
#include "login.h"
// 檢查會話是否有效
void _check_session () {
    // 獲取全局請求數(shù)據(jù)
    reqdata *rd;
    get-req data to rd
    // 自用戶瀏覽器獲取 cookies
    get-cookie rd->sess_userId="sess_userId"
    get-cookie rd->sess_id="sess_id"
    if (rd->sess_id[0] != 0) {
        // 檢查給定用戶 ID 下的會話 ID 是否正確
        char *email;
        run-query @db_multitenant_SaaS = "select email from users where userId='%s' and session='%s'" output email : rd->sess_userId, rd->sess_id row-count define rcount
            query-result email to email
        end-query
        if (rcount == 1) {
            // 如果正確,設置登錄標志
            rd->is_logged_in = true;
            // 如果登出鏈接不顯示,則顯示它
            if (rd->displayed_logout == false) {
                @Hi <<p-out email>>! <a >Logout</a><br/>
                rd->displayed_logout = true;
            }
        } else rd->is_logged_in = false;
    }
}

注冊、登錄、登出(login.vely)

任何多租戶系統(tǒng)的基礎便是具有用戶注冊\登錄和登出的功能。通常情況下,注冊包括驗證電子郵件地址;不止于此,同一電子郵件地址會作為一個用戶名。這里就是這種情況。

這里實現(xiàn)了幾個執(zhí)行該功能所必須的子請求:

  • 注冊新用戶時,顯示 HTML 表單以收集信息。它的 URL 請求簽名是 req=login&action=newuser
  • 作為對注冊表單的響應,創(chuàng)建一個新用戶。URL 請求的簽名是 req=login&action=createuser。輸入參數(shù)(input-param)信號獲取 email 和 pwd 的 POST 表單字段。密碼值是單向散列,電子郵件驗證令牌是一個隨機的 5 位數(shù)字。這些被插入到 users 表中,創(chuàng)建一個新用戶。系統(tǒng)會發(fā)送一封驗證郵件,并提示用戶閱讀郵件并輸入代碼。
  • 通過輸入發(fā)送到該電子郵件的驗證碼來驗證電子郵件。URL 請求的簽名是 req=login&action=verify
  • 顯示一個登錄表單,讓用戶登錄。URL 請求的簽名是 req=login(例如,action 為空)。
  • 通過驗證電子郵件地址(用戶名)和密碼登錄。URL 請求的簽名是 req=login&action=login
  • 應用戶要求登出。URL 請求的簽名是 req=login&action=logout
  • 應用程序的登錄頁。URL 請求的簽名是 req=login&action=begin
  • 如果用戶當前已登錄,轉到應用程序的登錄頁面。

可以看看下面這些例子:

#include "vely.h"
#include "login.h"
// 處理云端多租戶應用程序的會話維護、登錄、注銷、會話驗證
void login () {
    // 獲取 URL 的輸入參數(shù) `action`
    input-param action
    // 獲取全局請求數(shù)據(jù),我們在其中記錄會話信息,所以它很方便
    reqdata *rd;
    get-req data to rd
    // 如果會話已經建立,我們不會
    // 繼續(xù)到應用程序主頁的唯一原因是我們正在登出
    if (rd->is_logged_in) {
        if (strcmp(action, "logout")) {
            _show_home();
            exit-request
        }
    }
    // 應用程序頁面啟動。顯示登錄或注冊的鏈接,
    // 并顯示適當?shù)闹髌聊?    if (!strcmp (action, "begin")) {
        _show_home();
        exit-request
    // 開始創(chuàng)建新用戶。詢問電子郵件和密碼,
    // 然后提交此表單時創(chuàng)建用戶。
    } else if (!strcmp (action, "newuser")) {
        @Create New User<hr/>
        @<form action="https://opensource.com/?req=login" method="POST">
        @<input name="action" type="hidden" value="createuser">
        @<input name="email" type="text" value="" size="50" maxlength="50" required autofocus placeholder="Email">
        @<input name="pwd" type="password" value="" size="50" maxlength="50" required placeholder="Password">
        @<input type="submit" value="Sign Up">
        @</form>
    // 驗證用戶發(fā)送到電子郵件的代碼。代碼必須匹配,從而驗證電子郵件地址   
    } else if (!strcmp (action, "verify")) {
        input-param code
        input-param email
        // 獲取基于電子郵件的驗證令牌
        run-query @db_multitenant_SaaS = "select verify_token from users where email='%s'" output db_verify : email
            query-result db_verify to define db_verify
            // 將數(shù)據(jù)庫中記錄的令牌與用戶提供的令牌進行比較
            if (!strcmp (code, db_verify)) {
                @Your email has been verifed. Please <a >Login</a>.
                // 如果匹配,更新用戶信息以表明已驗證。
                run-query @db_multitenant_SaaS no-loop = "update users set verified=1 where email='%s'" : email
                exit-request
            }
        end-query
        @Could not verify the code. Please try <a >again</a>.
        exit-request
    // 創(chuàng)建用戶 —— 當用戶使用電子郵件和密碼提交表單以創(chuàng)建用戶時運行    
    } else if (!strcmp (action, "createuser")) {
        input-param email
        input-param pwd
        // 創(chuàng)建散列(單向)密碼
        hash-string pwd to define hashed_pwd
        // 生成隨機的 5 位數(shù)字字符串驗證代碼
        random-string to define verify length 5 number
        // 創(chuàng)建用戶:插入電子郵件、哈希密碼、驗證令牌。當前驗證狀態(tài)為 0,或未驗證
        begin-transaction @db_multitenant_SaaS
        run-query @db_multitenant_SaaS no-loop = "insert into users (email, hashed_pwd, verified, verify_token, session) values ('%s', '%s', '0', '%s', '')" : email, hashed_pwd, verify affected-rows define arows error define err on-error-continue
        if (strcmp (err, "0") || arows != 1) {
            // 如果不能添加用戶,則可能該用戶不存在。不管怎樣,我們都無法繼續(xù)。
            login_or_signup();
            @User with this email already exists.
            rollback-transaction @db_multitenant_SaaS
        } else {
            // 創(chuàng)建帶有驗證碼的電子郵件并將其發(fā)送給用戶
            write-string define msg
                @From: vely@vely.dev
                @To: <<p-out email>>
                @Subject: verify your account
                @
                @Your verification code is: <<p-out verify>>
            end-write-string
            exec-program "/usr/sbin/sendmail" args "-i", "-t" input msg status define st
            if (st != 0) {
                @Could not send email to <<p-out email>>, code is <<p-out verify>>
                rollback-transaction @db_multitenant_SaaS
                exit-request
            }
            commit-transaction @db_multitenant_SaaS
            // 通知用戶查看郵件并輸入驗證碼
            @Please check your email and enter verification code here:
            @<form action="https://opensource.com/?req=login" method="POST">
            @<input name="action" type="hidden" value="verify" size="50" maxlength="50">
            @<input name="email" type="hidden" value="<<p-out email>>">
            @<input name="code" type="text" value="" size="50" maxlength="50" required autofocus placeholder="Verification code">
            @<button type="submit">Verify</button>
            @</form>
        }
    // 這里在登錄用戶登出時運行    
    } else if (!strcmp (action, "logout")) {
        // 更新用戶表以清除會話,即沒有該用戶登錄
        if (rd->is_logged_in) {
            run-query @db_multitenant_SaaS = "update users set session='' where userId='%s'" : rd->sess_userId no-loop affected-rows define arows
            if (arows == 1) {
                rd->is_logged_in = false; // 提示用戶未登錄
                @You have been logged out.<hr/>
            }
        }
        _show_home();
    // 登錄:當用戶輸入用戶名和密碼時運行
    } else if (!strcmp (action, "login")) {
        input-param pwd
        input-param email
        // 創(chuàng)建單向散列,目的是與用戶表進行比較 —— 密碼**永遠不會**被記錄
        hash-string pwd to define hashed_pwd
        // 為會話 ID 創(chuàng)建一個隨機的 30 位長的字符串
        random-string to rd->sess_id length 30
        // 檢查用戶名和哈希密碼是否匹配
        run-query @db_multitenant_SaaS = "select userId from users where email='%s' and hashed_pwd='%s'" output sess_userId : email, hashed_pwd
            query-result sess_userId to rd->sess_userId
            // 如果匹配,使用會話 ID 更新用戶表
            run-query @db_multitenant_SaaS no-loop = "update users set session='%s' where userId='%s'" : rd->sess_id, rd->sess_userId affected-rows define arows
            if (arows != 1) {
                @Could not create a session. Please try again. <<.login_or_signup();>> <hr/>
                exit-request
            }
            // 設置“用戶 ID”和“會話 ID”為 cookie。用戶的瀏覽器將在每個請求中返回這些信息
            set-cookie "sess_userId" = rd->sess_userId
            set-cookie "sess_id" = rd->sess_id
            // 顯示主頁,確保會話是正確的,并設置標志
            _check_session();
            _show_home();
            exit-request
        end-query
        @Email or password are not correct. <<.login_or_signup();>><hr/>
    // 登錄界面,要求用戶輸入用戶名和密碼  
    } else if (!strcmp (action, "")) {
        login_or_signup();
        @Please Login:<hr/>
        @<form action="https://opensource.com/?req=login" method="POST">
        @<input name="action" type="hidden" value="login" size="50" maxlength="50">
        @<input name="email" type="text" value="" size="50" maxlength="50" required autofocus placeholder="Email">
        @<input name="pwd" type="password" value="" size="50" maxlength="50" required placeholder="Password">
        @<button type="submit">Go</button>
        @</form>
    }
}
// 顯示登錄或注冊鏈接
void login_or_signup() {
        @<a >Login</a> & & <a >Sign Up</a><hr/>
}

通用應用程序(_show_home.vely)

借助本教程,你可以創(chuàng)建你想要的任何多租戶 SaaS 應用程序。上面的多租戶處理模塊(login.vely)調用 _show_home() 函數(shù),它可以容納你的任何代碼。這個示例代碼展示了筆記應用程序,但它可以是任何內容。_show_home() 函數(shù)可以調用你想要的任何代碼,它是一個通用的多租戶應用程序插件:

#include "vely.h"

void _show_home() {
    notes();
    exit-request
}

筆記應用程序(notes.vely)

該應用程序能夠添加、列舉以及刪除任何給定的筆記:

#include "vely.h"
#include "login.h"
// 多租戶云中的筆記應用程序
void notes () {
    // 獲取全局請求數(shù)據(jù)
    reqdata *rd;
    get-req data to rd
    // 如果會話有效,顯示登錄或注冊
    if (!rd->is_logged_in) {
        login_or_signup();
    }
    // 問候用戶
    @<h1>Welcome to Notes!</h1><hr/>
    // 如果沒有登出,退出 —— 這里確保對用戶身份的安全驗證
    if (!rd->is_logged_in) {
        exit-request
    }
    // 獲取 URL 參數(shù),告訴筆記要做什么
    input-param subreq
    // 顯示筆記能夠做什么操作(添加或列舉筆記)
    @<a >Add Note</a> <a >List Notes</a><hr/>
    // 列舉該用戶的所有筆記
    if (!strcmp (subreq, "list")) {
        // **只**選取該用戶的筆記
        run-query @db_multitenant_SaaS = "select dateOf, note, noteId from notes where userId='%s' order by dateOf desc" : rd->sess_userId output dateOf, note, noteId
            query-result dateOf to define dateOf
            query-result note to define note
            query-result noteId to define noteId
            // 使用快速緩存正則表達式將新行更改為<br/>
            match-regex "\n" in note replace-with "<br/>\n" result define with_breaks status define st cache
            if (st == 0) with_breaks = note; // 什么都沒有發(fā)現(xiàn)/替換,只用原來的
            // 顯示筆記
            @Date: <<p-out dateOf>> (<a >delete note</a>)<br/>
            @Note: <<p-out with_breaks>><br/>
            @<hr/>
        end-query
    }
    // 要求刪除筆記
    else if (!strcmp (subreq, "delete_note_ask")) {
        input-param note_id
        @Are you sure you want to delete a note? Use Back button to go back, or <a >delete note now</a>.
    }
    // 刪除筆記
    else if (!strcmp (subreq, "delete_note")) {
        input-param note_id
        // 刪除筆記
        run-query @db_multitenant_SaaS = "delete from notes where noteId='%s' and userId='%s'" : note_id, rd->sess_userId affected-rows define arows no-loop error define errnote
        // 告知用戶狀態(tài)
        if (arows == 1) {
            @Note deleted
        } else {
            @Could not delete note (<<p-out errnote>>)
        }
    }
    // 添加筆記
    else if (!strcmp (subreq, "add_note")) {
        // 從 note 表單中獲取 URL POST 數(shù)據(jù)
        input-param note
        // 在該用戶的 ID 下插入筆記
        run-query @db_multitenant_SaaS = "insert into notes (dateOf, userId, note) values (now(), '%s', '%s')" : rd->sess_userId, note affected-rows define arows no-loop error define errnote
        // 告知用戶狀態(tài)
        if (arows == 1) {
            @Note added
        } else {
            @Could not add note (<<p-out errnote>>)
        }
    }
    // 顯示一個 HTML 表單來收集筆記,并將其發(fā)送回這里(使用 subreq="add_note" URL 參數(shù))
    else if (!strcmp (subreq, "add")) {
        @Add New Note
        @<form action="https://opensource.com/?req=notes" method="POST">
        @<input name="subreq" type="hidden" value="add_note">
        @<textarea name="note" rows="5" cols="50" required autofocus placeholder="Enter Note"></textarea>
        @<button type="submit">Create</button>
        @</form>
    }
}

具有 C 性能的 SaaS

Vely 語言使得 C 語言在你的網絡應用程序中得到充分利用這件事成為可能。多租戶 SaaS 應用程序便是從中受益的一個典型用例。

看一看參考代碼示例,寫一寫代碼,然后試試 Vely。

責任編輯:龐桂玉 來源: Linux中國
相關推薦

2016-09-27 09:45:27

Linux發(fā)行版構建

2011-04-26 15:18:23

CentOS發(fā)行版

2014-07-30 09:35:36

DockerPaaS

2023-07-30 17:34:53

KV存儲ChunkPosit

2018-03-22 11:00:45

PythonRSS

2011-09-09 10:49:18

2016-09-18 10:08:38

Linux發(fā)行版SUSE Studio

2020-10-26 08:34:18

知識體系普適性

2011-11-25 10:18:48

SaaS云計算

2022-06-23 09:44:01

LinuxLive CD

2017-02-09 09:30:18

UbuntuDokuWikiApache

2021-01-21 16:03:15

Java文本編輯器編程語言

2018-07-27 16:18:30

PythonTwitter機器人

2016-12-02 17:32:45

LinuxGlyphr

2015-08-24 11:20:17

SaaS云服務ASP

2015-10-14 10:43:17

PaaSSaaS應用構建

2015-09-11 15:56:52

內核構建Linux

2015-03-10 09:51:56

云開發(fā)云應用程構建PaaS

2021-08-24 16:20:38

Linux終端

2017-05-08 14:27:49

PHP框架函數(shù)框架
點贊
收藏

51CTO技術棧公眾號

男女午夜激情视频| 3d精品h动漫啪啪一区二区 | 亚洲乱码一区| 懂色av影视一区二区三区| 亚洲国产精品久久久久久女王| 国产丰满美女做爰| 美女视频一区免费观看| 伦理中文字幕亚洲| 天堂久久精品忘忧草| 国产日韩一区二区三免费高清| 欧美日韩国产黄| 在线观看一区欧美| 婷婷五月综合久久中文字幕| 麻豆一区二区三| 68精品国产免费久久久久久婷婷| 国产精品一区二区亚洲| 青青操综合网| 日韩免费一区二区三区在线播放| 欧美日韩在线成人| 99色在线观看| 日韩理论在线观看| 日本一区二区在线| 无码精品视频一区二区三区 | 国产美女精品免费电影| 中文字幕在线字幕中文| 中文字幕一区二区精品区| 亚洲午夜国产成人av电影男同| www.黄色网| 精品国产麻豆| 欧美日韩一级视频| 久久国产乱子伦免费精品| 国产精品69xx| 亚洲在线观看免费视频| 蜜臀av.com| 日本电影在线观看网站| 国产亚洲一区二区三区| 蜜桃传媒一区二区| 午夜影院免费视频| jizz一区二区| 激情视频在线观看一区二区三区| www.黄色一片| 国产成人精品三级| 91热福利电影| 99国产在线播放| 国产麻豆日韩欧美久久| 国产一区视频在线播放| 中文字幕无线码一区| 三级欧美韩日大片在线看| 欧美性视频精品| 在线观看免费国产视频| 中文亚洲免费| 日韩av手机在线看| 国产精品久免费的黄网站| 国产一级久久| 日本国产精品视频| 懂色av蜜臀av粉嫩av分享吧最新章节| 亚洲中字在线| 国产精品r级在线| 亚洲第一网站在线观看| 久久午夜激情| 国产精品久久久久久久久久久久久 | www.污网站| 国产一区二区三区免费观看在线| 91麻豆精品国产综合久久久久久 | 成人动漫av在线| 国产一区二区自拍| 日本啊v在线| 国产精品欧美精品| 国产精品8888| 国产精品一区二区日韩| 一本在线高清不卡dvd| 亚洲视频在线观看一区二区三区| 免费欧美电影| 欧美巨大另类极品videosbest | 国产美女三级视频| 精品123区| 日韩一级片网址| 91精品小视频| 日韩1区在线| 操人视频在线观看欧美| 中文字幕一区二区三区手机版 | 成人亚洲免费视频| 北条麻妃一区二区三区在线| 国产视频精品免费播放| 极品尤物一区二区| 一区久久精品| 国产精品白嫩美女在线观看 | 亚洲网站在线观看| 麻豆天美蜜桃91| 中文日韩在线| 成人黄色免费在线观看| 熟妇高潮一区二区高潮| 国产欧美在线观看一区| 97久久国产亚洲精品超碰热| 人人草在线视频| 欧美精品欧美精品系列| 久久人妻少妇嫩草av无码专区| 欧美日韩中字| 欧美激情视频播放| 中文字幕一区二区人妻痴汉电车| 国产一区二区三区黄视频| 麻豆成人av| 天天干在线视频论坛| 在线观看91精品国产入口| 风韵丰满熟妇啪啪区老熟熟女| 少妇精品久久久一区二区三区| 欧美成aaa人片免费看| 免费污污视频在线观看| 国产精品亚洲视频| 四虎影院一区二区三区| 国产天堂在线播放视频| 7777精品伊人久久久大香线蕉完整版 | 国产男女无遮挡| 韩国一区二区三区视频| 亚洲日本成人女熟在线观看| 欧美日韩国产精品综合 | 在线视频日韩欧美| 国产99精品一区| 久久久久久久影院| 国产美女免费看| 国产精品水嫩水嫩| 六月激情综合网| 国产ts一区| 久久国产视频网站| 中文字幕777| 久久精品综合网| 啊啊啊一区二区| 999久久精品| 久久99久国产精品黄毛片入口| 羞羞色院91蜜桃| 国产午夜久久久久| 日韩视频第二页| 婷婷成人综合| 性日韩欧美在线视频| 亚洲黄色在线免费观看| 综合久久给合久久狠狠狠97色| 亚洲成人av免费看| 国产精品午夜一区二区三区| 国产91精品青草社区| 天堂av在线7| 欧美日韩免费区域视频在线观看| 逼特逼视频在线观看| 亚洲视频在线免费| 成人免费网站在线观看| 自拍视频在线| 欧美挠脚心视频网站| 中国免费黄色片| 精品999成人| 国产偷久久久精品专区| 91禁在线看| 亚洲国产毛片完整版| 日本特黄特色aaa大片免费| 国产69精品久久久久毛片| 成人午夜免费在线视频| 4438全国亚洲精品观看视频| 欧美激情视频网站| 天天操天天干天天操| 偷窥少妇高潮呻吟av久久免费| 亚洲欧美日韩偷拍| 亚洲一区欧美激情| 视频一区视频二区视频三区高| 精品国模一区二区三区| 在线日韩精品视频| 一级黄在线观看| 一区二区高清在线| 污污内射在线观看一区二区少妇| 一本色道久久综合| 日韩高清三级| 91麻豆精品一二三区在线| 美日韩精品免费视频| 人妻视频一区二区三区| 日本精品一区二区三区高清| 天天操天天舔天天射| 狠狠久久亚洲欧美| 欧美精品久久久久久久久久久| av综合网站| 日本精品在线视频| 免费在线视频欧美| 亚洲国产天堂久久综合| 波多野结衣一区二区三区在线| 国产精品福利一区二区三区| 欧美xxxx黑人| 亚欧美中日韩视频| 中文字幕中文字幕一区三区| 国产精品主播在线观看| 国产精品成人观看视频国产奇米| 欧美极品视频| 亚洲精美色品网站| 影音先锋国产资源| 亚洲福利视频三区| 国产三级短视频| 成人aaaa免费全部观看| 亚洲色图久久久| 国产一区日韩一区| 水蜜桃亚洲精品| 欧美wwwwww| 51午夜精品| 99久久精品一区二区成人| 久久久亚洲天堂| 一级毛片视频在线| 亚洲国产一区自拍| 伊人成人在线观看| 欧美日韩国产中文精品字幕自在自线| 亚洲一级片在线播放| 成人av综合在线| 不用播放器的免费av| 免费一区视频| 久操手机在线视频| 66国产精品| 亚洲高清资源综合久久精品| 免费看久久久| 7777精品久久久大香线蕉小说| 久久久一本精品| 97国产suv精品一区二区62| 怡红院av在线| www.亚洲一区| 成人免费高清在线播放| 日韩精品视频在线观看免费| 亚洲精品一区二区三区不卡| 欧美日韩国产综合一区二区三区| 久久久免费高清视频| 亚洲一区二区三区四区五区黄| 艳妇荡乳欲伦69影片| 国产日韩欧美精品综合| 亚洲av片不卡无码久久| 成人一区二区在线观看| 无码人妻一区二区三区在线视频| 久久精品av麻豆的观看方式| 国产一区二区三区精彩视频| 亚洲三级毛片| 欧美一区二区视频在线播放| 亚洲xxx拳头交| 亚洲欧洲日夜超级视频| 精品一区二区三区的国产在线观看| 精选一区二区三区四区五区| 91九色鹿精品国产综合久久香蕉| 国产欧美日韩精品专区| 国产精品4hu.www| 国产精选久久久久久| 浪潮色综合久久天堂| 日韩av免费在线观看| 日韩欧美看国产| 国产成人极品视频| 成人精品电影在线| 国产精品国产福利国产秒拍| 日本欧美不卡| 国产精品香蕉av| 青青久久精品| 亚洲一区二区少妇| 麻豆精品一区| 国产精品乱码一区二区三区| 红杏一区二区三区| 久精品国产欧美| 久久成人高清| 亚洲高清123| 五月综合激情| 欧美另类videosbestsex日本| 欧美96在线丨欧| 黄色一级视频在线播放| 国产日韩专区| 美女网站视频黄色| 久久国产精品色| 久久精品一二三四| 91视视频在线观看入口直接观看www | 五月天激情国产综合婷婷婷| 色天使色偷偷av一区二区| 正在播放亚洲精品| 日韩一级完整毛片| 亚洲av激情无码专区在线播放| 亚洲欧美日韩中文视频| 日本成a人片在线观看| 色综合久久天天综线观看| 岛国av在线网站| 国产精品久久久久久影视| www.久久草.com| 国产日韩亚洲精品| 欧美丝袜激情| 天天干天天干天天操| 成人性生交大片免费看中文| 水蜜桃av无码| 中文字幕欧美日本乱码一线二线 | 亚洲黄页在线观看| 一本色道婷婷久久欧美| 欧美午夜电影在线观看| 成人毛片视频网站| 精品一区二区在线播放| 国产又粗又猛又色| 国产精品人妖ts系列视频| 久久精品欧美一区二区| 色婷婷综合激情| 性色av蜜臀av| 一区二区在线免费视频| h片视频在线观看| 国产精品久久久久久久app| 在线观看视频一区二区三区| 日本一区二区久久精品| 激情一区二区| 亚洲综合婷婷久久| 91视频一区二区三区| 在线观看成人毛片| 色欧美片视频在线观看在线视频| 国产成人精品一区二区无码呦 | 免费看污黄网站在线观看| 综合久久国产九一剧情麻豆| 日韩精品在线观看免费| 日韩一级二级三级| a天堂中文在线| 4438全国成人免费| 欧美片网站免费| 亚洲国产午夜伦理片大全在线观看网站| 激情视频一区| 精品人妻一区二区三区免费| 久久九九久久九九| 男人的天堂一区| 日韩欧美美女一区二区三区| av在线首页| 日本久久久久久久久| 国产精品45p| 老司机午夜网站| 麻豆国产精品官网| 极品人妻videosss人妻| 欧美午夜精品久久久久久久| 亚洲大尺度网站| 久久国产精品久久久久久久久久| 国产91亚洲精品久久久| 欧美成人在线免费观看| 日韩视频二区| 日本一卡二卡在线| 亚洲国产精品一区二区久久恐怖片| 国产乱码精品一区二区| 色诱女教师一区二区三区| 浪潮色综合久久天堂| 欧美精品与人动性物交免费看| 亚洲国产激情| 欧美极品jizzhd欧美仙踪林| 亚洲九九爱视频| 国产wwwwwww| 欧美日韩国产成人| 欧美三级一区| 97在线免费视频观看| 国产精品一二二区| 久久久久久久久97| 精品久久久久久久久久久久久久久久久| 中文字幕中文字幕在线中高清免费版 | 自拍偷拍99| 国产黄人亚洲片| 久草成人在线视频| 亚洲精品一区二区三区在线观看 | 日本wwww色| 亚洲一级不卡视频| 神马久久高清| 国产精品91在线| 99re6这里只有精品| 日韩va在线观看| 一区二区三区在线影院| 丰满人妻一区二区三区免费视频 | 久久亚洲AV无码| 日韩av影院在线观看| 欧美成人精品一区二区男人小说| 茄子视频成人在线观看| 麻豆传媒一区二区三区| 精品国产乱码久久久久久鸭王1| 日韩精品一区在线观看| 182在线视频观看| 欧美日韩一区在线播放| 日本系列欧美系列| 91久久国产综合| 亚洲娇小xxxx欧美娇小| 性高爱久久久久久久久| 一区二区三区在线视频看| 国产精品综合av一区二区国产馆| 日韩精品人妻中文字幕| 国产一区二区黄| 91亚洲精品视频在线观看| 韩国日本在线视频| 一区在线中文字幕| 天天干,夜夜操| 国产精品永久在线| 好吊日精品视频| 人妻aⅴ无码一区二区三区| 欧美嫩在线观看| 欧美男人天堂| 中文字幕av日韩精品| 国产.欧美.日韩| 一级一级黄色片| 欧美国产第一页| 日韩精品1区| 小毛片在线观看| 欧美裸体一区二区三区| 国产黄色大片在线观看| 日本一区不卡| 成人福利视频网站| 国产又粗又猛又爽| 欧美亚洲日本黄色| 女人香蕉久久**毛片精品| 欧美肉大捧一进一出免费视频| 欧美亚洲免费在线一区| 6699嫩草久久久精品影院| 亚洲精品中文字幕乱码三区不卡| 成人高清av在线|