2020/06/17


今まで C++ でちょっとしたウェブアプリを作る際は crow という micro-framework を使ってきました。

GitHub - ipkn/crow: Crow is very fast and easy to use C++ micro web framework (inspired by Python Flask)

How to Build If you just want to use crow, copy amalgamate/crow_all.h and include it. Requirements C...

https://github.com/ipkn/crow

ヘッダオンリーで使えてとても便利だったのですが、boost に依存している点があまり好きじゃなかったのと、最近 crow の開発が止まり最新の boost でビルド出来なくなってしまったので、自分で作る事にしました。

GitHub - mattn/clask: Web micro-framework like flask in C++.

# include " clask/core.hpp " int main () { auto s = clask::server (); s. GET ( " / " , [](clask::req...

https://github.com/mattn/clask

C++ から flask ぽく使える事を目指しました。ヘッダオンリーで使えます。HTTP ヘッダを解析する所だけ kazuho さんの picohttpparser を使わせて頂いています。

#include "clask/core.hpp"

int main() {
  auto s = clask::server();
  s.GET("/", [](clask::request& req) {
    return "OK!";
  });
  s.GET("/foo", [](clask::response& resp, clask::request& req) {
    resp.set_header("content-type""text/html");
    resp.write("he<b>l</b>lo");
  });
  s.run();
}

boost にも依存していませんし Windows でも問題なく動作します。ただしコンパイルには C++17 をサポートしているコンパイラが必要です。keep-alive に対応したマルチスレッドなウェブサーバなので、静的な2文字("OK)くらいのコンテンツだと 70000req/sec くらい出ます(ログ出力を無効にした場合/Ryzen 5)。まだまだ実験的ですが、幾らかアプリケーションが作れるまで来たので、今後簡単な C++ のウェブアプリは clask を使って行こうと思っています。ドキュメントが皆無なのですが、これから整備していく予定です。使用例を5つほど用意していますので、興味のある方は pull-request 頂けると嬉しいです。

clask/example at master · mattn/clask · GitHub

Explore GitHub → Learn & contribute Topics Collections Trending Learning Lab Open source guides...

https://github.com/mattn/clask/tree/master/example
Posted at by



2020/05/30


WSL2 がリリースされ Windows 10 Home Edition でも使える様になったので色々遊んでるのだけど、Windows 側とテキストを交換したい時に面倒で、クリップボードを共有する方法を模索した。

最悪 /dev/clipboard を実装するまで考えたけど、面倒過ぎたし exe の実行厳しい(何か常駐させてユーザランドから起動する為にサーバがいる)だろうから別の方法を考えた。WSL2 は binfmt (たぶん違うけど良く似た奴だろう) で Windows の exe が起動できるので、コマンド経由で stdin/stdout を read/write できる物を起動する方法を考えた。

で自分で書くかと Windows Terminal 起動した時点で「Windows Terminal からコピペできるやん、いらなくね?」となり、本来の目的を忘れかけていたので、おとなしく GitHub からそういったコマンドを探した。

GitHub - equalsraf/win32yank: Windows clipboard tool

Dismiss Join GitHub today GitHub is home to over 50 million developers working together to host and ...

https://github.com/equalsraf/win32yank

こちら便利そうだったけど、僕は Go 言語使いなので、go get で一発で入るのが欲しかった。最終的には以下のリポジトリにある gocopy と gopaste が良さそうだった。

GitHub - atotto/clipboard: clipboard for golang

Clipboard for Go Provide copying and pasting to the Clipboard for Go. Build: -1 go get github.com/ato...

https://github.com/atotto/clipboard

Windows 側では以下の様にインストールする。

go get github.com/atotto/clipboard/cmd/gocopy
go get github.com/atotto/clipboard/cmd/gopaste

あとは WSL2 の .bash_aliases に以下を足した。

alias gocopy=/mnt/c/Users/mattn/go/bin/gocopy.exe
alias gopaste=/mnt/c/Users/mattn/go/bin/gopaste.exe

パスは個人によって違うの修正して下さい。

$ echo あいう | gocopy

$ gopaste
あいう

こんな感じに使う。

追記

Vim から :w !goclip したいのであれば alias じゃなく shell で wrapper 書くかシンボリックリンクを WSL2 のパスの通った所に張るのが良さそうです。ちなみに PowerShell の get-clipboard と clip.exe でも出来るけど遅いのが嫌いなのでこの方法にしました。

Posted at by



2020/04/12


僕はよく C++ 用の SQLite3 ライブラリを探し歩いていて、見つけるたびに「1行掲示板」を実装してみている。

ウェブサーバは crow というライブラリを使い、SQLite3 の部分だけ差し替えて試すという感じ。初代は MySQL 用に作った。

GitHub - mattn/crow-bbs
https://github.com/mattn/crow-bbs

これを SQLite3 向けに直したのが crow-bbs-sqlite3

GitHub - mattn/crow-bbs-sqlite3
https://github.com/mattn/crow-bbs-sqlite3

さらにそれを sqlpp11 向けに直したのが crow-bbs-sqlite3-sqlpp11

GitHub - mattn/crow-bbs-sqlite3-sqlpp11
https://github.com/mattn/crow-bbs-sqlite3-sqlpp11

sqlpp11 は SQLite3 専用という訳ではなく、connector を使って異なる RDBMS も扱える。

先日、C++ 用 SQLite3 ORM の sqlite_orm を見つけたのでこれも試してみた。

GitHub - fnc12/sqlite_orm: ❤️ SQLite ORM light header only library for modern C++

// SELECT AVG(id) FROM users auto averageId = storage.avg(&User::id); cout << " averageId = " << ave...

https://github.com/fnc12/sqlite_orm

作った物はこちら。

GitHub - mattn/crow-bbs-sqlite3-sqlite_orm
https://github.com/mattn/crow-bbs-sqlite3-sqlite_orm

sqlite_orm は SQLite3 専用ではあるものの、sqlite3 ネイティブライブラリの様に SQLite3 色が濃くなく、sqlpp11 の様に SQL も登場しない。初回のスキーマ構築で struct との bind を行う。

struct Post {
  int id;
  std::string text;
  std::string created;
};
auto storage = sqlite_orm::make_storage("bbs.db",
    sqlite_orm::make_table("bbs",
      sqlite_orm::make_column("id", &Post::id, sqlite_orm::autoincrement(), sqlite_orm::primary_key()),
      sqlite_orm::make_column("text", &Post::text),
      sqlite_orm::make_column("created", &Post::created)
));
storage.sync_schema();

全ての Post を得るのであれば1行で出来る。

auto posts = storage.get_all<Post>();

追加も簡単

Post post = {.text = q, .created = storage.select(sqlite_orm::datetime("now""localtime")).front()};
storage.insert(post);

1行掲示板くらいのアプリであればとても小さく書ける。

#include <memory>
#include <stdexcept>
#include "crow_all.h"
#include <sqlite_orm/sqlite_orm.h>

struct Post {
  int id;
  std::string text;
  std::string created;
};

int
main() {
  auto storage = sqlite_orm::make_storage("bbs.db",
      sqlite_orm::make_table("bbs",
        sqlite_orm::make_column("id", &Post::id, sqlite_orm::autoincrement(), sqlite_orm::primary_key()),
        sqlite_orm::make_column("text", &Post::text),
        sqlite_orm::make_column("created", &Post::created)
  ));
  storage.sync_schema();
  crow::SimpleApp app;
  crow::mustache::set_base(".");

  CROW_ROUTE(app, "/")
  ([&] {
    crow::mustache::context ctx;
    auto posts = storage.get_all<Post>();
    int n = 0;
    for(auto &post : posts) {
      ctx["posts"][n]["id"] = post.id;
      ctx["posts"][n]["text"] = post.text;
      ctx["posts"][n]["created"] = post.created;
      n++;
    }
    return crow::mustache::load("bbs.html").render(ctx);
  });

  CROW_ROUTE(app, "/post").methods("POST"_method)
  ([&](const crow::request& req, crow::response& res) {
    crow::query_string params(std::string("?") + req.body);
    char* q = params.get("text");
    if (q == nullptr) {
      res = crow::response(400);
      res.write("bad request");
      res.end();
      return;
    }

    Post post = {.text = q, .created = storage.select(sqlite_orm::datetime("now""localtime")).front()};
    storage.insert(post);
    res = crow::response(302);
    res.set_header("Location""/");
    res.end();
  });

  app.port(40081)
    //.multithreaded()
    .run();
}

ちょっと触ってみた感じだと SQLite3 を扱うのであれば一番便利かもしれない。

Posted at by