ble-april/service/ble-service.go

344 lines
7.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package service
import (
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"net/http"
"strings"
"time"
MQTT "github.com/eclipse/paho.mqtt.golang"
"github.com/shirou/gopsutil/cpu"
"github.com/shirou/gopsutil/disk"
"github.com/shirou/gopsutil/mem"
"github.com/sirupsen/logrus"
"github.com/spf13/viper"
"github.com/vmihailenco/msgpack"
"myschools.me/wyh/ble-april/mosquitto"
)
var m map[string]*IBeancon
var chn chan *IBeancon
var token string
var expiretime time.Time
func init() {
m = make(map[string]*IBeancon, 500)
chn = make(chan *IBeancon, 500)
}
type Bletoken struct {
AppKey string
AppSecret string
}
type BleResponse struct {
Code int
Msg string
Data struct {
Token string
Expire int64
}
}
func Bletokeninit() {
for {
if time.Now().Before(expiretime) {
time.Sleep(5 * time.Minute)
continue
}
bb, err := json.Marshal(&Bletoken{
AppKey: viper.GetString("api.appkey"),
AppSecret: viper.GetString("api.appsecret"),
})
if err != nil {
logrus.WithFields(logrus.Fields{
"func": "Bletokeninit",
}).Warnf("%s", err.Error())
continue
}
reader := strings.NewReader(string(bb))
//生成要访问的url
url := fmt.Sprintf("%s/oauth", viper.GetString("srv.host"))
resp, err := http.Post(url, "application/json;charset=UTF-8", reader)
if err != nil {
logrus.WithFields(logrus.Fields{
"func": "BleMessagePush",
}).Warnf("http.post: %s", err.Error())
continue
}
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
logrus.Println("ioutil.ReadAll:", err.Error())
continue
}
logrus.Println("body", string(body))
// 解析返回值,正确时添加入内存
retbody := &BleResponse{}
err = json.Unmarshal(body, retbody)
if err != nil {
logrus.Println("err: ", err)
}
token = retbody.Data.Token
expire := retbody.Data.Expire
expiretime = time.Now().Add(time.Duration(time.Duration(expire) * time.Second))
}
}
//蓝牙接收服务
var connHandler MQTT.OnConnectHandler = func(client MQTT.Client) {
token := client.Subscribe("gw/april", 0, serviceHandler)
if token.Wait() && token.Error() != nil {
fmt.Println(token.Error())
}
}
var connLostHandler MQTT.ConnectionLostHandler = func(client MQTT.Client, err error) {
fmt.Println(err.Error())
}
//具体业务订阅的处理,此处为示例
var serviceHandler MQTT.MessageHandler = func(client MQTT.Client, msg MQTT.Message) {
out1 := make(map[string]interface{}, 0)
if err := msgpack.Unmarshal(msg.Payload(), &out1); err != nil {
logrus.WithFields(logrus.Fields{
"func": "NewiBeacon",
}).Warnf("%s", err.Error())
return
}
// 解析out1.device
bles := BleDecode(out1["devices"].([]interface{}))
for _, d := range bles {
chn <- &IBeancon{
DeviceID: fmt.Sprintf("%s:%s:%s:%s:%s:%s", d.Mac[0:2], d.Mac[2:4], d.Mac[4:6], d.Mac[6:8], d.Mac[8:10], d.Mac[10:12]),
HappenTime: time.Now(),
Updated: time.Now().Unix(),
}
}
}
func BleDelivery() {
if err := mosquitto.Subscribe(connHandler, connLostHandler); err != nil {
logrus.WithFields(logrus.Fields{
"func": "BleDelivery",
}).Warnf("%s", err.Error())
return
}
}
// 取出数据进行处理
func BleMessagePush() {
for {
if b, ok := <-chn; ok {
// // 上传服务器
bb, err := json.Marshal(b)
if err != nil {
continue
}
reader := strings.NewReader(string(bb))
// 发送请求
url := fmt.Sprintf("%s/receive", viper.GetString("srv.host"))
client := &http.Client{}
//生成要访问的url
//提交请求
reqest, err := http.NewRequest("POST", url, reader)
//增加header选项
reqest.Header.Set("token", token)
reqest.Header.Set("Content-Type", "application/json;charset=UTF-8")
if err != nil {
logrus.WithFields(logrus.Fields{
"func": "BleMessagePush",
}).Warnf("%s", err.Error())
continue
}
//处理返回结果
resp, err := client.Do(reqest)
if err != nil {
logrus.WithFields(logrus.Fields{
"func": "BleMessagePush",
}).Warnf("%s", err.Error())
continue
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
logrus.Println("ioutil.ReadAll:", err.Error())
continue
}
logrus.Println("body", string(body))
// 解析返回值,正确时添加入内存
i := make(map[string]interface{}, 0)
err = json.Unmarshal(body, &i)
if err != nil {
logrus.Println("err: ", err.Error())
continue
}
if i["msg"] == "ok" {
m[b.DeviceID] = b
}
}
}
}
type IBeancon struct {
DeviceID string
HappenTime time.Time
Updated int64 `json:"-"`
}
type BleHeart struct {
Cpu float64
Mem float64
Disk float64
}
func BleHeartBeat() {
for {
time.Sleep(1 * time.Minute)
// 判断60内有无通讯
if len(m) != 0 {
continue
}
percent, _ := cpu.Percent(time.Second, false)
memInfo, _ := mem.VirtualMemory()
parts, _ := disk.Partitions(true)
diskInfo, _ := disk.Usage(parts[0].Mountpoint)
heart := &BleHeart{
Cpu: percent[0],
Mem: memInfo.UsedPercent,
Disk: diskInfo.UsedPercent,
}
ht, err := json.Marshal(heart)
if err != nil {
logrus.Println("json.Marshal: ", err.Error())
continue
}
reader := strings.NewReader(string(ht))
// 发送请求
url := fmt.Sprintf("%s/heart", viper.GetString("srv.host"))
client := &http.Client{}
//生成要访问的url
//提交请求
reqest, err := http.NewRequest("POST", url, reader)
//增加header选项
reqest.Header.Set("token", token)
reqest.Header.Set("Content-Type", "application/json;charset=UTF-8")
if err != nil {
logrus.WithFields(logrus.Fields{
"func": "BleMessagePush",
}).Warnf("%s", err.Error())
continue
}
//处理返回结果
resp, err := client.Do(reqest)
if err != nil {
logrus.WithFields(logrus.Fields{
"func": "BleMessagePush",
}).Warnf("%s", err.Error())
continue
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
logrus.Println("ioutil.ReadAll:", err.Error())
continue
}
logrus.Println("heart", string(body))
// 解析返回值,正确时添加入内存
i := make(map[string]interface{}, 0)
err = json.Unmarshal(body, &i)
if err != nil {
logrus.Println("err: ", err.Error())
continue
}
if i["msg"] != "ok" {
logrus.WithFields(logrus.Fields{
"func": "BleHeartBeat",
}).Warnf("%s", errors.New("Push Heart Fail"))
continue
}
// 没有通讯发送请求cpu内存磁盘占用率
}
}
type BeaconAprilBag struct {
VFirmware string `json:"v-firmware"`
MID uint `json:"mid"`
Time int64 `json:"time"`
IP string `json:"ip"`
Mac string `json:"mac"`
Devices []byte `json:"devices"`
}
type BeaconApril struct {
AdvType string
Mac string
Rssi string
AdvertisementData string
}
// func NewiBeacon(data []byte, mac string) (*IBeancon, error) {
// // bytes.Split()
// if len(data) < 25 || binary.BigEndian.Uint32(data) != 0x4c000215 {
// return nil, errors.New("not an iBeacon")
// }
// beacon := new(IBeancon)
// beacon.DeviceID = blespril.Mac
// beacon.HappenTime = time.Now()
// beacon.Updated = time.Now().Unix()
// return beacon, nil
// }
// 清除缓存
func BleCacheClear() {
t := viper.GetInt64("option.interval")
if t < 30 {
t = 30
}
for {
now := time.Now().Unix()
for k, v := range m {
if now-v.Updated > t {
delete(m, k)
}
}
time.Sleep(time.Duration(t/5) * time.Second)
}
}
// 蓝牙解密
func BleDecode(data []interface{}) []*BeaconApril {
bles := make([]*BeaconApril, 0)
for _, val := range data {
vals := strings.ToUpper(hex.EncodeToString(val.([]byte)))
bles = append(bles, &BeaconApril{
AdvType: vals[0:2],
Mac: vals[2:14],
Rssi: vals[14:16],
AdvertisementData: vals[16:],
})
}
return bles
}