調整さんで絶対に回答させるline botを作ってみた【2】

開発楽しい、ナナオです。 前回まででMessaging APIのwebhookとの疎通確認ができました。 今回はもう少し踏み込んで期日設定を行えるようにしていきます。 ShutleにPostgresを導入する まず、設定された期日を保存しておくためのDBを用意します。 これにはShuttleが提供しているPostgresを使用します。 Shuttle Shared Databases - Shuttle また、基本的にDBクライアントとしてはSqlXを使用することが推奨されているようなので、依存関係を追加しておきます。 [dependencies] axum = "0.6.20" serde_json = "1.0.108" shuttle-axum = "0.31.0" shuttle-runtime = "0.31.0" shuttle-shared-db = { version = "0.31.0", features = ["postgres"] } sqlx = { version = "0.7.2", features = ["runtime-tokio-native-tls", "postgres"] } また、SqlX CLIもインストールしておきます。 cargo install sqlx-cli SQLX CLIでルートパッケージからマイグレーションファイルを追加しておきます。 sqlx migrate add init これでmigrationsというディレクトリがルートパッケージに作成されるはずです。 続けてマイグレーションファイルにグループテーブルを作成するSQLを実装します。 とりあえずグループIDと期日があれば十分でしょう。 -- Add migration script here CREATE TABLE line_group ( id varchar(33) primary key, deadline_date date ); ちなみにグループIDは33桁の文字列で、C[0-9a-f]{32}という正規表現で表されます。 LINEプラットフォーム用語集 - グループID 以下のdocker-composeファイルから、ローカルにDBを起動しておきます。 ...

11月 6, 2023 · にあえん

ローカルのWebサーバーを一時的に外部に公開!ngrokを試してみた

WebHookのテストどうすればいいのか悩んでます、ナナオです。 今回はローカルのHTTPサーバーを簡単に外部URLとして公開することができるngrokを触ってみたいと思います。 インストール Windows11であれば、以下のコマンドでインストールできるようです。 winget install Ngrok.Ngrok ただ、僕の環境だとうまくインストールできなかったので、chocolateryを使用しました。 choco install ngrok インストールできました。 ローカルサーバーを外部URLで公開する 適当にdockerでNginxサーバーを実行してみます。 docker run -d -p 8000:80 nginx:latest では、ngrokで外部URLを取得してみましょう。 ngrok http 8000 外部URLが払い出されたので、早速アクセスしてみます。 エラーになってしまいました。 どうやらHTMLを表示するにはサインアップが必要なようですね。 以下のページからサインアップを済ませます。 ngrok - Online in One Line サインアップができたら以下のような画面が表示されるので、この画面にあるコマンドを実行します。 ngrok config add-authtoken [認証キー] この状態で再度外部URLを取得すると、先ほどとは違う画面が表示されるようになります。 この画面の「Visit Site」をクリックすることで、ローカルのNginxサーバーにアクセスすることが可能になります! 外部URLからローカルのNginxにアクセスできた! まとめ すごい…すごすぎる…。 これでWebHookの実装がめちゃくちゃ楽になりそう。 今回は紹介していませんが、Node・Rust・Go・PythonでSDKがあったり、HTTP以外にもTCPで公開できたり、Basic認証もOAuthもOpenID Connectも使えるし、開発者にとってはうれしいことしかない機能が盛りだくさんで失神してしまいそうです。 Ngrok docs 少し使ってみただけでももうハードユーズ確定な予感がします。とりあえず使っているすべてのPCに入れたい。。

11月 4, 2023 · にあえん

Rustのshuttleを使ってみる【3】

Shuttleはいいぞ~、ナナオです。 今回で三回目になります、Shuttleのチュートリアル記事です。 複数のサービスを動かす shuttle_runtime::Serviceを実装してあげることで、Webサービスとスケジューラを同時に動かすようなユースケースが実装可能になります。 Welcome to Shuttle's Docs - Start Building Backends Fast - Shuttle こちらのチュートリアルではdiscordのBOTを動かしていますね。 以前までの実装にスケジューラを追加して、継続的にログにhello worldを出力させてみましょう。 ただactix-webでの実装がわからなかったので、axumの実装に直しました。 また、スケジューラにはtokio-cron-schedulerを使用しました。 依存関係は以下のとおりです。 [dependencies] axum = "0.6.20" shuttle-runtime = "0.31.0" tokio = "1.26.0" tokio-cron-scheduler = "0.9.4" では、以下が完成したコードです。 use axum::{routing::get, Router, response::IntoResponse}; use tokio_cron_scheduler::{Job, JobScheduler}; async fn hello_world() -> impl IntoResponse { "Hello World!" } pub struct MultipleService { router: Router, scheduler: JobScheduler, } impl MultipleService { pub async fn new() -> Result<MultipleService, shuttle_runtime::Error> { let router = Router::new() .route("/", get(hello_world)); let mut scheduler = JobScheduler::new().await.unwrap(); scheduler.add( Job::new("1/10 * * * * *", |_uuid, _l| { println!("I run every 10 seconds"); }).unwrap() ).await.unwrap(); Ok(Self { router, scheduler, }) } } #[shuttle_runtime::async_trait] impl shuttle_runtime::Service for MultipleService { async fn bind(mut self, addr: std::net::SocketAddr) -> Result<(), shuttle_runtime::Error> { let server = axum::Server::bind(&addr); let (_runner_hdl, _axum_hdl) = tokio::join!(self.scheduler.start(), server.serve(self.router.into_make_service())); Ok(()) } } #[shuttle_runtime::main] async fn main() -> Result<MultipleService, shuttle_runtime::Error> { MultipleService::new().await } 順番に説明します。 ...

11月 3, 2023 · にあえん

Rustのshuttleを使ってみる【2】

タダでもうれしいのはOSSだけ、ナナオです。 前回に引き続き、Shuttleを使ってみようと思います。 ワークスペースでプロジェクトをデプロイする shuttleはワークスペースをサポートしています。 これにより、複雑なコードをカプセル化しつつ、可読性高く開発することができます。 (私の最初のイメージでは、ワークスペースのメンバーそれぞれがプロジェクトとして独立した形でデプロイされるのかと思ってたんですが、ルートパッケージが一つのプロジェクトとして扱われるようになる感じでした…) Project structure - Shuttle ただし、既存のパッケージをプロジェクトとして独立させるみたいなことをするのは少し厄介です。 というのも、どうやらそもそもローカルにあるCargoディレクトリの移動ということが想定されていないためか、既にデプロイしているディレクトリを移動するとデプロイができなくなってしまいます。 また、内部的にgitのコミットを追っているというのもあり、gitの管理をいったん外すといったことができなくなります。 つまり、新たに作成したワークスペースのメンバーに既存のCargoパッケージを追加する場合、本来はルートパッケージ側でgitを管理したいのにそれができなくなってしまうということが考えられます。 (まぁこの辺は単に私のドキュメントの読み込み不足という可能性もあるので、その辺は指摘あればコメントください) ということで、前回の記事で作成したプロジェクトは一旦リモートのプロジェクトからは削除して、新たにワークスペース単位でリソース管理ができるようにしてみましょう。 まずはベースになるルートパッケージを作成します。 cargo new shuttle-playground 次に、前回作成したプロジェクトを削除します。 # 前回作成したshuttle-playground-nanaoを削除します # 削除前にサーバーを止めておく必要がある cargo shuttle stop # 停止後に削除ができるようになる cargo shuttle project delete これできれいになりました! 次にルートプロジェクト内に前回のshuttle-playground-nanaoを移動します。 ローカルでの名前は変えておきましょうか。 mv shuttle-playground-nanao shuttle-playground/backend backendをワークスペースのメンバーに追加してあげます。 [workspace] members = [ "backend", ] このままのパッケージ名だとありふれているため競合してしまいますが、ルートパッケージ配下にShuttle.tomlを作成することで解決できます。 ここでは以前と同じ名前にしておきましょう。 name = "shuttle-playground-nanao" この状態で、ルートパッケージのファーストコミットを行っておきます。 git add --all git commit -m "first commit" ではデプロイしていきます。 # Shuttleプロジェクトを開始 cargo shuttle project start # プロジェクトにデプロイ cargo shuttle deploy デプロイ後、アクセスした様子が以下になります。 ...

11月 2, 2023 · にあえん

Rustのshuttleを使ってみる【1】

Rustで無料で建てられるサーバーがあるだって?やったー!ナナオです。 今回はそんなshuttleが気になったので使ってみます。 Installation - Shuttle Shuttleとは インフラ構築なしでバックエンドをデプロイできるサービスです。 firebaseと似たような、いわゆるBaaSってやつですね。 主な使い方としては簡易なWebサーバーの構築や、Discordクライアントとして使用できるようです。 無料プランの中でデータ永続化サービスとしてPostgresも使えるので、結構充実しています。 #[shuttle_runtime::main] async fn main( // automatic db provisioning + hands you back an authenticated connection pool #[shuttle_shared_db::Postgres] pool: PgPool, ) -> ShuttleRocket<...> { // application code } 以下のライブラリをサポートしているため、これらのライブラリの使用経験があればすぐにでもデプロイができると思います。 Axum Actix Web Rocket Warp Tower Salvo Poem Tide Thruster shuttle-next 早速使ってみる まずはshuttle cliをインストールしておきます。 cargo install shuttle CLIからshuttleアプリケーションを初期化できます。 質問形式でプロジェクトをセットアップできます。 > cargo shuttle init First, let's log in to your Shuttle account. If your browser did not automatically open, go to https://console.shuttle.rs/new-project ✔ API key · ******** What do you want to name your project? It will be hosted at ${project_name}.shuttleapp.rs, so choose something unique! ✔ Project name · shuttle-playground-nanao Where should we create this project? ✔ Directory · C:\Users\Nanao\Project\study\shuttle-playground Shuttle works with a range of web frameworks. Which one do you want to use? ✔ Framework · actix-web Creating project "shuttle-playground-nanao" in "C:\Users\Nanao\Project\study\shuttle-playground" Hint: Check the examples repo for a full list of templates: https://github.com/shuttle-hq/shuttle-examples Hint: You can also use `cargo shuttle init --from` to clone templates. See https://docs.shuttle.rs/getting-started/shuttle-commands or run `cargo shuttle init --help` ✔ Claim the project name "shuttle-playground-nanao" by starting a project container on Shuttle? · yes Project "shuttle-playground-nanao" is ready Your project will sleep if it is idle for 30 minutes. To change the idle time refer to the docs: https://docs.shuttle.rs/getting-started/idle-projects Run `cargo shuttle deploy --allow-dirty` to deploy your Shuttle service. You can `cd` to the directory, then: Run `cargo shuttle run` to run the app locally. APIキーが必要なため、事前にブラウザ側でshuttleのコンソールにログインしている必要があります。 ...

11月 2, 2023 · にあえん

最近のRaspberry PI OSの入れ方

ラズパイ4を買って3年放置していました、ナナオです。 ミーハーなので買ったんですが、買ったはいいものの使わずに放置していました。(MOTTAINAI) それを最近思い出したので、とりあえず軽量OS入れてk8sサーバーとして使ってあげようかなと思い調べてみると、以前とOSの入れ方が結構変わっていたので備忘録として書いておこうと思います。 Raspberry OSの入れ方 OSイメージを対象のmicroSDに入れるためのツールをダウンロードします。 Windows11の場合、以下のコマンドでダウンロード可能です。 winget install RaspberryPiFoundation.RaspberryPiImager なんと、このツール一つだけで簡単にmicroSDに入れることができるようになったみたいです! 素晴らしいですね。 スタート画面はこんな感じ 適当なSDカードを用意して、これを使ってイメージを入れましょう。 今回使用したいOSにはk8sを入れたいです。 GUIは特にいらないので、軽量版を選択します。 諸項目を選択したら「次へ」を選択します。 事前に設定する項目を編集するかどうか聞かれるので「はい」にしておきます。 ここではwifiやsshといった設定が事前にできます。 SSHの設定をしておけば、いちいちモニタをつなぎなおしたりする必要もないのでとても便利ですね。 設定ができたら保存を押して、「はい」を選択します。 SDカードにまだ何かデータが存在した場合、データは消去されるという警告が出ます。 事前にバックアップはとったのではいで進めます。 イメージの書き込みが開始されます。しばらく待ちましょう。 書き込みが無事完了したらその旨が表示されます。 これで準備はできました! あとはRaspberry PI4に挿してあげれば起動します。 まとめ イメージが簡単にSDカードに入りました。 以前だったらラズパイのOSダウンロードページからISOをダウンロードしてSDカードに入れるのには別のツールを使っていたと思うんですが、これ一本でできるので便利ですね。 放置しててごめんねラズパイ。

11月 1, 2023 · にあえん

調整さんで絶対に回答させるline botを作ってみた【1】

早いものでもう11月ですね。ナナオです。 年末に近づいて忘年会シーズンとなってきました。 ただ忘年会の幹事をするとなると全員の日程調整がめんどくさいじゃないですか。 なかなか日程が合わないということもありますが、日程に関する回答をしてくれない人がいると何も決まりませんよね。 ということで今回は、調整さんで絶対に回答させるline botを作っていこうと思います。 仕様 絶対に回答させるのに効果的な方法ってなんだと思いますか? 丁寧にお願いする?相手を信じて待つ? いいえ違います、相手が回答するまで鬼電するのです。 結局これが一番効くんですよね。 ということで、line botの趣旨としては「鬼電」です。 たださすがに電話はできないので、メッセージをちょうどうざいくらいの間隔で送るようにします。 期日を過ぎてからの経過時間でどんどんメッセージ送信量が増えていくみたいな感じにします。 期日まで 未回答者に1日に一回催促のDMが送られる 期日経過~1日 未回答者に1時間に一回催促のDMが送られる 期日経過1日~2日 未回答者に30分に一回催促のDMが送られる 期日経過3日~ 未回答者に15分に一回催促のDMが送られる 設計 簡単にフローにしてみます。 LINEグループにbotを入れる 期日を設定する 期日を確認(全員回答するまで呼び出し続ける) 回答していない人を確認 回答していない人がいる場合、期日に応じた処理(DM送信)を行う なので、プログラムとしては「期日を設定する」ものと「期日を確認する」ものの二つが必要になります。 呼び出される場面がそれぞれ違います。 期日を設定する line botに対して期日を設定するメッセージが送られたとき 期日を確認する 定期的に呼び出す 15分に一回 回答していない人がいる場合、期日からの経過日数によって処理を分ける 期日設定に関してはMessaging APIのWebhookイベントを使用します。 今回はRustアプリを無料でデプロイ可能なクラウドプラットフォームShuttleを利用します! Shuttle - Build Backends Fast Shuttleはよくわからなかったので、事前にちょっと触りつつ予習しておきました。 よければこちらの記事もぜひ。 Rustのshuttleを使ってみる【1】 Rustのshuttleを使ってみる【2】 Rustのshuttleを使ってみる【3】 調整さんから回答していない人の取得実装は、参考になるブログを見つけました。 調整さんリマインダLINE BOTを作ってみた - やらなイカ? どうやら、調整さんのスケジュールIDが分かれば日にち候補をCSV形式でダウンロードができるようです。 (APIキーとか使わなくてもいいのはセキュリティ的にちょっと気になるけど) これを使って「参加者の誰が回答していないか」を取得し、未回答者がいる場合は適切な制裁を加えていきます。 実装のセットアップ まずはLine Messaging APIのチャネルを作成しましょう。 LINE Developers これがline botのベースになります。 ぼくの場合すでに以前プロバイダの作成をしていたので、チャネルの作成だけします。 とりあえず準備ができました。 ...

11月 1, 2023 · にあえん

Windows11で、cargo newで作ったgitリポジトリが「detected dubious ownership in repository」というエラーで使えない

Windows11に乗り換えたばっかりのエンジニア、ナナオです。 やはり乗り換えると今までと使い勝手が変わるので、何かするたびにエラーになりますね。 今回はGit関連でエラーが起きたので備忘録を残します。 どんなエラー? cargo newでCargoパッケージ作成すると、ありがたいことに最初からgit関連の設定もされた状態になっていると思いますが、そのパッケージ内でgitコマンドを使用するとこのようなエラーになってしまいました。 > git status fatal: detected dubious ownership in repository at 'C:/Users/Nanao/Project/study/rust-playground' 'C:/Users/Nanao/Project/study/rust-playground/.git' is owned by: 'S-1-5-32-544' but the current user is: 'S-1-5-21-2894757817-1525132421-3221859733-1001' To add an exception for this directory, call: git config --global --add safe.directory C:/Users/Nanao/Project/study/rust-playground このエラーはなんなの? 要は「このgitリポジトリの所有者はあなたじゃないから操作できませんよ」というエラーです。 結論としては以下のようなコマンドをPowerShell上で実行することで解決します。 takeown.exe /f [gitリポジトリのパス] /r | Out-Null takeownはファイルの所有者を変更するコマンドです。 Windows�Ńt�@�C���̏��L�҂��ύX�����i�R�}���h�v�����v�g�ҁj�FTech TIPS - ��IT Linuxのchownと同じようなものですね。 Linuxコマンド【 chown 】ファイルの所有者やグループを変更 - Linux入門 - Webkaru このコマンドを使用して所有者を自身に再設定しています。 まとめ いちいちこのコマンドで所有者を変更するのも面倒だなぁ…まぁ慣れればいいか…? 参考 krymtkts - git で local repo が自分のものじゃないとなったやつ ...

10月 30, 2023 · にあえん

Windowsでexaを使う

最近メインPCをWindows11にしました。ナナオです。 cargoなどの初期セットアップがだいぶ終わって作業しやすくなってきましたが、lsの高速版であるexaを入れようとしたら詰まったので備忘録を残しておこうと思います。 exaのインストール Windows以外であれば以下のコマンドでインストールは終わります。 cargo install exa ただし、exaはまだ正式にWindows版をリリースしていないため、同じ事をwindowsでやるとエラーになります。 (以下は実際のエラー) > cargo install exa Updating crates.io index Downloaded exa v0.10.1 Downloaded 1 crate (136.6 KB) in 1.23s Installing exa v0.10.1 Updating crates.io index Downloaded number_prefix v0.4.0 Downloaded users v0.11.0 Downloaded term_size v0.3.2 Downloaded byteorder v1.5.0 Downloaded ansi_term v0.12.1 Downloaded scoped_threadpool v0.1.9 Downloaded jobserver v0.1.27 Downloaded libgit2-sys v0.12.26+1.3.0 Downloaded natord v1.0.9 Downloaded term_grid v0.1.7 Downloaded zoneinfo_compiled v0.5.1 Downloaded locale v0.2.2 Downloaded pad v0.1.6 Downloaded datetime v0.5.2 Downloaded git2 v0.13.25 Downloaded 15 crates (1.9 MB) in 1.29s (largest was `libgit2-sys` at 1.5 MB) Compiling libc v0.2.149 Compiling winapi v0.3.9 Compiling jobserver v0.1.27 Compiling pkg-config v0.3.27 Compiling vcpkg v0.2.15 Compiling tinyvec_macros v0.1.1 Compiling unicode-width v0.1.11 Compiling unicode-bidi v0.3.13 Compiling percent-encoding v2.3.0 Compiling log v0.4.20 Compiling bitflags v1.3.2 Compiling byteorder v1.5.0 Compiling glob v0.3.1 Compiling num_cpus v1.16.0 Compiling number_prefix v0.4.0 Compiling natord v1.0.9 Compiling scoped_threadpool v0.1.9 Compiling lazy_static v1.4.0 Compiling tinyvec v1.6.0 Compiling pad v0.1.6 Compiling term_grid v0.1.7 Compiling form_urlencoded v1.2.0 Compiling cc v1.0.83 Compiling locale v0.2.2 Compiling users v0.11.0 error[E0433]: failed to resolve: could not find `unix` in `os` --> C:\Users\Nanao\.cargo\registry\src\index.crates.io-6f17d22bba15001f\users-0.11.0\src\base.rs:36:14 | 36 | use std::os::unix::ffi::OsStrExt; | ^^^^ could not find `unix` in `os` error[E0432]: unresolved imports `libc::uid_t`, `libc::gid_t` --> C:\Users\Nanao\.cargo\registry\src\index.crates.io-6f17d22bba15001f\users-0.11.0\src\lib.rs:128:16 | 128 | pub use libc::{uid_t, gid_t}; | ^^^^^ ^^^^^ no `gid_t` in the root | | | no `uid_t` in the root error[E0432]: unresolved imports `libc::uid_t`, `libc::gid_t` --> C:\Users\Nanao\.cargo\registry\src\index.crates.io-6f17d22bba15001f\users-0.11.0\src\base.rs:45:20 | 45 | use libc::{c_char, uid_t, gid_t, c_int}; | ^^^^^ ^^^^^ no `gid_t` in the root | | | no `uid_t` in the root | = help: consider importing this unresolved item through its public re-export instead: uid_t = help: consider importing this unresolved item through its public re-export instead: gid_t error[E0432]: unresolved import `libc::passwd` --> C:\Users\Nanao\.cargo\registry\src\index.crates.io-6f17d22bba15001f\users-0.11.0\src\base.rs:46:5 | 46 | use libc::passwd as c_passwd; | ^^^^^^^^^^^^^^^^^^^^^^^^ no `passwd` in the root error[E0432]: unresolved import `libc::group` --> C:\Users\Nanao\.cargo\registry\src\index.crates.io-6f17d22bba15001f\users-0.11.0\src\base.rs:47:5 | 47 | use libc::group as c_group; | ^^^^^^^^^^^^^^^^^^^^^^ no `group` in the root error[E0432]: unresolved imports `libc::uid_t`, `libc::gid_t` --> C:\Users\Nanao\.cargo\registry\src\index.crates.io-6f17d22bba15001f\users-0.11.0\src\cache.rs:87:12 | 87 | use libc::{uid_t, gid_t}; | ^^^^^ ^^^^^ no `gid_t` in the root | | | no `uid_t` in the root | = help: consider importing this unresolved item through its public re-export instead: uid_t = help: consider importing this unresolved item through its public re-export instead: gid_t error[E0432]: unresolved imports `libc::uid_t`, `libc::gid_t` --> C:\Users\Nanao\.cargo\registry\src\index.crates.io-6f17d22bba15001f\users-0.11.0\src\mock.rs:63:16 | 63 | pub use libc::{uid_t, gid_t}; | ^^^^^ ^^^^^ no `gid_t` in the root | | | no `uid_t` in the root | = help: consider importing this unresolved item through its public re-export instead: uid_t = help: consider importing this unresolved item through its public re-export instead: gid_t error[E0432]: unresolved imports `libc::uid_t`, `libc::gid_t` --> C:\Users\Nanao\.cargo\registry\src\index.crates.io-6f17d22bba15001f\users-0.11.0\src\switch.rs:4:12 | 4 | use libc::{uid_t, gid_t, c_int}; | ^^^^^ ^^^^^ no `gid_t` in the root | | | no `uid_t` in the root | = help: consider importing this unresolved item through its public re-export instead: uid_t = help: consider importing this unresolved item through its public re-export instead: gid_t error[E0432]: unresolved imports `libc::uid_t`, `libc::gid_t` --> C:\Users\Nanao\.cargo\registry\src\index.crates.io-6f17d22bba15001f\users-0.11.0\src\traits.rs:4:12 | 4 | use libc::{uid_t, gid_t}; | ^^^^^ ^^^^^ no `gid_t` in the root | | | no `uid_t` in the root | = help: consider importing this unresolved item through its public re-export instead: uid_t = help: consider importing this unresolved item through its public re-export instead: gid_t error[E0433]: failed to resolve: could not find `UserExtras` in `os` --> C:\Users\Nanao\.cargo\registry\src\index.crates.io-6f17d22bba15001f\users-0.11.0\src\base.rs:78:26 | 78 | let extras = os::UserExtras::default(); | ^^^^^^^^^^ could not find `UserExtras` in `os` error[E0433]: failed to resolve: could not find `GroupExtras` in `os` --> C:\Users\Nanao\.cargo\registry\src\index.crates.io-6f17d22bba15001f\users-0.11.0\src\base.rs:192:26 | 192 | let extras = os::GroupExtras::default(); | ^^^^^^^^^^^ could not find `GroupExtras` in `os` error[E0433]: failed to resolve: could not find `UserExtras` in `os` --> C:\Users\Nanao\.cargo\registry\src\index.crates.io-6f17d22bba15001f\users-0.11.0\src\base.rs:266:28 | 266 | extras: os::UserExtras::from_passwd(passwd), | ^^^^^^^^^^ could not find `UserExtras` in `os` error[E0433]: failed to resolve: could not find `GroupExtras` in `os` --> C:\Users\Nanao\.cargo\registry\src\index.crates.io-6f17d22bba15001f\users-0.11.0\src\base.rs:280:23 | 280 | extras: os::GroupExtras::from_struct(group), | ^^^^^^^^^^^ could not find `GroupExtras` in `os` error[E0412]: cannot find type `UserExtras` in module `os` --> C:\Users\Nanao\.cargo\registry\src\index.crates.io-6f17d22bba15001f\users-0.11.0\src\base.rs:57:17 | 57 | extras: os::UserExtras, | ^^^^^^^^^^ not found in `os` | note: found an item that was configured out --> C:\Users\Nanao\.cargo\registry\src\index.crates.io-6f17d22bba15001f\users-0.11.0\src\base.rs:1176:14 | 1176 | pub type UserExtras = bsd::UserExtras; | ^^^^^^^^^^ note: found an item that was configured out --> C:\Users\Nanao\.cargo\registry\src\index.crates.io-6f17d22bba15001f\users-0.11.0\src\base.rs:1180:14 | 1180 | pub type UserExtras = unix::UserExtras; | ^^^^^^^^^^ error[E0412]: cannot find type `GroupExtras` in module `os` --> C:\Users\Nanao\.cargo\registry\src\index.crates.io-6f17d22bba15001f\users-0.11.0\src\base.rs:171:17 | 171 | extras: os::GroupExtras, | ^^^^^^^^^^^ not found in `os` | note: found an item that was configured out --> C:\Users\Nanao\.cargo\registry\src\index.crates.io-6f17d22bba15001f\users-0.11.0\src\base.rs:1184:14 | 1184 | pub type GroupExtras = unix::GroupExtras; | ^^^^^^^^^^^ error[E0425]: cannot find function `getpwuid_r` in crate `libc` --> C:\Users\Nanao\.cargo\registry\src\index.crates.io-6f17d22bba15001f\users-0.11.0\src\base.rs:336:19 | 336 | libc::getpwuid_r(uid, &mut passwd, buf.as_mut_ptr(), buf.len(), &mut result) | ^^^^^^^^^^ not found in `libc` error[E0425]: cannot find function `getpwnam_r` in crate `libc` --> C:\Users\Nanao\.cargo\registry\src\index.crates.io-6f17d22bba15001f\users-0.11.0\src\base.rs:398:19 | 398 | libc::getpwnam_r(username.as_ptr(), &mut passwd, buf.as_mut_ptr(), buf.len(), &mut result) | ^^^^^^^^^^ not found in `libc` error[E0425]: cannot find function `getgrgid_r` in crate `libc` --> C:\Users\Nanao\.cargo\registry\src\index.crates.io-6f17d22bba15001f\users-0.11.0\src\base.rs:451:19 | 451 | libc::getgrgid_r(gid, &mut passwd, buf.as_mut_ptr(), buf.len(), &mut result) | ^^^^^^^^^^ not found in `libc` error[E0425]: cannot find function `getgrnam_r` in crate `libc` --> C:\Users\Nanao\.cargo\registry\src\index.crates.io-6f17d22bba15001f\users-0.11.0\src\base.rs:513:19 | 513 | libc::getgrnam_r(groupname.as_ptr(), &mut group, buf.as_mut_ptr(), buf.len(), &mut result) | ^^^^^^^^^^ not found in `libc` error[E0425]: cannot find function `getuid` in crate `libc` --> C:\Users\Nanao\.cargo\registry\src\index.crates.io-6f17d22bba15001f\users-0.11.0\src\base.rs:556:20 | 556 | unsafe { libc::getuid() } | ^^^^^^ help: a function with a similar name exists: `getpid` | ::: C:\Users\Nanao\.cargo\registry\src\index.crates.io-6f17d22bba15001f\libc-0.2.149\src\windows\mod.rs:491:5 | 491 | pub fn getpid() -> ::c_int; | -------------------------- similarly named function `getpid` defined here error[E0425]: cannot find function `geteuid` in crate `libc` --> C:\Users\Nanao\.cargo\registry\src\index.crates.io-6f17d22bba15001f\users-0.11.0\src\base.rs:603:20 | 603 | unsafe { libc::geteuid() } | ^^^^^^^ help: a function with a similar name exists: `getpid` | ::: C:\Users\Nanao\.cargo\registry\src\index.crates.io-6f17d22bba15001f\libc-0.2.149\src\windows\mod.rs:491:5 | 491 | pub fn getpid() -> ::c_int; | -------------------------- similarly named function `getpid` defined here error[E0425]: cannot find function `getgid` in crate `libc` --> C:\Users\Nanao\.cargo\registry\src\index.crates.io-6f17d22bba15001f\users-0.11.0\src\base.rs:647:20 | 647 | unsafe { libc::getgid() } | ^^^^^^ help: a function with a similar name exists: `getpid` | ::: C:\Users\Nanao\.cargo\registry\src\index.crates.io-6f17d22bba15001f\libc-0.2.149\src\windows\mod.rs:491:5 | 491 | pub fn getpid() -> ::c_int; | -------------------------- similarly named function `getpid` defined here error[E0425]: cannot find function `getegid` in crate `libc` --> C:\Users\Nanao\.cargo\registry\src\index.crates.io-6f17d22bba15001f\users-0.11.0\src\base.rs:691:20 | 691 | unsafe { libc::getegid() } | ^^^^^^^ help: a function with a similar name exists: `getpid` | ::: C:\Users\Nanao\.cargo\registry\src\index.crates.io-6f17d22bba15001f\libc-0.2.149\src\windows\mod.rs:491:5 | 491 | pub fn getpid() -> ::c_int; | -------------------------- similarly named function `getpid` defined here error[E0425]: cannot find function `getgroups` in crate `libc` --> C:\Users\Nanao\.cargo\registry\src\index.crates.io-6f17d22bba15001f\users-0.11.0\src\base.rs:745:15 | 745 | libc::getgroups(1024, buff.as_mut_ptr()) | ^^^^^^^^^ not found in `libc` error[E0425]: cannot find value `buff` in this scope --> C:\Users\Nanao\.cargo\registry\src\index.crates.io-6f17d22bba15001f\users-0.11.0\src\base.rs:783:21 | 783 | let mut count = buff.len() as c_int; | ^^^^ not found in this scope error[E0425]: cannot find value `res` in this scope --> C:\Users\Nanao\.cargo\registry\src\index.crates.io-6f17d22bba15001f\users-0.11.0\src\base.rs:799:8 | 799 | if res < 0 { | ^^^ not found in this scope error[E0425]: cannot find value `buff` in this scope --> C:\Users\Nanao\.cargo\registry\src\index.crates.io-6f17d22bba15001f\users-0.11.0\src\base.rs:803:9 | 803 | buff.dedup(); | ^^^^ not found in this scope error[E0425]: cannot find value `buff` in this scope --> C:\Users\Nanao\.cargo\registry\src\index.crates.io-6f17d22bba15001f\users-0.11.0\src\base.rs:804:9 | 804 | buff.into_iter() | ^^^^ not found in this scope error[E0425]: cannot find function `setpwent` in crate `libc` --> C:\Users\Nanao\.cargo\registry\src\index.crates.io-6f17d22bba15001f\users-0.11.0\src\base.rs:858:11 | 858 | libc::setpwent(); | ^^^^^^^^ not found in `libc` error[E0425]: cannot find function `endpwent` in crate `libc` --> C:\Users\Nanao\.cargo\registry\src\index.crates.io-6f17d22bba15001f\users-0.11.0\src\base.rs:873:24 | 873 | unsafe { libc::endpwent() }; | ^^^^^^^^ not found in `libc` error[E0425]: cannot find function `getpwent` in crate `libc` --> C:\Users\Nanao\.cargo\registry\src\index.crates.io-6f17d22bba15001f\users-0.11.0\src\base.rs:890:37 | 890 | let result = unsafe { libc::getpwent() }; | ^^^^^^^^ not found in `libc` error[E0425]: cannot find function `setuid` in crate `libc` --> C:\Users\Nanao\.cargo\registry\src\index.crates.io-6f17d22bba15001f\users-0.11.0\src\switch.rs:41:26 | 41 | match unsafe { libc::setuid(uid) } { | ^^^^^^ help: a function with a similar name exists: `getpid` | ::: C:\Users\Nanao\.cargo\registry\src\index.crates.io-6f17d22bba15001f\libc-0.2.149\src\windows\mod.rs:491:5 | 491 | pub fn getpid() -> ::c_int; | -------------------------- similarly named function `getpid` defined here error[E0425]: cannot find function `setgid` in crate `libc` --> C:\Users\Nanao\.cargo\registry\src\index.crates.io-6f17d22bba15001f\users-0.11.0\src\switch.rs:72:26 | 72 | match unsafe { libc::setgid(gid) } { | ^^^^^^ help: a function with a similar name exists: `getpid` | ::: C:\Users\Nanao\.cargo\registry\src\index.crates.io-6f17d22bba15001f\libc-0.2.149\src\windows\mod.rs:491:5 | 491 | pub fn getpid() -> ::c_int; | -------------------------- similarly named function `getpid` defined here error[E0425]: cannot find function `seteuid` in crate `libc` --> C:\Users\Nanao\.cargo\registry\src\index.crates.io-6f17d22bba15001f\users-0.11.0\src\switch.rs:103:26 | 103 | match unsafe { libc::seteuid(uid) } { | ^^^^^^^ not found in `libc` error[E0425]: cannot find function `setegid` in crate `libc` --> C:\Users\Nanao\.cargo\registry\src\index.crates.io-6f17d22bba15001f\users-0.11.0\src\switch.rs:134:26 | 134 | match unsafe { libc::setegid(gid) } { | ^^^^^^^ not found in `libc` error[E0599]: no function or associated item named `from_bytes` found for struct `OsStr` in the current scope --> C:\Users\Nanao\.cargo\registry\src\index.crates.io-6f17d22bba15001f\users-0.11.0\src\base.rs:252:20 | 252 | T::from(OsStr::from_bytes(CStr::from_ptr(p).to_bytes())) | ^^^^^^^^^^ function or associated item not found in `OsStr` error[E0599]: no method named `as_bytes` found for reference `&OsStr` in the current scope --> C:\Users\Nanao\.cargo\registry\src\index.crates.io-6f17d22bba15001f\users-0.11.0\src\base.rs:380:57 | 380 | let username = match CString::new(username.as_ref().as_bytes()) { | ^^^^^^^^ method not found in `&OsStr` Compiling unicode-normalization v0.1.22 error[E0599]: no method named `as_bytes` found for reference `&OsStr` in the current scope --> C:\Users\Nanao\.cargo\registry\src\index.crates.io-6f17d22bba15001f\users-0.11.0\src\base.rs:495:59 | 495 | let groupname = match CString::new(groupname.as_ref().as_bytes()) { | ^^^^^^^^ method not found in `&OsStr` error[E0599]: no method named `as_bytes` found for reference `&OsStr` in the current scope --> C:\Users\Nanao\.cargo\registry\src\index.crates.io-6f17d22bba15001f\users-0.11.0\src\base.rs:782:47 | 782 | let name = CString::new(username.as_ref().as_bytes()).unwrap(); | ^^^^^^^^ method not found in `&OsStr` error[E0282]: type annotations needed --> C:\Users\Nanao\.cargo\registry\src\index.crates.io-6f17d22bba15001f\users-0.11.0\src\cache.rs:207:43 | 207 | Occupied(e) => return e.get().as_ref().map(Arc::clone), | ^^^^^^ cannot infer type for type parameter `V` error[E0282]: type annotations needed --> C:\Users\Nanao\.cargo\registry\src\index.crates.io-6f17d22bba15001f\users-0.11.0\src\cache.rs:288:43 | 288 | Occupied(e) => return e.get().as_ref().map(Arc::clone), | ^^^^^^ cannot infer type for type parameter `V` Some errors have detailed explanations: E0282, E0412, E0425, E0432, E0433, E0599. For more information about an error, try `rustc --explain E0282`. error: could not compile `users` (lib) due to 41 previous errors warning: build failed, waiting for other jobs to finish... error: failed to compile `exa v0.10.1`, intermediate artifacts can be found at `C:\Users\Nanao\AppData\Local\Temp\cargo-installiJkMjV`. To reuse those artifacts with a future compilation, set the environment variable `CARGO_TARGET_DIR` to that path. C:\Users\Nanao\Project\study\proc-macro-workshop\builder>cargo install libc Updating crates.io index error: there is nothing to install in `libc v0.2.149`, because it has no binaries `cargo install` is only for installing programs, and can't be used with libraries. To use a library crate, add it as a dependency to a Cargo project with `cargo add`. とまあこんな感じなので、バックドア的な方法でインストールしてあげる必要があります。 ...

10月 29, 2023 · にあえん

「proc-macro-workshop」で学ぶ手続き型マクロ

Rustにハマりつつあるナナオです。 最近Rustばかり触っているのですが、Rustはpythonと比べるととにかくコーディングに時間がかかってしまうのが欠点だなと思うこの頃… 自前の構造体とか作って運用してると、気をつけないと同じよーな処理がプロジェクト内に点在してしまいがちだなと感じています。 (deriveを活用できていないケースとか) そこで今回はRustのメタプログラミングツール、マクロについて学んでいこうと思います。 -> 僕がマクロを学ぶきっかけになった記事はこちら 前提知識となるマクロの参考資料は以下。 マクロ - The Rust Programming Language 日本語版 Rustのマクロを覚える #Rust - Qiita マクロのチュートリアルを実践する マクロを学ぶためのちょうどいいリポジトリがありました。 GitHub - dtolnay/proc-macro-workshop: Learn to write Rust procedural macros [Rust Latam conference, Montevideo Uruguay, March 2019] マクロを使用するパターンについて、いくつかのケーススタディが用意されています。 bitfield builder debug seq sorted とりあえず聞き馴染みのあるbuilderからやってみます。 9つテストケースが用意されており、一つづつパスできるようにしていくことで、段階的にBuilderマクロを実装できるという内容になっています。 わかりやすい。。 ここからは自分の備忘録も兼ねて答えとなるコードを載せていきます。 もし自分で解きたいと言う場合はこれから先の閲覧は注意してください。 01-parse.rs これはとりあえずTokenStreamを返却できればいいだけですね。 必要なライブラリを追加してあげます。 cargo add syn quote とりあえずquote!マクロの結果を返却するだけでこのテストは通ります。 use proc_macro::TokenStream; use quote::quote; #[proc_macro_derive(Builder)] pub fn derive(input: TokenStream) -> TokenStream { let _ = input; let q = quote! {} q.into() } 02-create-builder.rs さて、ここからが本番です。 ...

10月 10, 2023 · にあえん