lihua
5 years ago
20 changed files with 2494 additions and 1 deletions
@ -0,0 +1,12 @@ |
|||
{ |
|||
"otaa": false, |
|||
"gatewayId": "0102030405060708", |
|||
"devEui": "6ef1881ba5541419", |
|||
"devAddr": "0c18699", |
|||
"appKey": "", |
|||
"appSKey": "33998df974421457437d986eff739ffa", |
|||
"nwkSKey": "33998df974421457437d986eff739ffa", |
|||
"fPort": 2, |
|||
"fCnt": 0, |
|||
"freq": 470.3 |
|||
} |
@ -0,0 +1,838 @@ |
|||
package main |
|||
|
|||
import ( |
|||
"LoRaDTUMock/model" |
|||
"LoRaDTUMock/packets" |
|||
"bytes" |
|||
"crypto/aes" |
|||
"crypto/tls" |
|||
"crypto/x509" |
|||
"encoding/hex" |
|||
"encoding/json" |
|||
"fmt" |
|||
"github.com/brocaar/loraserver/api/gw" |
|||
"github.com/brocaar/lorawan" |
|||
paho "github.com/eclipse/paho.mqtt.golang" |
|||
"github.com/golang/protobuf/proto" |
|||
"github.com/lxn/walk" |
|||
. "github.com/lxn/walk/declarative" |
|||
"github.com/lxn/win" |
|||
"github.com/pkg/errors" |
|||
"io/ioutil" |
|||
"math/rand" |
|||
"os" |
|||
"syscall" |
|||
"time" |
|||
) |
|||
|
|||
type ConnectConfig struct { |
|||
Host string `json:"host"` |
|||
Port int `json:"port"` |
|||
Username string `json:"username"` |
|||
Password string `json:"password"` |
|||
CACert string `json:"ca_cert"` |
|||
TLSCert string `json:"tls_cert"` |
|||
TLSKey string `json:"tls_key"` |
|||
} |
|||
|
|||
type DTUConfig struct { |
|||
OTAA bool `json:"otaa"` |
|||
GatewayId string `json:"gatewayId"` |
|||
DevEui string `json:"devEui"` |
|||
DevAddr string `json:"devAddr"` |
|||
AppKey string `json:"appKey"` |
|||
AppSKey string `json:"appSKey"` |
|||
NwkSKey string `json:"nwkSKey"` |
|||
FPort uint8 `json:"fPort"` |
|||
FCnt uint32 `json:"fCnt"` |
|||
Freq float64 `json:"freq"` |
|||
msg []byte |
|||
devNonce lorawan.DevNonce |
|||
} |
|||
|
|||
type DTUMainWindow struct { |
|||
*walk.MainWindow |
|||
mqttClient paho.Client |
|||
upModel *model.DTUUpModel |
|||
downModel *model.DTUDownModel |
|||
upTv,downTv *walk.TableView |
|||
host,username,password *walk.LineEdit |
|||
port *walk.NumberEdit |
|||
connect, disconnect,caConf,send *walk.PushButton |
|||
msg *walk.TextEdit |
|||
ssl *walk.CheckBox |
|||
connConf ConnectConfig |
|||
dtuConf DTUConfig |
|||
connConfFileName string |
|||
dtuConfFileName string |
|||
} |
|||
func BytesToString(b []byte) string { |
|||
_,err := syscall.UTF16FromString(string(b)) |
|||
if err == nil { |
|||
return string(b) |
|||
} |
|||
return "" |
|||
} |
|||
func main() { |
|||
mw := &DTUMainWindow{upModel: model.NewDTUUpModel(),downModel:model.NewDTUDownModel()} |
|||
maxWidth := int(win.GetSystemMetrics(win.SM_CXSCREEN)) - 200 |
|||
maxHeight := int(win.GetSystemMetrics(win.SM_CYSCREEN)) - 100 |
|||
err := MainWindow{ |
|||
AssignTo: &mw.MainWindow, |
|||
Title: "LoRaDTUMock", |
|||
//Icon: "test.ico",
|
|||
Size: Size{maxWidth,maxHeight }, |
|||
Layout: VBox{}, |
|||
Children: []Widget{ |
|||
Composite{ |
|||
Layout: HBox{MarginsZero: true}, |
|||
Children: []Widget{ |
|||
Label{Text:"主机/IP:"}, |
|||
LineEdit{AssignTo:&mw.host}, |
|||
Label{Text:"端口:"}, |
|||
NumberEdit{AssignTo:&mw.port,MinSize:Size{Width:50}}, |
|||
Label{Text:"用户名:"}, |
|||
LineEdit{AssignTo:&mw.username}, |
|||
Label{Text:"密码:"}, |
|||
LineEdit{AssignTo:&mw.password,PasswordMode:true}, |
|||
PushButton{Text:"连接", AssignTo: &mw.connect,OnClicked:mw.Connect}, |
|||
PushButton{Text:"断开连接", AssignTo:&mw.disconnect, Enabled:false, OnClicked: mw.Disconnect}, |
|||
CheckBox{Text:"开启SSL/TLS",AssignTo:&mw.ssl,OnClicked:mw.SSL}, |
|||
PushButton{Text:"证书配置",Enabled:false,AssignTo:&mw.caConf,OnClicked: mw.ConnectConfig}, |
|||
PushButton{Text:"终端配置",OnClicked: mw.DTUConfig}, |
|||
PushButton{Text:"发送",AssignTo:&mw.send,OnClicked: mw.Send}, |
|||
}, |
|||
}, |
|||
Composite{ |
|||
Layout: HBox{}, |
|||
Children: []Widget{ |
|||
TableView{ |
|||
AssignTo: &mw.upTv, |
|||
CheckBoxes: true, |
|||
ColumnsOrderable: true, |
|||
MultiSelection: true, |
|||
Columns: []TableViewColumn{ |
|||
{Title: "序号"}, |
|||
{Title: "终端EUI"}, |
|||
{Title: "网关ID"}, |
|||
{Title: "信号强度"}, |
|||
{Title: "信噪比"}, |
|||
{Title: "频率"}, |
|||
{Title: "计数"}, |
|||
{Title: "端口"}, |
|||
{Title: "HEX数据"}, |
|||
{Title: "ASCII数据"}, |
|||
{Title: "时间"}, |
|||
}, |
|||
Model: mw.upModel, |
|||
OnItemActivated: mw.upTvItemActivated, |
|||
}, |
|||
TableView{ |
|||
AssignTo: &mw.downTv, |
|||
CheckBoxes: true, |
|||
ColumnsOrderable: true, |
|||
MultiSelection: true, |
|||
Columns: []TableViewColumn{ |
|||
{Title: "序号"}, |
|||
{Title: "终端EUI"}, |
|||
{Title: "网关ID"}, |
|||
{Title: "频率"}, |
|||
{Title: "计数"}, |
|||
{Title: "端口"}, |
|||
{Title: "HEX数据"}, |
|||
{Title: "ASCII数据"}, |
|||
{Title: "时间"}, |
|||
}, |
|||
Model: mw.downModel, |
|||
OnItemActivated: mw.downTvItemActivated, |
|||
}, |
|||
}, |
|||
}, |
|||
}, |
|||
}.Create() |
|||
if err != nil { |
|||
panic("LoRaDTUMock窗口创建失败") |
|||
} |
|||
_ = mw.port.SetValue(1883) |
|||
dir,_ := os.Getwd() |
|||
mw.connConfFileName = dir + "/LoRaDTUMock.json" |
|||
mw.dtuConfFileName = dir + "/LoRaDTUConf.json" |
|||
data, err := ioutil.ReadFile(mw.connConfFileName) |
|||
if err == nil { |
|||
err = json.Unmarshal(data, &mw.connConf) |
|||
if err != nil { |
|||
msg := "配置文件格式错误:" + err.Error() |
|||
walk.MsgBox(mw, "错误", msg, walk.MsgBoxIconError) |
|||
return |
|||
} |
|||
_ = mw.host.SetText(mw.connConf.Host) |
|||
_ = mw.port.SetValue(float64(mw.connConf.Port)) |
|||
_ = mw.username.SetText(mw.connConf.Username) |
|||
_ = mw.password.SetText(mw.connConf.Password) |
|||
} |
|||
mw.Run() |
|||
} |
|||
|
|||
func newTLSConfig(cafile, certFile, certKeyFile string) (*tls.Config, error) { |
|||
if cafile == "" && certFile == "" && certKeyFile == "" { |
|||
return nil, nil |
|||
} |
|||
|
|||
tlsConfig := &tls.Config{} |
|||
|
|||
// Import trusted certificates from CAfile.pem.
|
|||
if cafile != "" { |
|||
cacert, err := ioutil.ReadFile(cafile) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
certpool := x509.NewCertPool() |
|||
certpool.AppendCertsFromPEM(cacert) |
|||
|
|||
tlsConfig.RootCAs = certpool // RootCAs = certs used to verify server cert.
|
|||
} |
|||
|
|||
// Import certificate and the key
|
|||
if certFile != "" && certKeyFile != "" { |
|||
kp, err := tls.LoadX509KeyPair(certFile, certKeyFile) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
tlsConfig.Certificates = []tls.Certificate{kp} |
|||
} |
|||
|
|||
return tlsConfig, nil |
|||
} |
|||
|
|||
func (mw *DTUMainWindow) Connect() { |
|||
go func() { |
|||
if mw.host.Text() != "" && mw.port.Value() > 0 { |
|||
opts := paho.NewClientOptions() |
|||
serverAddr := fmt.Sprintf("%s:%d",mw.host.Text(),int(mw.port.Value())) |
|||
if mw.ssl.Checked() { |
|||
if mw.connConf.CACert != "" { |
|||
serverAddr = fmt.Sprintf("ssl://%s:%d",mw.host.Text(),int(mw.port.Value())) |
|||
tlsconfig, err := newTLSConfig(mw.connConf.CACert, mw.connConf.TLSCert, mw.connConf.TLSKey) |
|||
if err != nil { |
|||
msg := "证书加载错误:" + err.Error() |
|||
walk.MsgBox(mw, "错误", msg, walk.MsgBoxIconError) |
|||
} |
|||
if tlsconfig != nil { |
|||
opts.SetTLSConfig(tlsconfig) |
|||
} |
|||
}else{ |
|||
msg := "证书未配置,服务端单向认证只需配置CA证书,双向认证还需配置客户端证书及秘钥" |
|||
walk.MsgBox(mw, "错误", msg, walk.MsgBoxIconError) |
|||
return |
|||
} |
|||
} |
|||
opts.AddBroker(serverAddr) |
|||
opts.SetUsername(mw.username.Text()) |
|||
opts.SetPassword(mw.password.Text()) |
|||
opts.SetConnectTimeout(5 * time.Second) |
|||
mw.mqttClient = paho.NewClient(opts) |
|||
token := mw.mqttClient.Connect() |
|||
if token.Wait() && token.Error() == nil { |
|||
mw.connConf.Host = mw.host.Text() |
|||
mw.connConf.Port = int(mw.port.Value()) |
|||
mw.connConf.Username = mw.username.Text() |
|||
mw.connConf.Password = mw.password.Text() |
|||
var confData bytes.Buffer |
|||
d,_ := json.Marshal(&mw.connConf) |
|||
_ = json.Indent(&confData, d, "", "\t") |
|||
_ = ioutil.WriteFile(mw.connConfFileName,confData.Bytes(),0644) |
|||
mw.host.SetEnabled(false) |
|||
mw.port.SetEnabled(false) |
|||
mw.username.SetEnabled(false) |
|||
mw.password.SetEnabled(false) |
|||
mw.disconnect.SetEnabled(true) |
|||
mw.connect.SetEnabled(false) |
|||
mw.caConf.SetEnabled(false) |
|||
topic := "gateway/+/command/#" |
|||
token := mw.mqttClient.Subscribe(topic,0, mw.HandleData) |
|||
if token.Wait() && token.Error() != nil { |
|||
msg := "订阅失败:" + token.Error().Error() |
|||
walk.MsgBox(mw, "错误", msg, walk.MsgBoxIconError) |
|||
} |
|||
}else{ |
|||
msg := "连接失败:" + token.Error().Error() |
|||
walk.MsgBox(mw, "错误", msg, walk.MsgBoxIconError) |
|||
} |
|||
}else{ |
|||
msg := "主机/IP不能为空,端口不能为0" |
|||
walk.MsgBox(mw, "错误", msg, walk.MsgBoxIconError) |
|||
} |
|||
}() |
|||
} |
|||
|
|||
func (mw *DTUMainWindow) Disconnect() { |
|||
mw.connect.SetEnabled(true) |
|||
mw.host.SetEnabled(true) |
|||
mw.port.SetEnabled(true) |
|||
mw.username.SetEnabled(true) |
|||
mw.password.SetEnabled(true) |
|||
mw.disconnect.SetEnabled(false) |
|||
mw.caConf.SetEnabled(true) |
|||
mw.mqttClient.Disconnect(0) |
|||
} |
|||
|
|||
func (mw *DTUMainWindow) DTUConfig() { |
|||
var dlg *walk.Dialog |
|||
var otaa *walk.CheckBox |
|||
var gatewayId,devEUI,devAddr,appKey,appSKey,nwkSKey *walk.LineEdit |
|||
var fPort,fCnt,freq *walk.NumberEdit |
|||
var msg *walk.TextEdit |
|||
var acceptPB, cancelPB *walk.PushButton |
|||
_ = Dialog{ |
|||
Title: "DTU配置", |
|||
Layout: VBox{}, |
|||
AssignTo: &dlg, |
|||
DefaultButton: &acceptPB, |
|||
CancelButton: &cancelPB, |
|||
MinSize: Size{400, 200}, |
|||
Children: []Widget{ |
|||
Composite{ |
|||
Layout:Grid{Columns: 2}, |
|||
Children:[]Widget{ |
|||
Label{Text:"入网方式:"}, |
|||
CheckBox{AssignTo: &otaa,Text:"OTAA入网",OnClicked: func() { |
|||
if otaa.Checked() { |
|||
appKey.SetEnabled(true) |
|||
devAddr.SetEnabled(false) |
|||
appSKey.SetEnabled(false) |
|||
nwkSKey.SetEnabled(false) |
|||
}else{ |
|||
appKey.SetEnabled(false) |
|||
devAddr.SetEnabled(true) |
|||
appSKey.SetEnabled(true) |
|||
nwkSKey.SetEnabled(true) |
|||
} |
|||
}}, |
|||
Label{Text:"网关ID:"}, |
|||
LineEdit{AssignTo:&gatewayId}, |
|||
Label{Text:"终端EUI:"}, |
|||
LineEdit{AssignTo:&devEUI}, |
|||
Label{Text:"终端地址:"}, |
|||
LineEdit{AssignTo:&devAddr}, |
|||
Label{Text:"应用秘钥:"}, |
|||
LineEdit{AssignTo:&appKey,Enabled:false}, |
|||
Label{Text:"应用会话秘钥:"}, |
|||
LineEdit{AssignTo:&appSKey}, |
|||
Label{Text:"网络会话秘钥:"}, |
|||
LineEdit{AssignTo:&nwkSKey}, |
|||
Label{Text:"端口:"}, |
|||
NumberEdit{AssignTo:&fPort}, |
|||
Label{Text:"计数:"}, |
|||
NumberEdit{AssignTo:&fCnt}, |
|||
Label{Text:"频率:"}, |
|||
NumberEdit{AssignTo:&freq,Decimals:2}, |
|||
Label{Text:"消息:"}, |
|||
TextEdit{AssignTo:&msg}, |
|||
}, |
|||
}, |
|||
Composite{ |
|||
Layout: HBox{}, |
|||
Children: []Widget{ |
|||
HSpacer{}, |
|||
PushButton{ |
|||
AssignTo: &acceptPB, |
|||
Text: "确定", |
|||
OnClicked: func() { |
|||
mw.dtuConf.OTAA = otaa.Checked() |
|||
mw.dtuConf.GatewayId = gatewayId.Text() |
|||
mw.dtuConf.DevEui = devEUI.Text() |
|||
mw.dtuConf.DevAddr = devAddr.Text() |
|||
mw.dtuConf.AppKey = appKey.Text() |
|||
mw.dtuConf.AppSKey = appSKey.Text() |
|||
mw.dtuConf.NwkSKey = nwkSKey.Text() |
|||
mw.dtuConf.FPort = uint8(fPort.Value()) |
|||
mw.dtuConf.FCnt = uint32(fCnt.Value()) |
|||
mw.dtuConf.Freq = freq.Value() |
|||
mw.dtuConf.msg = []byte(msg.Text()) |
|||
|
|||
var confData bytes.Buffer |
|||
d,_ := json.Marshal(&mw.dtuConf) |
|||
_ = json.Indent(&confData, d, "", "\t") |
|||
_ = ioutil.WriteFile(mw.dtuConfFileName,confData.Bytes(),0644) |
|||
dlg.Accept() |
|||
}, |
|||
}, |
|||
PushButton{ |
|||
AssignTo: &cancelPB, |
|||
Text: "取消", |
|||
OnClicked: func() { dlg.Cancel() }, |
|||
}, |
|||
}, |
|||
}, |
|||
}, |
|||
}.Create(mw) |
|||
data, err := ioutil.ReadFile(mw.dtuConfFileName) |
|||
if err == nil { |
|||
err = json.Unmarshal(data, &mw.dtuConf) |
|||
if err != nil { |
|||
msg := "配置文件格式错误:" + err.Error() |
|||
walk.MsgBox(mw, "错误", msg, walk.MsgBoxIconError) |
|||
return |
|||
} |
|||
} |
|||
otaa.SetChecked(mw.dtuConf.OTAA) |
|||
_ = gatewayId.SetText(mw.dtuConf.GatewayId) |
|||
_ = devEUI.SetText(mw.dtuConf.DevEui) |
|||
_ = devAddr.SetText(mw.dtuConf.DevAddr) |
|||
_ = appKey.SetText(mw.dtuConf.AppKey) |
|||
_ = appSKey.SetText(mw.dtuConf.AppSKey) |
|||
_ = nwkSKey.SetText(mw.dtuConf.NwkSKey) |
|||
_ = fPort.SetValue(float64(mw.dtuConf.FPort)) |
|||
_ = fCnt.SetValue(float64(mw.dtuConf.FCnt)) |
|||
_ = freq.SetValue(mw.dtuConf.Freq) |
|||
_ = msg.SetText(string(mw.dtuConf.msg)) |
|||
|
|||
dlg.Run() |
|||
} |
|||
func (mw *DTUMainWindow) SSL() { |
|||
if mw.ssl.Checked() { |
|||
mw.caConf.SetEnabled(true) |
|||
}else{ |
|||
mw.caConf.SetEnabled(false) |
|||
} |
|||
} |
|||
|
|||
func (mw *DTUMainWindow) ConnectConfig() { |
|||
var dlg *walk.Dialog |
|||
var caCert,tlsCert,tlsKey *walk.LineEdit |
|||
var acceptPB, cancelPB *walk.PushButton |
|||
_ = Dialog{ |
|||
Title: "连接配置", |
|||
Layout: VBox{}, |
|||
AssignTo: &dlg, |
|||
DefaultButton: &acceptPB, |
|||
CancelButton: &cancelPB, |
|||
MinSize: Size{400, 200}, |
|||
Children: []Widget{ |
|||
Composite{ |
|||
Layout:Grid{Columns: 3}, |
|||
Children:[]Widget{ |
|||
Label{Text:"CA证书:"}, |
|||
LineEdit{Text:Bind("CACert"),AssignTo:&caCert}, |
|||
PushButton{Text:"打开",OnClicked: func() { |
|||
dlg := new(walk.FileDialog) |
|||
dlg.Title = "请选择CA证书" |
|||
dlg.Filter = "CA证书 (*.crt)|*.crt|所有文件 (*.*)|*.*" |
|||
if ok, err := dlg.ShowOpen(mw); err != nil { |
|||
return |
|||
} else if !ok { |
|||
return |
|||
} |
|||
_ = caCert.SetText(dlg.FilePath) |
|||
}}, |
|||
Label{Text:"客户端证书:"}, |
|||
LineEdit{Text:Bind("TLSCert"),AssignTo:&tlsCert}, |
|||
PushButton{Text:"打开",OnClicked: func() { |
|||
dlg := new(walk.FileDialog) |
|||
dlg.Title = "请选择客户端证书" |
|||
dlg.Filter = "客户端证书 (*.crt)|*.crt|所有文件 (*.*)|*.*" |
|||
if ok, err := dlg.ShowOpen(mw); err != nil { |
|||
return |
|||
} else if !ok { |
|||
return |
|||
} |
|||
_ = tlsCert.SetText(dlg.FilePath) |
|||
}}, |
|||
Label{Text:"客户端证书秘钥:"}, |
|||
LineEdit{Text:Bind("TLSKey"),AssignTo:&tlsKey}, |
|||
PushButton{Text:"打开",OnClicked: func() { |
|||
dlg := new(walk.FileDialog) |
|||
dlg.Title = "请选择客户端证书秘钥" |
|||
dlg.Filter = "客户端证书秘钥 (*.key)|*.key|所有文件 (*.*)|*.*" |
|||
if ok, err := dlg.ShowOpen(mw); err != nil { |
|||
return |
|||
} else if !ok { |
|||
return |
|||
} |
|||
_ = tlsKey.SetText(dlg.FilePath) |
|||
}}, |
|||
}, |
|||
}, |
|||
Composite{ |
|||
Layout: HBox{}, |
|||
Children: []Widget{ |
|||
HSpacer{}, |
|||
PushButton{ |
|||
AssignTo: &acceptPB, |
|||
Text: "确定", |
|||
OnClicked: func() { |
|||
mw.connConf.CACert = caCert.Text() |
|||
mw.connConf.TLSCert = tlsCert.Text() |
|||
mw.connConf.TLSKey = tlsKey.Text() |
|||
dlg.Accept() |
|||
}, |
|||
}, |
|||
PushButton{ |
|||
AssignTo: &cancelPB, |
|||
Text: "取消", |
|||
OnClicked: func() { dlg.Cancel() }, |
|||
}, |
|||
}, |
|||
}, |
|||
}, |
|||
}.Create(mw) |
|||
_ = caCert.SetText(mw.connConf.CACert) |
|||
_ = tlsCert.SetText(mw.connConf.TLSCert) |
|||
_ = tlsKey.SetText(mw.connConf.TLSKey) |
|||
dlg.Run() |
|||
} |
|||
|
|||
func (mw *DTUMainWindow) BuildUpData() (*packets.PushDataPacket,*lorawan.PHYPayload) { |
|||
now := time.Now().Round(time.Second) |
|||
compactTS := packets.CompactTime(now) |
|||
tmms := int64(time.Second / time.Millisecond) |
|||
|
|||
var phy lorawan.PHYPayload |
|||
phy.MHDR.MType = lorawan.ConfirmedDataUp |
|||
phy.MHDR.Major = lorawan.LoRaWANR1 |
|||
var mac lorawan.MACPayload |
|||
_ = mac.FHDR.DevAddr.UnmarshalText([]byte(mw.dtuConf.DevAddr)) |
|||
_ = mac.FHDR.FCtrl.UnmarshalBinary([]byte{128}) |
|||
mac.FHDR.FCnt = mw.dtuConf.FCnt |
|||
mac.FPort = &mw.dtuConf.FPort |
|||
var dataPayload lorawan.DataPayload |
|||
_ = dataPayload.UnmarshalBinary(true, mw.dtuConf.msg) |
|||
mac.FRMPayload = []lorawan.Payload{&dataPayload} |
|||
phy.MACPayload = &mac |
|||
var aseKey lorawan.AES128Key |
|||
_ = aseKey.UnmarshalText([]byte(mw.dtuConf.NwkSKey)) |
|||
_ = phy.EncryptFRMPayload(aseKey) |
|||
sf :=[...]string{"SF12","SF11","SF10","SF9","SF8","SF7"} |
|||
var dr uint8 = 5 |
|||
var ch uint8 = 2 |
|||
_ = phy.SetUplinkDataMIC(lorawan.LoRaWAN1_0, 0, dr, ch, aseKey, aseKey) |
|||
data,_ := phy.MarshalBinary() |
|||
var gatewayMac lorawan.EUI64 |
|||
_ = gatewayMac.UnmarshalText([]byte(mw.dtuConf.GatewayId)) |
|||
return &packets.PushDataPacket{ |
|||
ProtocolVersion: packets.ProtocolVersion2, |
|||
RandomToken: uint16(rand.Uint32()), |
|||
GatewayMAC: gatewayMac, |
|||
Payload: packets.PushDataPayload{ |
|||
RXPK: []packets.RXPK{ |
|||
{ |
|||
Time: &compactTS, |
|||
Tmst: 708016819, |
|||
Tmms: &tmms, |
|||
Freq: mw.dtuConf.Freq, |
|||
Chan: ch, |
|||
RFCh: 1, |
|||
Stat: 1, |
|||
Modu: "LORA", |
|||
DatR: packets.DatR{LoRa: sf[dr]+"BW125"}, |
|||
CodR: "4/5", |
|||
RSSI: -51, |
|||
LSNR: 7, |
|||
Size: uint16(len(data)), |
|||
Data: data, |
|||
}, |
|||
}, |
|||
}, |
|||
},&phy |
|||
} |
|||
|
|||
func (mw *DTUMainWindow) BuildJoin() (*packets.PushDataPacket,*lorawan.PHYPayload) { |
|||
now := time.Now().Round(time.Second) |
|||
compactTS := packets.CompactTime(now) |
|||
tmms := int64(time.Second / time.Millisecond) |
|||
var phy lorawan.PHYPayload |
|||
phy.MHDR.MType = lorawan.JoinRequest |
|||
phy.MHDR.Major = lorawan.LoRaWANR1 |
|||
var DevEUI lorawan.EUI64 |
|||
_ = DevEUI.UnmarshalText([]byte(mw.dtuConf.DevEui)) |
|||
mw.dtuConf.devNonce = lorawan.DevNonce(rand.Uint32()) |
|||
phy.MACPayload = &lorawan.JoinRequestPayload{ |
|||
DevEUI: DevEUI, |
|||
JoinEUI: lorawan.EUI64{8, 7, 6, 5, 4, 3, 2, 1}, |
|||
DevNonce: mw.dtuConf.devNonce, |
|||
} |
|||
var aseKey lorawan.AES128Key |
|||
_ = aseKey.UnmarshalText([]byte(mw.dtuConf.AppKey)) |
|||
sf :=[...]string{"SF12","SF11","SF10","SF9","SF8","SF7"} |
|||
var dr uint8 = 5 |
|||
var ch uint8 = 2 |
|||
_ = phy.SetUplinkJoinMIC(aseKey) |
|||
data,_ := phy.MarshalBinary() |
|||
var gatewayMac lorawan.EUI64 |
|||
_ = gatewayMac.UnmarshalText([]byte(mw.dtuConf.GatewayId)) |
|||
return &packets.PushDataPacket{ |
|||
ProtocolVersion: packets.ProtocolVersion2, |
|||
RandomToken: uint16(rand.Uint32()), |
|||
GatewayMAC: gatewayMac, |
|||
Payload: packets.PushDataPayload{ |
|||
RXPK: []packets.RXPK{ |
|||
{ |
|||
Time: &compactTS, |
|||
Tmst: 708016819, |
|||
Tmms: &tmms, |
|||
Freq: mw.dtuConf.Freq, |
|||
Chan: ch, |
|||
RFCh: 1, |
|||
Stat: 1, |
|||
Modu: "LORA", |
|||
DatR: packets.DatR{LoRa: sf[dr]+"BW125"}, |
|||
CodR: "4/5", |
|||
RSSI: -51, |
|||
LSNR: 7, |
|||
Size: uint16(len(data)), |
|||
Data: data, |
|||
}, |
|||
}, |
|||
}, |
|||
},&phy |
|||
} |
|||
|
|||
// getNwkSKey returns the network session key.
|
|||
func getNwkSKey(appkey lorawan.AES128Key, netID lorawan.NetID, joinNonce lorawan.JoinNonce, devNonce lorawan.DevNonce) (lorawan.AES128Key, error) { |
|||
return getSKey(0x01, appkey, netID, joinNonce, devNonce) |
|||
} |
|||
|
|||
// getAppSKey returns the application session key.
|
|||
func getAppSKey(appkey lorawan.AES128Key, netID lorawan.NetID, joinNonce lorawan.JoinNonce, devNonce lorawan.DevNonce) (lorawan.AES128Key, error) { |
|||
return getSKey(0x02, appkey, netID, joinNonce, devNonce) |
|||
} |
|||
|
|||
func getSKey(typ byte, nwkKey lorawan.AES128Key, netID lorawan.NetID,joinNonce lorawan.JoinNonce, devNonce lorawan.DevNonce) (lorawan.AES128Key, error) { |
|||
var key lorawan.AES128Key |
|||
b := make([]byte, 16) |
|||
b[0] = typ |
|||
|
|||
netIDB, err := netID.MarshalBinary() |
|||
if err != nil { |
|||
return key, errors.Wrap(err, "marshal binary error") |
|||
} |
|||
|
|||
joinNonceB, err := joinNonce.MarshalBinary() |
|||
if err != nil { |
|||
return key, errors.Wrap(err, "marshal binary error") |
|||
} |
|||
|
|||
devNonceB, err := devNonce.MarshalBinary() |
|||
if err != nil { |
|||
return key, errors.Wrap(err, "marshal binary error") |
|||
} |
|||
|
|||
copy(b[1:4], joinNonceB) |
|||
copy(b[4:7], netIDB) |
|||
copy(b[7:9], devNonceB) |
|||
|
|||
block, err := aes.NewCipher(nwkKey[:]) |
|||
if err != nil { |
|||
return key, err |
|||
} |
|||
if block.BlockSize() != len(b) { |
|||
return key, fmt.Errorf("block-size of %d bytes is expected", len(b)) |
|||
} |
|||
block.Encrypt(key[:], b) |
|||
|
|||
return key, nil |
|||
} |
|||
|
|||
func MarshalFRMPayload(p *lorawan.MACPayload) ([]byte, error) { |
|||
var out []byte |
|||
var b []byte |
|||
var err error |
|||
for _, fp := range p.FRMPayload { |
|||
if mac, ok := fp.(*lorawan.MACCommand); ok { |
|||
if p.FPort == nil || (p.FPort != nil && *p.FPort != 0) { |
|||
return []byte{}, errors.New("lorawan: a MAC command is only allowed when FPort=0") |
|||
} |
|||
b, err = mac.MarshalBinary() |
|||
} else { |
|||
b, err = fp.MarshalBinary() |
|||
} |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
out = append(out, b...) |
|||
} |
|||
return out, nil |
|||
} |
|||
|
|||
func (mw *DTUMainWindow) HandleData(client paho.Client, message paho.Message){ |
|||
var downlinkFrame gw.DownlinkFrame |
|||
err := proto.Unmarshal(message.Payload(),&downlinkFrame) |
|||
if err == nil { |
|||
packet,err := packets.GetPullRespPacket(packets.ProtocolVersion2, uint16(rand.Uint32()),downlinkFrame) |
|||
if err == nil{ |
|||
var phy lorawan.PHYPayload |
|||
err = phy.UnmarshalBinary(packet.Payload.TXPK.Data) |
|||
if err == nil { |
|||
switch phy.MHDR.MType { |
|||
case lorawan.JoinAccept: |
|||
mw.HandleJoinAccept(&phy) |
|||
case lorawan.ConfirmedDataDown,lorawan.UnconfirmedDataDown: |
|||
mw.HandleDataDown(&phy) |
|||
default: |
|||
fmt.Println("未处理的帧") |
|||
} |
|||
var origData bytes.Buffer |
|||
jsonData,_ := phy.MarshalJSON() |
|||
_ = json.Indent(&origData, jsonData, "", " ") |
|||
dd := &model.DTUDown{ |
|||
Index: mw.downModel.Len() + 1, |
|||
DevEUI: mw.dtuConf.DevEui, |
|||
DevAddr: mw.dtuConf.DevAddr, |
|||
GatewayID: hex.EncodeToString(downlinkFrame.TxInfo.GatewayId), |
|||
Time:time.Now().Format("2006-01-02 15:04:05"), |
|||
OrigData:origData.String(), |
|||
} |
|||
if phy.MHDR.MType == lorawan.ConfirmedDataDown || phy.MHDR.MType == lorawan.UnconfirmedDataDown { |
|||
mpl := phy.MACPayload.(*lorawan.MACPayload) |
|||
if mpl.FPort != nil { |
|||
dd.FPort = *mpl.FPort |
|||
} |
|||
dd.FCnt = mpl.FHDR.FCnt |
|||
p,err := MarshalFRMPayload(mpl) |
|||
if err == nil { |
|||
dd.AsciiData = BytesToString(p) |
|||
dd.HexData = hex.EncodeToString(p) |
|||
} |
|||
} |
|||
mw.downModel.Items = append(mw.downModel.Items, dd) |
|||
mw.downModel.PublishRowsReset() |
|||
_ = mw.downTv.SetSelectedIndexes([]int{}) |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
func (mw *DTUMainWindow) HandleJoinAccept(phy *lorawan.PHYPayload){ |
|||
key := mw.dtuConf.AppKey |
|||
var aseKey lorawan.AES128Key |
|||
_ = aseKey.UnmarshalText([]byte(key)) |
|||
err := phy.DecryptJoinAcceptPayload(aseKey) |
|||
if err != nil { |
|||
fmt.Println(err) |
|||
} |
|||
jap,ok := phy.MACPayload.(*lorawan.JoinAcceptPayload) |
|||
if !ok { |
|||
fmt.Println("lorawan: MACPayload must be of type *JoinAcceptPayload") |
|||
} |
|||
mw.dtuConf.DevAddr = jap.DevAddr.String() |
|||
dn := mw.dtuConf.devNonce |
|||
appSKey,err := getAppSKey(aseKey,jap.HomeNetID,jap.JoinNonce,dn) |
|||
if err == nil { |
|||
mw.dtuConf.AppSKey = appSKey.String() |
|||
fmt.Println(mw.dtuConf.AppSKey) |
|||
} |
|||
nwkSKey,err := getNwkSKey(aseKey,jap.HomeNetID,jap.JoinNonce,dn) |
|||
if err == nil { |
|||
mw.dtuConf.NwkSKey = nwkSKey.String() |
|||
fmt.Println(mw.dtuConf.NwkSKey) |
|||
} |
|||
} |
|||
|
|||
func (mw *DTUMainWindow) HandleDataDown(phy *lorawan.PHYPayload){ |
|||
key := mw.dtuConf.NwkSKey |
|||
var aseKey lorawan.AES128Key |
|||
_ = aseKey.UnmarshalText([]byte(key)) |
|||
err := phy.DecryptFRMPayload(aseKey) |
|||
if err == nil { |
|||
mpl := phy.MACPayload.(*lorawan.MACPayload) |
|||
mw.dtuConf.DevAddr = mpl.FHDR.DevAddr.String() |
|||
} |
|||
} |
|||
|
|||
func (mw *DTUMainWindow) PushData(gatewayEUI string,event string, msg proto.Message) { |
|||
topic := fmt.Sprintf("gateway/%s/event/%s",gatewayEUI,event) |
|||
b, err := proto.Marshal(msg) |
|||
if err != nil { |
|||
fmt.Println("marshal message error") |
|||
} |
|||
|
|||
if token := mw.mqttClient.Publish(topic, 0, false, b); token.Wait() && token.Error() == nil { |
|||
fmt.Println("mqtt message ok") |
|||
}else{ |
|||
fmt.Println("mqtt message error") |
|||
} |
|||
} |
|||
|
|||
func (mw *DTUMainWindow) Send(){ |
|||
if mw.dtuConf.OTAA && mw.dtuConf.DevAddr == ""{ |
|||
packet,phy := mw.BuildJoin() |
|||
var origData bytes.Buffer |
|||
jsonData,_ := phy.MarshalJSON() |
|||
_ = json.Indent(&origData, jsonData, "", " ") |
|||
du := &model.DTUUp{ |
|||
Index:mw.upModel.Len() + 1, |
|||
DevEUI:mw.dtuConf.DevEui, |
|||
MType:phy.MHDR.MType.String(), |
|||
GatewayID:mw.dtuConf.GatewayId, |
|||
Rssi:packet.Payload.RXPK[0].RSSI, |
|||
LoRaSNR:packet.Payload.RXPK[0].LSNR, |
|||
Frequency:packet.Payload.RXPK[0].Freq, |
|||
Time:time.Now().Format("2006-01-02 15:04:05"), |
|||
OrigData:origData.String(), |
|||
} |
|||
mw.upModel.Items = append(mw.upModel.Items, du) |
|||
mw.upModel.PublishRowsReset() |
|||
_ = mw.upTv.SetSelectedIndexes([]int{}) |
|||
frames,_:= packet.GetUplinkFrames(true,false) |
|||
for j := range frames { |
|||
mw.PushData(mw.dtuConf.GatewayId,"up",&frames[j]) |
|||
} |
|||
fmt.Println("push join ") |
|||
for cnt := 0;mw.dtuConf.DevAddr == "" && cnt < 5;cnt ++ { |
|||
time.Sleep(time.Second) |
|||
} |
|||
if mw.dtuConf.DevAddr != "" { |
|||
fmt.Println("join ok") |
|||
}else{ |
|||
fmt.Println("join failed") |
|||
return |
|||
} |
|||
} |
|||
packet,phy := mw.BuildUpData() |
|||
var origData bytes.Buffer |
|||
jsonData,_ := phy.MarshalJSON() |
|||
_ = json.Indent(&origData, jsonData, "", " ") |
|||
du := &model.DTUUp{ |
|||
Index:mw.upModel.Len() + 1, |
|||
DevEUI:mw.dtuConf.DevEui, |
|||
MType:phy.MHDR.MType.String(), |
|||
GatewayID:mw.dtuConf.GatewayId, |
|||
Rssi:packet.Payload.RXPK[0].RSSI, |
|||
LoRaSNR:packet.Payload.RXPK[0].LSNR, |
|||
Frequency:packet.Payload.RXPK[0].Freq, |
|||
FCnt:mw.dtuConf.FCnt, |
|||
FPort:mw.dtuConf.FPort, |
|||
HexData:hex.EncodeToString(mw.dtuConf.msg), |
|||
AsciiData:BytesToString(mw.dtuConf.msg), |
|||
Time:time.Now().Format("2006-01-02 15:04:05"), |
|||
OrigData:origData.String(), |
|||
} |
|||
mw.upModel.Items = append(mw.upModel.Items, du) |
|||
mw.upModel.PublishRowsReset() |
|||
_ = mw.upTv.SetSelectedIndexes([]int{}) |
|||
frames,_:= packet.GetUplinkFrames(true,false) |
|||
for j := range frames { |
|||
mw.PushData(mw.dtuConf.GatewayId,"up",&frames[j]) |
|||
} |
|||
mw.dtuConf.FCnt ++ |
|||
var confData bytes.Buffer |
|||
d,_ := json.Marshal(&mw.dtuConf) |
|||
_ = json.Indent(&confData, d, "", "\t") |
|||
_ = ioutil.WriteFile(mw.dtuConfFileName,confData.Bytes(),0644) |
|||
} |
|||
|
|||
func (mw *DTUMainWindow) upTvItemActivated() { |
|||
msg := "" |
|||
for _, i := range mw.upTv.SelectedIndexes() { |
|||
msg += mw.upModel.Items[i].OrigData + "\n" |
|||
} |
|||
walk.MsgBox(mw, "原始数据", msg, walk.MsgBoxOK) |
|||
} |
|||
|
|||
func (mw *DTUMainWindow) downTvItemActivated() { |
|||
msg := "" |
|||
for _, i := range mw.downTv.SelectedIndexes() { |
|||
msg += mw.downModel.Items[i].OrigData + "\n" |
|||
} |
|||
walk.MsgBox(mw, "原始数据", msg, walk.MsgBoxOK) |
|||
} |
@ -0,0 +1,9 @@ |
|||
{ |
|||
"host": "39.98.253.192", |
|||
"port": 1885, |
|||
"username": "", |
|||
"password": "", |
|||
"ca_cert": "", |
|||
"tls_cert": "", |
|||
"tls_key": "" |
|||
} |
@ -0,0 +1,15 @@ |
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> |
|||
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> |
|||
<assemblyIdentity version="1.0.0.0" processorArchitecture="*" name="SomeFunkyNameHere" type="win32"/> |
|||
<dependency> |
|||
<dependentAssembly> |
|||
<assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*"/> |
|||
</dependentAssembly> |
|||
</dependency> |
|||
<application xmlns="urn:schemas-microsoft-com:asm.v3"> |
|||
<windowsSettings> |
|||
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2, PerMonitor</dpiAwareness> |
|||
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">True</dpiAware> |
|||
</windowsSettings> |
|||
</application> |
|||
</assembly> |
@ -0,0 +1,3 @@ |
|||
rem set GOARCH=386 |
|||
set CGO_ENABLED=0 |
|||
go build -ldflags "-H windowsgui" |
@ -0,0 +1,14 @@ |
|||
module LoRaDTUMock |
|||
|
|||
go 1.12 |
|||
|
|||
require ( |
|||
github.com/brocaar/loraserver v0.0.0-20190729122155-2f0bb9c308bc |
|||
github.com/brocaar/lorawan v0.0.0-20190709091804-c3a80883a8fa |
|||
github.com/eclipse/paho.mqtt.golang v1.2.0 |
|||
github.com/golang/protobuf v1.3.2 |
|||
github.com/lxn/walk v0.0.0-20191113135339-bf589de20b3c |
|||
github.com/lxn/win v0.0.0-20191106123917-121afc750dd3 |
|||
github.com/pkg/errors v0.8.1 |
|||
gopkg.in/Knetic/govaluate.v3 v3.0.0 // indirect |
|||
) |
@ -0,0 +1,595 @@ |
|||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= |
|||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= |
|||
cloud.google.com/go v0.37.4/go.mod h1:NHPJ89PdicEuT9hdPXMROBD91xc5uRDxsMtSB16k7hw= |
|||
contrib.go.opencensus.io/exporter/ocagent v0.4.12/go.mod h1:450APlNTSR6FrvC3CTRqYosuDstRB9un7SOx2k/9ckA= |
|||
github.com/Azure/azure-amqp-common-go v1.1.4/go.mod h1:FhZtXirFANw40UXI2ntweO+VOkfaw8s6vZxUiRhLYW8= |
|||
github.com/Azure/azure-sdk-for-go v21.3.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= |
|||
github.com/Azure/azure-sdk-for-go v27.3.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= |
|||
github.com/Azure/azure-service-bus-go v0.5.1/go.mod h1:Tctgev//M0s8G6mdA+ZH9esoIXuiq7qEkxoDLZwfCrA= |
|||
github.com/Azure/go-autorest v11.0.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= |
|||
github.com/Azure/go-autorest v11.1.1+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= |
|||
github.com/Azure/go-autorest/tracing v0.1.0/go.mod h1:ROEEAFwXycQw7Sn3DXNtEedEvdeRAgDr0izn4z5Ij88= |
|||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= |
|||
github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= |
|||
github.com/NickBall/go-aes-key-wrap v0.0.0-20170929221519-1c3aa3e4dfc5/go.mod h1:w5D10RxC0NmPYxmQ438CC1S07zaC1zpvuNW7s5sUk2Q= |
|||
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= |
|||
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= |
|||
github.com/ajg/form v0.0.0-20160822230020-523a5da1a92f/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= |
|||
github.com/alecthomas/kingpin v2.2.6+incompatible/go.mod h1:59OFYbFVLKQKq+mqrL6Rw5bR0c3ACQaawgXx0QYndlE= |
|||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= |
|||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= |
|||
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= |
|||
github.com/apex/log v1.1.0/go.mod h1:yA770aXIDQrhVOIGurT/pVdfCpSq1GQV/auzMN5fzvY= |
|||
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= |
|||
github.com/aws/aws-sdk-go v1.15.64/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM= |
|||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= |
|||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= |
|||
github.com/blakesmith/ar v0.0.0-20150311145944-8bd4349a67f2/go.mod h1:PkYb9DJNAwrSvRx5DYA+gUcOIgTGVMNkfSCbZM8cWpI= |
|||
github.com/brocaar/loraserver v0.0.0-20190729122155-2f0bb9c308bc h1:bum9Ye6oZBx+H1yHqZhlNy9V7CDf/fBCYadMpV9xcng= |
|||
github.com/brocaar/loraserver v0.0.0-20190729122155-2f0bb9c308bc/go.mod h1:nu05fgUCXdcEJQ7KJHMw5lHO5Efxq7j+g4r5g9PryhY= |
|||
github.com/brocaar/loraserver v2.5.0+incompatible h1:Fna4CF0jW2Vl4UpjLIhR5ifW4g+oZD/w3Dq09TiJ8Z8= |
|||
github.com/brocaar/loraserver v2.5.0+incompatible/go.mod h1:VBTim0YtfWAKehjJ6k17jCnG44DzXVdL4iu+hwxg2ik= |
|||
github.com/brocaar/lorawan v0.0.0-20190709091804-c3a80883a8fa h1:UcT94Q1RMA+lTAD0kxDY5RjkhagJgcoAjIKlKvs7A8o= |
|||
github.com/brocaar/lorawan v0.0.0-20190709091804-c3a80883a8fa/go.mod h1:Fm+51pxK6mZoAQjIaWJqPmnRuXecozsM5Mf9c+kr/ko= |
|||
github.com/brocaar/lorawan v0.0.0-20191115102621-6095d473cf60 h1:jecx8QFcsUAWZojNIqOZaoAWFwkBbd3VOHZ3kv6FQxE= |
|||
github.com/brocaar/lorawan v0.0.0-20191115102621-6095d473cf60/go.mod h1:VgyRGAJ/wl1JfqZZmNlCTM8fyaIKF11YvYAGIVtedL8= |
|||
github.com/caarlos0/ctrlc v1.0.0/go.mod h1:CdXpj4rmq0q/1Eb44M9zi2nKB0QraNKuRGYGrrHhcQw= |
|||
github.com/campoy/unique v0.0.0-20180121183637-88950e537e7e/go.mod h1:9IOqJGCPMSc6E5ydlp5NIonxObaeu/Iub/X03EKPVYo= |
|||
github.com/census-instrumentation/opencensus-proto v0.2.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= |
|||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= |
|||
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= |
|||
github.com/cockroachdb/cockroach-go v0.0.0-20181001143604-e0a95dfd547c/go.mod h1:XGLbWH/ujMcbPbhZq52Nv6UrCghb1yGn//133kEsvDk= |
|||
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= |
|||
github.com/codegangsta/negroni v1.0.0/go.mod h1:v0y3T5G7Y1UlFfyxFn/QLRU4a2EuNau2iZY63YTKWo0= |
|||
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= |
|||
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= |
|||
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= |
|||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= |
|||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= |
|||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= |
|||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= |
|||
github.com/dustin/go-humanize v0.0.0-20180713052910-9f541cc9db5d/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= |
|||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= |
|||
github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= |
|||
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= |
|||
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= |
|||
github.com/eclipse/paho.mqtt.golang v1.2.0 h1:1F8mhG9+aO5/xpdtFkW4SxOJB67ukuDC3t2y2qayIX0= |
|||
github.com/eclipse/paho.mqtt.golang v1.2.0/go.mod h1:H9keYFcgq3Qr5OUJm/JZI/i6U7joQ8SYLhZwfeOo6Ts= |
|||
github.com/elazarl/go-bindata-assetfs v1.0.0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4= |
|||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= |
|||
github.com/fatih/structs v1.0.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= |
|||
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= |
|||
github.com/fortytw2/leaktest v1.2.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= |
|||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= |
|||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= |
|||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= |
|||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= |
|||
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= |
|||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= |
|||
github.com/gobuffalo/buffalo v0.12.8-0.20181004233540-fac9bb505aa8/go.mod h1:sLyT7/dceRXJUxSsE813JTQtA3Eb1vjxWfo/N//vXIY= |
|||
github.com/gobuffalo/buffalo v0.13.0/go.mod h1:Mjn1Ba9wpIbpbrD+lIDMy99pQ0H0LiddMIIDGse7qT4= |
|||
github.com/gobuffalo/buffalo-plugins v1.0.2/go.mod h1:pOp/uF7X3IShFHyobahTkTLZaeUXwb0GrUTb9ngJWTs= |
|||
github.com/gobuffalo/buffalo-plugins v1.0.4/go.mod h1:pWS1vjtQ6uD17MVFWf7i3zfThrEKWlI5+PYLw/NaDB4= |
|||
github.com/gobuffalo/buffalo-plugins v1.4.3/go.mod h1:uCzTY0woez4nDMdQjkcOYKanngeUVRO2HZi7ezmAjWY= |
|||
github.com/gobuffalo/buffalo-plugins v1.5.1/go.mod h1:jbmwSZK5+PiAP9cC09VQOrGMZFCa/P0UMlIS3O12r5w= |
|||
github.com/gobuffalo/buffalo-plugins v1.6.4/go.mod h1:/+N1aophkA2jZ1ifB2O3Y9yGwu6gKOVMtUmJnbg+OZI= |
|||
github.com/gobuffalo/buffalo-plugins v1.6.5/go.mod h1:0HVkbgrVs/MnPZ/FOseDMVanCTm2RNcdM0PuXcL1NNI= |
|||
github.com/gobuffalo/buffalo-plugins v1.6.7/go.mod h1:ZGZRkzz2PiKWHs0z7QsPBOTo2EpcGRArMEym6ghKYgk= |
|||
github.com/gobuffalo/buffalo-plugins v1.6.9/go.mod h1:yYlYTrPdMCz+6/+UaXg5Jm4gN3xhsvsQ2ygVatZV5vw= |
|||
github.com/gobuffalo/buffalo-plugins v1.6.11/go.mod h1:eAA6xJIL8OuynJZ8amXjRmHND6YiusVAaJdHDN1Lu8Q= |
|||
github.com/gobuffalo/buffalo-plugins v1.8.2/go.mod h1:9te6/VjEQ7pKp7lXlDIMqzxgGpjlKoAcAANdCgoR960= |
|||
github.com/gobuffalo/buffalo-plugins v1.8.3/go.mod h1:IAWq6vjZJVXebIq2qGTLOdlXzmpyTZ5iJG5b59fza5U= |
|||
github.com/gobuffalo/buffalo-plugins v1.9.4/go.mod h1:grCV6DGsQlVzQwk6XdgcL3ZPgLm9BVxlBmXPMF8oBHI= |
|||
github.com/gobuffalo/buffalo-plugins v1.10.0/go.mod h1:4osg8d9s60txLuGwXnqH+RCjPHj9K466cDFRl3PErHI= |
|||
github.com/gobuffalo/buffalo-plugins v1.11.0/go.mod h1:rtIvAYRjYibgmWhnjKmo7OadtnxuMG5ZQLr25ozAzjg= |
|||
github.com/gobuffalo/buffalo-pop v1.0.5/go.mod h1:Fw/LfFDnSmB/vvQXPvcXEjzP98Tc+AudyNWUBWKCwQ8= |
|||
github.com/gobuffalo/envy v1.6.4/go.mod h1:Abh+Jfw475/NWtYMEt+hnJWRiC8INKWibIMyNt1w2Mc= |
|||
github.com/gobuffalo/envy v1.6.5/go.mod h1:N+GkhhZ/93bGZc6ZKhJLP6+m+tCNPKwgSpH9kaifseQ= |
|||
github.com/gobuffalo/envy v1.6.6/go.mod h1:N+GkhhZ/93bGZc6ZKhJLP6+m+tCNPKwgSpH9kaifseQ= |
|||
github.com/gobuffalo/envy v1.6.7/go.mod h1:N+GkhhZ/93bGZc6ZKhJLP6+m+tCNPKwgSpH9kaifseQ= |
|||
github.com/gobuffalo/envy v1.6.8/go.mod h1:N+GkhhZ/93bGZc6ZKhJLP6+m+tCNPKwgSpH9kaifseQ= |
|||
github.com/gobuffalo/envy v1.6.9/go.mod h1:N+GkhhZ/93bGZc6ZKhJLP6+m+tCNPKwgSpH9kaifseQ= |
|||
github.com/gobuffalo/envy v1.6.10/go.mod h1:X0CFllQjTV5ogsnUrg+Oks2yTI+PU2dGYBJOEI2D1Uo= |
|||
github.com/gobuffalo/envy v1.6.11/go.mod h1:Fiq52W7nrHGDggFPhn2ZCcHw4u/rqXkqo+i7FB6EAcg= |
|||
github.com/gobuffalo/envy v1.6.12/go.mod h1:qJNrJhKkZpEW0glh5xP2syQHH5kgdmgsKss2Kk8PTP0= |
|||
github.com/gobuffalo/events v1.0.3/go.mod h1:Txo8WmqScapa7zimEQIwgiJBvMECMe9gJjsKNPN3uZw= |
|||
github.com/gobuffalo/events v1.0.7/go.mod h1:z8txf6H9jWhQ5Scr7YPLWg/cgXBRj8Q4uYI+rsVCCSQ= |
|||
github.com/gobuffalo/events v1.0.8/go.mod h1:A5KyqT1sA+3GJiBE4QKZibse9mtOcI9nw8gGrDdqYGs= |
|||
github.com/gobuffalo/events v1.1.3/go.mod h1:9yPGWYv11GENtzrIRApwQRMYSbUgCsZ1w6R503fCfrk= |
|||
github.com/gobuffalo/events v1.1.4/go.mod h1:09/YRRgZHEOts5Isov+g9X2xajxdvOAcUuAHIX/O//A= |
|||
github.com/gobuffalo/events v1.1.5/go.mod h1:3YUSzgHfYctSjEjLCWbkXP6djH2M+MLaVRzb4ymbAK0= |
|||
github.com/gobuffalo/events v1.1.7/go.mod h1:6fGqxH2ing5XMb3EYRq9LEkVlyPGs4oO/eLzh+S8CxY= |
|||
github.com/gobuffalo/events v1.1.8/go.mod h1:UFy+W6X6VbCWS8k2iT81HYX65dMtiuVycMy04cplt/8= |
|||
github.com/gobuffalo/events v1.1.9/go.mod h1:/0nf8lMtP5TkgNbzYxR6Bl4GzBy5s5TebgNTdRfRbPM= |
|||
github.com/gobuffalo/fizz v1.0.12/go.mod h1:C0sltPxpYK8Ftvf64kbsQa2yiCZY4RZviurNxXdAKwc= |
|||
github.com/gobuffalo/flect v0.0.0-20180907193754-dc14d8acaf9f/go.mod h1:rCiQgmAE4axgBNl3jZWzS5rETRYTGOsrixTRaCPzNdA= |
|||
github.com/gobuffalo/flect v0.0.0-20181002182613-4571df4b1daf/go.mod h1:rCiQgmAE4axgBNl3jZWzS5rETRYTGOsrixTRaCPzNdA= |
|||
github.com/gobuffalo/flect v0.0.0-20181007231023-ae7ed6bfe683/go.mod h1:rCiQgmAE4axgBNl3jZWzS5rETRYTGOsrixTRaCPzNdA= |
|||
github.com/gobuffalo/flect v0.0.0-20181018182602-fd24a256709f/go.mod h1:rCiQgmAE4axgBNl3jZWzS5rETRYTGOsrixTRaCPzNdA= |
|||
github.com/gobuffalo/flect v0.0.0-20181019110701-3d6f0b585514/go.mod h1:rCiQgmAE4axgBNl3jZWzS5rETRYTGOsrixTRaCPzNdA= |
|||
github.com/gobuffalo/flect v0.0.0-20181024204909-8f6be1a8c6c2/go.mod h1:rCiQgmAE4axgBNl3jZWzS5rETRYTGOsrixTRaCPzNdA= |
|||
github.com/gobuffalo/flect v0.0.0-20181104133451-1f6e9779237a/go.mod h1:rCiQgmAE4axgBNl3jZWzS5rETRYTGOsrixTRaCPzNdA= |
|||
github.com/gobuffalo/flect v0.0.0-20181114183036-47375f6d8328/go.mod h1:0HvNbHdfh+WOvDSIASqJOSxTOWSxCCUF++k/Y53v9rI= |
|||
github.com/gobuffalo/flect v0.0.0-20181210151238-24a2b68e0316/go.mod h1:en58vff74S9b99Eg42Dr+/9yPu437QjlNsO/hBYPuOk= |
|||
github.com/gobuffalo/flect v0.0.0-20190104192022-4af577e09bf2/go.mod h1:en58vff74S9b99Eg42Dr+/9yPu437QjlNsO/hBYPuOk= |
|||
github.com/gobuffalo/flect v0.0.0-20190117212819-a62e61d96794/go.mod h1:397QT6v05LkZkn07oJXXT6y9FCfwC8Pug0WA2/2mE9k= |
|||
github.com/gobuffalo/genny v0.0.0-20180924032338-7af3a40f2252/go.mod h1:tUTQOogrr7tAQnhajMSH6rv1BVev34H2sa1xNHMy94g= |
|||
github.com/gobuffalo/genny v0.0.0-20181003150629-3786a0744c5d/go.mod h1:WAd8HmjMVrnkAZbmfgH5dLBUchsZfqzp/WS5sQz+uTM= |
|||
github.com/gobuffalo/genny v0.0.0-20181005145118-318a41a134cc/go.mod h1:WAd8HmjMVrnkAZbmfgH5dLBUchsZfqzp/WS5sQz+uTM= |
|||
github.com/gobuffalo/genny v0.0.0-20181007153042-b8de7d566757/go.mod h1:+oG5Ljrw04czAHbPXREwaFojJbpUvcIy4DiOnbEJFTA= |
|||
github.com/gobuffalo/genny v0.0.0-20181012161047-33e5f43d83a6/go.mod h1:+oG5Ljrw04czAHbPXREwaFojJbpUvcIy4DiOnbEJFTA= |
|||
github.com/gobuffalo/genny v0.0.0-20181017160347-90a774534246/go.mod h1:+oG5Ljrw04czAHbPXREwaFojJbpUvcIy4DiOnbEJFTA= |
|||
github.com/gobuffalo/genny v0.0.0-20181024195656-51392254bf53/go.mod h1:o9GEH5gn5sCKLVB5rHFC4tq40rQ3VRUzmx6WwmaqISE= |
|||
github.com/gobuffalo/genny v0.0.0-20181025145300-af3f81d526b8/go.mod h1:uZ1fFYvdcP8mu0B/Ynarf6dsGvp7QFIpk/QACUuFUVI= |
|||
github.com/gobuffalo/genny v0.0.0-20181027191429-94d6cfb5c7fc/go.mod h1:x7SkrQQBx204Y+O9EwRXeszLJDTaWN0GnEasxgLrQTA= |
|||
github.com/gobuffalo/genny v0.0.0-20181027195209-3887b7171c4f/go.mod h1:JbKx8HSWICu5zyqWOa0dVV1pbbXOHusrSzQUprW6g+w= |
|||
github.com/gobuffalo/genny v0.0.0-20181106193839-7dcb0924caf1/go.mod h1:x61yHxvbDCgQ/7cOAbJCacZQuHgB0KMSzoYcw5debjU= |
|||
github.com/gobuffalo/genny v0.0.0-20181107223128-f18346459dbe/go.mod h1:utQD3aKKEsdb03oR+Vi/6ztQb1j7pO10N3OBoowRcSU= |
|||
github.com/gobuffalo/genny v0.0.0-20181114215459-0a4decd77f5d/go.mod h1:kN2KZ8VgXF9VIIOj/GM0Eo7YK+un4Q3tTreKOf0q1ng= |
|||
github.com/gobuffalo/genny v0.0.0-20181119162812-e8ff4adce8bb/go.mod h1:BA9htSe4bZwBDJLe8CUkoqkypq3hn3+CkoHqVOW718E= |
|||
github.com/gobuffalo/genny v0.0.0-20181127225641-2d959acc795b/go.mod h1:l54xLXNkteX/PdZ+HlgPk1qtcrgeOr3XUBBPDbH+7CQ= |
|||
github.com/gobuffalo/genny v0.0.0-20181128191930-77e34f71ba2a/go.mod h1:FW/D9p7cEEOqxYA71/hnrkOWm62JZ5ZNxcNIVJEaWBU= |
|||
github.com/gobuffalo/genny v0.0.0-20181203165245-fda8bcce96b1/go.mod h1:wpNSANu9UErftfiaAlz1pDZclrYzLtO5lALifODyjuM= |
|||
github.com/gobuffalo/genny v0.0.0-20181203201232-849d2c9534ea/go.mod h1:wpNSANu9UErftfiaAlz1pDZclrYzLtO5lALifODyjuM= |
|||
github.com/gobuffalo/genny v0.0.0-20181206121324-d6fb8a0dbe36/go.mod h1:wpNSANu9UErftfiaAlz1pDZclrYzLtO5lALifODyjuM= |
|||
github.com/gobuffalo/genny v0.0.0-20181207164119-84844398a37d/go.mod h1:y0ysCHGGQf2T3vOhCrGHheYN54Y/REj0ayd0Suf4C/8= |
|||
github.com/gobuffalo/genny v0.0.0-20181211165820-e26c8466f14d/go.mod h1:sHnK+ZSU4e2feXP3PA29ouij6PUEiN+RCwECjCTB3yM= |
|||
github.com/gobuffalo/genny v0.0.0-20190104222617-a71664fc38e7/go.mod h1:QPsQ1FnhEsiU8f+O0qKWXz2RE4TiDqLVChWkBuh1WaY= |
|||
github.com/gobuffalo/genny v0.0.0-20190112155932-f31a84fcacf5/go.mod h1:CIaHCrSIuJ4il6ka3Hub4DR4adDrGoXGEEt2FbBxoIo= |
|||
github.com/gobuffalo/github_flavored_markdown v1.0.4/go.mod h1:uRowCdK+q8d/RF0Kt3/DSalaIXbb0De/dmTqMQdkQ4I= |
|||
github.com/gobuffalo/github_flavored_markdown v1.0.5/go.mod h1:U0643QShPF+OF2tJvYNiYDLDGDuQmJZXsf/bHOJPsMY= |
|||
github.com/gobuffalo/github_flavored_markdown v1.0.7/go.mod h1:w93Pd9Lz6LvyQXEG6DktTPHkOtCbr+arAD5mkwMzXLI= |
|||
github.com/gobuffalo/httptest v1.0.2/go.mod h1:7T1IbSrg60ankme0aDLVnEY0h056g9M1/ZvpVThtB7E= |
|||
github.com/gobuffalo/licenser v0.0.0-20180924033006-eae28e638a42/go.mod h1:Ubo90Np8gpsSZqNScZZkVXXAo5DGhTb+WYFIjlnog8w= |
|||
github.com/gobuffalo/licenser v0.0.0-20181025145548-437d89de4f75/go.mod h1:x3lEpYxkRG/XtGCUNkio+6RZ/dlOvLzTI9M1auIwFcw= |
|||
github.com/gobuffalo/licenser v0.0.0-20181027200154-58051a75da95/go.mod h1:BzhaaxGd1tq1+OLKObzgdCV9kqVhbTulxOpYbvMQWS0= |
|||
github.com/gobuffalo/licenser v0.0.0-20181109171355-91a2a7aac9a7/go.mod h1:m+Ygox92pi9bdg+gVaycvqE8RVSjZp7mWw75+K5NPHk= |
|||
github.com/gobuffalo/licenser v0.0.0-20181128165715-cc7305f8abed/go.mod h1:oU9F9UCE+AzI/MueCKZamsezGOOHfSirltllOVeRTAE= |
|||
github.com/gobuffalo/licenser v0.0.0-20181203160806-fe900bbede07/go.mod h1:ph6VDNvOzt1CdfaWC+9XwcBnlSTBz2j49PBwum6RFaU= |
|||
github.com/gobuffalo/licenser v0.0.0-20181211173111-f8a311c51159/go.mod h1:ve/Ue99DRuvnTaLq2zKa6F4KtHiYf7W046tDjuGYPfM= |
|||
github.com/gobuffalo/logger v0.0.0-20181022175615-46cfb361fc27/go.mod h1:8sQkgyhWipz1mIctHF4jTxmJh1Vxhp7mP8IqbljgJZo= |
|||
github.com/gobuffalo/logger v0.0.0-20181027144941-73d08d2bb969/go.mod h1:7uGg2duHKpWnN4+YmyKBdLXfhopkAdVM6H3nKbyFbz8= |
|||
github.com/gobuffalo/logger v0.0.0-20181027193913-9cf4dd0efe46/go.mod h1:7uGg2duHKpWnN4+YmyKBdLXfhopkAdVM6H3nKbyFbz8= |
|||
github.com/gobuffalo/logger v0.0.0-20181109185836-3feeab578c17/go.mod h1:oNErH0xLe+utO+OW8ptXMSA5DkiSEDW1u3zGIt8F9Ew= |
|||
github.com/gobuffalo/logger v0.0.0-20181117211126-8e9b89b7c264/go.mod h1:5etB91IE0uBlw9k756fVKZJdS+7M7ejVhmpXXiSFj0I= |
|||
github.com/gobuffalo/logger v0.0.0-20181127160119-5b956e21995c/go.mod h1:+HxKANrR9VGw9yN3aOAppJKvhO05ctDi63w4mDnKv2U= |
|||
github.com/gobuffalo/makr v1.1.5/go.mod h1:Y+o0btAH1kYAMDJW/TX3+oAXEu0bmSLLoC9mIFxtzOw= |
|||
github.com/gobuffalo/mapi v1.0.0/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc= |
|||
github.com/gobuffalo/mapi v1.0.1/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc= |
|||
github.com/gobuffalo/meta v0.0.0-20181018155829-df62557efcd3/go.mod h1:XTTOhwMNryif3x9LkTTBO/Llrveezd71u3quLd0u7CM= |
|||
github.com/gobuffalo/meta v0.0.0-20181018192820-8c6cef77dab3/go.mod h1:E94EPzx9NERGCY69UWlcj6Hipf2uK/vnfrF4QD0plVE= |
|||
github.com/gobuffalo/meta v0.0.0-20181025145500-3a985a084b0a/go.mod h1:YDAKBud2FP7NZdruCSlmTmDOZbVSa6bpK7LJ/A/nlKg= |
|||
github.com/gobuffalo/meta v0.0.0-20181114191255-b130ebedd2f7/go.mod h1:K6cRZ29ozr4Btvsqkjvg5nDFTLOgTqf03KA70Ks0ypE= |
|||
github.com/gobuffalo/meta v0.0.0-20181127070345-0d7e59dd540b/go.mod h1:RLO7tMvE0IAKAM8wny1aN12pvEKn7EtkBLkUZR00Qf8= |
|||
github.com/gobuffalo/meta v0.0.0-20190120163247-50bbb1fa260d/go.mod h1:KKsH44nIK2gA8p0PJmRT9GvWJUdphkDUA8AJEvFWiqM= |
|||
github.com/gobuffalo/mw-basicauth v1.0.3/go.mod h1:dg7+ilMZOKnQFHDefUzUHufNyTswVUviCBgF244C1+0= |
|||
github.com/gobuffalo/mw-contenttype v0.0.0-20180802152300-74f5a47f4d56/go.mod h1:7EvcmzBbeCvFtQm5GqF9ys6QnCxz2UM1x0moiWLq1No= |
|||
github.com/gobuffalo/mw-csrf v0.0.0-20180802151833-446ff26e108b/go.mod h1:sbGtb8DmDZuDUQoxjr8hG1ZbLtZboD9xsn6p77ppcHo= |
|||
github.com/gobuffalo/mw-forcessl v0.0.0-20180802152810-73921ae7a130/go.mod h1:JvNHRj7bYNAMUr/5XMkZaDcw3jZhUZpsmzhd//FFWmQ= |
|||
github.com/gobuffalo/mw-i18n v0.0.0-20180802152014-e3060b7e13d6/go.mod h1:91AQfukc52A6hdfIfkxzyr+kpVYDodgAeT5cjX1UIj4= |
|||
github.com/gobuffalo/mw-paramlogger v0.0.0-20181005191442-d6ee392ec72e/go.mod h1:6OJr6VwSzgJMqWMj7TYmRUqzNe2LXu/W1rRW4MAz/ME= |
|||
github.com/gobuffalo/mw-tokenauth v0.0.0-20181001105134-8545f626c189/go.mod h1:UqBF00IfKvd39ni5+yI5MLMjAf4gX7cDKN/26zDOD6c= |
|||
github.com/gobuffalo/packd v0.0.0-20181027182251-01ad393492c8/go.mod h1:SmdBdhj6uhOsg1Ui4SFAyrhuc7U4VCildosO5IDJ3lc= |
|||
github.com/gobuffalo/packd v0.0.0-20181027190505-aafc0d02c411/go.mod h1:SmdBdhj6uhOsg1Ui4SFAyrhuc7U4VCildosO5IDJ3lc= |
|||
github.com/gobuffalo/packd v0.0.0-20181027194105-7ae579e6d213/go.mod h1:SmdBdhj6uhOsg1Ui4SFAyrhuc7U4VCildosO5IDJ3lc= |
|||
github.com/gobuffalo/packd v0.0.0-20181031195726-c82734870264/go.mod h1:Yf2toFaISlyQrr5TfO3h6DB9pl9mZRmyvBGQb/aQ/pI= |
|||
github.com/gobuffalo/packd v0.0.0-20181104210303-d376b15f8e96/go.mod h1:Yf2toFaISlyQrr5TfO3h6DB9pl9mZRmyvBGQb/aQ/pI= |
|||
github.com/gobuffalo/packd v0.0.0-20181111195323-b2e760a5f0ff/go.mod h1:Yf2toFaISlyQrr5TfO3h6DB9pl9mZRmyvBGQb/aQ/pI= |
|||
github.com/gobuffalo/packd v0.0.0-20181114190715-f25c5d2471d7/go.mod h1:Yf2toFaISlyQrr5TfO3h6DB9pl9mZRmyvBGQb/aQ/pI= |
|||
github.com/gobuffalo/packd v0.0.0-20181124090624-311c6248e5fb/go.mod h1:Foenia9ZvITEvG05ab6XpiD5EfBHPL8A6hush8SJ0o8= |
|||
github.com/gobuffalo/packd v0.0.0-20181207120301-c49825f8f6f4/go.mod h1:LYc0TGKFBBFTRC9dg2pcRcMqGCTMD7T2BIMP7OBuQAA= |
|||
github.com/gobuffalo/packd v0.0.0-20181212173646-eca3b8fd6687/go.mod h1:LYc0TGKFBBFTRC9dg2pcRcMqGCTMD7T2BIMP7OBuQAA= |
|||
github.com/gobuffalo/packr v1.13.7/go.mod h1:KkinLIn/n6+3tVXMwg6KkNvWwVsrRAz4ph+jgpk3Z24= |
|||
github.com/gobuffalo/packr v1.15.0/go.mod h1:t5gXzEhIviQwVlNx/+3SfS07GS+cZ2hn76WLzPp6MGI= |
|||
github.com/gobuffalo/packr v1.15.1/go.mod h1:IeqicJ7jm8182yrVmNbM6PR4g79SjN9tZLH8KduZZwE= |
|||
github.com/gobuffalo/packr v1.19.0/go.mod h1:MstrNkfCQhd5o+Ct4IJ0skWlxN8emOq8DsoT1G98VIU= |
|||
github.com/gobuffalo/packr v1.20.0/go.mod h1:JDytk1t2gP+my1ig7iI4NcVaXr886+N0ecUga6884zw= |
|||
github.com/gobuffalo/packr v1.21.0/go.mod h1:H00jGfj1qFKxscFJSw8wcL4hpQtPe1PfU2wa6sg/SR0= |
|||
github.com/gobuffalo/packr v1.22.0/go.mod h1:Qr3Wtxr3+HuQEwWqlLnNW4t1oTvK+7Gc/Rnoi/lDFvA= |
|||
github.com/gobuffalo/packr/v2 v2.0.0-rc.8/go.mod h1:y60QCdzwuMwO2R49fdQhsjCPv7tLQFR0ayzxxla9zes= |
|||
github.com/gobuffalo/packr/v2 v2.0.0-rc.9/go.mod h1:fQqADRfZpEsgkc7c/K7aMew3n4aF1Kji7+lIZeR98Fc= |
|||
github.com/gobuffalo/packr/v2 v2.0.0-rc.10/go.mod h1:4CWWn4I5T3v4c1OsJ55HbHlUEKNWMITG5iIkdr4Px4w= |
|||
github.com/gobuffalo/packr/v2 v2.0.0-rc.11/go.mod h1:JoieH/3h3U4UmatmV93QmqyPUdf4wVM9HELaHEu+3fk= |
|||
github.com/gobuffalo/packr/v2 v2.0.0-rc.12/go.mod h1:FV1zZTsVFi1DSCboO36Xgs4pzCZBjB/tDV9Cz/lSaR8= |
|||
github.com/gobuffalo/packr/v2 v2.0.0-rc.13/go.mod h1:2Mp7GhBFMdJlOK8vGfl7SYtfMP3+5roE39ejlfjw0rA= |
|||
github.com/gobuffalo/packr/v2 v2.0.0-rc.14/go.mod h1:06otbrNvDKO1eNQ3b8hst+1010UooI2MFg+B2Ze4MV8= |
|||
github.com/gobuffalo/packr/v2 v2.0.0-rc.15/go.mod h1:IMe7H2nJvcKXSF90y4X1rjYIRlNMJYCxEhssBXNZwWs= |
|||
github.com/gobuffalo/plush v3.7.16+incompatible/go.mod h1:rQ4zdtUUyZNqULlc6bqd5scsPfLKfT0+TGMChgduDvI= |
|||
github.com/gobuffalo/plush v3.7.20+incompatible/go.mod h1:rQ4zdtUUyZNqULlc6bqd5scsPfLKfT0+TGMChgduDvI= |
|||
github.com/gobuffalo/plush v3.7.21+incompatible/go.mod h1:rQ4zdtUUyZNqULlc6bqd5scsPfLKfT0+TGMChgduDvI= |
|||
github.com/gobuffalo/plush v3.7.22+incompatible/go.mod h1:rQ4zdtUUyZNqULlc6bqd5scsPfLKfT0+TGMChgduDvI= |
|||
github.com/gobuffalo/plush v3.7.23+incompatible/go.mod h1:rQ4zdtUUyZNqULlc6bqd5scsPfLKfT0+TGMChgduDvI= |
|||
github.com/gobuffalo/plush v3.7.30+incompatible/go.mod h1:rQ4zdtUUyZNqULlc6bqd5scsPfLKfT0+TGMChgduDvI= |
|||
github.com/gobuffalo/plush v3.7.31+incompatible/go.mod h1:rQ4zdtUUyZNqULlc6bqd5scsPfLKfT0+TGMChgduDvI= |
|||
github.com/gobuffalo/plush v3.7.32+incompatible/go.mod h1:rQ4zdtUUyZNqULlc6bqd5scsPfLKfT0+TGMChgduDvI= |
|||
github.com/gobuffalo/plushgen v0.0.0-20181128164830-d29dcb966cb2/go.mod h1:r9QwptTFnuvSaSRjpSp4S2/4e2D3tJhARYbvEBcKSb4= |
|||
github.com/gobuffalo/plushgen v0.0.0-20181203163832-9fc4964505c2/go.mod h1:opEdT33AA2HdrIwK1aibqnTJDVVKXC02Bar/GT1YRVs= |
|||
github.com/gobuffalo/plushgen v0.0.0-20181207152837-eedb135bd51b/go.mod h1:Lcw7HQbEVm09sAQrCLzIxuhFbB3nAgp4c55E+UlynR0= |
|||
github.com/gobuffalo/plushgen v0.0.0-20190104222512-177cd2b872b3/go.mod h1:tYxCozi8X62bpZyKXYHw1ncx2ZtT2nFvG42kuLwYjoc= |
|||
github.com/gobuffalo/pop v4.8.2+incompatible/go.mod h1:DwBz3SD5SsHpTZiTubcsFWcVDpJWGsxjVjMPnkiThWg= |
|||
github.com/gobuffalo/pop v4.8.3+incompatible/go.mod h1:DwBz3SD5SsHpTZiTubcsFWcVDpJWGsxjVjMPnkiThWg= |
|||
github.com/gobuffalo/pop v4.8.4+incompatible/go.mod h1:DwBz3SD5SsHpTZiTubcsFWcVDpJWGsxjVjMPnkiThWg= |
|||
github.com/gobuffalo/release v1.0.35/go.mod h1:VtHFAKs61vO3wboCec5xr9JPTjYyWYcvaM3lclkc4x4= |
|||
github.com/gobuffalo/release v1.0.38/go.mod h1:VtHFAKs61vO3wboCec5xr9JPTjYyWYcvaM3lclkc4x4= |
|||
github.com/gobuffalo/release v1.0.42/go.mod h1:RPs7EtafH4oylgetOJpGP0yCZZUiO4vqHfTHJjSdpug= |
|||
github.com/gobuffalo/release v1.0.52/go.mod h1:RPs7EtafH4oylgetOJpGP0yCZZUiO4vqHfTHJjSdpug= |
|||
github.com/gobuffalo/release v1.0.53/go.mod h1:FdF257nd8rqhNaqtDWFGhxdJ/Ig4J7VcS3KL7n/a+aA= |
|||
github.com/gobuffalo/release v1.0.54/go.mod h1:Pe5/RxRa/BE8whDpGfRqSI7D1a0evGK1T4JDm339tJc= |
|||
github.com/gobuffalo/release v1.0.61/go.mod h1:mfIO38ujUNVDlBziIYqXquYfBF+8FDHUjKZgYC1Hj24= |
|||
github.com/gobuffalo/release v1.0.72/go.mod h1:NP5NXgg/IX3M5XmHmWR99D687/3Dt9qZtTK/Lbwc1hU= |
|||
github.com/gobuffalo/release v1.1.1/go.mod h1:Sluak1Xd6kcp6snkluR1jeXAogdJZpFFRzTYRs/2uwg= |
|||
github.com/gobuffalo/release v1.1.3/go.mod h1:CuXc5/m+4zuq8idoDt1l4va0AXAn/OSs08uHOfMVr8E= |
|||
github.com/gobuffalo/release v1.1.6/go.mod h1:18naWa3kBsqO0cItXZNJuefCKOENpbbUIqRL1g+p6z0= |
|||
github.com/gobuffalo/shoulders v1.0.1/go.mod h1:V33CcVmaQ4gRUmHKwq1fiTXuf8Gp/qjQBUL5tHPmvbA= |
|||
github.com/gobuffalo/syncx v0.0.0-20181120191700-98333ab04150/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw= |
|||
github.com/gobuffalo/syncx v0.0.0-20181120194010-558ac7de985f/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw= |
|||
github.com/gobuffalo/tags v2.0.11+incompatible/go.mod h1:9XmhOkyaB7UzvuY4UoZO4s67q8/xRMVJEaakauVQYeY= |
|||
github.com/gobuffalo/tags v2.0.14+incompatible/go.mod h1:9XmhOkyaB7UzvuY4UoZO4s67q8/xRMVJEaakauVQYeY= |
|||
github.com/gobuffalo/tags v2.0.15+incompatible/go.mod h1:9XmhOkyaB7UzvuY4UoZO4s67q8/xRMVJEaakauVQYeY= |
|||
github.com/gobuffalo/uuid v2.0.3+incompatible/go.mod h1:ErhIzkRhm0FtRuiE/PeORqcw4cVi1RtSpnwYrxuvkfE= |
|||
github.com/gobuffalo/uuid v2.0.4+incompatible/go.mod h1:ErhIzkRhm0FtRuiE/PeORqcw4cVi1RtSpnwYrxuvkfE= |
|||
github.com/gobuffalo/uuid v2.0.5+incompatible/go.mod h1:ErhIzkRhm0FtRuiE/PeORqcw4cVi1RtSpnwYrxuvkfE= |
|||
github.com/gobuffalo/validate v2.0.3+incompatible/go.mod h1:N+EtDe0J8252BgfzQUChBgfd6L93m9weay53EWFVsMM= |
|||
github.com/gobuffalo/x v0.0.0-20181003152136-452098b06085/go.mod h1:WevpGD+5YOreDJznWevcn8NTmQEW5STSBgIkpkjzqXc= |
|||
github.com/gobuffalo/x v0.0.0-20181007152206-913e47c59ca7/go.mod h1:9rDPXaB3kXdKWzMc4odGQQdG2e2DIEmANy5aSJ9yesY= |
|||
github.com/gofrs/uuid v3.1.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= |
|||
github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= |
|||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= |
|||
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= |
|||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= |
|||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= |
|||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= |
|||
github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= |
|||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= |
|||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= |
|||
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= |
|||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= |
|||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= |
|||
github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= |
|||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= |
|||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= |
|||
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= |
|||
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= |
|||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= |
|||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= |
|||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= |
|||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= |
|||
github.com/gopherjs/gopherjs v0.0.0-20190328170749-bb2674552d8f h1:4Gslotqbs16iAg+1KR/XdabIfq8TlAWHdwS5QJFksLc= |
|||
github.com/gopherjs/gopherjs v0.0.0-20190328170749-bb2674552d8f/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= |
|||
github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= |
|||
github.com/goreleaser/goreleaser v0.106.0/go.mod h1:YCWszXb4t6HZ7gzeg5TcbPJC2Ad8cFvsknUS0CwS3yY= |
|||
github.com/goreleaser/nfpm v0.11.0/go.mod h1:F2yzin6cBAL9gb+mSiReuXdsfTrOQwDMsuSpULof+y4= |
|||
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= |
|||
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= |
|||
github.com/gorilla/pat v0.0.0-20180118222023-199c85a7f6d1/go.mod h1:YeAe0gNeiNT5hoiZRI4yiOky6jVdNvfO2N6Kav/HmxY= |
|||
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= |
|||
github.com/gorilla/sessions v1.1.2/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w= |
|||
github.com/gorilla/sessions v1.1.3/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w= |
|||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= |
|||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= |
|||
github.com/grpc-ecosystem/grpc-gateway v1.8.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= |
|||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= |
|||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= |
|||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= |
|||
github.com/imdario/mergo v0.3.4/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= |
|||
github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= |
|||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= |
|||
github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ= |
|||
github.com/jackc/pgx v3.2.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I= |
|||
github.com/jacobsa/crypto v0.0.0-20180924003735-d95898ceee07 h1:/PaS1RNKtbBEndIvzCqIgYh6GAH9ZFc8Mj4tVRVyfOA= |
|||
github.com/jacobsa/crypto v0.0.0-20180924003735-d95898ceee07/go.mod h1:LadVJg0XuawGk+8L1rYnIED8451UyNxEMdTWCEt5kmU= |
|||
github.com/jacobsa/crypto v0.0.0-20190317225127-9f44e2d11115 h1:YuDUUFNM21CAbyPOpOP8BicaTD/0klJEKt5p8yuw+uY= |
|||
github.com/jacobsa/crypto v0.0.0-20190317225127-9f44e2d11115/go.mod h1:LadVJg0XuawGk+8L1rYnIED8451UyNxEMdTWCEt5kmU= |
|||
github.com/jacobsa/oglematchers v0.0.0-20150720000706-141901ea67cd h1:9GCSedGjMcLZCrusBZuo4tyKLpKUPenUUqi34AkuFmA= |
|||
github.com/jacobsa/oglematchers v0.0.0-20150720000706-141901ea67cd/go.mod h1:TlmyIZDpGmwRoTWiakdr+HA1Tukze6C6XbRVidYq02M= |
|||
github.com/jacobsa/oglemock v0.0.0-20150831005832-e94d794d06ff h1:2xRHTvkpJ5zJmglXLRqHiZQNjUoOkhUyhTAhEQvPAWw= |
|||
github.com/jacobsa/oglemock v0.0.0-20150831005832-e94d794d06ff/go.mod h1:gJWba/XXGl0UoOmBQKRWCJdHrr3nE0T65t6ioaj3mLI= |
|||
github.com/jacobsa/ogletest v0.0.0-20170503003838-80d50a735a11 h1:BMb8s3ENQLt5ulwVIHVDWFHp8eIXmbfSExkvdn9qMXI= |
|||
github.com/jacobsa/ogletest v0.0.0-20170503003838-80d50a735a11/go.mod h1:+DBdDyfoO2McrOyDemRBq0q9CMEByef7sYl7JH5Q3BI= |
|||
github.com/jacobsa/reqtrace v0.0.0-20150505043853-245c9e0234cb h1:uSWBjJdMf47kQlXMwWEfmc864bA1wAC+Kl3ApryuG9Y= |
|||
github.com/jacobsa/reqtrace v0.0.0-20150505043853-245c9e0234cb/go.mod h1:ivcmUvxXWjb27NsPEaiYK7AidlZXS7oQ5PowUS9z3I4= |
|||
github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= |
|||
github.com/jmoiron/sqlx v0.0.0-20180614180643-0dae4fefe7c0/go.mod h1:IiEW3SEiiErVyFdH8NTuWjSifiEQKUoyK3LNqr2kCHU= |
|||
github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks= |
|||
github.com/joho/godotenv v1.2.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= |
|||
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= |
|||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= |
|||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= |
|||
github.com/jteeuwen/go-bindata v3.0.7+incompatible/go.mod h1:JVvhzYOiGBnFSYRyV00iY8q7/0PThjIYav1p9h5dmKs= |
|||
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= |
|||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= |
|||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= |
|||
github.com/kamilsk/retry/v4 v4.0.0/go.mod h1:0af33qDvzbhQqdOBi7iOjEpmP4brbPmNZpo7chYlgcc= |
|||
github.com/karrick/godirwalk v1.7.5/go.mod h1:2c9FRhkDxdIbgkOnCEvnSWs71Bhugbl46shStcFDJ34= |
|||
github.com/karrick/godirwalk v1.7.7/go.mod h1:2c9FRhkDxdIbgkOnCEvnSWs71Bhugbl46shStcFDJ34= |
|||
github.com/karrick/godirwalk v1.7.8/go.mod h1:2c9FRhkDxdIbgkOnCEvnSWs71Bhugbl46shStcFDJ34= |
|||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= |
|||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= |
|||
github.com/konsorten/go-windows-terminal-sequences v0.0.0-20180402223658-b729f2633dfe/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= |
|||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= |
|||
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= |
|||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= |
|||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= |
|||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= |
|||
github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= |
|||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= |
|||
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= |
|||
github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= |
|||
github.com/lxn/walk v0.0.0-20191113135339-bf589de20b3c h1:4pJw1uBKndwiBBJpcbqP1Bf90YfqTJUsHG9DVoAfIQ8= |
|||
github.com/lxn/walk v0.0.0-20191113135339-bf589de20b3c/go.mod h1:E23UucZGqpuUANJooIbHWCufXvOcT6E7Stq81gU+CSQ= |
|||
github.com/lxn/win v0.0.0-20191106123917-121afc750dd3 h1:DvGEvKK/Qnhph/EgdBN9zXA7pEosgJ0k57ojII51JAo= |
|||
github.com/lxn/win v0.0.0-20191106123917-121afc750dd3/go.mod h1:ouWl4wViUNh8tPSIwxTVMuS014WakR1hqvBc2I0bMoA= |
|||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= |
|||
github.com/markbates/deplist v1.0.4/go.mod h1:gRRbPbbuA8TmMiRvaOzUlRfzfjeCCBqX2A6arxN01MM= |
|||
github.com/markbates/deplist v1.0.5/go.mod h1:gRRbPbbuA8TmMiRvaOzUlRfzfjeCCBqX2A6arxN01MM= |
|||
github.com/markbates/going v1.0.2/go.mod h1:UWCk3zm0UKefHZ7l8BNqi26UyiEMniznk8naLdTcy6c= |
|||
github.com/markbates/grift v1.0.4/go.mod h1:wbmtW74veyx+cgfwFhlnnMWqhoz55rnHR47oMXzsyVs= |
|||
github.com/markbates/hmax v1.0.0/go.mod h1:cOkR9dktiESxIMu+65oc/r/bdY4bE8zZw3OLhLx0X2c= |
|||
github.com/markbates/inflect v1.0.0/go.mod h1:oTeZL2KHA7CUX6X+fovmK9OvIOFuqu0TwdQrZjLTh88= |
|||
github.com/markbates/inflect v1.0.1/go.mod h1:uv3UVNBe5qBIfCm8O8Q+DW+S1EopeyINj+Ikhc7rnCk= |
|||
github.com/markbates/inflect v1.0.3/go.mod h1:1fR9+pO2KHEO9ZRtto13gDwwZaAKstQzferVeWqbgNs= |
|||
github.com/markbates/inflect v1.0.4/go.mod h1:1fR9+pO2KHEO9ZRtto13gDwwZaAKstQzferVeWqbgNs= |
|||
github.com/markbates/oncer v0.0.0-20180924031910-e862a676800b/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE= |
|||
github.com/markbates/oncer v0.0.0-20180924034138-723ad0170a46/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE= |
|||
github.com/markbates/oncer v0.0.0-20181014194634-05fccaae8fc4/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE= |
|||
github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE= |
|||
github.com/markbates/refresh v1.4.10/go.mod h1:NDPHvotuZmTmesXxr95C9bjlw1/0frJwtME2dzcVKhc= |
|||
github.com/markbates/safe v1.0.0/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0= |
|||
github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0= |
|||
github.com/markbates/sigtx v1.0.0/go.mod h1:QF1Hv6Ic6Ca6W+T+DL0Y/ypborFKyvUY9HmuCD4VeTc= |
|||
github.com/markbates/willie v1.0.9/go.mod h1:fsrFVWl91+gXpx/6dv715j7i11fYPfZ9ZGfH0DQzY7w= |
|||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= |
|||
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= |
|||
github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= |
|||
github.com/mattn/go-zglob v0.0.0-20171230104132-4959821b4817/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo= |
|||
github.com/mattn/go-zglob v0.0.0-20180803001819-2ea3427bfa53/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo= |
|||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= |
|||
github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= |
|||
github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc= |
|||
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= |
|||
github.com/mitchellh/mapstructure v1.0.0/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= |
|||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= |
|||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= |
|||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= |
|||
github.com/monoculum/formam v0.0.0-20180901015400-4e68be1d79ba/go.mod h1:RKgILGEJq24YyJ2ban8EO0RUVSJlF1pGsEvoLEACr/Q= |
|||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= |
|||
github.com/nicksnyder/go-i18n v1.10.0/go.mod h1:HrK7VCrbOvQoUAQ7Vpy7i87N7JZZZ7R2xBGjv0j365Q= |
|||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= |
|||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= |
|||
github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= |
|||
github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= |
|||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= |
|||
github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= |
|||
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= |
|||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= |
|||
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= |
|||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= |
|||
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= |
|||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= |
|||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= |
|||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= |
|||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= |
|||
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= |
|||
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= |
|||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= |
|||
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= |
|||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= |
|||
github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= |
|||
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= |
|||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= |
|||
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= |
|||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= |
|||
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= |
|||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= |
|||
github.com/rogpeppe/go-internal v1.0.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= |
|||
github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= |
|||
github.com/rubenv/sql-migrate v0.0.0-20181213081019-5a8808c14925/go.mod h1:WS0rl9eEliYI8DPnr3TOwz4439pay+qNgzJoVya/DmY= |
|||
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= |
|||
github.com/serenize/snaker v0.0.0-20171204205717-a683aaf2d516/go.mod h1:Yow6lPLSAXx2ifx470yD/nUe22Dv5vBvxK/UK9UUTVs= |
|||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= |
|||
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= |
|||
github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= |
|||
github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ= |
|||
github.com/shurcooL/highlight_diff v0.0.0-20170515013008-09bb4053de1b/go.mod h1:ZpfEhSmds4ytuByIcDnOLkTHGUI6KNqRNPDLHDk+mUU= |
|||
github.com/shurcooL/highlight_go v0.0.0-20170515013102-78fb10f4a5f8/go.mod h1:UDKB5a1T23gOMUJrI+uSuH0VRDStOiUVSjBTRDVBVag= |
|||
github.com/shurcooL/octicon v0.0.0-20180602230221-c42b0e3b24d9/go.mod h1:eWdoE5JD4R5UVWDucdOPg1g2fqQRq78IQa9zlOV1vpQ= |
|||
github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= |
|||
github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= |
|||
github.com/sirupsen/logrus v1.1.0/go.mod h1:zrgwTnHtNr00buQ1vSptGe8m1f/BbgsPukg8qsT7A+A= |
|||
github.com/sirupsen/logrus v1.1.1/go.mod h1:zrgwTnHtNr00buQ1vSptGe8m1f/BbgsPukg8qsT7A+A= |
|||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= |
|||
github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= |
|||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= |
|||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= |
|||
github.com/smartystreets/assertions v0.0.0-20190401211740-f487f9de1cd3 h1:hBSHahWMEgzwRyS6dRpxY0XyjZsHyQ61s084wo5PJe0= |
|||
github.com/smartystreets/assertions v0.0.0-20190401211740-f487f9de1cd3/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= |
|||
github.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM= |
|||
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a h1:pa8hGb/2YqsZKovtsgrwcDH1RZhVbTKCjLp47XpqCDs= |
|||
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= |
|||
github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE= |
|||
github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA= |
|||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= |
|||
github.com/spf13/afero v1.2.0/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= |
|||
github.com/spf13/cast v1.2.0/go.mod h1:r2rcYCSwa1IExKTDiTfzaxqT2FNHs8hODu4LnUfgKEg= |
|||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= |
|||
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= |
|||
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= |
|||
github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= |
|||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= |
|||
github.com/spf13/viper v1.2.1/go.mod h1:P4AexN0a+C9tGAnUFNwDMYYZv3pjFuvmeiMyKRaNVlI= |
|||
github.com/spf13/viper v1.3.1/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= |
|||
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= |
|||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= |
|||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= |
|||
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= |
|||
github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= |
|||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= |
|||
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= |
|||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= |
|||
github.com/uber-go/atomic v1.3.2/go.mod h1:/Ct5t2lcmbJ4OSe/waGBoaVvVqtO0bmtfVNex1PFV8g= |
|||
github.com/uber/jaeger-client-go v2.15.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= |
|||
github.com/uber/jaeger-lib v1.5.0/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U= |
|||
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= |
|||
github.com/unrolled/secure v0.0.0-20180918153822-f340ee86eb8b/go.mod h1:mnPT77IAdsi/kV7+Es7y+pXALeV3h7G6dQF6mNYjcLA= |
|||
github.com/unrolled/secure v0.0.0-20181005190816-ff9db2ff917f/go.mod h1:mnPT77IAdsi/kV7+Es7y+pXALeV3h7G6dQF6mNYjcLA= |
|||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= |
|||
github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0= |
|||
go.opencensus.io v0.15.0/go.mod h1:UffZAU+4sDEINUGP/B7UfBBkq4fqLu9zXAX7ke6CHW0= |
|||
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= |
|||
go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= |
|||
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= |
|||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= |
|||
golang.org/x/crypto v0.0.0-20180910181607-0e37d006457b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= |
|||
golang.org/x/crypto v0.0.0-20181001203147-e3636079e1a4/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= |
|||
golang.org/x/crypto v0.0.0-20181009213950-7c1a557ab941/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= |
|||
golang.org/x/crypto v0.0.0-20181015023909-0c41d7ab0a0e/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= |
|||
golang.org/x/crypto v0.0.0-20181024171144-74cb1d3d52f4/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= |
|||
golang.org/x/crypto v0.0.0-20181025113841-85e1b3f9139a/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= |
|||
golang.org/x/crypto v0.0.0-20181025213731-e84da0312774/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= |
|||
golang.org/x/crypto v0.0.0-20181106171534-e4dc69e5b2fd/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= |
|||
golang.org/x/crypto v0.0.0-20181112202954-3d3f9f413869/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= |
|||
golang.org/x/crypto v0.0.0-20181127143415-eb0de9b17e85/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= |
|||
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= |
|||
golang.org/x/crypto v0.0.0-20190102171810-8d7daa0c54b3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= |
|||
golang.org/x/crypto v0.0.0-20190103213133-ff983b9c42bc/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= |
|||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= |
|||
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= |
|||
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= |
|||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= |
|||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= |
|||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= |
|||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= |
|||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= |
|||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= |
|||
golang.org/x/net v0.0.0-20180816102801-aaf60122140d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= |
|||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= |
|||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= |
|||
golang.org/x/net v0.0.0-20180921000356-2f5d2388922f/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= |
|||
golang.org/x/net v0.0.0-20180926154720-4dfa2610cdf3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= |
|||
golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= |
|||
golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= |
|||
golang.org/x/net v0.0.0-20181017193950-04a2e542c03f/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= |
|||
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= |
|||
golang.org/x/net v0.0.0-20181102091132-c10e9556a7bc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= |
|||
golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= |
|||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= |
|||
golang.org/x/net v0.0.0-20181207154023-610586996380/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= |
|||
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= |
|||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= |
|||
golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= |
|||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= |
|||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= |
|||
golang.org/x/net v0.0.0-20190322120337-addf6b3196f6/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= |
|||
golang.org/x/net v0.0.0-20190328230028-74de082e2cca h1:hyA6yiAgbUwuWqtscNvWAI7U1CtlaD1KilQ6iudt1aI= |
|||
golang.org/x/net v0.0.0-20190328230028-74de082e2cca/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= |
|||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= |
|||
golang.org/x/net v0.0.0-20190628185345-da137c7871d7 h1:rTIdg5QFRR7XCaK4LCjBiPbx8j4DQRpdYMnGn/bJUEU= |
|||
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= |
|||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= |
|||
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= |
|||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= |
|||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= |
|||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= |
|||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= |
|||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= |
|||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= |
|||
golang.org/x/sys v0.0.0-20180816055513-1c9583448a9c/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
|||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
|||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
|||
golang.org/x/sys v0.0.0-20180906133057-8cf3aee42992/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
|||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
|||
golang.org/x/sys v0.0.0-20180921163948-d47a0f339242/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
|||
golang.org/x/sys v0.0.0-20180927150500-dad3d9fb7b6e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
|||
golang.org/x/sys v0.0.0-20181005133103-4497e2df6f9e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
|||
golang.org/x/sys v0.0.0-20181011152604-fa43e7bc11ba/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
|||
golang.org/x/sys v0.0.0-20181022134430-8a28ead16f52/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
|||
golang.org/x/sys v0.0.0-20181024145615-5cd93ef61a7c/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
|||
golang.org/x/sys v0.0.0-20181025063200-d989b31c8746/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
|||
golang.org/x/sys v0.0.0-20181026064943-731415f00dce/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
|||
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
|||
golang.org/x/sys v0.0.0-20181030150119-7e31e0c00fa0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
|||
golang.org/x/sys v0.0.0-20181106135930-3a76605856fd/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
|||
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
|||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
|||
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
|||
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
|||
golang.org/x/sys v0.0.0-20181206074257-70b957f3b65e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
|||
golang.org/x/sys v0.0.0-20190102155601-82a175fd1598/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
|||
golang.org/x/sys v0.0.0-20190116161447-11f53e031339/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
|||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
|||
golang.org/x/sys v0.0.0-20190402054613-e4093980e83e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd h1:DBH9mDw0zluJT/R+nGuV3jWFWLFaHyYZWD4tOT+cjn0= |
|||
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= |
|||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= |
|||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= |
|||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= |
|||
golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= |
|||
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= |
|||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= |
|||
golang.org/x/tools v0.0.0-20181003024731-2f84ea8ef872/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= |
|||
golang.org/x/tools v0.0.0-20181006002542-f60d9635b16a/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= |
|||
golang.org/x/tools v0.0.0-20181008205924-a2b3f7f249e9/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= |
|||
golang.org/x/tools v0.0.0-20181013182035-5e66757b835f/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= |
|||
golang.org/x/tools v0.0.0-20181017214349-06f26fdaaa28/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= |
|||
golang.org/x/tools v0.0.0-20181024171208-a2dc47679d30/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= |
|||
golang.org/x/tools v0.0.0-20181026183834-f60e5f99f081/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= |
|||
golang.org/x/tools v0.0.0-20181105230042-78dc5bac0cac/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= |
|||
golang.org/x/tools v0.0.0-20181107215632-34b416bd17b3/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= |
|||
golang.org/x/tools v0.0.0-20181114190951-94339b83286c/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= |
|||
golang.org/x/tools v0.0.0-20181119130350-139d099f6620/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= |
|||
golang.org/x/tools v0.0.0-20181127195227-b4e97c0ed882/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= |
|||
golang.org/x/tools v0.0.0-20181127232545-e782529d0ddd/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= |
|||
golang.org/x/tools v0.0.0-20181203210056-e5f3ab76ea4b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= |
|||
golang.org/x/tools v0.0.0-20181205224935-3576414c54a4/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= |
|||
golang.org/x/tools v0.0.0-20181206194817-bcd4e47d0288/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= |
|||
golang.org/x/tools v0.0.0-20181207183836-8bc39b988060/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= |
|||
golang.org/x/tools v0.0.0-20181212172921-837e80568c09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= |
|||
golang.org/x/tools v0.0.0-20190102213336-ca9055ed7d04/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= |
|||
golang.org/x/tools v0.0.0-20190104182027-498d95493402/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= |
|||
golang.org/x/tools v0.0.0-20190111214448-fc1d57b08d7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= |
|||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= |
|||
golang.org/x/tools v0.0.0-20190118193359-16909d206f00/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= |
|||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= |
|||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= |
|||
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= |
|||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= |
|||
golang.org/x/tools v0.0.0-20190708203411-c8855242db9c/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= |
|||
gonum.org/v1/gonum v0.0.0-20190115205657-1b07048b32c6/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= |
|||
gonum.org/v1/netlib v0.0.0-20190219113230-9992c5f5eae4/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= |
|||
google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= |
|||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= |
|||
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= |
|||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= |
|||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= |
|||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= |
|||
google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= |
|||
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= |
|||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= |
|||
google.golang.org/grpc v1.19.1/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= |
|||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= |
|||
gopkg.in/Knetic/govaluate.v3 v3.0.0 h1:18mUyIt4ZlRlFZAAfVetz4/rzlJs9yhN+U02F4u1AOc= |
|||
gopkg.in/Knetic/govaluate.v3 v3.0.0/go.mod h1:csKLBORsPbafmSCGTEh3U7Ozmsuq8ZSIlKk1bcqph0E= |
|||
gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= |
|||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= |
|||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk= |
|||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= |
|||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= |
|||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= |
|||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= |
|||
gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= |
|||
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw= |
|||
gopkg.in/gorp.v1 v1.7.2/go.mod h1:Wo3h+DBQZIxATwftsglhdD/62zRFPhGhTiu5jUJmCaw= |
|||
gopkg.in/mail.v2 v2.0.0-20180731213649-a0242b2233b4/go.mod h1:htwXN1Qh09vZJ1NVKxQqHPBaCBbzKhp5GzuJEA4VJWw= |
|||
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= |
|||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= |
|||
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= |
|||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= |
|||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= |
|||
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= |
|||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= |
|||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= |
|||
pack.ag/amqp v0.8.0/go.mod h1:4/cbmt4EJXSKlG6LCfWHoqmN0uFdy5i/+YFz+fTfhV4= |
|||
pack.ag/amqp v0.11.0/go.mod h1:4/cbmt4EJXSKlG6LCfWHoqmN0uFdy5i/+YFz+fTfhV4= |
@ -0,0 +1,107 @@ |
|||
package model |
|||
|
|||
import ( |
|||
"github.com/lxn/walk" |
|||
"sort" |
|||
) |
|||
|
|||
type DTUDown struct { |
|||
Index int |
|||
DevEUI string |
|||
MType string |
|||
DevAddr string |
|||
GatewayID string |
|||
FCnt uint32 |
|||
FPort uint8 |
|||
HexData string |
|||
AsciiData string |
|||
Time string |
|||
checked bool |
|||
OrigData string |
|||
} |
|||
|
|||
type DTUDownModel struct { |
|||
walk.TableModelBase |
|||
walk.SorterBase |
|||
SortColumn int |
|||
SortOrder walk.SortOrder |
|||
Items []*DTUDown |
|||
} |
|||
|
|||
func (m *DTUDownModel) RowCount() int { |
|||
return len(m.Items) |
|||
} |
|||
|
|||
func (m *DTUDownModel) Value(row, col int) interface{} { |
|||
item := m.Items[row] |
|||
|
|||
switch col { |
|||
case 0: |
|||
return item.Index |
|||
case 1: |
|||
return item.DevEUI |
|||
case 2: |
|||
return item.MType |
|||
case 3: |
|||
return item.DevAddr |
|||
case 4: |
|||
return item.GatewayID |
|||
case 5: |
|||
return item.FCnt |
|||
case 6: |
|||
return item.FPort |
|||
case 7: |
|||
return item.HexData |
|||
case 8: |
|||
return item.AsciiData |
|||
case 9: |
|||
return item.Time |
|||
} |
|||
panic("unexpected col") |
|||
} |
|||
|
|||
func (m *DTUDownModel) Checked(row int) bool { |
|||
return m.Items[row].checked |
|||
} |
|||
|
|||
func (m *DTUDownModel) SetChecked(row int, checked bool) error { |
|||
m.Items[row].checked = checked |
|||
return nil |
|||
} |
|||
|
|||
func (m *DTUDownModel) Sort(col int, order walk.SortOrder) error { |
|||
m.SortColumn, m.SortOrder = col, order |
|||
sort.Stable(m) |
|||
return m.SorterBase.Sort(col, order) |
|||
} |
|||
|
|||
func (m *DTUDownModel) Len() int { |
|||
return len(m.Items) |
|||
} |
|||
|
|||
func (m *DTUDownModel) Less(i, j int) bool { |
|||
a, b := m.Items[i], m.Items[j] |
|||
c := func(ls bool) bool { |
|||
if m.SortOrder == walk.SortAscending { |
|||
return ls |
|||
} |
|||
return !ls |
|||
} |
|||
|
|||
switch m.SortColumn { |
|||
case 0: |
|||
return c(a.Index < b.Index) |
|||
case 2: |
|||
return c(a.DevEUI < b.DevEUI) |
|||
default: |
|||
return false |
|||
} |
|||
} |
|||
|
|||
func (m *DTUDownModel) Swap(i, j int) { |
|||
m.Items[i], m.Items[j] = m.Items[j], m.Items[i] |
|||
} |
|||
|
|||
func NewDTUDownModel() *DTUDownModel { |
|||
return new(DTUDownModel) |
|||
} |
@ -0,0 +1,119 @@ |
|||
package model |
|||
|
|||
import ( |
|||
"github.com/lxn/walk" |
|||
"sort" |
|||
) |
|||
|
|||
type DTUUp struct { |
|||
Index int |
|||
DevEUI string |
|||
MType string |
|||
GatewayID string |
|||
Rssi int16 |
|||
LoRaSNR float64 |
|||
Frequency float64 |
|||
FCnt uint32 |
|||
FPort uint8 |
|||
HexData string |
|||
AsciiData string |
|||
Time string |
|||
checked bool |
|||
OrigData string |
|||
} |
|||
|
|||
type DTUUpModel struct { |
|||
walk.TableModelBase |
|||
walk.SorterBase |
|||
SortColumn int |
|||
SortOrder walk.SortOrder |
|||
Items []*DTUUp |
|||
} |
|||
|
|||
func (m *DTUUpModel) RowCount() int { |
|||
return len(m.Items) |
|||
} |
|||
|
|||
func (m *DTUUpModel) Value(row, col int) interface{} { |
|||
item := m.Items[row] |
|||
|
|||
switch col { |
|||
case 0: |
|||
return item.Index |
|||
case 1: |
|||
return item.DevEUI |
|||
case 2: |
|||
return item.MType |
|||
case 3: |
|||
return item.GatewayID |
|||
case 4: |
|||
return item.Rssi |
|||
case 5: |
|||
return item.LoRaSNR |
|||
case 6: |
|||
return item.Frequency |
|||
case 7: |
|||
return item.FCnt |
|||
case 8: |
|||
return item.FPort |
|||
case 9: |
|||
return item.HexData |
|||
case 10: |
|||
return item.AsciiData |
|||
case 11: |
|||
return item.Time |
|||
} |
|||
panic("unexpected col") |
|||
} |
|||
|
|||
func (m *DTUUpModel) Checked(row int) bool { |
|||
return m.Items[row].checked |
|||
} |
|||
|
|||
func (m *DTUUpModel) SetChecked(row int, checked bool) error { |
|||
m.Items[row].checked = checked |
|||
return nil |
|||
} |
|||
|
|||
func (m *DTUUpModel) Sort(col int, order walk.SortOrder) error { |
|||
m.SortColumn, m.SortOrder = col, order |
|||
sort.Stable(m) |
|||
return m.SorterBase.Sort(col, order) |
|||
} |
|||
|
|||
func (m *DTUUpModel) Len() int { |
|||
return len(m.Items) |
|||
} |
|||
|
|||
func (m *DTUUpModel) Less(i, j int) bool { |
|||
a, b := m.Items[i], m.Items[j] |
|||
c := func(ls bool) bool { |
|||
if m.SortOrder == walk.SortAscending { |
|||
return ls |
|||
} |
|||
return !ls |
|||
} |
|||
|
|||
switch m.SortColumn { |
|||
case 0: |
|||
return c(a.Index < b.Index) |
|||
case 2: |
|||
return c(a.DevEUI < b.DevEUI) |
|||
case 4: |
|||
return c(a.Rssi < b.Rssi) |
|||
case 5: |
|||
return c(a.LoRaSNR < b.LoRaSNR) |
|||
case 6: |
|||
return c(a.Frequency < b.Frequency) |
|||
default: |
|||
return false |
|||
} |
|||
} |
|||
|
|||
func (m *DTUUpModel) Swap(i, j int) { |
|||
m.Items[i], m.Items[j] = m.Items[j], m.Items[i] |
|||
} |
|||
|
|||
func NewDTUUpModel() *DTUUpModel { |
|||
return new(DTUUpModel) |
|||
} |
@ -0,0 +1,126 @@ |
|||
//go:generate stringer -type=PacketType
|
|||
|
|||
package packets |
|||
|
|||
import ( |
|||
"errors" |
|||
"strconv" |
|||
"strings" |
|||
"time" |
|||
) |
|||
|
|||
// PacketType defines the packet type.
|
|||
type PacketType byte |
|||
|
|||
// Available packet types
|
|||
const ( |
|||
PushData PacketType = iota |
|||
PushACK |
|||
PullData |
|||
PullResp |
|||
PullACK |
|||
TXACK |
|||
) |
|||
|
|||
// Protocol versions
|
|||
const ( |
|||
ProtocolVersion1 uint8 = 0x01 |
|||
ProtocolVersion2 uint8 = 0x02 |
|||
) |
|||
|
|||
// Errors
|
|||
var ( |
|||
ErrInvalidProtocolVersion = errors.New("gateway: invalid protocol version") |
|||
) |
|||
|
|||
// GetPacketType returns the packet type for the given packet data.
|
|||
func GetPacketType(data []byte) (PacketType, error) { |
|||
if len(data) < 4 { |
|||
return PacketType(0), errors.New("gateway: at least 4 bytes of data are expected") |
|||
} |
|||
|
|||
if !protocolSupported(data[0]) { |
|||
return PacketType(0), ErrInvalidProtocolVersion |
|||
} |
|||
|
|||
return PacketType(data[3]), nil |
|||
} |
|||
|
|||
func protocolSupported(p uint8) bool { |
|||
if p == ProtocolVersion1 || p == ProtocolVersion2 { |
|||
return true |
|||
} |
|||
return false |
|||
} |
|||
|
|||
// ExpandedTime implements time.Time but (un)marshals to and from
|
|||
// ISO 8601 'expanded' format.
|
|||
type ExpandedTime time.Time |
|||
|
|||
// MarshalJSON implements the json.Marshaler interface.
|
|||
func (t ExpandedTime) MarshalJSON() ([]byte, error) { |
|||
return []byte(time.Time(t).UTC().Format(`"2006-01-02 15:04:05 MST"`)), nil |
|||
} |
|||
|
|||
// UnmarshalJSON implements the json.Unmarshaler interface.
|
|||
func (t *ExpandedTime) UnmarshalJSON(data []byte) error { |
|||
t2, err := time.Parse(`"2006-01-02 15:04:05 MST"`, string(data)) |
|||
if err != nil { |
|||
return err |
|||
} |
|||
*t = ExpandedTime(t2) |
|||
return nil |
|||
} |
|||
|
|||
// CompactTime implements time.Time but (un)marshals to and from
|
|||
// ISO 8601 'compact' format.
|
|||
type CompactTime time.Time |
|||
|
|||
// MarshalJSON implements the json.Marshaler interface.
|
|||
func (t CompactTime) MarshalJSON() ([]byte, error) { |
|||
t2 := time.Time(t) |
|||
if t2.IsZero() { |
|||
return []byte("null"), nil |
|||
} |
|||
return []byte(t2.UTC().Format(`"` + time.RFC3339Nano + `"`)), nil |
|||
} |
|||
|
|||
// UnmarshalJSON implements the json.Unmarshaler interface.
|
|||
func (t *CompactTime) UnmarshalJSON(data []byte) error { |
|||
if string(data) == `""` { |
|||
return nil |
|||
} |
|||
|
|||
t2, err := time.Parse(`"`+time.RFC3339Nano+`"`, string(data)) |
|||
if err != nil { |
|||
return err |
|||
} |
|||
*t = CompactTime(t2) |
|||
return nil |
|||
} |
|||
|
|||
// DatR implements the data rate which can be either a string (LoRa identifier)
|
|||
// or an unsigned integer in case of FSK (bits per second).
|
|||
type DatR struct { |
|||
LoRa string |
|||
FSK uint32 |
|||
} |
|||
|
|||
// MarshalJSON implements the json.Marshaler interface.
|
|||
func (d DatR) MarshalJSON() ([]byte, error) { |
|||
if d.LoRa != "" { |
|||
return []byte(`"` + d.LoRa + `"`), nil |
|||
} |
|||
return []byte(strconv.FormatUint(uint64(d.FSK), 10)), nil |
|||
} |
|||
|
|||
// UnmarshalJSON implements the json.Unmarshaler interface.
|
|||
func (d *DatR) UnmarshalJSON(data []byte) error { |
|||
i, err := strconv.ParseUint(string(data), 10, 32) |
|||
if err != nil { |
|||
d.LoRa = strings.Trim(string(data), `"`) |
|||
return nil |
|||
} |
|||
d.FSK = uint32(i) |
|||
return nil |
|||
} |
@ -0,0 +1,16 @@ |
|||
// Code generated by "stringer -type=PacketType"; DO NOT EDIT.
|
|||
|
|||
package packets |
|||
|
|||
import "strconv" |
|||
|
|||
const _PacketType_name = "PushDataPushACKPullDataPullRespPullACKTXACK" |
|||
|
|||
var _PacketType_index = [...]uint8{0, 8, 15, 23, 31, 38, 43} |
|||
|
|||
func (i PacketType) String() string { |
|||
if i >= PacketType(len(_PacketType_index)-1) { |
|||
return "PacketType(" + strconv.FormatInt(int64(i), 10) + ")" |
|||
} |
|||
return _PacketType_name[_PacketType_index[i]:_PacketType_index[i+1]] |
|||
} |
@ -0,0 +1,38 @@ |
|||
package packets |
|||
|
|||
import ( |
|||
"encoding/binary" |
|||
"errors" |
|||
) |
|||
|
|||
// PullACKPacket is used by the server to confirm that the network route is
|
|||
// open and that the server can send PULL_RESP packets at any time.
|
|||
type PullACKPacket struct { |
|||
ProtocolVersion uint8 |
|||
RandomToken uint16 |
|||
} |
|||
|
|||
// MarshalBinary marshals the object in binary form.
|
|||
func (p PullACKPacket) MarshalBinary() ([]byte, error) { |
|||
out := make([]byte, 4) |
|||
out[0] = p.ProtocolVersion |
|||
binary.LittleEndian.PutUint16(out[1:3], p.RandomToken) |
|||
out[3] = byte(PullACK) |
|||
return out, nil |
|||
} |
|||
|
|||
// UnmarshalBinary decodes the object from binary form.
|
|||
func (p *PullACKPacket) UnmarshalBinary(data []byte) error { |
|||
if len(data) != 4 { |
|||
return errors.New("gateway: 4 bytes of data are expected") |
|||
} |
|||
if data[3] != byte(PullACK) { |
|||
return errors.New("gateway: identifier mismatch (PULL_ACK expected)") |
|||
} |
|||
if !protocolSupported(data[0]) { |
|||
return ErrInvalidProtocolVersion |
|||
} |
|||
p.ProtocolVersion = data[0] |
|||
p.RandomToken = binary.LittleEndian.Uint16(data[1:3]) |
|||
return nil |
|||
} |
@ -0,0 +1,43 @@ |
|||
package packets |
|||
|
|||
import ( |
|||
"encoding/binary" |
|||
"errors" |
|||
) |
|||
|
|||
// PullDataPacket is used by the gateway to poll data from the server.
|
|||
type PullDataPacket struct { |
|||
ProtocolVersion uint8 |
|||
RandomToken uint16 |
|||
GatewayMAC [8]byte |
|||
} |
|||
|
|||
// MarshalBinary marshals the object in binary form.
|
|||
func (p PullDataPacket) MarshalBinary() ([]byte, error) { |
|||
out := make([]byte, 4, 12) |
|||
out[0] = p.ProtocolVersion |
|||
binary.LittleEndian.PutUint16(out[1:3], p.RandomToken) |
|||
out[3] = byte(PullData) |
|||
out = append(out, p.GatewayMAC[0:len(p.GatewayMAC)]...) |
|||
return out, nil |
|||
} |
|||
|
|||
// UnmarshalBinary decodes the object from binary form.
|
|||
func (p *PullDataPacket) UnmarshalBinary(data []byte) error { |
|||
if len(data) != 12 { |
|||
return errors.New("gateway: 12 bytes of data are expected") |
|||
} |
|||
if data[3] != byte(PullData) { |
|||
return errors.New("gateway: identifier mismatch (PULL_DATA expected)") |
|||
} |
|||
|
|||
if !protocolSupported(data[0]) { |
|||
return ErrInvalidProtocolVersion |
|||
} |
|||
p.ProtocolVersion = data[0] |
|||
p.RandomToken = binary.LittleEndian.Uint16(data[1:3]) |
|||
for i := 0; i < 8; i++ { |
|||
p.GatewayMAC[i] = data[4+i] |
|||
} |
|||
return nil |
|||
} |
@ -0,0 +1,162 @@ |
|||
package packets |
|||
|
|||
import ( |
|||
"encoding/binary" |
|||
"encoding/json" |
|||
"fmt" |
|||
"time" |
|||
|
|||
"github.com/golang/protobuf/ptypes" |
|||
"github.com/pkg/errors" |
|||
|
|||
"github.com/brocaar/loraserver/api/common" |
|||
"github.com/brocaar/loraserver/api/gw" |
|||
) |
|||
|
|||
// PullRespPacket is used by the server to send RF packets and associated
|
|||
// metadata that will have to be emitted by the gateway.
|
|||
type PullRespPacket struct { |
|||
ProtocolVersion uint8 |
|||
RandomToken uint16 |
|||
Payload PullRespPayload |
|||
} |
|||
|
|||
// MarshalBinary marshals the object in binary form.
|
|||
func (p PullRespPacket) MarshalBinary() ([]byte, error) { |
|||
pb, err := json.Marshal(&p.Payload) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
out := make([]byte, 4, 4+len(pb)) |
|||
out[0] = p.ProtocolVersion |
|||
|
|||
if p.ProtocolVersion != ProtocolVersion1 { |
|||
// these two bytes are unused in ProtocolVersion1
|
|||
binary.LittleEndian.PutUint16(out[1:3], p.RandomToken) |
|||
} |
|||
out[3] = byte(PullResp) |
|||
out = append(out, pb...) |
|||
return out, nil |
|||
} |
|||
|
|||
// UnmarshalBinary decodes the object from binary form.
|
|||
func (p *PullRespPacket) UnmarshalBinary(data []byte) error { |
|||
if len(data) < 5 { |
|||
return errors.New("gateway: at least 5 bytes of data are expected") |
|||
} |
|||
if data[3] != byte(PullResp) { |
|||
return errors.New("gateway: identifier mismatch (PULL_RESP expected)") |
|||
} |
|||
if !protocolSupported(data[0]) { |
|||
return ErrInvalidProtocolVersion |
|||
} |
|||
p.ProtocolVersion = data[0] |
|||
p.RandomToken = binary.LittleEndian.Uint16(data[1:3]) |
|||
return json.Unmarshal(data[4:], &p.Payload) |
|||
} |
|||
|
|||
// PullRespPayload represents the downstream JSON data structure.
|
|||
type PullRespPayload struct { |
|||
TXPK TXPK `json:"txpk"` |
|||
} |
|||
|
|||
// TXPK contains a RF packet to be emitted and associated metadata.
|
|||
type TXPK struct { |
|||
Imme bool `json:"imme"` // Send packet immediately (will ignore tmst & time)
|
|||
RFCh uint8 `json:"rfch"` // Concentrator "RF chain" used for TX (unsigned integer)
|
|||
Powe uint8 `json:"powe"` // TX output power in dBm (unsigned integer, dBm precision)
|
|||
Ant uint8 `json:"ant"` // Antenna number on which signal has been received
|
|||
Brd uint32 `json:"brd"` // Concentrator board used for RX (unsigned integer)
|
|||
Tmst *uint32 `json:"tmst,omitempty"` // Send packet on a certain timestamp value (will ignore time)
|
|||
Tmms *int64 `json:"tmms,omitempty"` // Send packet at a certain GPS time (GPS synchronization required)
|
|||
Freq float64 `json:"freq"` // TX central frequency in MHz (unsigned float, Hz precision)
|
|||
Modu string `json:"modu"` // Modulation identifier "LORA" or "FSK"
|
|||
DatR DatR `json:"datr"` // LoRa datarate identifier (eg. SF12BW500) || FSK datarate (unsigned, in bits per second)
|
|||
CodR string `json:"codr,omitempty"` // LoRa ECC coding rate identifier
|
|||
FDev uint16 `json:"fdev,omitempty"` // FSK frequency deviation (unsigned integer, in Hz)
|
|||
NCRC bool `json:"ncrc,omitempty"` // If true, disable the CRC of the physical layer (optional)
|
|||
IPol bool `json:"ipol"` // Lora modulation polarization inversion
|
|||
Prea uint16 `json:"prea,omitempty"` // RF preamble size (unsigned integer)
|
|||
Size uint16 `json:"size"` // RF packet payload size in bytes (unsigned integer)
|
|||
Data []byte `json:"data"` // Base64 encoded RF packet payload, padding optional
|
|||
} |
|||
|
|||
// GetPullRespPacket returns a PullRespPacket for the given gw.DownlinkFrame.
|
|||
func GetPullRespPacket(protoVersion uint8, randomToken uint16, frame gw.DownlinkFrame) (PullRespPacket, error) { |
|||
packet := PullRespPacket{ |
|||
ProtocolVersion: protoVersion, |
|||
RandomToken: randomToken, |
|||
Payload: PullRespPayload{ |
|||
TXPK: TXPK{ |
|||
Freq: float64(frame.TxInfo.Frequency) / 1000000, |
|||
Powe: uint8(frame.TxInfo.Power), |
|||
Modu: frame.TxInfo.Modulation.String(), |
|||
Size: uint16(len(frame.PhyPayload)), |
|||
Data: frame.PhyPayload, |
|||
Ant: uint8(frame.TxInfo.Antenna), |
|||
Brd: uint32(frame.TxInfo.Board), |
|||
}, |
|||
}, |
|||
} |
|||
|
|||
if frame.TxInfo.Modulation == common.Modulation_LORA { |
|||
modInfo := frame.TxInfo.GetLoraModulationInfo() |
|||
if modInfo == nil { |
|||
return packet, errors.New("gateway: lora_modulation_info must not be nil") |
|||
} |
|||
packet.Payload.TXPK.DatR.LoRa = fmt.Sprintf("SF%dBW%d", modInfo.SpreadingFactor, modInfo.Bandwidth) |
|||
packet.Payload.TXPK.CodR = modInfo.CodeRate |
|||
packet.Payload.TXPK.IPol = modInfo.PolarizationInversion |
|||
} |
|||
|
|||
if frame.TxInfo.Modulation == common.Modulation_FSK { |
|||
modInfo := frame.TxInfo.GetFskModulationInfo() |
|||
if modInfo == nil { |
|||
return packet, errors.New("gateway: fsk_modulation_info must not be nil") |
|||
} |
|||
packet.Payload.TXPK.DatR.FSK = modInfo.Bitrate |
|||
packet.Payload.TXPK.FDev = uint16(modInfo.Bitrate / 2) // TODO: is this correct?!
|
|||
} |
|||
|
|||
switch frame.TxInfo.Timing { |
|||
case gw.DownlinkTiming_IMMEDIATELY: |
|||
packet.Payload.TXPK.Imme = true |
|||
|
|||
case gw.DownlinkTiming_DELAY: |
|||
timingInfo := frame.TxInfo.GetDelayTimingInfo() |
|||
if timingInfo == nil { |
|||
return packet, errors.New("delay_timing_info must not be nil") |
|||
} |
|||
|
|||
delay, err := ptypes.Duration(timingInfo.Delay) |
|||
if err != nil { |
|||
return packet, errors.Wrap(err, "get delay duration error") |
|||
} |
|||
|
|||
if len(frame.TxInfo.Context) < 4 { |
|||
return packet, fmt.Errorf("context must contain at least 4 bytes, got: %d", len(frame.TxInfo.Context)) |
|||
} |
|||
timestamp := binary.BigEndian.Uint32(frame.TxInfo.Context[0:4]) |
|||
timestamp += uint32(delay / time.Microsecond) |
|||
packet.Payload.TXPK.Tmst = ×tamp |
|||
|
|||
case gw.DownlinkTiming_GPS_EPOCH: |
|||
timingInfo := frame.TxInfo.GetGpsEpochTimingInfo() |
|||
if timingInfo == nil { |
|||
return packet, errors.New("gps_epoch_timing must not be nil") |
|||
} |
|||
|
|||
dur, err := ptypes.Duration(timingInfo.TimeSinceGpsEpoch) |
|||
if err != nil { |
|||
return packet, errors.Wrap(err, "parse time_since_gps_epoch error") |
|||
} |
|||
|
|||
durMS := int64(dur / time.Millisecond) |
|||
packet.Payload.TXPK.Tmms = &durMS |
|||
|
|||
default: |
|||
return packet, fmt.Errorf("unexpected downlink timing: %s", frame.TxInfo.Timing) |
|||
} |
|||
|
|||
return packet, nil |
|||
} |
@ -0,0 +1,39 @@ |
|||
package packets |
|||
|
|||
import ( |
|||
"encoding/binary" |
|||
"errors" |
|||
) |
|||
|
|||
// PushACKPacket is used by the server to acknowledge immediately all the
|
|||
// PUSH_DATA packets received.
|
|||
type PushACKPacket struct { |
|||
ProtocolVersion uint8 |
|||
RandomToken uint16 |
|||
} |
|||
|
|||
// MarshalBinary marshals the object in binary form.
|
|||
func (p PushACKPacket) MarshalBinary() ([]byte, error) { |
|||
out := make([]byte, 4) |
|||
out[0] = p.ProtocolVersion |
|||
binary.LittleEndian.PutUint16(out[1:3], p.RandomToken) |
|||
out[3] = byte(PushACK) |
|||
return out, nil |
|||
} |
|||
|
|||
// UnmarshalBinary decodes the object from binary form.
|
|||
func (p *PushACKPacket) UnmarshalBinary(data []byte) error { |
|||
if len(data) != 4 { |
|||
return errors.New("gateway: 4 bytes of data are expected") |
|||
} |
|||
if data[3] != byte(PushACK) { |
|||
return errors.New("gateway: identifier mismatch (PUSH_ACK expected)") |
|||
} |
|||
|
|||
if !protocolSupported(data[0]) { |
|||
return ErrInvalidProtocolVersion |
|||
} |
|||
p.ProtocolVersion = data[0] |
|||
p.RandomToken = binary.LittleEndian.Uint16(data[1:3]) |
|||
return nil |
|||
} |
@ -0,0 +1,283 @@ |
|||
package packets |
|||
|
|||
import ( |
|||
"encoding/binary" |
|||
"encoding/json" |
|||
"regexp" |
|||
"strconv" |
|||
"time" |
|||
|
|||
"github.com/golang/protobuf/ptypes" |
|||
"github.com/pkg/errors" |
|||
|
|||
"github.com/brocaar/loraserver/api/common" |
|||
"github.com/brocaar/loraserver/api/gw" |
|||
"github.com/brocaar/lorawan" |
|||
) |
|||
|
|||
// loRaDataRateRegex contains a regexp for parsing the data-rate string.
|
|||
var loRaDataRateRegex = regexp.MustCompile(`SF(\d+)BW(\d+)`) |
|||
|
|||
// PushDataPacket type is used by the gateway mainly to forward the RF packets
|
|||
// received, and associated metadata, to the server.
|
|||
type PushDataPacket struct { |
|||
ProtocolVersion uint8 |
|||
RandomToken uint16 |
|||
GatewayMAC lorawan.EUI64 |
|||
Payload PushDataPayload |
|||
} |
|||
|
|||
// MarshalBinary encodes the packet into binary form compatible with the
|
|||
// Semtech UDP protocol.
|
|||
func (p PushDataPacket) MarshalBinary() ([]byte, error) { |
|||
pb, err := json.Marshal(&p.Payload) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
|
|||
out := make([]byte, 4, len(pb)+12) |
|||
out[0] = p.ProtocolVersion |
|||
binary.LittleEndian.PutUint16(out[1:3], p.RandomToken) |
|||
out[3] = byte(PushData) |
|||
out = append(out, p.GatewayMAC[0:len(p.GatewayMAC)]...) |
|||
out = append(out, pb...) |
|||
return out, nil |
|||
} |
|||
|
|||
// GetGatewayStats returns the gw.GatewayStats object (if the packet contains stats).
|
|||
func (p PushDataPacket) GetGatewayStats() (*gw.GatewayStats, error) { |
|||
if p.Payload.Stat == nil { |
|||
return nil, nil |
|||
} |
|||
|
|||
stats := gw.GatewayStats{ |
|||
GatewayId: p.GatewayMAC[:], |
|||
RxPacketsReceived: p.Payload.Stat.RXNb, |
|||
RxPacketsReceivedOk: p.Payload.Stat.RXOK, |
|||
TxPacketsEmitted: p.Payload.Stat.TXNb, |
|||
TxPacketsReceived: p.Payload.Stat.DWNb, |
|||
} |
|||
|
|||
// time
|
|||
ts, err := ptypes.TimestampProto(time.Time(p.Payload.Stat.Time)) |
|||
if err != nil { |
|||
return nil, errors.Wrap(err, "timestamp proto error") |
|||
} |
|||
stats.Time = ts |
|||
|
|||
// location
|
|||
if p.Payload.Stat.Lati != 0 && p.Payload.Stat.Long != 0 && p.Payload.Stat.Alti != 0 { |
|||
stats.Location = &common.Location{ |
|||
Latitude: p.Payload.Stat.Lati, |
|||
Longitude: p.Payload.Stat.Long, |
|||
Altitude: float64(p.Payload.Stat.Alti), |
|||
Source: common.LocationSource_GPS, |
|||
} |
|||
} |
|||
|
|||
return &stats, nil |
|||
} |
|||
|
|||
// GetUplinkFrames returns a slice of gw.UplinkFrame.
|
|||
func (p PushDataPacket) GetUplinkFrames(skipCRCCheck bool, FakeRxInfoTime bool) ([]gw.UplinkFrame, error) { |
|||
var frames []gw.UplinkFrame |
|||
|
|||
for i := range p.Payload.RXPK { |
|||
// validate CRC
|
|||
if p.Payload.RXPK[i].Stat != 1 && !skipCRCCheck { |
|||
continue |
|||
} |
|||
|
|||
if len(p.Payload.RXPK[i].RSig) == 0 { |
|||
frame, err := getUplinkFrame(p.GatewayMAC[:], p.Payload.RXPK[i], FakeRxInfoTime) |
|||
if err != nil { |
|||
return nil, errors.Wrap(err, "gateway: get uplink frame error") |
|||
} |
|||
frames = append(frames, frame) |
|||
} else { |
|||
for j := range p.Payload.RXPK[i].RSig { |
|||
frame, err := getUplinkFrame(p.GatewayMAC[:], p.Payload.RXPK[i], FakeRxInfoTime) |
|||
if err != nil { |
|||
return nil, errors.Wrap(err, "gateway: get uplink frame error") |
|||
} |
|||
frame = setUplinkFrameRSig(frame, p.Payload.RXPK[i], p.Payload.RXPK[i].RSig[j]) |
|||
frames = append(frames, frame) |
|||
} |
|||
} |
|||
} |
|||
|
|||
return frames, nil |
|||
} |
|||
|
|||
func setUplinkFrameRSig(frame gw.UplinkFrame, rxPK RXPK, rSig RSig) gw.UplinkFrame { |
|||
frame.RxInfo.Antenna = uint32(rSig.Ant) |
|||
frame.RxInfo.Channel = uint32(rSig.Chan) |
|||
frame.RxInfo.Rssi = int32(rSig.RSSIC) |
|||
frame.RxInfo.LoraSnr = rSig.LSNR |
|||
|
|||
if len(rSig.ETime) != 0 { |
|||
frame.RxInfo.FineTimestampType = gw.FineTimestampType_ENCRYPTED |
|||
frame.RxInfo.FineTimestamp = &gw.UplinkRXInfo_EncryptedFineTimestamp{ |
|||
EncryptedFineTimestamp: &gw.EncryptedFineTimestamp{ |
|||
EncryptedNs: rSig.ETime, |
|||
AesKeyIndex: uint32(rxPK.AESK), |
|||
}, |
|||
} |
|||
} |
|||
|
|||
return frame |
|||
} |
|||
|
|||
func getUplinkFrame(gatewayID []byte, rxpk RXPK, FakeRxInfoTime bool) (gw.UplinkFrame, error) { |
|||
frame := gw.UplinkFrame{ |
|||
PhyPayload: rxpk.Data, |
|||
TxInfo: &gw.UplinkTXInfo{ |
|||
Frequency: uint32(rxpk.Freq * 1000000), |
|||
}, |
|||
RxInfo: &gw.UplinkRXInfo{ |
|||
GatewayId: gatewayID, |
|||
Rssi: int32(rxpk.RSSI), |
|||
LoraSnr: rxpk.LSNR, |
|||
Channel: uint32(rxpk.Chan), |
|||
RfChain: uint32(rxpk.RFCh), |
|||
Board: uint32(rxpk.Brd), |
|||
Context: make([]byte, 4), |
|||
}, |
|||
} |
|||
|
|||
// Context
|
|||
binary.BigEndian.PutUint32(frame.RxInfo.Context, rxpk.Tmst) |
|||
|
|||
// Time.
|
|||
if rxpk.Time != nil && !time.Time(*rxpk.Time).IsZero() { |
|||
ts, err := ptypes.TimestampProto(time.Time(*rxpk.Time)) |
|||
if err != nil { |
|||
return frame, errors.Wrap(err, "gateway: timestamp proto error") |
|||
} |
|||
frame.RxInfo.Time = ts |
|||
} else if FakeRxInfoTime { |
|||
ts, _ := ptypes.TimestampProto(time.Now().UTC()) |
|||
frame.RxInfo.Time = ts |
|||
} |
|||
|
|||
// Time since GPS epoch
|
|||
if rxpk.Tmms != nil { |
|||
d := time.Duration(*rxpk.Tmms) * time.Millisecond |
|||
frame.RxInfo.TimeSinceGpsEpoch = ptypes.DurationProto(d) |
|||
} |
|||
|
|||
// LoRa data-rate
|
|||
if rxpk.DatR.LoRa != "" { |
|||
frame.TxInfo.Modulation = common.Modulation_LORA |
|||
|
|||
match := loRaDataRateRegex.FindStringSubmatch(rxpk.DatR.LoRa) |
|||
// parse e.g. SF12BW250 into separate variables
|
|||
if len(match) != 3 { |
|||
return frame, errors.New("gateway: could not parse LoRa data-rate") |
|||
} |
|||
|
|||
// cast variables to ints
|
|||
sf, err := strconv.Atoi(match[1]) |
|||
if err != nil { |
|||
return frame, errors.Wrap(err, "gateway: could not convert sf to int") |
|||
} |
|||
|
|||
bw, err := strconv.Atoi(match[2]) |
|||
if err != nil { |
|||
return frame, errors.Wrap(err, "gateway: could not parse bandwidth to int") |
|||
} |
|||
|
|||
frame.TxInfo.ModulationInfo = &gw.UplinkTXInfo_LoraModulationInfo{ |
|||
LoraModulationInfo: &gw.LoRaModulationInfo{ |
|||
Bandwidth: uint32(bw), |
|||
SpreadingFactor: uint32(sf), |
|||
CodeRate: rxpk.CodR, |
|||
}, |
|||
} |
|||
} |
|||
|
|||
// FSK data-rate
|
|||
if rxpk.DatR.FSK != 0 { |
|||
frame.TxInfo.Modulation = common.Modulation_FSK |
|||
|
|||
frame.TxInfo.ModulationInfo = &gw.UplinkTXInfo_FskModulationInfo{ |
|||
FskModulationInfo: &gw.FSKModulationInfo{ |
|||
Bitrate: uint32(rxpk.DatR.FSK), |
|||
}, |
|||
} |
|||
} |
|||
|
|||
return frame, nil |
|||
} |
|||
|
|||
// UnmarshalBinary decodes the packet from Semtech UDP binary form.
|
|||
func (p *PushDataPacket) UnmarshalBinary(data []byte) error { |
|||
if len(data) < 13 { |
|||
return errors.New("gateway: at least 13 bytes are expected") |
|||
} |
|||
if data[3] != byte(PushData) { |
|||
return errors.New("gateway: identifier mismatch (PUSH_DATA expected)") |
|||
} |
|||
|
|||
if !protocolSupported(data[0]) { |
|||
return ErrInvalidProtocolVersion |
|||
} |
|||
|
|||
p.ProtocolVersion = data[0] |
|||
p.RandomToken = binary.LittleEndian.Uint16(data[1:3]) |
|||
for i := 0; i < 8; i++ { |
|||
p.GatewayMAC[i] = data[4+i] |
|||
} |
|||
|
|||
return json.Unmarshal(data[12:], &p.Payload) |
|||
} |
|||
|
|||
// PushDataPayload represents the upstream JSON data structure.
|
|||
type PushDataPayload struct { |
|||
RXPK []RXPK `json:"rxpk,omitempty"` |
|||
Stat *Stat `json:"stat,omitempty"` |
|||
} |
|||
|
|||
// Stat contains the status of the gateway.
|
|||
type Stat struct { |
|||
Time ExpandedTime `json:"time"` // UTC 'system' time of the gateway, ISO 8601 'expanded' format (e.g 2014-01-12 08:59:28 GMT)
|
|||
Lati float64 `json:"lati"` // GPS latitude of the gateway in degree (float, N is +)
|
|||
Long float64 `json:"long"` // GPS latitude of the gateway in degree (float, E is +)
|
|||
Alti int32 `json:"alti"` // GPS altitude of the gateway in meter RX (integer)
|
|||
RXNb uint32 `json:"rxnb"` // Number of radio packets received (unsigned integer)
|
|||
RXOK uint32 `json:"rxok"` // Number of radio packets received with a valid PHY CRC
|
|||
RXFW uint32 `json:"rxfw"` // Number of radio packets forwarded (unsigned integer)
|
|||
ACKR float64 `json:"ackr"` // Percentage of upstream datagrams that were acknowledged
|
|||
DWNb uint32 `json:"dwnb"` // Number of downlink datagrams received (unsigned integer)
|
|||
TXNb uint32 `json:"txnb"` // Number of packets emitted (unsigned integer)
|
|||
} |
|||
|
|||
// RXPK contain a RF packet and associated metadata.
|
|||
type RXPK struct { |
|||
Time *CompactTime `json:"time"` // UTC time of pkt RX, us precision, ISO 8601 'compact' format (e.g. 2013-03-31T16:21:17.528002Z)
|
|||
Tmms *int64 `json:"tmms"` // GPS time of pkt RX, number of milliseconds since 06.Jan.1980
|
|||
Tmst uint32 `json:"tmst"` // Internal timestamp of "RX finished" event (32b unsigned)
|
|||
AESK uint8 `json:"aesk"` //AES key index used for encrypting fine timestamps
|
|||
Chan uint8 `json:"chan"` // Concentrator "IF" channel used for RX (unsigned integer)
|
|||
RFCh uint8 `json:"rfch"` // Concentrator "RF chain" used for RX (unsigned integer)
|
|||
Stat int8 `json:"stat"` // CRC status: 1 = OK, -1 = fail, 0 = no CRC
|
|||
Freq float64 `json:"freq"` // RX central frequency in MHz (unsigned float, Hz precision)
|
|||
Brd uint32 `json:"brd"` // Concentrator board used for RX (unsigned integer)
|
|||
RSSI int16 `json:"rssi"` // RSSI in dBm (signed integer, 1 dB precision)
|
|||
Size uint16 `json:"size"` // RF packet payload size in bytes (unsigned integer)
|
|||
DatR DatR `json:"datr"` // LoRa datarate identifier (eg. SF12BW500) || FSK datarate (unsigned, in bits per second)
|
|||
Modu string `json:"modu"` // Modulation identifier "LORA" or "FSK"
|
|||
CodR string `json:"codr"` // LoRa ECC coding rate identifier
|
|||
LSNR float64 `json:"lsnr"` // Lora SNR ratio in dB (signed float, 0.1 dB precision)
|
|||
Data []byte `json:"data"` // Base64 encoded RF packet payload, padded
|
|||
RSig []RSig `json:"rsig"` // Received signal information, per antenna (Optional)
|
|||
} |
|||
|
|||
// RSig contains the received signal information per antenna.
|
|||
type RSig struct { |
|||
Ant uint8 `json:"ant"` // Antenna number on which signal has been received
|
|||
Chan uint8 `json:"chan"` // Concentrator "IF" channel used for RX (unsigned integer)
|
|||
RSSIC int16 `json:"rssic"` // RSSI in dBm of the channel (signed integer, 1 dB precision)
|
|||
LSNR float64 `json:"lsnr"` // Lora SNR ratio in dB (signed float, 0.1 dB precision)
|
|||
ETime []byte `json:"etime"` // Encrypted 'main' fine timestamp, ns precision [0..999999999] (Optional)
|
|||
} |
@ -0,0 +1,73 @@ |
|||
package packets |
|||
|
|||
import ( |
|||
"encoding/binary" |
|||
"encoding/json" |
|||
"errors" |
|||
|
|||
"github.com/brocaar/lorawan" |
|||
) |
|||
|
|||
// TXACKPacket is used by the gateway to send a feedback to the server
|
|||
// to inform if a downlink request has been accepted or rejected by the
|
|||
// gateway.
|
|||
type TXACKPacket struct { |
|||
ProtocolVersion uint8 |
|||
RandomToken uint16 |
|||
GatewayMAC lorawan.EUI64 |
|||
Payload *TXACKPayload |
|||
} |
|||
|
|||
// MarshalBinary marshals the object into binary form.
|
|||
func (p TXACKPacket) MarshalBinary() ([]byte, error) { |
|||
var pb []byte |
|||
if p.Payload != nil { |
|||
var err error |
|||
pb, err = json.Marshal(p.Payload) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
} |
|||
|
|||
out := make([]byte, 4, len(pb)+12) |
|||
out[0] = p.ProtocolVersion |
|||
binary.LittleEndian.PutUint16(out[1:3], p.RandomToken) |
|||
out[3] = byte(TXACK) |
|||
out = append(out, p.GatewayMAC[:]...) |
|||
out = append(out, pb...) |
|||
return out, nil |
|||
} |
|||
|
|||
// UnmarshalBinary decodes the object from binary form.
|
|||
func (p *TXACKPacket) UnmarshalBinary(data []byte) error { |
|||
if len(data) < 12 { |
|||
return errors.New("gateway: at least 12 bytes of data are expected") |
|||
} |
|||
if data[3] != byte(TXACK) { |
|||
return errors.New("gateway: identifier mismatch (TXACK expected)") |
|||
} |
|||
if !protocolSupported(data[0]) { |
|||
return ErrInvalidProtocolVersion |
|||
} |
|||
p.ProtocolVersion = data[0] |
|||
p.RandomToken = binary.LittleEndian.Uint16(data[1:3]) |
|||
for i := 0; i < 8; i++ { |
|||
p.GatewayMAC[i] = data[4+i] |
|||
} |
|||
if len(data) > 13 { // the min payload + the length of at least "{}"
|
|||
p.Payload = &TXACKPayload{} |
|||
return json.Unmarshal(data[12:], p.Payload) |
|||
} |
|||
return nil |
|||
} |
|||
|
|||
// TXACKPayload contains the TXACKPacket payload.
|
|||
type TXACKPayload struct { |
|||
TXPKACK TXPKACK `json:"txpk_ack"` |
|||
} |
|||
|
|||
// TXPKACK contains the status information of the associated PULL_RESP
|
|||
// packet.
|
|||
type TXPKACK struct { |
|||
Error string `json:"error"` |
|||
} |
Binary file not shown.
@ -0,0 +1 @@ |
|||
rsrc -manifest LoRaDTUMock.manifest -ico dot.ico -o rsrc.syso |
Loading…
Reference in new issue