我如何存储在结构中并在整个应用程序的不同功能中使用值?
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
的代码都会失败,因为客户端尚未初始化,因此您可能希望使用某种锁定以确保在使用全局变量之前设置它。
我想在结构中存储一个 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
的代码都会失败,因为客户端尚未初始化,因此您可能希望使用某种锁定以确保在使用全局变量之前设置它。