🔗 はじめに
日々Flutter情報を集めている中で偶然、リモートデスクトップソフトウェアのRustDesk
がしばらく前からクライアントアプリに全面的にFlutterを使用していることを知りました。
- デスクトップOS向けにも使い始めたのは去年(2022)の8月かららしい
RustDeskは「中継サーバ」を自分で立てて使う事が出来るようなので、今回は試しにGoogle Cloud
Platformの「無料枠」の範囲で中継サーバを立ててRustDeskを使ってみようと思います。
(※本記事は結果的にあまりFlutter感がありません、ご了承ください)
🔗 サーバの準備
RustDeskの「中継サーバ」を立てるには以下の番号のポートによる通信が必要なため、
- tcp: 21115-21119
- udp: 21116
それが出来るサーバ設置環境、そしてなるべくお安く試せるもの...ということで、一定の条件内で無料で仮想マシンを作ることが出来るGoogle Cloud Platform(GCP)のサービスであるCompute Engineで行うことにしました。
🔗 VM作り
まずはWebコンソールから無料枠の範囲で仮想マシン(VM)を作成します。
作成にあたってはこちらの記事
- (2023年版) Google Cloud 無料枠 ホントに課金されない?の検証
をとても参考にさせて頂きました🙏
OSは個人的な好みでDebian 12(bookworm)を選んでいます。
🔗 ファイアウォール設定
VM作成後、前述のポート番号(21115-21119)がpublicに通信可能になるようにファイアウォールを設定しました。
🔗 静的外部IPアドレス
無料枠内でも出来そうということで、特に頻繁に再起動するつもりもないですが静的外部 IP アドレスを予約するに従ってアドレスを割り当てました。
なお私はドメインを持っていないので今回この中継サーバはIPアドレス指定で使うことにします。
🔗 スワップ追加
無料枠VMのe2-micro
はメモリが1GBしかないので、スワップファイルを作って使うことにしました。
dd if=/dev/zero of=/swapfile.bin bs=1M count=4096
mkswap /swapfile.bin
chmod 0600 /swapfile.bin
swapon /swapfile.bin
/etc/fstab
に以下の行を追加しておきます。
/swapfile.bin none swap defaults 0 0
🔗 Docker Engineインストール
RustDeskサーバのコンテナを動かす(後述)ために、Docker Engineをインストールしました。
DebianリポジトリにもDocker Engineはありますが、現行バージョンのものを使うため公式サイトの手順を用いて download.docker.com
のものをインストールしました。
🔗 RustDesk Serverを動かす
RustDesk ServerはOSS版とPro版がありますが、今回はOSS版を使います。
OSS版のリポジトリ
- rustdesk/rustdesk-server
にはいくつかのインストール手順が紹介されており、また「rustdesk」で検索すると見つかる以下の記事では(当時のバージョンの)サーバソフトウェアを直接OSにインストールしていますが、
- RustDeskですいすい繋がるリモートデスクトップを実現する
今回はClassic imageとして紹介されているコンテナを2個動かす方法にしました。
(※S6-overlay based imagesの S6-overlay
に馴染みがなかったもので……)
You can also use docker-compose, using this configuration as a template:
と紹介されているテンプレートをほぼそのままコピーした compose.yaml
を用意し、 docker compose up -d
で起動します。
# https://github.com/rustdesk/rustdesk-server#classic-image
version: '3'
networks:
rustdesk-net:
external: false
services:
hbbs:
container_name: hbbs
ports:
- 21115:21115
- 21116:21116
- 21116:21116/udp
- 21118:21118
image: rustdesk/rustdesk-server:latest
# 元は command: hbbs -r rustdesk.example.com:21117 のようになっているが
# ドメイン未使用なので -r オプション割愛
command: hbbs
volumes:
- ./data:/root
networks:
- rustdesk-net
depends_on:
- hbbr
restart: unless-stopped
hbbr:
container_name: hbbr
ports:
- 21117:21117
- 21119:21119
image: rustdesk/rustdesk-server:latest
command: hbbr
volumes:
- ./data:/root
networks:
- rustdesk-net
restart: unless-stopped
🔗 クライアントアプリ
……ということで中継サーバを準備したので手元の各マシンにプラットフォームに応じたクライアントアプリを入れ、実際に使ってみました。
🔗 ビルド済みアプリ
ビルド済みのアプリはGitHubのリリースページ
にて配布されています。
🔗 GUIでセットアップ
普段から画面のある環境で使用しているGUIのあるマシン(手元ではWindowsやMacが該当)についてはGUIでアプリのインストールを行いました。
クライアントアプリを起動し、「認証・中継サーバー」の設定に外部静的IPアドレスで取得した中継サーバのIPアドレスを設定します。
Home画面に戻った後、下部のステータスバーに「準備完了」と出れば中継サーバへの接続成功です。
Home画面にはアプリインストール時に生成されたそのマシンのIDが表示されており(再生成もできます)、他のマシンのアプリからはそのIDを指定して接続します。
またHome画面には「ワンタイムパスワード」も表示されておりそれを使って接続することも出来ますが一度使うと変わってしまうので、リモートマシンの画面を見ずに接続したい場合は「固定のパスワード」を設定して使います。
🔗 Linuxクライアント: GUIを使わずにセットアップ
GUI環境は整えてあるが普段はモニタを繋いでおらずSSH接続で使う、というLinuxマシン(Debian 12)が手元にあり、そこにもRustDeskを入れてみました。
アプリパッケージ(rustdesk-1.2.3-x86_64.deb)は別のマシンでブラウザからダウンロードしSFTPで送り込んでおき、インストールと設定を以下のようにしてGUIを使わずに行いました。
# gdebiを使ってrustdeskのdebをインストール
sudo apt update
sudo apt install gdebi-core
sudo gdebi -n rustdesk-1.2.3-x86_64.deb
# --get-idオプションを使うとIDが表示されるのでメモしておく
sudo rustdesk --get-id
# 固定パスワードを設定
sudo rustdesk --password <固定パスワード>
# 中継サーバーのアドレスを設定
sudo rustdesk --option relay-server xxx.xxx.xxx.xxx
sudo rustdesk --option custom-rendezvous-server xxx.xxx.xxx.xxx
# おまけ: 権限をFull accessに設定
# リモート接続でRustDeskのGUIアプリを操作して設定変更できるようになる
sudo rustdesk --option access-mode 'full'
# rustdeskのサービスを再起動
sudo systemctl restart rustdesk.service
なお、元より画面がないHeadless環境については「ダミー画面」を用いる手順がWikiに紹介されていました。
🔗 クライアントアプリをビルドしてみる
さて、ここまで中継サーバとビルド済みクライアントアプリをセットアップして普通に使うことは出来るようになったので、次はFlutter製であるクライアントアプリについて、ひとつソースからビルドしデバッグ実行してみようと思います。
🔗 macOSでのビルド
以下、当時のmasterブランチ先頭をmacOS(Sonoma 14.1.2)上でビルドに成功した時の大まかな手順をご紹介します。
どうも現状(2023/12)Flutter版の詳しいビルド手順はまとめられておらず、README.mdやドキュメントサイトで読める手順(例えばmacOS用)はFlutter以前(Sciter)向けのもののようでした。
そのため、以下の手順は bridge.ymlやflutter-build.ymlなどCIの設定ファイルから手順を読み取り独自にまとめたものとなります、ご了承ください。
🔗 Flutter/HomeBrew/Rust/Xcode
各種SDKやツールをインストールします。
- Flutter 3.13.9をインストール
- https://docs.flutter.dev/get-started/install/macos
flutter-build.yml
のFLUTTER_VERSIONを参考に3.13.9を使います。
- HomeBrewをインストール
- Rustをインストール、
~/.cargo/bin
へパスを通しcargo
コマンドを実行出来るようにしておく - Xcode 15をインストール
- Xcode 15.1での動作を確認しました。
🔗 brew install
Install build runtimeを参考に、以下のツールを brew install
します。
brew install llvm create-dmg nasm cmake gcc wget ninja pkg-config
🔗 vcpkg
Install vcpkg dependenciesや、「vcpkg version: 2023.10.19」の記述を参考に、vcpkg
の準備とパッケージのインストールを行います。
# 好みの場所にvcpkgをclone
git clone --depth 1 -b 2023.10.19 https://github.com/microsoft/vcpkg.git
cd vcpkg
./bootstrap-vcpkg.sh
./vcpkg install libvpx libyuv opus aom
vcpkg install
に成功したら、vcpkg
ディレクトリがお使いのシェルに環境変数VCPKG_ROOT
としてエクスポートされるように設定します。
# 例: ~/vcpkgにcloneした場合
export VCPKG_ROOT="${HOME}/vcpkg"
🔗 ソースコード準備
git clone https://github.com/rustdesk/rustdesk.git
# 当時のコミット
# git checkout 8452a17d79bc5111453e34ac84ada109d11f940e
🔗 flutter_rust_bridgeでbindingコード生成
cd rustdesk/flutter
flutter pub get
# flutter_rust_bridgeでbindingコード生成
~/.cargo/bin/flutter_rust_bridge_codegen --rust-input ../src/flutter_ffi.rs --dart-output ./lib/generated_bridge.dart --c-output ./macos/Runner/bridge_generated.h
🔗 cargo build
# liblibrustdesk.dylibビルド
cargo build --features "flutter,flutter_texture_render"
この時、もしHomeBrewでbinutilsがインストールされているなどの理由でar
とranlib
がApple製ではないものにパスが通ってしまっている場合は、Apple製のものが使われるように対策する必要があります。
(一時的に/usr/local/bin
を含まないPATH
をexportしたり、いっそbinutilsアンインストールでも?)
ビルドに成功すると rustdesk/target/debug/liblibrustdesk.dylib
が作られます。
🔗 アプリの実行
ここまで成功したらflutter run -d macos
や、rustdesk/flutter/
を開いたVS Code上から実行することが出来ます。
VS Code上で実行し適当なLinuxデスクトップに接続しつつブレークポイントで止めてみました。
デバッグ実行してわかりましたが設定画面で一部文字が入り切っておらず例の「工事中」出てますね🚧
(Debugバナーは非表示に設定されていました)
🔗 気になる技術要素/ライブラリ
ということで、クライアントアプリをソースからビルドし無事Flutter製であることが確認できました……が、RustDeskはそこそこの規模のコードなこともあってこれ以上の深掘りについては難しく、pubspec.yamlも眺めつつ「へぇ〜こんなの使ってるのか」と思う程度となってしまいました、何卒ご容赦ください🙇♂
🔗 flutter_rust_bridge
- そもそも「RustDesk」であり、中継サーバもRustで出来ていますがクライアントアプリでもRustがガッツリ使われています。中核となるリモートデスクトップ機能はRustで出来ており、Dart(Flutter)側との連携にflutter_rust_bridgeが用いられています。
🔗 texture_rgba_renderer
- 「This plugin is originally developed for RustDesk.」とあり、Rustで描画されるリモートデスクトップ画面をFlutterアプリ内に表示するために作られたもののようです。
- Rustの描画結果は最終的にこのあたりでFlutterのTextureウィジェットで表示されていました(ブレークポイントで止めたところ)。
🔗 dash_chat_2
- チャット機能の実装にdash_chat_2をforkして使っているようです。
🔗 window_manager / desktop_multi_window
- それぞれwindow_managerのforkと、pub.devにあるdesktop_multi_windowをforkしたもののforkのようです。
Flutter本体でのデスクトップOSサポートが今後どれくらい進むかわかりませんが、現時点では細かなウィンドウ管理などにはこれらプラグインが必要という事なのでしょう。
🔗 おわりに
以上、(最後が少しすぼみ気味ですが)RustDeskを使ってみた、となります。
9月にGoogle EarthがWeb/iOS/Android共通でFlutter化したりと、iOS/Androidアプリ以外での用途も少しずつ増えて来たように思います。
今後FlutterがどのようにWebやデスクトップ用途に広がっていくのか、RustDeskを使いながら見守っていきたいと思います。