You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

163 lines
4.3 KiB

package main
import (
"encoding/json"
"fmt"
mqtt "github.com/eclipse/paho.mqtt.golang"
"github.com/gin-gonic/gin"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql"
"io/ioutil"
"log"
"math/rand"
"net/http"
"strconv"
"time"
)
var client mqtt.Client
var db *gorm.DB
var conf Config
type DeviceInfo struct {
ID int64 `json:"id"`
DevEui string `json:"devEUI"`
DevAddr string `json:"devAddr"`
Username string `json:"username"`
CreateAt time.Time `json:"createAt"`
}
type Config struct {
Server struct {
Port string
}
DB struct {
Host string
Port int
User string
Password string
Name string
LogMode bool
}
MQTT struct {
Server string
Topic string
}
}
func loadConfig(filename string, c *Config) error {
data, err := ioutil.ReadFile(filename)
if err != nil {
return nil
}
err = json.Unmarshal(data, c)
if err != nil {
return err
}
return nil
}
func Krand(size int, kind int) []byte {
ikind, kinds, result := kind, [][]int{[]int{10, 48}, []int{26, 97}, []int{26, 65}}, make([]byte, size)
is_all := kind > 2 || kind < 0
for i :=0; i < size; i++ {
if is_all { // random ikind
ikind = rand.Intn(3)
}
scope, base := kinds[ikind][0], kinds[ikind][1]
result[i] = uint8(base+rand.Intn(scope))
}
return result
}
func Setup(c *Config) {
var err error
dsn := fmt.Sprintf("%s:%s@(%s:%d)/%s?charset=utf8&parseTime=True&loc=Local", c.DB.User, c.DB.Password, c.DB.Host, c.DB.Port,c.DB.Name)
db, err = gorm.Open("mysql", dsn)
if err != nil {
panic(err)
}
db.LogMode(c.DB.LogMode)
db.AutoMigrate(&DeviceInfo{})
db.Model(&DeviceInfo{}).AddUniqueIndex("idx_dev_eui","dev_eui")
db.Model(&DeviceInfo{}).AddUniqueIndex("idx_dev_addr", "dev_addr")
db.Model(&DeviceInfo{}).AddIndex("idx_create_at", "create_at")
opts := mqtt.NewClientOptions().AddBroker(c.MQTT.Server).SetClientID("deviceIDServer_"+string(Krand(16,3)))
client = mqtt.NewClient(opts)
if token := client.Connect(); token.Wait() && token.Error() != nil {
panic(token.Error())
}
}
func PostDevice(c *gin.Context) {
var device DeviceInfo
device.CreateAt = time.Now()
if err := c.BindJSON(&device); err != nil {
log.Println("bind json error: ",err)
c.JSON(http.StatusOK,gin.H{"code":-1,"msg": err.Error()})
return
}
if err := db.Create(&device).Error; err != nil {
log.Println("db insert error: ",err)
c.JSON(http.StatusOK,gin.H{"code":-1,"msg": err.Error()})
return
}
data,_ := json.Marshal(device)
token := client.Publish(conf.MQTT.Topic,0,false,data)
if token.Wait() && token.Error() != nil {
log.Println("mqtt publish error: ",token.Error())
c.JSON(http.StatusOK,gin.H{"code":-1,"msg": token.Error().Error()})
return
}
log.Println("devEUI: "+ device.DevEui + " post success")
c.JSON(http.StatusOK,gin.H{"code":0,"msg": "OK"})
return
}
func GetDevice(c *gin.Context) {
devEui := c.Query("dev_eui")
limit,_ := strconv.Atoi(c.DefaultQuery("limit","10"))
offset,_ := strconv.Atoi(c.DefaultQuery("offset","0"))
total := 0
var deviceInfos []DeviceInfo
devEui = "%" + devEui + "%"
db.Model(&DeviceInfo{}).Where("dev_eui like ?", devEui).Count(&total)
err := db.Where("dev_eui like ?",devEui).Limit(limit).Offset(offset).Order("create_at desc").Find(&deviceInfos).Error
if err != nil {
log.Println("query db error",err)
c.JSON(http.StatusOK,gin.H{"code":-1,"msg": err.Error()})
} else {
c.JSON(http.StatusOK,gin.H{"code":0,"msg": "OK","data":gin.H{"total": total, "result": deviceInfos}})
}
}
func DelDevice(c *gin.Context) {
id,err := strconv.Atoi(c.Param("id"))
if err != nil{
log.Println("param error",err)
c.JSON(http.StatusOK,gin.H{"code":-1,"msg": err.Error()})
}
if err = db.Delete(&DeviceInfo{},"id = ?", id).Error;err != nil {
log.Println("del id error",err)
c.JSON(http.StatusOK,gin.H{"code":-1,"msg": err.Error()})
} else {
c.JSON(http.StatusOK,gin.H{"code":0,"msg": "OK"})
}
}
func main() {
err := loadConfig("./config.json",&conf)
if err != nil {
panic(err)
}
Setup(&conf)
gin.SetMode(gin.ReleaseMode)
engine := gin.Default()
engine.GET("/device/info", GetDevice)
engine.POST("/device/info", PostDevice)
engine.DELETE("/device/:id",DelDevice)
log.Println("start deviceIDServer port " + conf.Server.Port)
err = engine.Run(":" + conf.Server.Port)
if err != nil {
panic(err)
}
_ = db.Close()
}