mochi-mqtt / server

The fully compliant, embeddable high-performance Go MQTT v5 server for IoT, smarthome, and pubsub
MIT License
1.29k stars 222 forks source link

I want to use this as a library for GIN #288

Closed DarkiT closed 1 year ago

DarkiT commented 1 year ago

I want to use this as a GIN library, because I want to reuse the MQTT port with the WEB port of the GIN framework. Can you add support? For example:

func main() {
    server := mqtt.New(nil)
    _ = server.AddHook(new(auth.AllowHook), nil)
    ws := listeners.NewWebsocket("websocket")
    if err := server.AddListener(ws); err != nil {
        log.Error(err.Error())
    }
    go func() {
        err := server.Serve()
        if err != nil {
            log.Error(err.Error())
        }
    }()
    r := gin.Default()
    r.GET("/socket", func(c *gin.Context) {
        ws.Handler(c.Writer, c.Request)
    })

    r.Run()
}
dgduncan commented 1 year ago

I am having a little trouble following your use case. Is the problem you are trying to solve that you have port that is currently being used by GIN in some capacity and you want that port to essentially serve two purposes; one for whatever GIN uses it for and the other for mqtt?

DarkiT commented 1 year ago

I am having a little trouble following your use case. Is the problem you are trying to solve that you have port that is currently being used by GIN in some capacity and you want that port to essentially serve two purposes; one for whatever GIN uses it for and the other for mqtt?

Yes, that's it

dgduncan commented 1 year ago

@DarkiT Just for curiosity, is there a reason why you can not just change the ports either for GIN or for mochi? Such as this

ws := listeners.NewWebsocket("ws1", ":1884", nil)
err = server.AddListener(ws)
if err != nil {
    log.Fatal(err)
}
DarkiT commented 1 year ago

Due to policy restrictions, I cannot expose multiple ports to the outside world, so I hope that the webserver and mqtt ws share a port.

werbenhu commented 1 year ago

@DarkiT 这个应该能满足你的需求,你自己去优化组织下代码.You can do it like this.

// websocket.go

// Websocket is a listener for establishing websocket connections.
type Websocket struct { // [MQTT-4.2.0-1]
    sync.RWMutex
    id        string              // the internal id of the listener
    address   string              // the network address to bind to
    config    *Config             // configuration values for the listener
    listen    *http.Server        // an http server for serving websocket connections
    log       *zerolog.Logger     // server logger
    establish EstablishFn         // the server's establish connection handler
    upgrader  *websocket.Upgrader //  upgrade the incoming http/tcp connection to a websocket compliant connection.
    end       uint32              // ensure the close methods are only called once

    Router *gin.Engine  
}

// ...

// Init initializes the listener.
func (l *Websocket) Init(log *zerolog.Logger) error {
    l.log = log
    l.Router = gin.Default()
    l.Router.GET("/", func(c *gin.Context) {
        l.handler(c.Writer, c.Request)
    })

    l.listen = &http.Server{
        Addr:    l.address,
        Handler: l.Router,
    }
    return nil
}
// main.go
// SPDX-License-Identifier: MIT
// SPDX-FileCopyrightText: 2022 mochi-mqtt, mochi-co
// SPDX-FileContributor: mochi-co

package main

import (
    "flag"
    "log"
    "os"
    "os/signal"
    "syscall"

    "github.com/gin-gonic/gin"
    mqtt "github.com/mochi-mqtt/server/v2"
    "github.com/mochi-mqtt/server/v2/hooks/auth"
    "github.com/mochi-mqtt/server/v2/listeners"
)

func main() {
    wsAddr := flag.String("ws", ":1882", "network address for Websocket listener")
    flag.Parse()

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

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

    ws := listeners.NewWebsocket("ws1", *wsAddr, nil)
    err := server.AddListener(ws)
    if err != nil {
        log.Fatal(err)
    }

    // 这里添加你自己的http路由和处理
    // Add your own HTTP routes and handlers.
    ws.Router.GET("/hello", func(c *gin.Context) {
        c.JSON(200, gin.H{
            "message": "world!",
        })
    })

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

    <-done
    server.Log.Warn().Msg("caught signal, stopping...")
    server.Close()
    server.Log.Info().Msg("main.go finished")
}
DarkiT commented 1 year ago

@DarkiT 这个应该能满足你的需求,你自己去优化组织下代码.You can do it like this.

// websocket.go

// Websocket is a listener for establishing websocket connections.
type Websocket struct { // [MQTT-4.2.0-1]
  sync.RWMutex
  id        string              // the internal id of the listener
  address   string              // the network address to bind to
  config    *Config             // configuration values for the listener
  listen    *http.Server        // an http server for serving websocket connections
  log       *zerolog.Logger     // server logger
  establish EstablishFn         // the server's establish connection handler
  upgrader  *websocket.Upgrader //  upgrade the incoming http/tcp connection to a websocket compliant connection.
  end       uint32              // ensure the close methods are only called once

  Router *gin.Engine  
}

// ...

// Init initializes the listener.
func (l *Websocket) Init(log *zerolog.Logger) error {
  l.log = log
  l.Router = gin.Default()
  l.Router.GET("/", func(c *gin.Context) {
      l.handler(c.Writer, c.Request)
  })

  l.listen = &http.Server{
      Addr:    l.address,
      Handler: l.Router,
  }
  return nil
}
// main.go
// SPDX-License-Identifier: MIT
// SPDX-FileCopyrightText: 2022 mochi-mqtt, mochi-co
// SPDX-FileContributor: mochi-co

package main

import (
  "flag"
  "log"
  "os"
  "os/signal"
  "syscall"

  "github.com/gin-gonic/gin"
  mqtt "github.com/mochi-mqtt/server/v2"
  "github.com/mochi-mqtt/server/v2/hooks/auth"
  "github.com/mochi-mqtt/server/v2/listeners"
)

func main() {
  wsAddr := flag.String("ws", ":1882", "network address for Websocket listener")
  flag.Parse()

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

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

  ws := listeners.NewWebsocket("ws1", *wsAddr, nil)
  err := server.AddListener(ws)
  if err != nil {
      log.Fatal(err)
  }

  // 这里添加你自己的http路由和处理
  // Add your own HTTP routes and handlers.
  ws.Router.GET("/hello", func(c *gin.Context) {
      c.JSON(200, gin.H{
          "message": "world!",
      })
  })

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

  <-done
  server.Log.Warn().Msg("caught signal, stopping...")
  server.Close()
  server.Log.Info().Msg("main.go finished")
}

@werbenhu ,自己尝试试了一下,实现了这个需求,不过看了您的代码,确实您更加优雅的实现了,感谢指导。

dgduncan commented 1 year ago

@werbenhu Thank you for your help!

mochi-co commented 1 year ago

Agree - thanks @werbenhu!