| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225 |
- package reporter
- import (
- "crypto/md5"
- "encoding/hex"
- "encoding/json"
- "fmt"
- "io"
- "net/url"
- "os"
- "hnyfkj.com.cn/rtu/bxs-sy/baseapp"
- )
- type rpcRequest struct {
- JSONRPC string `json:"jsonrpc"` // 版本号, 固定: "2.0"
- Method string `json:"method"` // 调用方法, 执行函数名
- Params json.RawMessage `json:"params,omitempty"` // 请求参数, 可选可为空
- ID int `json:"id"` // 请求ID, 用于标识请求
- }
- type rpcError struct {
- Code int `json:"code"` // 错误码
- Message string `json:"message"` // 错误信息
- }
- type rpcResponse struct {
- JSONRPC string `json:"jsonrpc"` // 版本号, 固定: "2.0"
- Result json.RawMessage `json:"result,omitempty"` // 响应结果, 可选可为空
- Error *rpcError `json:"error,omitempty"` // 错误信息, 可选可为空
- ID int `json:"id"` // 应答ID, 响应匹配请求
- }
- func makeLoginReq(imei, iccid, rssi, appVersion, inheritDUI string) ([]byte, error) {
- type params struct {
- DeviceType string `json:"deviceType"`
- IMEI string `json:"imei"`
- ICCID string `json:"iccid"`
- RSSI string `json:"rssi"`
- AppVersion string `json:"appVersion"`
- InheritID string `json:"inheritDUI,omitempty"` // 继承的DUI, 可选可为空
- }
- paramsVar := params{
- DeviceType: "33", // 便携式色诱产品类型为: 33
- IMEI: imei,
- ICCID: iccid,
- RSSI: rssi,
- AppVersion: appVersion,
- InheritID: inheritDUI,
- }
- paramsBytes, err := json.Marshal(paramsVar)
- if err != nil {
- return nil, err
- }
- req := rpcRequest{
- JSONRPC: "2.0",
- Method: "login",
- Params: paramsBytes,
- ID: 1,
- }
- return json.Marshal(req)
- }
- func parseLoginResp(data []byte) (string, string, error) {
- var resp rpcResponse
- if err := json.Unmarshal(data, &resp); err != nil {
- return "", "", err
- }
- if resp.Error != nil {
- return "", "", fmt.Errorf("服务器返回错误: %d, %s", resp.Error.Code, resp.Error.Message)
- }
- var result struct {
- IMEI string `json:"imei"`
- DUI string `json:"DUI"`
- }
- if err := json.Unmarshal(resp.Result, &result); err != nil {
- return "", "", err
- }
- if len(result.DUI) != 14 || !isDecimal(result.DUI) {
- return "", "", fmt.Errorf("无效DUI: %q", result.DUI)
- }
- return result.IMEI, result.DUI, nil
- }
- func makeLogoutMsg(imei string) ([]byte, error) {
- type params struct {
- IMEI string `json:"imei"`
- }
- paramsVar := params{
- IMEI: imei,
- }
- paramsBytes, err := json.Marshal(paramsVar)
- if err != nil {
- return nil, err
- }
- req := rpcRequest{
- JSONRPC: "2.0",
- Method: "logout",
- Params: paramsBytes,
- ID: 1,
- }
- return json.Marshal(req)
- }
- func makeCustomError(err error) *rpcError {
- if err == nil {
- return nil
- }
- return &rpcError{-32000, fmt.Sprintf("Custom error: %v", err)}
- }
- type mcuParams struct {
- Version string `json:"version"` // 版本号 x.x.x.x, 定义: [major(8bit)].[minor(8bit)].[patch(8bit)].[build(8bit)]
- CtrlMode string `json:"ctrlMode"` // 定时控制模式(0=光控, 1=时控)
- LightDuration string `json:"lightDuration"` // 光控定时时长(小时, 1-10, 仅光控模式有效)
- StartHour string `json:"startHour"` // 时控开始时间(小时, 0-23, 仅时控模式有效)
- EndHour string `json:"endHour"` // 时控结束时间(小时, 0-23, 仅时控模式有效)
- PhotoIntervalMinutes string `json:"takePhotoIntervalMinutes"` // 拍照间隔(分钟)
- }
- func isDecimal(s string) bool {
- for _, ch := range s {
- if ch < '0' || ch > '9' {
- return false
- }
- }
- return s != "" // 不允许空字符串
- }
- func parseMCUParams(data []byte) (mcuParams, error) {
- var req rpcRequest
- if err := json.Unmarshal(data, &req); err != nil {
- return mcuParams{}, err
- }
- if len(req.Params) == 0 {
- return mcuParams{}, fmt.Errorf("missing params")
- }
- var params mcuParams
- if err := json.Unmarshal(req.Params, ¶ms); err != nil {
- return mcuParams{}, err
- }
- var verCode baseapp.VersionCode
- err := verCode.FromString(params.Version)
- if err != nil || !isDecimal(params.CtrlMode) || !isDecimal(params.LightDuration) ||
- !isDecimal(params.StartHour) || !isDecimal(params.EndHour) || !isDecimal(params.PhotoIntervalMinutes) {
- return mcuParams{}, fmt.Errorf("invalid params")
- }
- return params, nil
- }
- func parseUpgradeAppResp(data []byte) (serverAddr, loginUser, loginPass, remoteFile, md5value string, err error) {
- var req rpcRequest
- if err := json.Unmarshal(data, &req); err != nil {
- return "", "", "", "", "", err
- }
- if len(req.Params) == 0 {
- return "", "", "", "", "", fmt.Errorf("missing params")
- }
- var params struct {
- URL string `json:"url"` // 升级包的URL地址
- MD5 string `json:"md5"` // 升级包的MD5校验值, 32个十六进制数字组成, 16字节
- }
- if err := json.Unmarshal(req.Params, ¶ms); err != nil {
- return "", "", "", "", "", err
- }
- u, err := url.Parse(params.URL)
- if err != nil {
- return "", "", "", "", "", fmt.Errorf("invalid URL: %s", params.URL)
- }
- if u.Scheme != "ftp" {
- return "", "", "", "", "", fmt.Errorf("unsupported scheme: %s", u.Scheme)
- }
- host := u.Hostname()
- port := u.Port()
- if port == "" {
- port = "21"
- }
- serverAddr = fmt.Sprintf("%s:%s", host, port)
- loginUser = u.User.Username()
- loginPass, _ = u.User.Password()
- remoteFile = u.Path
- if remoteFile == "" {
- return "", "", "", "", "", fmt.Errorf("missing remote file path")
- }
- md5value = params.MD5
- return serverAddr, loginUser, loginPass, remoteFile, md5value, nil
- }
- func fileMD5(path string) (string, error) {
- f, err := os.Open(path)
- if err != nil {
- return "", err
- }
- defer f.Close()
- h := md5.New()
- if _, err := io.Copy(h, f); err != nil {
- return "", err
- }
- return hex.EncodeToString(h.Sum(nil)), nil
- }
|