Skip to content

Commit

Permalink
Merge pull request #1 from thingio/dev-yobol
Browse files Browse the repository at this point in the history
first commit
  • Loading branch information
thingio authored Dec 22, 2021
2 parents db62167 + 537a84d commit 934f17a
Show file tree
Hide file tree
Showing 35 changed files with 2,740 additions and 1 deletion.
21 changes: 21 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib

# Test binary, built with `go test -c`
*.test

# Output of the go coverage tool, specifically when used with LiteIDE
*.out

# Dependency directories (remove the comment below to include it)
# vendor/

# Dependency
go.sum

# IDEA
.idea
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
# edge-device-std
# edge-device-std

## 文档

移步[中文文档](./docs/zh)
8 changes: 8 additions & 0 deletions config/common.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package config

type CommonOptions struct {
DriverHealthCheckIntervalSecond int `json:"driver_health_check_interval_second" yaml:"driver_health_check_interval_second"`
DeviceHealthCheckIntervalSecond int `json:"device_health_check_interval_second" yaml:"device_health_check_interval_second"`
DeviceAutoReconnect bool `json:"device_auto_reconnect" yaml:"device_auto_reconnect"`
DeviceAutoReconnectIntervalSecond int `json:"device_auto_reconnect_interval_second" yaml:"device_auto_reconnect_interval_second"`
}
47 changes: 47 additions & 0 deletions config/define.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package config

import (
"flag"
"github.com/mitchellh/mapstructure"
"github.com/spf13/viper"
"github.com/thingio/edge-device-std/errors"
)

const (
EnvPrefix = "eds"
FilePath = "etc"
FileName = "config"
FileFormat = "yaml"
)

type Configuration struct {
CommonOptions CommonOptions `json:"common" yaml:"common"`
MessageBus MessageBusOptions `json:"msgbus" yaml:"msgbus"`
}

func NewConfiguration() (*Configuration, errors.EdgeError) {
// read the configuration file path
var configPath string
flag.StringVar(&configPath, "cp", FilePath, "config file path, e.g. \"/etc\"")
var configName string
flag.StringVar(&configName, "cn", FileName, "config file name, e.g. \"config\", excluding the suffix")
flag.Parse()

viper.SetEnvPrefix(EnvPrefix)
viper.AutomaticEnv()
viper.AddConfigPath(configPath)
viper.SetConfigName(configName)
viper.SetConfigType(FileFormat)
if err := viper.ReadInConfig(); err != nil {
return nil, errors.Configuration.Cause(err, "fail to read the configuration file")
}

cfg := new(Configuration)
if err := viper.Unmarshal(cfg, func(dc *mapstructure.DecoderConfig) {
dc.TagName = FileFormat
}); err != nil {
return nil, errors.Configuration.Cause(err, "fail to unmarshal the configuration file")
}

return cfg, nil
}
93 changes: 93 additions & 0 deletions config/msgbus.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package config

import (
"crypto/tls"
"crypto/x509"
"fmt"
"io/ioutil"
)

type (
MessageBusType = string
MessageBusProtocolType = string
)

const (
MessageBusTypeMQTT MessageBusType = "MQTT"

MessageBusProtocolTypeTCP MessageBusProtocolType = "tcp"
MessageBusProtocolTypeSSL MessageBusProtocolType = "ssl"
)

type MessageBusOptions struct {
Type MessageBusType `json:"type" yaml:"type"`
MQTT MQTTMessageBusOptions `json:"mqtt" yaml:"mqtt"`
}

type MQTTMessageBusOptions struct {
// Host is the hostname or IP address of the MQTT broker.
Host string `json:"host" yaml:"host"`
// Port is the port of the MQTT broker.
Port int `json:"port" yaml:"port"`
// Username is the username of the MQTT broker.
Username string `json:"username" yaml:"username"`
// Password is the password of the MQTT broker.
Password string `json:"password" yaml:"password"`

// ConnectTimoutMillisecond indicates the timeout of connecting to the MQTT broker.
ConnectTimoutMillisecond int `json:"connect_timout_millisecond" yaml:"connect_timout_millisecond"`
// TokenTimeoutMillisecond indicates the timeout of mqtt token.
TokenTimeoutMillisecond int `json:"token_timeout_millisecond" yaml:"token_timeout_millisecond"`
// QoS is the abbreviation of MQTT Quality of Service.
QoS int `json:"qos" yaml:"qos"`
// CleanSession indicates whether retain messages after reconnecting for QoS1 and QoS2.
CleanSession bool `json:"clean_session" yaml:"clean_session"`

// MethodCallTimeoutMillisecond indicates the timeout of method call.
MethodCallTimeoutMillisecond int `json:"method_call_timeout_millisecond" yaml:"method_call_timeout_millisecond"`

WithTLS bool `json:"with_tls" yaml:"with_tls"`
CAPath string `json:"ca_path" yaml:"ca_path"`
CertPath string `json:"cert_path" yaml:"cert_path"`
KeyPath string `json:"key_path" yaml:"key_path"`
}

func (o *MQTTMessageBusOptions) NewTLSConfig() (*tls.Config, error) {
cert, rootPool, err := o.loadTLSConfig()
if err != nil {
return nil, err
}
return &tls.Config{
Certificates: []tls.Certificate{cert},
RootCAs: rootPool,
InsecureSkipVerify: true,
MinVersion: tls.VersionTLS12,
}, nil
}

func (o *MQTTMessageBusOptions) loadTLSConfig() (tls.Certificate, *x509.CertPool, error) {
cert, err := tls.LoadX509KeyPair(o.CertPath, o.KeyPath)
if err != nil {
return cert, nil, fmt.Errorf("fail to load the certificate files: %s", err.Error())
}
rootPool := x509.NewCertPool()
caCert, err := ioutil.ReadFile(o.CAPath)
if err != nil {
return cert, nil, fmt.Errorf("fail to load the root ca file: %s", err.Error())
}
ok := rootPool.AppendCertsFromPEM(caCert)
if !ok {
return cert, nil, fmt.Errorf("fail to parse the root ca file")
}
return cert, rootPool, nil
}

func (o *MQTTMessageBusOptions) GetBroker() string {
var protocolType MessageBusProtocolType
if o.WithTLS {
protocolType = MessageBusProtocolTypeSSL
} else {
protocolType = MessageBusProtocolTypeTCP
}
return fmt.Sprintf("%s://%s:%d", protocolType, o.Host, o.Port)
}
23 changes: 23 additions & 0 deletions docs/zh/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# CHANGELOG

## 2021.12

1. 确定[系统基本架构](./系统架构/README.md)
2. [设备驱动示例(生成随机数)](https://github.com/thingio/edge-randnum-driver)
3. 新增特性:
- 支持 command-line flag 指定配置文件路径,如 `xxx -cp etc -cn config` 表示指定配置文件为 `./etc/config.yaml`
- 定义 MessageBus 接口封装 MQ 操作逻辑,并提供了 MQTTMessageBus 作为默认支持
- 定义 MetaStore 接口封装元数据操作逻辑,并提供了 FileMetaStore 作为默认支持
- 区分单向和双向操作,对于双向操作(基于 MessageBus 的 Call 方法实现)而言,使用全局唯一的 UUID - `ReqID` 标识同一组操作
- 区分属性软读(soft-read)和硬读(hard-read),前者会从设备影子(DeviceTwin)中获取该属性的缓存值,后者会直接从真实设备中读取该属性的值
- 支持 MQTTS 配置,可参考 [MQTT 使用 TLS 建立安全连接](./系统安全/MQTTS:%20MQTT%20使用%20TLS%20建立安全连接.md)
- 将设备数据封装为类似于 DeviceData 的结构体,包含属性名、数据类型、数据值、数据采集时间戳等信息

## TODO

1. 支持设备级别的 MQTT(S) QoS 配置
2.`edge-device-manager` & `edge-device-accessor` 提供 HTTP(S) & WS(S) 访问接口及 Client,与业务无关的代码封装在 `edge-device-std`
中提供基础服务
3. `edge-device-accessor` 确定业务边界、架构设计与代码实现
4. 调整 Protocol、Product 与 Device 元数据结构的定义,如 DeviceStatus 是动态消息,只能由系统更改,不应该放在 Device 这样的元数据中
5. 调研 TCP & MQTT(mosquitto) 如何切分数据包,主要是要确定当传输一个大数据文件(如图片)时,MQTT 如何将其拆分,TCP 如何将其拆分?
Loading

0 comments on commit 934f17a

Please sign in to comment.