Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion README-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ MQTT 代表 MQ Telemetry Transport。它是一种发布/订阅、非常简单和
- 客户端特定的写入缓冲区,避免因读取速度慢或客户端不规范行为而产生的问题。
- 通过所有 [Paho互操作性测试](https://github.com/eclipse/paho.mqtt.testing/tree/master/interoperability)(MQTT v5 和 MQTT v3)。
- 超过一千多个经过仔细考虑的单元测试场景。
- 支持 TCP、Websocket(包括 SSL/TLS)和$SYS 服务状态监控。
- 支持 TCP、Websocket(包括 SSL/TLS)、QUIC 和 $SYS 服务状态监控。
- MQTT over QUIC 支持,提供低延迟、多路复用连接(兼容 NanoSDK 和 paho.mqtt.golang 客户端)。
- 内置 基于Redis、Badger、Pebble 和 Bolt 的持久化(使用Hook钩子,你也可以自己创建)。
- 内置基于规则的认证和 ACL 权限管理(使用Hook钩子,你也可以自己创建)。

Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ MQTT stands for [MQ Telemetry Transport](https://en.wikipedia.org/wiki/MQTT). It
- Client-specific write buffers to avoid issues with slow-reading or irregular client behaviour.
- Passes all [Paho Interoperability Tests](https://github.com/eclipse/paho.mqtt.testing/tree/master/interoperability) for MQTT v5 and MQTT v3.
- Over a thousand carefully considered unit test scenarios.
- TCP, Websocket (including SSL/TLS), and $SYS Dashboard listeners.
- TCP, Websocket (including SSL/TLS), QUIC, and $SYS Dashboard listeners.
- MQTT over QUIC support for low-latency, multiplexed connections (compatible with NanoSDK and paho.mqtt.golang clients).
- Built-in Redis, Badger, Pebble and Bolt Persistence using Hooks (but you can also make your own).
- Built-in Rule-based Authentication and ACL Ledger using Hooks (also make your own).

Expand Down
144 changes: 144 additions & 0 deletions examples/quic/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
// SPDX-License-Identifier: MIT
// SPDX-FileCopyrightText: 2024 mochi-mqtt, mochi-co
// SPDX-FileContributor: mochi-co

// Package main demonstrates how to use MQTT over QUIC with mochi-mqtt.
//
// QUIC provides improved performance over TCP, especially in high-latency
// or lossy network conditions, with features like:
// - 0-RTT connection establishment
// - Multiplexed streams without head-of-line blocking
// - Connection migration
// - Built-in TLS 1.3 encryption
//
// Client URL formats:
// - NanoSDK (C): mqtt-quic://localhost:14567
// - Paho (Go): quic://localhost:14567
//
// The server listens on UDP port and accepts both formats.
package main

import (
"crypto/ed25519"
"crypto/rand"
"crypto/tls"
"crypto/x509"
"log"
"math/big"
"os"
"os/signal"
"syscall"
"time"

mqtt "github.com/mochi-mqtt/server/v2"
"github.com/mochi-mqtt/server/v2/hooks/auth"
"github.com/mochi-mqtt/server/v2/listeners"
"github.com/quic-go/quic-go"
)

const (
// Default ports
quicPort = ":14567" // MQTT over QUIC port
tcpPort = ":1883" // Standard MQTT TCP port
)

// generateTLSConfig creates a self-signed TLS configuration for testing.
// In production, use proper certificates from a trusted CA.
func generateTLSConfig() *tls.Config {
_, priv, err := ed25519.GenerateKey(rand.Reader)
if err != nil {
log.Fatal(err)
}

template := x509.Certificate{
SerialNumber: big.NewInt(1),
NotBefore: time.Now(),
NotAfter: time.Now().Add(365 * 24 * time.Hour),
}

certDER, err := x509.CreateCertificate(rand.Reader, &template, &template, priv.Public(), priv)
if err != nil {
log.Fatal(err)
}

return &tls.Config{
Certificates: []tls.Certificate{{
Certificate: [][]byte{certDER},
PrivateKey: priv,
}},
NextProtos: []string{"mqtt"}, // ALPN protocol for MQTT over QUIC
}
}

func main() {
sigs := make(chan os.Signal, 1)
done := make(chan bool, 1)
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
go func() {
<-sigs
done <- true
}()

// Create TLS configuration (required for QUIC)
tlsConfig := generateTLSConfig()

// Optional: Configure QUIC-specific settings optimized for MQTT
// If nil is passed to NewQUIC, default optimized settings will be used
quicConfig := &quic.Config{
MaxIdleTimeout: listeners.DefaultQUICMaxIdleTimeout,
KeepAlivePeriod: listeners.DefaultQUICKeepAlivePeriod,
MaxIncomingStreams: listeners.DefaultQUICMaxIncomingStreams,
MaxIncomingUniStreams: listeners.DefaultQUICMaxIncomingUniStreams,
InitialStreamReceiveWindow: listeners.DefaultQUICInitialStreamReceiveWindow,
MaxStreamReceiveWindow: listeners.DefaultQUICMaxStreamReceiveWindow,
InitialConnectionReceiveWindow: listeners.DefaultQUICInitialConnectionReceiveWindow,
MaxConnectionReceiveWindow: listeners.DefaultQUICMaxConnectionReceiveWindow,
Allow0RTT: false, // Disable 0-RTT for security by default
}

// Create MQTT server
server := mqtt.New(nil)
_ = server.AddHook(new(auth.AllowHook), nil)

// Add QUIC listener (mqtt-quic:// protocol)
// Compatible with NanoSDK clients using mqtt-quic://host:port format
quicListener := listeners.NewQUIC(listeners.Config{
ID: "quic1",
Address: quicPort,
TLSConfig: tlsConfig,
}, quicConfig)

err := server.AddListener(quicListener)
if err != nil {
log.Fatal(err)
}

// Optionally, also add TCP listener for backward compatibility
tcpListener := listeners.NewTCP(listeners.Config{
ID: "tcp1",
Address: tcpPort,
TLSConfig: tlsConfig,
})
err = server.AddListener(tcpListener)
if err != nil {
log.Fatal(err)
}

log.Println("Starting MQTT server...")
log.Println(" QUIC listener (mqtt-quic) on", quicPort)
log.Println(" - NanoSDK client: mqtt-quic://localhost" + quicPort)
log.Println(" - Paho Go client: quic://localhost" + quicPort)
log.Println(" TCP listener on", tcpPort)

go func() {
err := server.Serve()
if err != nil {
log.Fatal(err)
}
}()

<-done
server.Log.Warn("caught signal, stopping...")
_ = server.Close()
server.Log.Info("server stopped")
}
75 changes: 41 additions & 34 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,56 +1,63 @@
module github.com/mochi-mqtt/server/v2

go 1.21
go 1.24.0

require (
github.com/alicebob/miniredis/v2 v2.23.0
github.com/cockroachdb/pebble v1.1.0
github.com/dgraph-io/badger/v4 v4.2.0
github.com/cockroachdb/pebble v1.1.5
github.com/dgraph-io/badger/v4 v4.8.0
github.com/go-redis/redis/v8 v8.11.5
github.com/gorilla/websocket v1.5.0
github.com/gorilla/websocket v1.5.3
github.com/jinzhu/copier v0.3.5
github.com/rs/xid v1.4.0
github.com/stretchr/testify v1.8.1
go.etcd.io/bbolt v1.3.5
github.com/quic-go/quic-go v0.57.1
github.com/rs/xid v1.6.0
github.com/stretchr/testify v1.11.1
go.etcd.io/bbolt v1.4.3
gopkg.in/yaml.v3 v3.0.1
)

require (
github.com/DataDog/zstd v1.4.5 // indirect
github.com/DataDog/zstd v1.5.7 // indirect
github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/cockroachdb/errors v1.11.1 // indirect
github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect
github.com/cockroachdb/redact v1.1.5 // indirect
github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/cockroachdb/errors v1.12.0 // indirect
github.com/cockroachdb/fifo v0.0.0-20240816210425-c5d0cb0b6fc0 // indirect
github.com/cockroachdb/logtags v0.0.0-20241215232642-bb51bb14a506 // indirect
github.com/cockroachdb/redact v1.1.6 // indirect
github.com/cockroachdb/tokenbucket v0.0.0-20250429170803-42689b6311bb // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dgraph-io/ristretto v0.1.1 // indirect
github.com/dgraph-io/ristretto/v2 v2.3.0 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/dustin/go-humanize v1.0.0 // indirect
github.com/getsentry/sentry-go v0.18.0 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/getsentry/sentry-go v0.40.0 // indirect
github.com/go-logr/logr v1.4.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/glog v1.2.4 // indirect
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/google/flatbuffers v1.12.1 // indirect
github.com/klauspost/compress v1.15.15 // indirect
github.com/golang/snappy v1.0.0 // indirect
github.com/google/flatbuffers v25.9.23+incompatible // indirect
github.com/klauspost/compress v1.18.2 // indirect
github.com/kr/pretty v0.3.1 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/onsi/gomega v1.27.6 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_golang v1.12.0 // indirect
github.com/prometheus/client_model v0.2.1-0.20210607210712-147c58e9608a // indirect
github.com/prometheus/common v0.32.1 // indirect
github.com/prometheus/procfs v0.7.3 // indirect
github.com/rogpeppe/go-internal v1.9.0 // indirect
github.com/prometheus/client_golang v1.23.2 // indirect
github.com/prometheus/client_model v0.6.2 // indirect
github.com/prometheus/common v0.67.4 // indirect
github.com/prometheus/procfs v0.19.2 // indirect
github.com/rogpeppe/go-internal v1.14.1 // indirect
github.com/yuin/gopher-lua v0.0.0-20210529063254-f4c35e4016d9 // indirect
go.opencensus.io v0.22.5 // indirect
golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df // indirect
golang.org/x/net v0.33.0 // indirect
golang.org/x/sys v0.28.0 // indirect
golang.org/x/text v0.21.0 // indirect
google.golang.org/protobuf v1.33.0 // indirect
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
go.opentelemetry.io/otel v1.39.0 // indirect
go.opentelemetry.io/otel/metric v1.39.0 // indirect
go.opentelemetry.io/otel/trace v1.39.0 // indirect
go.yaml.in/yaml/v2 v2.4.3 // indirect
golang.org/x/crypto v0.46.0 // indirect
golang.org/x/exp v0.0.0-20251209150349-8475f28825e9 // indirect
golang.org/x/net v0.48.0 // indirect
golang.org/x/sys v0.39.0 // indirect
golang.org/x/text v0.32.0 // indirect
google.golang.org/protobuf v1.36.10 // indirect
)
Loading