初始
This commit is contained in:
		
							
								
								
									
										4
									
								
								api/video_hat/ws2/ws.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								api/video_hat/ws2/ws.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,4 @@ | ||||
| package ws2 | ||||
|  | ||||
| type WsRouter struct { | ||||
| } | ||||
							
								
								
									
										112
									
								
								api/video_hat/ws2/ws2.1.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								api/video_hat/ws2/ws2.1.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,112 @@ | ||||
| package ws2 | ||||
|  | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"github.com/gogf/gf/v2/frame/g" | ||||
| 	"github.com/gorilla/websocket" | ||||
| 	"github.com/tiger1103/gfast/v3/api/constant" | ||||
| 	"golang.org/x/net/context" | ||||
| 	"log" | ||||
| 	"time" | ||||
| ) | ||||
|  | ||||
| // 根据 Token 去登录 WS 请求 | ||||
| func Login(conn *websocket.Conn) { | ||||
| 	loginMessage := map[string]string{ | ||||
| 		"act":          "ma_login", | ||||
| 		"user_name":    constant.Username, | ||||
| 		"access_token": constant.Token, | ||||
| 	} | ||||
| 	conn.WriteJSON(loginMessage) | ||||
| 	// 休眠两秒钟,以便第三方服务端记录连接的信息 | ||||
| 	time.Sleep(time.Second * 3) | ||||
| } | ||||
|  | ||||
| // 定义管理员登录响应结构体 | ||||
| type AdminLoginResponse struct { | ||||
| 	Cmd       string    `json:"cmd"` | ||||
| 	Status    bool      `json:"status"` | ||||
| 	Msg       string    `json:"msg"` | ||||
| 	AdminInfo AdminInfo `json:"admin_info"` | ||||
| } | ||||
|  | ||||
| // 定义管理员信息结构体 | ||||
| type AdminInfo struct { | ||||
| 	AdminID    string  `json:"admin_id"` | ||||
| 	UserName   string  `json:"user_name"` | ||||
| 	Mobile     string  `json:"mobile"` | ||||
| 	CTime      string  `json:"c_time"` | ||||
| 	Pwd        string  `json:"pwd"` | ||||
| 	PID        string  `json:"p_id"` | ||||
| 	Department string  `json:"department"` | ||||
| 	Role       string  `json:"role"` | ||||
| 	SIPInfo    SIPInfo `json:"sip_info"` | ||||
| } | ||||
|  | ||||
| // 定义 SIP 信息结构体 | ||||
| type SIPInfo struct { | ||||
| 	SIPID    string `json:"sip_id" dc:"SIPID"` | ||||
| 	SIPPwd   string `json:"sip_pwd" dc:"SIP密码"` | ||||
| 	SIPHost  string `json:"sip_host" dc:"SIP服务器URL"` | ||||
| 	WSSURL   string `json:"wss_url" dc:"WSS地址"` | ||||
| 	STUNHost string `json:"stun_host" dc:"stun服务器"` | ||||
| 	TurnHost string `json:"turn_host" dc:"turnserver地址"` | ||||
| 	TurnUser string `json:"turn_user" dc:"turnserver账号"` | ||||
| 	TurnPwd  string `json:"turn_pwd" dc:"turnserver密码"` | ||||
| } | ||||
|  | ||||
| // 处理登录 | ||||
| func HandleLogin(jsonString string) { | ||||
| 	var response AdminLoginResponse | ||||
| 	err := json.Unmarshal([]byte(jsonString), &response) | ||||
| 	if err != nil { | ||||
| 		log.Fatal("Error decoding JSON to struct:", err) | ||||
| 	} | ||||
| 	sipInfo := response.AdminInfo.SIPInfo | ||||
| 	// 查询是否存在该数据 | ||||
| 	IfExists, _ := g.Model("sip_info").Where("id = ?", 1).Count() | ||||
| 	// 如果不存在,则插入数据 | ||||
| 	if IfExists == 0 { | ||||
| 		sipinfo := g.Map{ | ||||
| 			"sip_id":    sipInfo.SIPID, | ||||
| 			"sip_pwd":   sipInfo.SIPPwd, | ||||
| 			"sip_host":  sipInfo.SIPHost, | ||||
| 			"wss_url":   sipInfo.WSSURL, | ||||
| 			"stun_host": sipInfo.STUNHost, | ||||
| 			"turn_host": sipInfo.TurnHost, | ||||
| 			"turn_user": sipInfo.TurnUser, | ||||
| 			"turn_pwd":  sipInfo.TurnPwd, | ||||
| 		} | ||||
| 		g.Model("sip_info").Data(sipinfo).Insert() | ||||
| 	} else { | ||||
| 		// 存在则更新数据 | ||||
| 		sipinfo := g.Map{ | ||||
| 			"sip_id":    sipInfo.SIPID, | ||||
| 			"sip_pwd":   sipInfo.SIPPwd, | ||||
| 			"sip_host":  sipInfo.SIPHost, | ||||
| 			"wss_url":   sipInfo.WSSURL, | ||||
| 			"stun_host": sipInfo.STUNHost, | ||||
| 			"turn_host": sipInfo.TurnHost, | ||||
| 			"turn_user": sipInfo.TurnUser, | ||||
| 			"turn_pwd":  sipInfo.TurnPwd, | ||||
| 		} | ||||
| 		g.Model("sip_info").Data(sipinfo).Where("id =?", 1).Update() | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // 管理员详情sip | ||||
| type GetAdminLoginInfoReq struct { | ||||
| 	g.Meta `path:"/device/admininfo" method:"get" tags:"视频安全帽相关" summary:"管理员详情sip"` | ||||
| } | ||||
|  | ||||
| type GetAdminLoginInfoRes struct { | ||||
| 	List []SIPInfo `json:"list"` | ||||
| } | ||||
|  | ||||
| func (w WsRouter) GetAdminLoginInfo(ctx context.Context, req *GetAdminLoginInfoReq) (res *GetAdminLoginInfoRes, err error) { | ||||
| 	res = new(GetAdminLoginInfoRes) | ||||
| 	var list []SIPInfo | ||||
| 	g.Model("sip_info").WithAll().Scan(&list) | ||||
| 	res.List = list | ||||
| 	return res, nil | ||||
| } | ||||
							
								
								
									
										194
									
								
								api/video_hat/ws2/ws2.2.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										194
									
								
								api/video_hat/ws2/ws2.2.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,194 @@ | ||||
| package ws2 | ||||
|  | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"github.com/gogf/gf/v2/frame/g" | ||||
| 	"github.com/gogf/gf/v2/util/gconv" | ||||
| 	"github.com/gorilla/websocket" | ||||
| 	"github.com/tiger1103/gfast/v3/api/constant" | ||||
| 	"log" | ||||
| 	"time" | ||||
| ) | ||||
|  | ||||
| // 获取实时、状态等心跳包的请求 | ||||
| func SendHeartbeat(conn *websocket.Conn) { | ||||
| 	activeDevicesMessage := map[string]string{ | ||||
| 		"act": "ma_get_active_devices", | ||||
| 	} | ||||
| 	conn.WriteJSON(activeDevicesMessage) | ||||
| } | ||||
|  | ||||
| // 定时任务 | ||||
| func SendHeartbeatTime(Conn *websocket.Conn) { | ||||
| 	// 使用匿名函数创建一个定时器,每隔60秒执行一次 | ||||
| 	ticker := time.NewTicker(60 * time.Second) | ||||
| 	defer ticker.Stop() | ||||
|  | ||||
| 	for { | ||||
| 		select { | ||||
| 		case <-ticker.C: | ||||
| 			SendHeartbeat(Conn) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Response 包含从服务器获取的设备数据 | ||||
| type LocationAndHeart struct { | ||||
| 	Cmd     string       `json:"cmd"` | ||||
| 	Status  bool         `json:"status"` | ||||
| 	Message string       `json:"msg"` | ||||
| 	Data    []DeviceData `json:"data"` | ||||
| 	MsgCode string       `json:"msg_code"` | ||||
| } | ||||
|  | ||||
| // UserInfo 包含有关用户的信息 | ||||
| type UserInfo struct { | ||||
| 	UserID            string `json:"user_id" dc:"用户id"` | ||||
| 	CAVersion         string `json:"ca_ver"` | ||||
| 	DeviceID          string `json:"device_id" dc:"设备id"` | ||||
| 	Mobile            string `json:"mobile"` | ||||
| 	SIM               string `json:"sim"` | ||||
| 	CTime             string `json:"c_time" dc:"创建时间"` | ||||
| 	CALastLoginTime   string `json:"ca_last_login_time"` | ||||
| 	UserName          string `json:"user_name" dc:"用户名字"` | ||||
| 	UserImg           string `json:"user_img"` | ||||
| 	Department        string `json:"department"` | ||||
| 	Role              string `json:"role"` | ||||
| 	FID               string `json:"f_id"` | ||||
| 	CapType           string `json:"cap_type"` | ||||
| 	B1                string `json:"b1"` | ||||
| 	B2                string `json:"b2"` | ||||
| 	SOSHeight         string `json:"sos_height"` | ||||
| 	CUserID           string `json:"c_user_id"` | ||||
| 	VoicePkg          string `json:"voice_pkg"` | ||||
| 	AppVersion        string `json:"app_version"` | ||||
| 	Headset           string `json:"headset"` | ||||
| 	UploadVideoNum    string `json:"upload_video_num"` | ||||
| 	NotUploadedVideos string `json:"notuploaded_video_count"` | ||||
| 	GID               string `json:"g_id"` | ||||
| 	SIPID             int    `json:"sip_id"` | ||||
| } | ||||
|  | ||||
| // LocationInfo 包含有关位置信息的数据 | ||||
| type LocationInfo struct { | ||||
| 	Act               string `json:"act"` | ||||
| 	BatteryLevel      string `json:"bat_l" dc:"电量百分比"` | ||||
| 	BatteryVoltage    string `json:"bat_v" dc:"电池电压"` | ||||
| 	Charging          string `json:"charging"` | ||||
| 	GPS               string `json:"gps"` | ||||
| 	GPSLevel          string `json:"gps_level"` | ||||
| 	InUse             string `json:"in_use"` | ||||
| 	IsWorn            string `json:"is_weared"` | ||||
| 	NetStrength       string `json:"net_strenth"` | ||||
| 	NetType           string `json:"net_type"` | ||||
| 	NotUploadedVideos string `json:"notuploaded_video_count"` | ||||
| 	OnlineType        string `json:"online_type"` | ||||
| 	PhoneNumber       string `json:"phoneNumber"` | ||||
| 	RailStatus        string `json:"rail_status"` | ||||
| 	SIMDataNum        string `json:"sim_data_num"` | ||||
| 	SIMStatus         string `json:"sim_status"` | ||||
| 	TCardStatus       string `json:"tcard_status"` | ||||
| 	TempData          string `json:"tempdata"` | ||||
| 	UserID            string `json:"user_id"` | ||||
| 	XPoint            string `json:"x_point"` | ||||
| 	YPoint            string `json:"y_point"` | ||||
| 	CTime             int64  `json:"ctime"` | ||||
| 	CapType           string `json:"cap_type"` | ||||
| } | ||||
|  | ||||
| // DeviceData 包含用户信息和位置信息 | ||||
| type DeviceData struct { | ||||
| 	UserInfo     UserInfo     `json:"user_info"` | ||||
| 	LocationInfo LocationInfo `json:"location_info"` | ||||
| } | ||||
|  | ||||
| // 处理收到的心跳和实时数据信息 | ||||
| func HandleLocation(jsonString string) { | ||||
| 	var response LocationAndHeart | ||||
| 	// 解析 JSON 字符串到结构体 | ||||
| 	err := json.Unmarshal([]byte(jsonString), &response) | ||||
| 	if err != nil { | ||||
| 		log.Fatal("Error decoding JSON to struct:", err) | ||||
| 	} | ||||
|  | ||||
| 	var IsLowBattery int | ||||
| 	// 用来跟踪当前活跃的设备编号 | ||||
| 	activeDevices := make(map[string]bool) | ||||
|  | ||||
| 	// 获取当前时间,格式化为 YYYY-MM-DD | ||||
| 	currentTime := time.Now() | ||||
| 	todayDate := currentTime.Format("2006-01-02") | ||||
|  | ||||
| 	for _, v := range response.Data { | ||||
| 		// 标记此设备ID为活跃 | ||||
| 		activeDevices[v.UserInfo.DeviceID] = true | ||||
|  | ||||
| 		// 将 Unix 时间戳(秒)转换为 time.Time 类型 | ||||
| 		createTime := time.Unix(gconv.Int64(v.UserInfo.CTime), 0) | ||||
|  | ||||
| 		// 判断电量是否低于20%,如果是,则标记为低电量 | ||||
| 		if gconv.Int(v.LocationInfo.BatteryLevel) <= constant.BatteryLevel { | ||||
| 			IsLowBattery = 1 | ||||
| 		} | ||||
|  | ||||
| 		// 检查数据库中是否存在该设备 | ||||
| 		IfExists, _ := g.Model("device_video_hat").Where("dev_num", v.UserInfo.DeviceID).Count() | ||||
|  | ||||
| 		if IfExists == 0 { | ||||
| 			// 如果设备不存在,则插入新设备数据(不包括设备名称) | ||||
| 			devHat := g.Map{ | ||||
| 				"dev_num":        v.UserInfo.DeviceID, | ||||
| 				"status":         v.LocationInfo.InUse, | ||||
| 				"uid":            v.UserInfo.UserID, | ||||
| 				"battery_level":  v.LocationInfo.BatteryLevel, | ||||
| 				"is_low_battery": IsLowBattery, | ||||
| 				"create_time":    createTime, | ||||
| 				"longitude":      v.LocationInfo.XPoint, | ||||
| 				"latitude":       v.LocationInfo.YPoint, | ||||
| 				"sip_id":         v.UserInfo.SIPID, | ||||
| 			} | ||||
| 			g.Model("device_video_hat").Data(devHat).Save() | ||||
| 		} else { | ||||
| 			// 更新已存在的设备数据 | ||||
| 			updateData := g.Map{ | ||||
| 				"status":         v.LocationInfo.InUse, | ||||
| 				"uid":            v.UserInfo.UserID, | ||||
| 				"battery_level":  v.LocationInfo.BatteryLevel, | ||||
| 				"is_low_battery": IsLowBattery, | ||||
| 				"create_time":    createTime, | ||||
| 				"longitude":      v.LocationInfo.XPoint, | ||||
| 				"latitude":       v.LocationInfo.YPoint, | ||||
| 				"sip_id":         v.UserInfo.SIPID, | ||||
| 			} | ||||
| 			g.Model("device_video_hat").Data(updateData).Where("dev_num", v.UserInfo.DeviceID).Update() | ||||
| 		} | ||||
|  | ||||
| 		// 检查 device_data_time 表是否已有当天的记录 | ||||
| 		count, err := g.Model("device_data_time").Where("dev_num = ? AND data_time = ?", v.UserInfo.DeviceID, todayDate).Count() | ||||
| 		if err != nil { | ||||
| 			log.Println("Error checking device_data_time:", err) | ||||
| 			continue | ||||
| 		} | ||||
| 		if count == 0 { | ||||
| 			// 如果没有记录,则插入新数据 | ||||
| 			g.Model("device_data_time").Data(g.Map{ | ||||
| 				"dev_num":   v.UserInfo.DeviceID, | ||||
| 				"data_time": todayDate, | ||||
| 			}).Insert() | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// 从数据库中检索所有设备 | ||||
| 	var allDevices []struct{ DevNum string } | ||||
| 	err = g.Model("device_video_hat").Fields("dev_num AS DevNum").Scan(&allDevices) | ||||
| 	if err != nil { | ||||
| 		log.Fatal("Error retrieving all devices:", err) | ||||
| 	} | ||||
|  | ||||
| 	// 为不活跃的设备设置状态为0 | ||||
| 	for _, device := range allDevices { | ||||
| 		if _, isActive := activeDevices[device.DevNum]; !isActive { | ||||
| 			g.Model("device_video_hat").Data(g.Map{"status": 0}).Where("dev_num", device.DevNum).Update() | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										153
									
								
								api/video_hat/ws2/ws2.4.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										153
									
								
								api/video_hat/ws2/ws2.4.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,153 @@ | ||||
| package ws2 | ||||
|  | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"github.com/gogf/gf/v2/frame/g" | ||||
| 	"github.com/tiger1103/gfast/v3/api/constant" | ||||
| 	"github.com/tiger1103/gfast/v3/api/video_hat/alarm" | ||||
| 	"io/ioutil" | ||||
| 	"log" | ||||
| 	"net/http" | ||||
| 	"strconv" | ||||
| 	"time" | ||||
| ) | ||||
|  | ||||
| type CaInfo struct { | ||||
| 	UserID           string `json:"user_id"` | ||||
| 	DeviceID         string `json:"device_id"` | ||||
| 	CaVer            string `json:"ca_ver"` | ||||
| 	Mobile           string `json:"mobile"` | ||||
| 	SIM              string `json:"sim"` | ||||
| 	Password         string `json:"pwd"` | ||||
| 	CTime            string `json:"c_time"` | ||||
| 	AppLastLoginTime string `json:"app_last_login_time"` | ||||
| 	CaLastLoginTime  string `json:"ca_last_login_time"` | ||||
| 	UserName         string `json:"user_name"` | ||||
| 	RealName         string `json:"real_name"` | ||||
| 	UserImg          string `json:"user_img"` | ||||
| 	Department       string `json:"department"` | ||||
| 	Role             string `json:"role"` | ||||
| 	FID              string `json:"f_id"` | ||||
| 	CapType          string `json:"cap_type"` | ||||
| } | ||||
|  | ||||
| type ServerPushCaSipSos struct { | ||||
| 	Cmd            string `json:"cmd"` | ||||
| 	Type           string `json:"type"` | ||||
| 	RoomID         string `json:"room_id"` | ||||
| 	SosRoomID      string `json:"sos_room_id"` | ||||
| 	PictureQuality string `json:"picture_quality"` | ||||
| 	CaInfo         CaInfo `json:"ca_info"` | ||||
| 	XPoint         string `json:"x_point"` | ||||
| 	YPoint         string `json:"y_point"` | ||||
| 	Time           int64  `json:"time"` | ||||
| } | ||||
|  | ||||
| // 处理SOS信息 | ||||
| func HandlePushCaSipSos(jsonString string) { | ||||
| 	var response ServerPushCaSipSos | ||||
| 	err := json.Unmarshal([]byte(jsonString), &response) | ||||
| 	deviceID := response.CaInfo.DeviceID | ||||
| 	var videoHat VideoDeviceHat | ||||
| 	g.Model("device_video_hat").Where("dev_num = ?", deviceID).Scan(&videoHat) | ||||
|  | ||||
| 	// 发送请求去获取设备的 sip_id 信息 https://caps.runde.pro/api/index.php?ctl=device&act=get_user_sip_id | ||||
| 	res, _ := getSipId(constant.Token, videoHat.Uid) | ||||
| 	sipid := res.Data.SIPID | ||||
|  | ||||
| 	// 收到了报警 SOS 信息,把数据写入数据库,处理标记为未处理 | ||||
| 	data := alarm.HatAlarm{ | ||||
| 		DevNum:       deviceID, | ||||
| 		DevName:      videoHat.DevName, | ||||
| 		ProjectID:    int(videoHat.ProjectID), | ||||
| 		BatteryLevel: videoHat.BatteryLevel, | ||||
| 		IsLowBattery: videoHat.IsLowBattery, | ||||
| 		RoomID:       response.RoomID, | ||||
| 		SipId:        sipid, | ||||
| 		IsHandle:     strconv.Itoa(0), | ||||
| 		HandleAt:     time.Time{}, | ||||
| 	} | ||||
| 	g.Model("hat_alarm").Data(data).Insert() | ||||
| 	if err != nil { | ||||
| 		log.Fatal("Error decoding JSON to struct:", err) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func getSipId(token string, userId int) (res *Response, err error) { | ||||
| 	res = new(Response) | ||||
|  | ||||
| 	// 创建请求 | ||||
| 	req, err := http.NewRequest("GET", "https://caps.runde.pro/api/index.php?ctl=device&act=get_user_sip_id", nil) | ||||
| 	if err != nil { | ||||
| 		return res, err | ||||
| 	} | ||||
|  | ||||
| 	// 添加请求头 | ||||
| 	req.Header.Set("Authentication", token) | ||||
|  | ||||
| 	// 添加查询参数 | ||||
| 	query := req.URL.Query() | ||||
| 	query.Add("user_id", strconv.Itoa(userId)) | ||||
| 	req.URL.RawQuery = query.Encode() | ||||
|  | ||||
| 	// 发送请求 | ||||
| 	client := &http.Client{} | ||||
| 	resp, err := client.Do(req) | ||||
| 	if err != nil { | ||||
| 		return res, err | ||||
| 	} | ||||
| 	defer resp.Body.Close() | ||||
|  | ||||
| 	// 读取响应体 | ||||
| 	respBody, err := ioutil.ReadAll(resp.Body) | ||||
| 	if err != nil { | ||||
| 		return res, err | ||||
| 	} | ||||
|  | ||||
| 	// 检查响应状态码 | ||||
| 	if resp.StatusCode != http.StatusOK { | ||||
| 		return res, errors.New(fmt.Sprintf("unexpected status code: %d", resp.StatusCode)) | ||||
| 	} | ||||
|  | ||||
| 	// 反序列化响应体到结构体 | ||||
| 	err = json.Unmarshal(respBody, &res) | ||||
| 	if err != nil { | ||||
| 		return res, err | ||||
| 	} | ||||
|  | ||||
| 	return res, nil | ||||
| } | ||||
|  | ||||
| type Response struct { | ||||
| 	Status  bool       `json:"status"` | ||||
| 	Msg     string     `json:"msg"` | ||||
| 	Data    DataObject `json:"data"` | ||||
| 	MsgCode string     `json:"msg_code"` | ||||
| } | ||||
|  | ||||
| type DataObject struct { | ||||
| 	SIPID string `json:"sip_id"` | ||||
| } | ||||
|  | ||||
| type VideoDeviceHat struct { | ||||
| 	DevNum       string    `json:"dev_num"`        // 设备编号 | ||||
| 	DevName      string    `json:"dev_name"`       // 设备名 | ||||
| 	Status       int       `json:"status"`         // 安全帽状态(0:离线,1:在线,2:监控中,3:通话中,4:隐私模式) | ||||
| 	ProjectID    int64     `json:"project_id"`     // 项目id | ||||
| 	UserID       string    `json:"user_id"`        // 用户id | ||||
| 	BatteryLevel string    `json:"battery_level"`  // 电量 | ||||
| 	IsLowBattery bool      `json:"is_low_battery"` // 是否处于低电量,true代表低电量,false则不是低电量 | ||||
| 	CreateTime   time.Time `json:"create_time"`    // 创建时间 | ||||
| 	UpdatedAt    time.Time `json:"updated_at"`     // 更新时间 | ||||
| 	Longitude    string    `json:"longitude"`      // 最新的经度 | ||||
| 	Latitude     string    `json:"latitude"`       // 最新的维度 | ||||
| 	SipId        int       `json:"sip_id"`         // SIPID | ||||
| 	Uid          int       `json:"uid"`            // 安全帽厂商返回的用户ID | ||||
| 	PushStatus   string    `json:"push_status"`    // 推流状态 | ||||
| 	Nickname     string    `json:"nick_name"`      // 用户名称 | ||||
| 	UserName     string    `json:"user_name"`      // 真实名称 | ||||
| 	HeadIcon     string    `json:"head_icon"`      // 头像 | ||||
| 	Phone        string    `json:"phone"`          // 电话 | ||||
| } | ||||
							
								
								
									
										84
									
								
								api/video_hat/ws2/ws2.5.1.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								api/video_hat/ws2/ws2.5.1.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,84 @@ | ||||
| package ws2 | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"github.com/gogf/gf/v2/frame/g" | ||||
| 	"github.com/gorilla/websocket" | ||||
| 	"github.com/tiger1103/gfast/v3/api/constant" | ||||
| 	"log" | ||||
| 	"strings" | ||||
| 	"time" | ||||
| ) | ||||
|  | ||||
| type OpenPushFlowReq struct { | ||||
| 	g.Meta `path:"/device/open" method:"post" tags:"视频安全帽相关" summary:"开启推流"` | ||||
| 	DevNum string `json:"devNum" dc:"设备id"` | ||||
| } | ||||
|  | ||||
| type OpenPushFlowRes struct { | ||||
| 	Url string `json:"Url" dc:"返回地址"` | ||||
| } | ||||
|  | ||||
| // 设备地址的 Map 映射通道 | ||||
| var deviceChannels = make(map[string]chan string) | ||||
|  | ||||
| func (w WsRouter) OpenPushFlow(ctx context.Context, req *OpenPushFlowReq) (res *OpenPushFlowRes, err error) { | ||||
| 	// 创建设备ID对应的通道 | ||||
| 	deviceChan := make(chan string, 1) // 缓冲为1 | ||||
| 	deviceChannels[req.DevNum] = deviceChan | ||||
|  | ||||
| 	// 触发WS的推流 | ||||
| 	SendDeviceEnablesPushFlow(constant.Conn, req.DevNum) | ||||
|  | ||||
| 	// 等待接收 URL 或超时 | ||||
| 	select { | ||||
| 	case url := <-deviceChan: | ||||
| 		res = &OpenPushFlowRes{Url: url} | ||||
| 	case <-time.After(time.Second * 10): // 设置超时时间为10秒 | ||||
| 		err = fmt.Errorf("timeout waiting for URL") | ||||
| 	} | ||||
| 	// 清理工作 | ||||
| 	delete(deviceChannels, req.DevNum) | ||||
| 	close(deviceChan) | ||||
| 	return res, err | ||||
| } | ||||
|  | ||||
| // 发送报文指定设备开启推流 | ||||
| func SendDeviceEnablesPushFlow(conn *websocket.Conn, DeviceId string) { | ||||
| 	activeDevicesMessage := map[string]string{ | ||||
| 		"act":       "ma_open_rtsp", | ||||
| 		"device_id": DeviceId, | ||||
| 	} | ||||
|  | ||||
| 	conn.WriteJSON(activeDevicesMessage) | ||||
| } | ||||
|  | ||||
| type MaOpenRtspResponse struct { | ||||
| 	Cmd       string   `json:"cmd"` | ||||
| 	DeviceId  string   `json:"device_id"` | ||||
| 	Status    bool     `json:"status"` | ||||
| 	Msg       string   `json:"msg"` | ||||
| 	ApiUrl    string   `json:"api_url"` | ||||
| 	PlayUrl   []string `json:"play_url"` | ||||
| 	MsgCode   string   `json:"msg_code"` | ||||
| 	WebrtcUrl string   `json:"webrtc_url"` | ||||
| } | ||||
|  | ||||
| // 处理函数 | ||||
| func HandleDeviceEnablesPushFlow(jsonString string) { | ||||
| 	var response MaOpenRtspResponse | ||||
| 	err := json.Unmarshal([]byte(jsonString), &response) | ||||
| 	if err != nil { | ||||
| 		log.Fatal("Error decoding JSON to struct:", err) | ||||
| 	} | ||||
| 	for _, url := range response.PlayUrl { | ||||
| 		// 截取 FLV 结尾的视频并发送到 HTTP 响应的通道中 | ||||
| 		if strings.HasSuffix(url, ".flv") { | ||||
| 			if deviceChan, ok := deviceChannels[response.DeviceId]; ok { | ||||
| 				deviceChan <- url // 将URL发送到对应的通道 | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										48
									
								
								api/video_hat/ws2/ws2.5.2.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								api/video_hat/ws2/ws2.5.2.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,48 @@ | ||||
| package ws2 | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"encoding/json" | ||||
| 	"github.com/gogf/gf/v2/frame/g" | ||||
| 	"github.com/gorilla/websocket" | ||||
|  | ||||
| 	"github.com/tiger1103/gfast/v3/api/constant" | ||||
| ) | ||||
|  | ||||
| type OffPushFlowReq struct { | ||||
| 	g.Meta `path:"/device/off" method:"post" tags:"视频安全帽相关" summary:"关闭推流"` | ||||
| 	DevNum string `json:"devNum" dc:"设备id"` | ||||
| } | ||||
|  | ||||
| type OffPushFlowRes struct { | ||||
| } | ||||
|  | ||||
| func (w WsRouter) OffPushFlow(ctx context.Context, req *OffPushFlowReq) (res *OffPushFlowRes, err error) { | ||||
| 	SendDeviceOffPushFlow(constant.Conn, req.DevNum) | ||||
| 	return res, nil | ||||
| } | ||||
|  | ||||
| // 设备关闭推流 | ||||
| func SendDeviceOffPushFlow(conn *websocket.Conn, DeviceId string) { | ||||
| 	activeDevicesMessage := map[string]string{ | ||||
| 		"act":       "ma_stop_rtsp", | ||||
| 		"device_id": DeviceId, | ||||
| 	} | ||||
|  | ||||
| 	conn.WriteJSON(activeDevicesMessage) | ||||
| } | ||||
|  | ||||
| // MaStopRtspCommand 定义了停止RTSP流的命令结构体 | ||||
| type MaStopRtspCommand struct { | ||||
| 	Cmd      string `json:"cmd"`       // cmd 指令标识 | ||||
| 	DeviceID string `json:"device_id"` // device_id 设备ID | ||||
| 	Status   bool   `json:"status"`    // status 返回状态 | ||||
| 	Msg      string `json:"msg"`       // msg 返回消息 | ||||
| 	MsgCode  string `json:"msg_code"`  // msg_code 返回消息码 | ||||
| } | ||||
|  | ||||
| func HandStopPush(jsonString string) { | ||||
| 	var response MaStopRtspCommand | ||||
| 	json.Unmarshal([]byte(jsonString), &response) | ||||
|  | ||||
| } | ||||
		Reference in New Issue
	
	Block a user