type tokin_json_struct struct {
Code int json:"code,omitempty"
Message string json:"message,omitempty"
TTL int json:"ttl,omitempty"
Data struct {
//设定数据类型
Group string json:"group,omitempty"
BusinessID int json:"business_id,omitempty"
RefreshRowFactor float64 json:"refresh_row_factor,omitempty"
RefreshRate int json:"refresh_rate,omitempty"
MaxDelay int json:"max_delay,omitempty"
Token string json:"token,omitempty"
HostList []struct {
//获取服务器地址
Host string json:"host,omitempty"
//获取服务器通讯端口
Port int json:"port,omitempty"
//获取服务器WS通讯端口
WssPort int json:"wss_port,omitempty"
//获取服务器WS+TLS通讯端口
WsPort int json:"ws_port,omitempty"
} json:"host_list,omitempty"
} json:"data,omitempty"
}
package main
import ( "bytes" "context" "encoding/binary" "encoding/json" "fmt" //"strings"
)
type tokin_json_struct struct { Code int
json:"code,omitempty"
Message stringjson:"message,omitempty"
TTL intjson:"ttl,omitempty"
Data struct { //设定数据类型 Group stringjson:"group,omitempty"
BusinessID intjson:"business_id,omitempty"
RefreshRowFactor float64json:"refresh_row_factor,omitempty"
RefreshRate intjson:"refresh_rate,omitempty"
MaxDelay intjson:"max_delay,omitempty"
Token stringjson:"token,omitempty"
HostList []struct { //获取服务器地址 Host stringjson:"host,omitempty"
//获取服务器通讯端口 Port intjson:"port,omitempty"
//获取服务器WS通讯端口 WssPort intjson:"wss_port,omitempty"
//获取服务器WS+TLS通讯端口 WsPort intjson:"ws_port,omitempty"
}json:"host_list,omitempty"
}json:"data,omitempty"
}func main() { //tokin 认证密钥 roomid 房间ID //data 返回的数据
}
// 获取服务器列表及端口 以及tokin func get_tokin(rid string) (string, [][4]string) { response, err := http.Get("https://api.live.bilibili.com/xlive/web-room/v1/index/getDanmuInfo?id=" + rid+"&type=0") if err != nil { panic(err) } //defer response.Body.Close() b_body, err2 := ioutil.ReadAll(response.Body) if err2 != nil { panic(err2) } var tokin_json tokin_json_struct err3 := json.Unmarshal(b_body, &tokin_json) if err3 != nil { panic(err3) } host_list_arry := make([][4]string, 4) for i := 0; i < len(tokin_json.Data.HostList); i++ { host_list_arry[i][0] = tokin_json.Data.HostList[i].Host host_list_arry[i][1] = strconv.Itoa(tokin_json.Data.HostList[i].Port) host_list_arry[i][2] = strconv.Itoa(tokin_json.Data.HostList[i].WsPort) host_list_arry[i][3] = strconv.Itoa(tokin_json.Data.HostList[i].WssPort) } return (tokin_json.Data.Token), (host_list_arry) }
func get_id(rid string) string { response, err := http.Get("https://api.live.bilibili.com/xlive/web-room/v1/index/getDanmuInfo?id=" + rid+"&type=0") if err != nil { panic(err) } //defer response.Body.Close() b_body, err2 := ioutil.ReadAll(response.Body) if err2 != nil { panic(err2) }
} // int64 转 []byte func Int16ToBytes(i int16) []byte { var buf = make([]byte, 2) binary.BigEndian.PutUint16(buf, uint16(i)) return buf }
// int32 转 []byte func Int32ToBytes(i int32) []byte { var buf = make([]byte, 4) binary.BigEndian.PutUint32(buf, uint32(i)) return buf }
// 构建数据包 opt=0 认证包 opt=1 心跳包 func build_pack(tok string,rid string, seq int, opt int) ([]byte, int) { //打包数据 var tx_pack_buff bytes.Buffer var data, sequence, oper_code, rx_pack_full_size, tx_pack []byte //包头大小 head_size := []byte(Int16ToBytes(int16(16))) //协议版本 agr_ver := []byte(Int16ToBytes(int16(1))) //seq sequence = []byte(Int32ToBytes(int32(1))) if opt == 0 { //认证包内容 data = []byte(string("\"uid\":26895052,\"roomid\":" + rid + ",\"protover\":3,\"platform\":\"web\",\"type\":2,\"key\":\""+ tok +"\"}")) //认证包SEQ //sequence = Int32ToBytes(int32(1)) //认证包操作码 oper_code = Int32ToBytes(int32(7)) } else if opt == 1 { //心跳包内容 data = []byte("{\"heart\":0}") //心跳包SEQ //sequence = Int32ToBytes(int32(seq+1)) //心跳包操作码 oper_code = Int32ToBytes(int32(2)) } //数据包总大小 rx_pack_full_size = Int32ToBytes(int32(len(data) + 16)) //组合包 tx_pack_buff.Write(rx_pack_full_size) tx_pack_buff.Write(head_size) tx_pack_buff.Write(agr_ver) tx_pack_buff.Write(oper_code) tx_pack_buff.Write(sequence) tx_pack_buff.Write(data) //组合完成体 tx_pack = tx_pack_buff.Bytes() if opt == 0 { return tx_pack, 1 } else if opt == 1 { return tx_pack, (seq + 1) } else { return []byte(""), 0 } }
// 构建webcocket 类 func build_wsclass(url string) net.Conn { ctx := context.Background() conn, , _, err4 := ws.Dial(ctx, url) //fmt.Println(Ws_seraddr) //conn, , _, err4 := ws.Dial(ctx,Ws_ser_addr) if err4 != nil { panic(err4) } return conn }
// 发包 func tx_ws(conn net.Conn, rx_pack []byte) int { //WebSocket认证包发送 err5 := wsutil.WriteClientMessage(conn, ws.OpBinary, rx_pack) if err5 != nil { panic(err5) } return 0 }
// 收包 0 认证回包 1 心跳包 2 普通包 func rxws(conn net.Conn) (string, int) { msg, , err6 := wsutil.ReadServerData(conn) if err6 != nil { panic(err6) } json_data := string(msg[16:]) json_data2 := string(msg[20:]) //fmt.Println("人气值(POP):" + string(msg[14:15]) + " Back_pack:" + json_data) if json_data == "{\"code\":0}" { return json_data, 0 } else if json_data2 == "{\"hea" { fmt.Println("Get_heart_Success") return "{\"pop\":" + string(msg[14:15]) + "}", 1 } else { return json_data, 2 } }
func TickerforHeart(conn net.Conn, tok string,rid string) int { var b_seq int seq := 1 var heart_pack []byte heart := time.NewTicker(15 * time.Second) defer heart.Stop() for range heart.C { heart_pack, b_seq = build_pack(tok,rid, seq, 1) //构建心跳包 if tx_ws(conn, heart_pack) == 0 { seq = b_seq //发送心跳包 fmt.Println("Send_heart_Success Seq:"+ strconv.Itoa(seq))
}
//发送认证包->接收认证包回应->接收普通包&(每30秒发送心跳包->接收心跳回应)