diff --git a/app/Console/Commands/MqttSyncAuth.php b/app/Console/Commands/MqttSyncAuth.php index 4f8910d..28bf72e 100644 --- a/app/Console/Commands/MqttSyncAuth.php +++ b/app/Console/Commands/MqttSyncAuth.php @@ -27,6 +27,14 @@ class MqttSyncAuth extends Command */ public function handle(MachineService $machineService) { + // 1. 同步 Gateway 自身的認證資料 (與 mqtt-gateway/main.go 對應) + $this->info("Syncing star-cloud-gateway auth..."); + $gatewayKey = "machine_auth:star-cloud-gateway"; + $gatewayPass = hash('sha256', "StarCloudSecret999"); + \Illuminate\Support\Facades\Redis::hSet($gatewayKey, 'password', $gatewayPass); + $this->info("Gateway auth synced."); + + // 2. 同步所有機台的認證資料 $machines = Machine::withoutGlobalScopes()->get(); $this->info("Syncing " . $machines->count() . " machines to Redis..."); diff --git a/compose.yaml b/compose.yaml index 6b1f9aa..ea9e6ad 100644 --- a/compose.yaml +++ b/compose.yaml @@ -105,6 +105,11 @@ services: - 'sail-emqx:/opt/emqx/data' networks: - sail + healthcheck: + test: ["CMD", "/opt/emqx/bin/emqx_ctl", "status"] + interval: 5s + timeout: 5s + retries: 5 depends_on: - redis mqtt-gateway: @@ -123,6 +128,7 @@ services: TZ: 'Asia/Taipei' networks: - sail + restart: always depends_on: - emqx - redis diff --git a/mqtt-gateway/main.go b/mqtt-gateway/main.go index 11e7cc1..b43a5ce 100644 --- a/mqtt-gateway/main.go +++ b/mqtt-gateway/main.go @@ -10,6 +10,8 @@ import ( "star-cloud-gateway/internal/handler" "syscall" + "time" + mqtt "github.com/eclipse/paho.mqtt.golang" "github.com/redis/go-redis/v9" ) @@ -17,29 +19,40 @@ import ( func main() { cfg := config.LoadConfig() - // 1. 初始化 Redis - rdb := redis.NewClient(&redis.Options{ - Addr: cfg.RedisAddr, - Password: cfg.RedisPassword, - DB: 0, - }) - if err := rdb.Ping(context.Background()).Err(); err != nil { - log.Fatalf("Failed to connect to Redis at %s: %v", cfg.RedisAddr, err) + var rdb *redis.Client + var client mqtt.Client + + // 1. 初始化 Redis (帶重試機制) + for { + rdb = redis.NewClient(&redis.Options{ + Addr: cfg.RedisAddr, + Password: cfg.RedisPassword, + DB: 0, + }) + if err := rdb.Ping(context.Background()).Err(); err != nil { + log.Printf("Waiting for Redis at %s... (%v)", cfg.RedisAddr, err) + time.Sleep(5 * time.Second) + continue + } + log.Printf("Connected to Redis at %s", cfg.RedisAddr) + break } - log.Printf("Connected to Redis at %s", cfg.RedisAddr) // 加入 Laravel 前綴,確保雙方桶子同一個 prefixedIncomingKey := "starcloud_database_" + cfg.IncomingQueueKey pusher := bridge.NewRedisPusher(rdb, prefixedIncomingKey) mqttHandler := handler.NewMqttHandler(pusher) - // 2. 初始化 MQTT + // 2. 初始化 MQTT (帶重試機制) opts := mqtt.NewClientOptions() opts.AddBroker(cfg.MQTTAddr) opts.SetClientID(cfg.MQTTClientID) opts.SetUsername("star-cloud-gateway") opts.SetPassword("StarCloudSecret999") // 與 Redis 中的 hash 對應 opts.SetCleanSession(false) + opts.SetAutoReconnect(true) + opts.SetMaxReconnectInterval(10 * time.Second) + opts.SetOnConnectHandler(func(c mqtt.Client) { log.Printf("Connected to MQTT Broker as Gateway [star-cloud-gateway] at %s", cfg.MQTTAddr) // 訂閱所有機台的上行 Topic @@ -52,9 +65,14 @@ func main() { } }) - client := mqtt.NewClient(opts) - if token := client.Connect(); token.Wait() && token.Error() != nil { - log.Fatalf("Failed to connect to MQTT: %v", token.Error()) + client = mqtt.NewClient(opts) + for { + if token := client.Connect(); token.Wait() && token.Error() != nil { + log.Printf("Waiting for MQTT Broker at %s... (%v)", cfg.MQTTAddr, token.Error()) + time.Sleep(5 * time.Second) + continue + } + break } // 3. 啟動 Redis Consumer (下行指令)