English | 简体中文 | 日本語 | Translators Wanted!
🎆 mochi-co/mqtt は新しい mochi-mqtt organisation の一部です. このページをお読みください
Mochi MQTT は Goで書かれたMQTT v5に完全に準拠しているMQTTブローカーで、IoTプロジェクトやテレメトリの開発プロジェクト向けに設計されています。 スタンドアロンのバイナリで使ったり、アプリケーションにライブラリとして組み込むことができ、プロジェクトのメンテナンス性と品質を確保できるように配慮しながら、 軽量で可能な限り速く動作するように設計されています。
MQTT は MQ Telemetry Transportを意味します。 Pub/Sub型のシンプルで軽量なメッセージプロトコルで、低帯域、高遅延、不安定なネットワーク下での制約を考慮して設計されています(MQTTについて詳しくはこちら)。 Mochi MQTTはMQTTプロトコルv5.0.0に完全準拠した実装をしています。
- MQTTv5への完全な準拠とMQTT v3.1.1 および v3.0.0 との互換性:
- MQTT v5で拡張されたユーザープロパティ
- トピック・エイリアス
- 共有サブスクリプション
- サブスクリプションオプションとサブスクリプションID
- メッセージの有効期限
- クライアントセッション
- 送受信QoSフロー制御クォータ
- サーバサイド切断と認証パケット
- Will遅延間隔
- 上記に加えてQoS(0,1,2)、$SYSトピック、retain機能などすべてのMQTT v1の特徴を持ちます
- Developer-centric:
- 開発者が制御できるように、ほとんどのコアブローカーのコードをエクスポートにしてアクセスできるようにしました。
- フル機能で柔軟なフックベースのインターフェイスにすることで簡単に'プラグイン'を開発できるようにしました。
- 特別なインラインクライアントを利用することでパケットインジェクションを行うか、既存のクライアントとしてマスカレードすることができます。
- パフォーマンスと安定性:
- 古典的なツリーベースのトピックサブスクリプションモデル
- クライアント固有に書き込みバッファーをもたせることにより、読み込みの遅さや不規則なクライアントの挙動の問題を回避しています。
- MQTT v5 and MQTT v3のすべてのPaho互換性テストをpassしています。
- 慎重に検討された多くのユニットテストシナリオでテストされています。
- TCP, Websocket (SSL/TLSを含む), $SYSのダッシュボードリスナー
- フックを利用した保存機能としてRedis, Badger, Boltを使うことができます(自作のHookも可能です)。
- フックを利用したルールベース認証機能とアクセス制御リストLedgerを使うことができます(自作のHookも可能です)。
MQTTv5とそれ以前との互換性から、サーバーはv5とv3両方のクライアントを受け入れることができますが、v5とv3のクライアントが接続された場合はv5でクライアント向けの特徴と機能はv3クライアントにダウングレードされます(ユーザープロパティなど)。 MQTT v3.0.0 と v3.1.1 のサポートはハイブリッド互換性があるとみなされます。それはv3と仕様に制限されていない場合、例えば、送信メッセージ、保持メッセージの有効期限とQoSフロー制御制限などについては、よりモダンで安全なv5の動作が使用されます
クリティカルなイシュー出ない限り、新しいリリースがされるのは週末です。
- 新しい特徴やイベントフックのリクエストは open an issue へ!
- クラスターのサポート
- メトリックスサポートの強化
- ファイルベースの設定(Dockerイメージのサポート)
Mochi MQTTはスタンドアロンのブローカーとして使うことができます。単純にこのレポジトリーをチェックアウトして、cmd/main.go を起動すると内部の cmd フォルダのエントリポイントにしてtcp (:1883), websocket (:1882), dashboard (:8080)のポートを外部にEXPOSEします。
cd cmd
go build -o mqtt && ./mqtt
Dockerレポジトリの official Mochi MQTT image から Pullして起動することができます。
docker pull mochimqtt/server
or
docker run mochimqtt/server
これは実装途中です。file-based configuration は、この実装をよりよくサポートするために開発中です。 より実質的なdockerのサポートが議論されています。Docker環境で使っている方は是非この議論に参加してください。 ここ や ここ。
cmd/main.goの Websocket, TCP, Statsサーバを実行するために、シンプルなDockerfileが提供されます。
docker build -t mochi:latest .
docker run -p 1883:1883 -p 1882:1882 -p 8080:8080 mochi:latest
Mochi MQTTをパッケージとしてインポートするにはほんの数行のコードで始めることができます。
import (
"log"
mqtt "github.com/mochi-mqtt/server/v2"
"github.com/mochi-mqtt/server/v2/hooks/auth"
"github.com/mochi-mqtt/server/v2/listeners"
)
func main() {
// Create signals channel to run server until interrupted
sigs := make(chan os.Signal, 1)
done := make(chan bool, 1)
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
go func() {
<-sigs
done <- true
}()
// Create the new MQTT Server.
server := mqtt.New(nil)
// Allow all connections.
_ = server.AddHook(new(auth.AllowHook), nil)
// Create a TCP listener on a standard port.
tcp := listeners.NewTCP(listeners.Config{ID: "t1", Address: ":1883"})
err := server.AddListener(tcp)
if err != nil {
log.Fatal(err)
}
go func() {
err := server.Serve()
if err != nil {
log.Fatal(err)
}
}()
// Run server until interrupted
<-done
// Cleanup
}
ブローカーの動作例は examplesフォルダにあります。
サーバは様々なプロトコルのコネクションのリスナーに対応しています。現在の対応リスナーは、
Listener | Usage |
---|---|
listeners.NewTCP | TCPリスナー |
listeners.NewUnixSock | Unixソケットリスナー |
listeners.NewNet | net.Listenerリスナー |
listeners.NewWebsocket | Websocketリスナー |
listeners.NewHTTPStats | HTTP $SYSダッシュボード |
listeners.NewHTTPHealthCheck | ヘルスチェック応答を提供するためのHTTPヘルスチェックリスナー(クラウドインフラ) |
新しいリスナーを開発するためには
listeners.Listener
を使ってください。使ったら是非教えてください!
TLSを設定するには*listeners.Config
を渡すことができます。
examples フォルダと cmd/main.goに使用例があります。
たくさんのオプションが利用可能です。サーバーの動作を変更したり、特定の機能へのアクセスを制限することができます。
server := mqtt.New(&mqtt.Options{
Capabilities: mqtt.Capabilities{
MaximumSessionExpiryInterval: 3600,
MaximumClientWritesPending: 3,
Compatibilities: mqtt.Compatibilities{
ObscureNotAuthorized: true,
},
},
ClientNetWriteBufferSize: 4096,
ClientNetReadBufferSize: 4096,
SysTopicResendInterval: 10,
InlineClient: false,
})
mqtt.Options、mqtt.Capabilities、mqtt.Compatibilitiesの構造体はオプションの理解に役立ちます。
必要に応じてClientNetWriteBufferSize
とClientNetReadBufferSize
はクライアントの使用するメモリに合わせて設定できます。
Capabilities.MaximumClientWritesPending
のサイズは、サーバーのメモリ使用量に影響を与えます。IoTデバイスが同時にオンラインで多数存在する場合、また設定値が非常に大きい場合、データの送受信がなくても、サーバーのメモリ使用量は大幅に増加します。デフォルト値は1024*8で、実際の状況に応じてこのパラメータを調整することができます。
いくつかのデフォルトの設定を決める際にいくつかの決定がなされましたのでここに記しておきます:
- デフォルトとして、敵対的なネットワーク上のDoSアタックにさらされるのを防ぐために
server.Options.Capabilities.MaximumMessageExpiryInterval
は86400 (24時間)に、とセットされています。有効期限を無限にすると、保持、送信メッセージが無限に蓄積されるからです。もし信頼できる環境であったり、より大きな保存期間が可能であれば、この設定はオーバーライドできます(0
を設定すると有効期限はなくなります。)
ユニバーサルイベントフックシステムは、開発者にサーバとクライアントの様々なライフサイクルをフックすることができ、ブローカーの機能を追加/変更することができます。それらのユニバーサルフックは認証、永続ストレージ、デバッグツールなど、あらゆるものに使用されています。 フックは複数重ねることができ、サーバに複数のフックを設定することができます。それらは追加した順番に動作します。いくつかのフックは値を変えて、その値は動作コードに返される前にあとに続くフックに渡されます。
Type | Import | Info |
---|---|---|
Access Control | mochi-mqtt/server/hooks/auth . AllowHook | すべてのトピックに対しての読み書きをすべてのクライアントに対して許可します。 |
Access Control | mochi-mqtt/server/hooks/auth . Auth | ルールベースのアクセスコントロール台帳です。 |
Persistence | mochi-mqtt/server/hooks/storage/bolt | BoltDB を使った永続ストレージ (非推奨). |
Persistence | mochi-mqtt/server/hooks/storage/badger | BadgerDBを使った永続ストレージ |
Persistence | mochi-mqtt/server/hooks/storage/redis | Redisを使った永続ストレージ |
Debugging | mochi-mqtt/server/hooks/debug | パケットフローを可視化するデバッグ用のフック |
たくさんの内部関数が開発者に公開されています、なので、上記の例を使って自分でフックを作ることができます。もし作ったら是非Open an issueに投稿して教えてください!
デフォルトで、Mochi MQTTはアクセスコントロールルールにDENY-ALLを使用しています。コネクションを許可するためには、アクセスコントロールフックを上書きする必要があります。一番単純なのはauth.AllowAll
フックで、ALLOW-ALLルールがすべてのコネクション、サブスクリプション、パブリッシュに適用されます。使い方は下記のようにするだけです:
server := mqtt.New(nil)
_ = server.AddHook(new(auth.AllowHook), nil)
もしインターネットや信頼できないネットワークにさらされる場合は行わないでください。これは開発・テスト・デバッグ用途のみであるべきです。
Auth Ledgerは構造体で定義したアクセスルールの洗練された仕組みを提供します。Auth Ledgerルール2つの形式から成ります、認証ルール(コネクション)とACLルール(パブリッシュ、サブスクライブ)です。
認証ルールは4つのクライテリアとアサーションフラグがあります:
Criteria | Usage |
---|---|
Client | 接続クライアントのID |
Username | 接続クライアントのユーザー名 |
Password | 接続クライアントのパスワード |
Remote | クライアントのリモートアドレスもしくはIP |
Allow | true(このユーザーを許可する)もしくはfalse(このユーザを拒否する) |
アクセスコントロールルールは3つのクライテリアとフィルターマッチがあります:
Criteria | Usage |
---|---|
Client | 接続クライアントのID |
Username | 接続クライアントのユーザー名 |
Remote | クライアントのリモートアドレスもしくはIP |
Filters | 合致するフィルターの配列 |
ルールはインデックス順(0,1,2,3)に処理され、はじめに合致したルールが適用されます。 hooks/auth/ledger.go の構造体を見てください。
server := mqtt.New(nil)
err := server.AddHook(new(auth.Hook), &auth.Options{
Ledger: &auth.Ledger{
Auth: auth.AuthRules{ // Auth disallows all by default
{Username: "peach", Password: "password1", Allow: true},
{Username: "melon", Password: "password2", Allow: true},
{Remote: "127.0.0.1:*", Allow: true},
{Remote: "localhost:*", Allow: true},
},
ACL: auth.ACLRules{ // ACL allows all by default
{Remote: "127.0.0.1:*"}, // local superuser allow all
{
// user melon can read and write to their own topic
Username: "melon", Filters: auth.Filters{
"melon/#": auth.ReadWrite,
"updates/#": auth.WriteOnly, // can write to updates, but can't read updates from others
},
},
{
// Otherwise, no clients have publishing permissions
Filters: auth.Filters{
"#": auth.ReadOnly,
"updates/#": auth.Deny,
},
},
},
}
})
ledgeはデータフィールドを使用してJSONもしくはYAML形式で保存したものを使用することもできます。
err := server.AddHook(new(auth.Hook), &auth.Options{
Data: data, // build ledger from byte slice: yaml or json
})
より詳しくはexamples/auth/encoded/main.goを見てください。
ブローカーに永続性を提供する基本的な Redis ストレージフックが利用可能です。他のフックと同じ方法で、いくつかのオプションを使用してサーバーに追加できます。それはフック内部で github.com/go-redis/redis/v8 を使用し、Optionsの値で詳しい設定を行うことができます。
err := server.AddHook(new(redis.Hook), &redis.Options{
Options: &rv8.Options{
Addr: "localhost:6379", // default redis address
Password: "", // your password
DB: 0, // your redis db
},
})
if err != nil {
log.Fatal(err)
}
Redisフックがどのように動くか、どのように使用するかについての詳しくは、examples/persistence/redis/main.go か hooks/storage/redis のソースコードを見てください。
もしファイルベースのストレージのほうが適しているのであれば、BadgerDBストレージも使用することができます。それもまた、他のフックと同様に追加、設定することができます(オプションは若干少ないです)。
err := server.AddHook(new(badger.Hook), &badger.Options{
Path: badgerPath,
})
if err != nil {
log.Fatal(err)
}
badgerフックがどのように動くか、どのように使用するかについての詳しくは、examples/persistence/badger/main.go か hooks/storage/badger のソースコードを見てください。
BoltDBフックはBadgerに代わって非推奨となりましたが、もし必要ならば examples/persistence/bolt/main.goをチェックしてください。
ブローカーとクライアントのライフサイクルに関わるたくさんのフックが利用できます。
そのすべてのフックとmqtt.Hook
インターフェイスの関数シグネチャはhooks.goに記載されています。
もっと柔軟なイベントフックはOnPacketRead、OnPacketEncodeとOnPacketSentです。それらは、すべての流入パケットと流出パケットをコントロール及び変更に使用されるフックです。
Function | Usage |
---|---|
OnStarted | サーバーが正常にスタートした際に呼ばれます。 |
OnStopped | サーバーが正常に終了した際に呼ばれます。 |
OnConnectAuthenticate | ユーザーがサーバと認証を試みた際に呼ばれます。このメソッドはサーバーへのアクセス許可もしくは拒否するためには必ず使用する必要があります(hooks/auth/allow_all or basicを見てください)。これは、データベースにユーザーが存在するか照合してチェックするカスタムフックに利用できます。許可する場合はtrueを返す実装をします。 |
OnACLCheck | ユーザーがあるトピックフィルタにpublishかsubscribeした際に呼ばれます。上と同様です |
OnSysInfoTick | $SYSトピック値がpublishされた場合に呼ばれます。 |
OnConnect | 新しいクライアントが接続した際によばれます、エラーかパケットコードを返して切断する場合があります。 |
OnSessionEstablish | 新しいクライアントが接続された後すぐ、セッションが確立されてCONNACKが送信される前に呼ばれます。 |
OnSessionEstablished | 新しいクライアントがセッションを確立した際(OnConnectの後)に呼ばれます。 |
OnDisconnect | クライアントが何らかの理由で切断された場合に呼ばれます。 |
OnAuthPacket | 認証パケットを受け取ったときに呼ばれます。これは開発者にmqtt v5の認証パケットを取り扱う仕組みを作成すること意図しています。パケットを変更することができます。 |
OnPacketRead | クライアントからパケットを受け取った際に呼ばれます。パケットを変更することができます。 |
OnPacketEncode | エンコードされたパケットがクライアントに送信する直前に呼ばれます。パケットを変更することができます。 |
OnPacketSent | クライアントにパケットが送信された際に呼ばれます。 |
OnPacketProcessed | パケットが届いてブローカーが正しく処理できた場合に呼ばれます。 |
OnSubscribe | クライアントが1つ以上のフィルタをsubscribeした場合に呼ばれます。パケットの変更ができます。 |
OnSubscribed | クライアントが1つ以上のフィルタをsubscribeに成功した場合に呼ばれます。 |
OnSelectSubscribers | サブスクライバーがトピックに収集されたとき、共有サブスクライバーが選択される前に呼ばれる。受信者は変更可能。 |
OnUnsubscribe | 1つ以上のあんサブスクライブが呼ばれた場合。パケットの変更は可能。 |
OnUnsubscribed | クライアントが正常に1つ以上のトピックフィルタをサブスクライブ解除した場合。 |
OnPublish | クライアントがメッセージをパブリッシュした場合。パケットの変更は可能。 |
OnPublished | クライアントがサブスクライバーにメッセージをパブリッシュし終わった場合。 |
OnPublishDropped | あるクライアントが反応に時間がかかった場合等のようにクライアントに到達する前にメッセージが失われた場合に呼ばれる。 |
OnRetainMessage | パブリッシュされたメッセージが保持された場合に呼ばれる。 |
OnRetainPublished | 保持されたメッセージがクライアントに到達した場合に呼ばれる。 |
OnQosPublish | QoSが1以上のパケットがサブスクライバーに発行された場合。 |
OnQosComplete | そのメッセージQoSフローが完了した場合に呼ばれる。 |
OnQosDropped | インフライトメッセージが完了前に期限切れになった場合に呼ばれる。 |
OnPacketIDExhausted | クライアントがパケットに割り当てるIDが枯渇した場合に呼ばれる。 |
OnWill | クライアントが切断し、WILLメッセージを発行しようとした場合に呼ばれる。パケットの変更が可能。 |
OnWillSent | LWTメッセージが切断されたクライアントから発行された場合に呼ばれる |
OnClientExpired | クライアントセッションが期限切れで削除するべき場合に呼ばれる。 |
OnRetainedExpired | 保持メッセージが期限切れで削除すべき場合に呼ばれる。 |
StoredClients | クライアントを返す。例えば永続ストレージから。 |
StoredSubscriptions | クライアントのサブスクリプションを返す。例えば永続ストレージから。 |
StoredInflightMessages | インフライトメッセージを返す。例えば永続ストレージから。 |
StoredRetainedMessages | 保持されたメッセージを返す。例えば永続ストレージから。 |
StoredSysInfo | システム情報の値を返す。例えば永続ストレージから。 |
もし永続ストレージフックを作成しようとしているのであれば、すでに存在する永続的なフックを見てインスピレーションとどのようなパターンがあるか見てみてください。もし認証フックを作成しようとしているのであれば、OnACLCheck
とOnConnectAuthenticate
が役立つでしょう。
トピックに対して埋め込まれたコードから直接サブスクライブとパブリッシュできます。そうするにはinline client
機能を使うことができます。インラインクライアント機能はサーバの一部として組み込まれているクライアントでサーバーのオプションとしてEnableにできます。
server := mqtt.New(&mqtt.Options{
InlineClient: true,
})
Enableにすると、server.Publish
, server.Subscribe
, server.Unsubscribe
のメソッドを利用できて、ブローカーから直接メッセージを送受信できます。
実際の使用例はdirect examplesを見てください。
組み込まれたアプリケーションからメッセージをパブリッシュするにはserver.Publish(topic string, payload []byte, retain bool, qos byte) error
メソッドを利用します。
err := server.Publish("direct/publish", []byte("packet scheduled message"), false, 0)
このケースでのQoSはサブスクライバーに設定できる上限でしか使用されません。これはMQTTv5の仕様に従っています。
組み込まれたアプリケーション内部からトピックフィルタをサブスクライブするには、server.Subscribe(filter string, subscriptionId int, handler InlineSubFn) error
メソッドがコールバックも含めて使用できます。
インラインサブスクリプションではQoS0のみが適用されます。もし複数のコールバックを同じフィルタに設定したい場合は、MQTTv5のsubscriptionId
のプロパティがその区別に使用できます。
callbackFn := func(cl *mqtt.Client, sub packets.Subscription, pk packets.Packet) {
server.Log.Info("inline client received message from subscription", "client", cl.ID, "subscriptionId", sub.Identifier, "topic", pk.TopicName, "payload", string(pk.Payload))
}
server.Subscribe("direct/#", 1, callbackFn)
インラインクライアントでサブスクリプション解除をしたい場合は、server.Unsubscribe(filter string, subscriptionId int) error
メソッドで行うことができます。
server.Unsubscribe("direct/#", 1)
もし、より制御したい場合や、特定のMQTTv5のプロパティやその他の値をセットしたい場合は、クライアントからのパブリッシュパケットを自ら作成することができます。この方法は単なるパブリッシュではなく、MQTTパケットをまるで特定のクライアントから受け取ったかのようにランタイムに直接インジェクションすることができます。
このパケットインジェクションは例えばPING ReqやサブスクリプションなどのどんなMQTTパケットでも使用できます。そしてクライアントの構造体とメソッドはエクスポートされているので、(もし、非常にカスタマイズ性の高い要求がある場合には)まるで接続されたクライアントに代わってパケットをインジェクションすることさえできます。
たいていの場合は上記のインラインクライアントを使用するのが良いでしょう、それはACLとトピックバリデーションをバイパスできる特権があるからです。これは$SYSトピックにさえパブリッシュできることも意味します。ビルトインのクライアントと同様に振る舞うインラインクライアントを作成できます。
cl := server.NewClient(nil, "local", "inline", true)
server.InjectPacket(cl, packets.Packet{
FixedHeader: packets.FixedHeader{
Type: packets.Publish,
},
TopicName: "direct/publish",
Payload: []byte("scheduled message"),
})
MQTTのパケットは正しく構成する必要があり、なのでthe test packets catalogueとMQTTv5 Specificationを参照してください。
この機能の動作を確認するにはhooks example を見てください。
それぞれの関数が期待通りの動作をするように考えられてMochi MQTTテストが作成されています。テストを走らせるには:
go run --cover ./...
examples/paho/main.go
を使用してブローカーを起動し、_interoperability_フォルダのpython3 client_test5.py
のmqttv5とv3のテストを実行することで、Paho Interoperability Testを確認することができます。
pahoスイートには現在は何個かの偽陰性に関わるissueがあるので、
paho/main.go
の例ではいくつかの互換性モードがオンになっていることに注意してください。
Mochi MQTTのパフォーマンスはMosquitto、EMQX、その他などの有名なブローカーに匹敵します。
ベンチマークはApple Macbook Air M2上でMQTT-Stresser、セッティングとしてcmd/main.go
のデフォルト設定を使用しています。高スループットと低スループットのバーストを考慮すると、中央値のスコアが最も信頼できます。この値は高いほど良いです。
ベンチマークの値は1秒あたりのメッセージ数のスループットのそのものを表しているわけではありません。これは、mqtt-stresserによる固有の計算に依存するものではありますが、すべてのブローカーに渡って一貫性のある値として利用しています。 ベンチマークは一般的なパフォーマンス予測ガイドラインとしてのみ提供されます。比較はそのまま使用したデフォルトの設定値で実行しています。
mqtt-stresser -broker tcp://localhost:1883 -num-clients=2 -num-messages=10000
Broker | publish fastest | median | slowest | receive fastest | median | slowest |
---|---|---|---|---|---|---|
Mochi v2.2.10 | 124,772 | 125,456 | 124,614 | 314,461 | 313,186 | 311,910 |
Mosquitto v2.0.15 | 155,920 | 155,919 | 155,918 | 185,485 | 185,097 | 184,709 |
EMQX v5.0.11 | 156,945 | 156,257 | 155,568 | 17,918 | 17,783 | 17,649 |
Rumqtt v0.21.0 | 112,208 | 108,480 | 104,753 | 135,784 | 126,446 | 117,108 |
mqtt-stresser -broker tcp://localhost:1883 -num-clients=10 -num-messages=10000
Broker | publish fastest | median | slowest | receive fastest | median | slowest |
---|---|---|---|---|---|---|
Mochi v2.2.10 | 41,825 | 31,663 | 23,008 | 144,058 | 65,903 | 37,618 |
Mosquitto v2.0.15 | 42,729 | 38,633 | 29,879 | 23,241 | 19,714 | 18,806 |
EMQX v5.0.11 | 21,553 | 17,418 | 14,356 | 4,257 | 3,980 | 3,756 |
Rumqtt v0.21.0 | 42,213 | 23,153 | 20,814 | 49,465 | 36,626 | 19,283 |
100万メッセージ試験 (100 万メッセージを一斉にサーバーに送信します):
mqtt-stresser -broker tcp://localhost:1883 -num-clients=100 -num-messages=10000
Broker | publish fastest | median | slowest | receive fastest | median | slowest |
---|---|---|---|---|---|---|
Mochi v2.2.10 | 13,532 | 4,425 | 2,344 | 52,120 | 7,274 | 2,701 |
Mosquitto v2.0.15 | 3,826 | 3,395 | 3,032 | 1,200 | 1,150 | 1,118 |
EMQX v5.0.11 | 4,086 | 2,432 | 2,274 | 434 | 333 | 311 |
Rumqtt v0.21.0 | 78,972 | 5,047 | 3,804 | 4,286 | 3,249 | 2,027 |
EMQXのここでの結果は何が起きているのかわかりませんが、おそらくDockerのそのままの設定が最適ではなかったのでしょう、なので、この結果はソフトウェアのひとつの側面にしか過ぎないと捉えてください。
コントリビューションとフィードバックは両方とも歓迎していますでバグを報告したり、質問したり、新機能のリクエストをしてください。もしプルリクエストするならば下記のガイドラインに従うようにしてください。
- 合理的で可能な限りテストカバレッジを維持してください
- なぜPRをしたのかとそのPRの内容について明確にしてください。
- 有意義な貢献をした場合はSPDX FileContributorタグをファイルにつけてください。
SPDX Annotationsはそのライセンス、著作権表記、コントリビューターについて明確するのために、それぞれのファイルに機械可読な形式で記されています。もし、新しいファイルをレポジトリに追加した場合は、下記のようなSPDXヘッダーを付与していることを確かめてください。
// SPDX-License-Identifier: MIT
// SPDX-FileCopyrightText: 2023 mochi-mqtt
// SPDX-FileContributor: Your name or alias <optional@email.address>
package name
ファイルにそれぞれのコントリビューターのSPDX-FileContributor
が追加されていることを確認してください、他のファイルを参考にしてください。あなたのこのプロジェクトへのコントリビュートは価値があり、高く評価されます!
Mochi MQTTをプロジェクトで使用していますか? 是非私達に教えてください!