我如何存储在结构中并在整个应用程序的不同功能中使用值?

How can i store in struct and use the value in different functions throughout the application?

我想在结构中存储一个 mqtt 客户端,并在整个应用程序中使用这个客户端。

我的项目结构如下所示:

-src
  -payloads
     -payload.go
  -repositories
     -repository.go 
-main.go

payload.go 看起来像这样:

package payload

import MQTT "github.com/eclipse/paho.mqtt.golang"

type MQTTClient struct {
    Client MQTT.Client
}

在我的 repository.go 中,我有一个 Connect() 函数,如下所示:

func Connect() MQTT.Client {

    deviceID := flag.String("device", "", "GCP Device-Id")
    bridge := struct {
        host *string
        port *string
    }{
        flag.String("mqtt_host", "", "MQTT Bridge Host"),
        flag.String("mqtt_port", "", "MQTT Bridge Port"),
    }
    projectID := flag.String("project", "", "GCP Project ID")
    registryID := flag.String("registry", "", "Cloud IoT Registry ID (short form)")
    region := flag.String("region", "", "GCP Region")
    certsCA := flag.String("ca_certs", "", "Download https://pki.google.com/roots.pem")
    privateKey := flag.String("private_key", "", "Path to private key file")

    server := fmt.Sprintf("ssl://%v:%v", *bridge.host, *bridge.port)
    topic := struct {
        config    string
        telemetry string
    }{
        config:    fmt.Sprintf("/devices/%v/config", *deviceID),
        telemetry: fmt.Sprintf("/devices/%v/events/", *deviceID),
    }
    qos := flag.Int("qos", 0, "The QoS to subscribe to messages at")
    clientid := fmt.Sprintf("projects/%v/locations/%v/registries/%v/devices/%v",
        *projectID,
        *region,
        *registryID,
        *deviceID,
    )
    log.Println("[main] Loading Google's roots")
    certpool := x509.NewCertPool()
    pemCerts, err := ioutil.ReadFile(*certsCA)
    if err == nil {
        certpool.AppendCertsFromPEM(pemCerts)
    }

    log.Println("[main] Creating TLS Config")
    config := &tls.Config{
        RootCAs:      certpool,
        ClientAuth:   tls.NoClientCert,
        ClientCAs:    nil,
        Certificates: []tls.Certificate{},
        MinVersion:   tls.VersionTLS12,
    }

    flag.Parse()

    connOpts := MQTT.NewClientOptions().
        AddBroker(server).
        SetClientID(clientid).
        SetAutoReconnect(true).
        SetConnectRetry(true).
        SetDefaultPublishHandler(onMessageReceived).
        SetConnectionLostHandler(connLostHandler).
        SetReconnectingHandler(reconnHandler).
        SetTLSConfig(config)
    connOpts.SetUsername("unused")
    ///JWT Generation Starts from Here
    token := jwt.New(jwt.SigningMethodES256)
    token.Claims = jwt.StandardClaims{
        Audience:  *projectID,
        IssuedAt:  time.Now().Unix(),
        ExpiresAt: time.Now().Add(24 * time.Hour).Unix(),
    }
    //Reading key file
    log.Println("[main] Load Private Key")
    keyBytes, err := ioutil.ReadFile(*privateKey)
    if err != nil {
        log.Fatal(err)
    }
    //Parsing key from file
    log.Println("[main] Parse Private Key")
    key, err := jwt.ParseECPrivateKeyFromPEM(keyBytes)
    if err != nil {
        log.Fatal(err)
    }
    //Signing JWT with private key
    log.Println("[main] Sign String")
    tokenString, err := token.SignedString(key)
    if err != nil {
        log.Fatal(err)
    }
    //JWT Generation Ends here

    connOpts.SetPassword(tokenString)
    connOpts.OnConnect = func(c MQTT.Client) {
        if token := c.Subscribe(topic.config, byte(*qos), nil); token.Wait() && token.Error() != nil {
            log.Fatal(token.Error())
        }
    }

    client := MQTT.NewClient(connOpts)
    if token := client.Connect(); token.Wait() && token.Error() != nil {
        fmt.Printf("Not Connected..Retrying...  %s\n", server)
    } else {
        fmt.Printf("Connected to %s\n", server)
    }
    return client

}

不,我在 go 例程中使用这个 Connect() 函数以及这样的 grpc 服务器..

func main() {
    fmt.Println("Server started at port 5005")
    lis, err := net.Listen("tcp", "0.0.0.0:5005")
    if err != nil {
        log.Fatalf("Failed to listen: %v", err)
    }
    //Creating keepAlive channel for mqttt subscribe
    keepAlive := make(chan os.Signal)
    defer close(keepAlive)
    go func() {
        //Connecting to mqtt client
        client := repositories.Connect()
        //passing the client to struct
        res := &payload.MQTTClient{
            Client: client,
        }
        fmt.Println(res)
        //looking for interupt(Ctrl+C)
        value := <-keepAlive
        //If Ctrl+C is pressed then exit the application
        if value == os.Interrupt {
            fmt.Printf("Exiting the application")
            os.Exit(3)
        }
    }()
    s := grpc.NewServer()
    MqttRepository := repositories.NewMqttRepository()
    // It creates a new gRPC server instance
    rpc.NewMqttServer(s, MqttRepository)
    if err := s.Serve(lis); err != nil {
        log.Fatalf("Failed to serve: %v", err)

    }
}

现在我将 Connect() 函数中的客户端存储到结构中,但我无法使用它。如何将客户端存储在 main.go 中的某个位置,然后在整个应用程序中使用它?

如果您想在整个代码中使用一个结构,您可能需要使用单例模式 [1]。

在 Go 中,您基本上是在一个包中定义一个导出的全局变量,所有导入该包的代码都可以使用它。

您可以让客户住在 payload 包中(或任何适合您的包,这只是一个示例):

package payload

import MQTT "github.com/eclipse/paho.mqtt.golang"

type MQTTClient struct {
    Client MQTT.Client
}

var SingletonClient *MQTTClient

然后在 main.go 而不是

res := &payload.MQTTClient{
    Client: client,
}

payload.SingletonClient = &payload.MQTTClient{
    Client: client,
}

瞧,现在你可以在导入 payload 包的任何地方使用 payload.SingletonClient

请注意,Singleton 模式不被认为是一种好的做法,如果您可以构建代码以在需要的地方传递客户端,那就更好了。不过有时它可能会有用。

请注意,任何在 main.go 中设置之前尝试使用 payload.SingletonClient 的代码都会失败,因为客户端尚未初始化,因此您可能希望使用某种锁定以确保在使用全局变量之前设置它。

[1] https://en.wikipedia.org/wiki/Singleton_pattern