github.com/jingruilea/kubeedge@v1.2.0-beta.0.0.20200410162146-4bb8902b3879/edge/pkg/eventbus/mqtt/client.go (about)

     1  package mqtt
     2  
     3  import (
     4  	"encoding/base64"
     5  	"fmt"
     6  	"strconv"
     7  	"strings"
     8  	"time"
     9  
    10  	MQTT "github.com/eclipse/paho.mqtt.golang"
    11  	"k8s.io/klog"
    12  
    13  	beehiveContext "github.com/kubeedge/beehive/pkg/core/context"
    14  	"github.com/kubeedge/beehive/pkg/core/model"
    15  	"github.com/kubeedge/kubeedge/edge/pkg/common/modules"
    16  	"github.com/kubeedge/kubeedge/edge/pkg/eventbus/common/util"
    17  )
    18  
    19  var (
    20  	// MQTTHub client
    21  	MQTTHub *Client
    22  	// GroupID stands for group id
    23  	GroupID string
    24  	// ConnectedTopic to send connect event
    25  	ConnectedTopic = "$hw/events/connected/%s"
    26  	// DisconnectedTopic to send disconnect event
    27  	DisconnectedTopic = "$hw/events/disconnected/%s"
    28  	// MemberGet to get membership device
    29  	MemberGet = "$hw/events/edgeGroup/%s/membership/get"
    30  	// MemberGetRes to get membership device
    31  	MemberGetRes = "$hw/events/edgeGroup/%s/membership/get/result"
    32  	// MemberDetail which edge-client should be pub when service start
    33  	MemberDetail = "$hw/events/edgeGroup/%s/membership/detail"
    34  	// MemberDetailRes MemberDetail topic resp
    35  	MemberDetailRes = "$hw/events/edgeGroup/%s/membership/detail/result"
    36  	// MemberUpdate updating of the twin
    37  	MemberUpdate = "$hw/events/edgeGroup/%s/membership/updated"
    38  	// GroupUpdate updates a edgegroup
    39  	GroupUpdate = "$hw/events/edgeGroup/%s/updated"
    40  	// GroupAuthGet get temperary aksk from cloudhub
    41  	GroupAuthGet = "$hw/events/edgeGroup/%s/authInfo/get"
    42  	// GroupAuthGetRes temperary aksk from cloudhub
    43  	GroupAuthGetRes = "$hw/events/edgeGroup/%s/authInfo/get/result"
    44  	// SubTopics which edge-client should be sub
    45  	SubTopics = []string{
    46  		"$hw/events/upload/#",
    47  		"$hw/events/device/+/state/update",
    48  		"$hw/events/device/+/twin/+",
    49  		"$hw/events/node/+/membership/get",
    50  		"SYS/dis/upload_records",
    51  	}
    52  )
    53  
    54  // Client struct
    55  type Client struct {
    56  	MQTTUrl string
    57  	PubCli  MQTT.Client
    58  	SubCli  MQTT.Client
    59  }
    60  
    61  // AccessInfo that deliever between edge-hub and cloud-hub
    62  type AccessInfo struct {
    63  	Name    string `json:"name"`
    64  	Type    string `json:"type"`
    65  	Topic   string `json:"topic"`
    66  	Content []byte `json:"content"`
    67  }
    68  
    69  func onPubConnectionLost(client MQTT.Client, err error) {
    70  	klog.Errorf("onPubConnectionLost with error: %v", err)
    71  	go MQTTHub.InitPubClient()
    72  }
    73  
    74  func onSubConnectionLost(client MQTT.Client, err error) {
    75  	klog.Errorf("onSubConnectionLost with error: %v", err)
    76  	go MQTTHub.InitSubClient()
    77  }
    78  
    79  func onSubConnect(client MQTT.Client) {
    80  	for _, t := range SubTopics {
    81  		token := client.Subscribe(t, 1, OnSubMessageReceived)
    82  		if rs, err := util.CheckClientToken(token); !rs {
    83  			klog.Errorf("edge-hub-cli subscribe topic: %s, %v", t, err)
    84  			return
    85  		}
    86  		klog.Infof("edge-hub-cli subscribe topic to %s", t)
    87  	}
    88  }
    89  
    90  // OnSubMessageReceived msg received callback
    91  func OnSubMessageReceived(client MQTT.Client, message MQTT.Message) {
    92  	klog.Infof("OnSubMessageReceived receive msg from topic: %s", message.Topic())
    93  	// for "$hw/events/device/+/twin/+", "$hw/events/node/+/membership/get", send to twin
    94  	// for other, send to hub
    95  	// for "SYS/dis/upload_records", no need to base64 topic
    96  	var target string
    97  	resource := base64.URLEncoding.EncodeToString([]byte(message.Topic()))
    98  	if strings.HasPrefix(message.Topic(), "$hw/events/device") || strings.HasPrefix(message.Topic(), "$hw/events/node") {
    99  		target = modules.TwinGroup
   100  	} else {
   101  		target = modules.HubGroup
   102  		if message.Topic() == "SYS/dis/upload_records" {
   103  			resource = "SYS/dis/upload_records"
   104  		}
   105  	}
   106  	// routing key will be $hw.<project_id>.events.user.bus.response.cluster.<cluster_id>.node.<node_id>.<base64_topic>
   107  	msg := model.NewMessage("").BuildRouter(modules.BusGroup, "user",
   108  		resource, "response").FillBody(string(message.Payload()))
   109  	klog.Info(fmt.Sprintf("received msg from mqttserver, deliver to %s with resource %s", target, resource))
   110  	beehiveContext.SendToGroup(target, *msg)
   111  }
   112  
   113  // InitSubClient init sub client
   114  func (mq *Client) InitSubClient() {
   115  	timeStr := strconv.FormatInt(time.Now().UnixNano()/1e6, 10)
   116  	right := len(timeStr)
   117  	if right > 10 {
   118  		right = 10
   119  	}
   120  	subID := fmt.Sprintf("hub-client-sub-%s", timeStr[0:right])
   121  	subOpts := util.HubClientInit(mq.MQTTUrl, subID, "", "")
   122  	subOpts.OnConnect = onSubConnect
   123  	subOpts.AutoReconnect = false
   124  	subOpts.OnConnectionLost = onSubConnectionLost
   125  	mq.SubCli = MQTT.NewClient(subOpts)
   126  	util.LoopConnect(subID, mq.SubCli)
   127  	klog.Info("finish hub-client sub")
   128  }
   129  
   130  // InitPubClient init pub client
   131  func (mq *Client) InitPubClient() {
   132  	timeStr := strconv.FormatInt(time.Now().UnixNano()/1e6, 10)
   133  	right := len(timeStr)
   134  	if right > 10 {
   135  		right = 10
   136  	}
   137  	pubID := fmt.Sprintf("hub-client-pub-%s", timeStr[0:right])
   138  	pubOpts := util.HubClientInit(mq.MQTTUrl, pubID, "", "")
   139  	pubOpts.OnConnectionLost = onPubConnectionLost
   140  	pubOpts.AutoReconnect = false
   141  	mq.PubCli = MQTT.NewClient(pubOpts)
   142  	util.LoopConnect(pubID, mq.PubCli)
   143  	klog.Info("finish hub-client pub")
   144  }