master
This commit is contained in:
commit
b4a7f4e53f
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
*.exe
|
||||
.idea
|
58
cert.crt
Normal file
58
cert.crt
Normal file
@ -0,0 +1,58 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEeDCCAmCgAwIBAgIIEtc4Hk5jNvIwDQYJKoZIhvcNAQELBQAwVDELMAkGA1UE
|
||||
BhMCQ04xDzANBgNVBAcTBlN1emhvdTEQMA4GA1UECgwHRXZhbl9DQTEQMA4GA1UE
|
||||
CwwHRXZhbl9DQTEQMA4GA1UEAwwHRXZhbl9DQTAeFw0yMDA5MDMwMTA1MDBaFw0y
|
||||
MTA5MDMwMTA1MDBaMBkxFzAVBgNVBAMMDioubWlyaWxsaXMuY29tMIIBIjANBgkq
|
||||
hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwcf0gqkGW79baJ39995n1YirD4x5KtnC
|
||||
3CsD1gftE/va3GZMToBsP3jdohi5TRvB/CnF6Ngv22kszDWTwLKg/K73D+5dfu8m
|
||||
xVyxx2kU4uzC0NR0Z2AtumWIS05N/S53PWESBbCgPBJLcGKqLULYXf9EvEPtXebh
|
||||
i68C4aGnCmWOcMCLH/VrCcwFT15eR6zsD3whv8Oqpdj5aneItpEaWd8dzBrHO69k
|
||||
byfqK/GL14eLtPClVoY0EQ8z6hNqNTil6eseBdEuwytND5LJnfzarXCBxdnh74CE
|
||||
u4nxZcgEIx3hoSpLJVtHiZfGXPZgtIech3LgcAcAmcaI6wtD94Z5pQIDAQABo4GI
|
||||
MIGFMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFK5Br4x8HWHZOIAYSdYxEj1JW/TF
|
||||
MA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw
|
||||
JwYDVR0RBCAwHoIOKi5taXJpbGxpcy5jb22CDG1pcmlsbGlzLmNvbTANBgkqhkiG
|
||||
9w0BAQsFAAOCAgEARlaPieyqlQgp9xsMd6Qc59Wx90NJF8BbkXOxxP9A84Pf93D/
|
||||
oYhSWJQepDl6Q9aw4BuXBYMOrBJiOpMwbm1cv8YdCiNZUAS3mOwhgffBUwcJPnGt
|
||||
/YjOulNDYu9sq09MlS6MALMZs7Dqfzh3RHzaWLsSEXZrsFUw2ONCKxjCT33Zv30v
|
||||
1uKpWONRRcfPQV/b72uYrJf+ByX7gYZKSssolj1aq3qtxBitZR05EV4iWCPBp7tz
|
||||
y0wQcz9+vbfE9tdo+VECuD8Rldl770VE6GZnL9/jAwLsv8VB+9z7jlvbcfwdatvv
|
||||
FYE1dSPkw2eQq0/urrFv2thqISKv/qO8SsHYnXfA6gbHuz8WHH6DYc57ArLAO329
|
||||
5bdVEn5hL/rWxUx/QipjCmtlIBG1eqUSfdAKOWK3PVUC3NqwoUSBoNLxJ9xU9rJB
|
||||
7xdOEP0TdXyCOhaiLYCv3FoHRfgTwrtHiSoi3hyHftxjwKGtyrFo1rS3FTdLHret
|
||||
IRWIzIV7NP9gGYNZaCG+V2fQqxOFjH+lR7hvrOHP+oX2M8D6rnIPWvJtZLpnxIyF
|
||||
kDPS2ch0TR5UtohXiGfO5mx/m4CVKcrcRTJGVQSkGv0VZ1cHSvxZayGgTfkOIUBu
|
||||
YPHJeQBt6agjGzAUOxHzRa4xdyYIUMC6/nv8SMAIPTUEBq1GvE4kPmB48MI=
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
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
|
||||
a2PBtACsbvJx70oiDxZ1yw==
|
||||
-----END CERTIFICATE-----
|
14
common.go
Normal file
14
common.go
Normal file
@ -0,0 +1,14 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
func formatJson(v interface{}) []byte {
|
||||
marshal, _ := json.Marshal(v)
|
||||
var b bytes.Buffer
|
||||
json.Indent(&b, marshal, "", " ")
|
||||
|
||||
return b.Bytes()
|
||||
}
|
25
login.go
Normal file
25
login.go
Normal file
@ -0,0 +1,25 @@
|
||||
package main
|
||||
|
||||
type LoginRequest struct {
|
||||
Login string `json:"login"`
|
||||
Password string `json:"password"`
|
||||
Fingerprint string `json:"fingerprint"`
|
||||
}
|
||||
|
||||
type LoginResponse struct {
|
||||
CreatedAt int64 `json:"created_at,omitempty"` //1599031125
|
||||
ApiKey string `json:"apikey,omitempty"` //"apikey-af461547-da12-5e33-9a99-c63d9000762b"
|
||||
MacAddress string `json:"mac_address,omitempty"` //"04ea56b3f380"
|
||||
Metadata string `json:"metadata,omitempty"` //"{\"os\":\"1\",\"state\":\"online\",\"streamer\":\"0\",\"type\":\"2\"}"
|
||||
Fingerprint string `json:"fingerprint,omitempty"` //"fingerprint": "45c9dd6c-6925-a994-3fc3-c26cdec786ce",
|
||||
Id string `json:"id,omitempty"` // "id": "device-4d4c9fba-4d11-5b10-b3b3-05346a7bd4d2",
|
||||
Client string `json:"client,omitempty"` //"client": "client-8c220f6e-3432-5f41-80f2-b830f7b60658",
|
||||
Name string `json:"name,omitemptys"` //"name": "DESKTOP-3H0CLPE"
|
||||
}
|
||||
|
||||
type AddDeviceRequest struct {
|
||||
Name string `json:"name"` //DESKTOP-3H0CLPE
|
||||
MacAddress string `json:"mac_address"` //04ea56b3f380
|
||||
Fingerprint string `json:"fingerprint"`
|
||||
Metadata string `json:"metadata"`
|
||||
}
|
251
management.go
Normal file
251
management.go
Normal file
@ -0,0 +1,251 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gorilla/websocket"
|
||||
uuid "github.com/satori/go.uuid"
|
||||
"math/rand"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type MonfloManagement struct {
|
||||
clients []*ClientInfo
|
||||
}
|
||||
|
||||
type ClientInfo struct {
|
||||
UserName string `json:"user_name"`
|
||||
Metadata string `json:"metadata"`
|
||||
Name string `json:"name"`
|
||||
PrivateAddr string `json:"private_addr"`
|
||||
PublicAddr string `json:"public_addr"`
|
||||
Key string `json:"key"`
|
||||
Bitrate int `json:"bitrate"`
|
||||
Formats []string `json:"formats"` //h264 h265
|
||||
Stream string `json:"stream"`
|
||||
ClientStatus string `json:"client_status"` //online offline
|
||||
StreamStatus string `json:"stream_status"` //ready busy
|
||||
CreatedAt int64 `json:"created_at"` //1599031125
|
||||
ApiKey string `json:"apikey"` //"apikey-af461547-da12-5e33-9a99-c63d9000762b"
|
||||
MacAddress string `json:"mac_address"` //"04ea56b3f380"
|
||||
Fingerprint string `json:"fingerprint"` //"fingerprint": "45c9dd6c-6925-a994-3fc3-c26cdec786ce",
|
||||
Id string `json:"id"` // "id": "device-4d4c9fba-4d11-5b10-b3b3-05346a7bd4d2",
|
||||
Client string `json:"client"` //"client": "client-8c220f6e-3432-5f41-80f2-b830f7b60658",
|
||||
wsConn *websocket.Conn
|
||||
StreamId string `json:"stream_id"` //40832596627
|
||||
ClientType string `json:"client_type"` //client server
|
||||
}
|
||||
|
||||
func (m *MonfloManagement) checkExist(userName string, fingerprint string) bool {
|
||||
if m.clients == nil {
|
||||
return false
|
||||
}
|
||||
for _, client := range m.clients {
|
||||
if client.Fingerprint == fingerprint && client.UserName == userName {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (m *MonfloManagement) getClient(userName string, fingerprint string) *ClientInfo {
|
||||
|
||||
for _, client := range m.clients {
|
||||
if client.Fingerprint == fingerprint && client.UserName == userName {
|
||||
return client
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MonfloManagement) getClientByApiKey(apiKey string) *ClientInfo {
|
||||
for _, client := range m.clients {
|
||||
if client.ApiKey == apiKey {
|
||||
return client
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MonfloManagement) getClientByFingerprint(fingerprint string) *ClientInfo {
|
||||
|
||||
for _, client := range m.clients {
|
||||
if client.Fingerprint == fingerprint {
|
||||
return client
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MonfloManagement) addClient(userName string, fingerprint string) {
|
||||
if !m.checkExist(userName, fingerprint) {
|
||||
client := &ClientInfo{
|
||||
UserName: userName,
|
||||
CreatedAt: time.Now().Unix(),
|
||||
ApiKey: "apikey-" + fingerprint,
|
||||
Fingerprint: fingerprint,
|
||||
Id: "device-" + fingerprint,
|
||||
Client: "client-" + fingerprint,
|
||||
ClientStatus: "offline",
|
||||
}
|
||||
m.clients = append(m.clients, client)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *MonfloManagement) addServer(clientStr string) *ClientInfo {
|
||||
for _, c := range m.clients {
|
||||
if c.Client == clientStr {
|
||||
return c
|
||||
}
|
||||
}
|
||||
client := &ClientInfo{
|
||||
Client: clientStr,
|
||||
CreatedAt: time.Now().Unix(),
|
||||
}
|
||||
m.clients = append(m.clients, client)
|
||||
return client
|
||||
}
|
||||
|
||||
func (m *MonfloManagement) addDevice(request AddDeviceRequest) {
|
||||
client := m.getClientByFingerprint(request.Fingerprint)
|
||||
client.Name = request.Name
|
||||
client.Fingerprint = request.Fingerprint
|
||||
client.Metadata = request.Metadata
|
||||
client.MacAddress = request.MacAddress
|
||||
if strings.Contains(request.Metadata, "\"streamer\":\"1\",") {
|
||||
client.ClientType = "server"
|
||||
} else {
|
||||
client.ClientType = "client"
|
||||
}
|
||||
}
|
||||
|
||||
func (m *MonfloManagement) getPeers(userName string) map[string]PeerInfo {
|
||||
peers := make(map[string]PeerInfo)
|
||||
|
||||
if m.clients == nil {
|
||||
return peers
|
||||
}
|
||||
for _, client := range m.clients {
|
||||
if client.UserName == userName {
|
||||
streams := make(map[string]StreamInfo)
|
||||
var formats = []string{"h264", "h265"}
|
||||
if client.Stream != "" {
|
||||
streams[client.Stream] = StreamInfo{
|
||||
Id: client.Stream,
|
||||
Status: client.StreamStatus,
|
||||
OwnerClient: client.Client,
|
||||
Name: client.Name,
|
||||
PrivateAddr: client.PrivateAddr,
|
||||
PublicAddr: client.PublicAddr,
|
||||
Key: client.Key,
|
||||
Bitrate: 500000,
|
||||
Formats: formats,
|
||||
}
|
||||
}
|
||||
peers[client.Client] = PeerInfo{
|
||||
Name: client.Name,
|
||||
Status: client.ClientStatus, //online;offline
|
||||
LastIP: IPInfo{
|
||||
PrivateAddr: client.PrivateAddr,
|
||||
PublicAddr: client.PublicAddr,
|
||||
},
|
||||
Streams: streams,
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return peers
|
||||
}
|
||||
|
||||
func (m *MonfloManagement) getDevices(userName string) []LoginResponse {
|
||||
var devices []LoginResponse
|
||||
|
||||
if m.clients == nil {
|
||||
return devices
|
||||
}
|
||||
for _, client := range m.clients {
|
||||
if client.UserName == userName {
|
||||
device := LoginResponse{
|
||||
CreatedAt: client.CreatedAt,
|
||||
ApiKey: client.ApiKey,
|
||||
MacAddress: client.MacAddress,
|
||||
Metadata: client.Metadata,
|
||||
Fingerprint: client.Fingerprint,
|
||||
Id: client.Id,
|
||||
Client: client.Client,
|
||||
Name: client.Name,
|
||||
}
|
||||
devices = append(devices, device)
|
||||
}
|
||||
}
|
||||
return devices
|
||||
}
|
||||
|
||||
func (m *MonfloManagement) genId(client *ClientInfo) {
|
||||
id := 10000000009 + 8*rand.Int63n(5)
|
||||
for {
|
||||
if !m.checkIdExist(strconv.FormatInt(id, 10)) {
|
||||
break
|
||||
}
|
||||
id = 10000000009 + 8*rand.Int63n(10000)
|
||||
}
|
||||
client.StreamId = strconv.FormatInt(id, 10)
|
||||
}
|
||||
|
||||
func (m *MonfloManagement) genStream(client *ClientInfo) {
|
||||
uid, _ := uuid.NewV4()
|
||||
client.Stream = "stream-" + uid.String()
|
||||
client.StreamStatus = "ready"
|
||||
}
|
||||
|
||||
func (m *MonfloManagement) checkIdExist(id string) bool {
|
||||
for _, c := range m.clients {
|
||||
if c.Id == id {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (m *MonfloManagement) setOffline(clientId string) {
|
||||
del := -1
|
||||
for i, c := range m.clients {
|
||||
if c.Client == clientId {
|
||||
if c.ApiKey == "" && c.Id == "" {
|
||||
del = i
|
||||
}
|
||||
c.ClientStatus = "offline"
|
||||
}
|
||||
}
|
||||
if del >= 0 {
|
||||
m.clients = append(m.clients[:del], m.clients[del+1:]...)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *MonfloManagement) getClientStream(stream string) *ClientInfo {
|
||||
for _, c := range m.clients {
|
||||
if c.Stream == stream {
|
||||
return c
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MonfloManagement) getClientStreamId(streamId string) *ClientInfo {
|
||||
for _, c := range m.clients {
|
||||
if c.StreamId == streamId {
|
||||
return c
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MonfloManagement) getUserAllClient(userName string) []*ClientInfo {
|
||||
var clients []*ClientInfo
|
||||
for _, c := range m.clients {
|
||||
if c.UserName == userName {
|
||||
clients = append(clients, c)
|
||||
}
|
||||
}
|
||||
return clients
|
||||
}
|
583
monflo.go
Normal file
583
monflo.go
Normal file
@ -0,0 +1,583 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/gorilla/websocket"
|
||||
uuid "github.com/satori/go.uuid"
|
||||
"io/ioutil"
|
||||
"math/rand"
|
||||
"net"
|
||||
"net/http"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
upgrader = websocket.Upgrader{
|
||||
//允许跨域访问
|
||||
CheckOrigin: func(r *http.Request) bool {
|
||||
return true
|
||||
},
|
||||
EnableCompression: false,
|
||||
}
|
||||
managementService = MonfloManagement{}
|
||||
)
|
||||
|
||||
func main() {
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
go stun()
|
||||
http.HandleFunc("/2015-10-26/verification", verification)
|
||||
http.HandleFunc("/2015-10-26/devices", device)
|
||||
http.HandleFunc("/2015-10-26", wsHandler)
|
||||
http.HandleFunc("/config", configHandler)
|
||||
http.HandleFunc("/set", configSetHandler)
|
||||
http.HandleFunc("/peer", peerHandler)
|
||||
err := http.ListenAndServeTLS("", "cert.crt", "private.key", nil)
|
||||
if err != nil {
|
||||
fmt.Print(err)
|
||||
}
|
||||
}
|
||||
|
||||
func configHandler(w http.ResponseWriter, r *http.Request) {
|
||||
marshal, _ := json.Marshal(managementService.clients)
|
||||
w.Write(marshal)
|
||||
}
|
||||
|
||||
func configSetHandler(w http.ResponseWriter, r *http.Request) {
|
||||
var clients []*ClientInfo
|
||||
data, _ := ioutil.ReadAll(r.Body)
|
||||
|
||||
json.Unmarshal(data, &clients)
|
||||
managementService.clients = clients
|
||||
}
|
||||
|
||||
func peerHandler(w http.ResponseWriter, r *http.Request) {
|
||||
peers := managementService.getPeers(r.FormValue("username"))
|
||||
marshal, _ := json.Marshal(peers)
|
||||
w.Write(marshal)
|
||||
}
|
||||
|
||||
func stun() {
|
||||
address := "0.0.0.0:3478"
|
||||
addr, err := net.ResolveUDPAddr("udp", address)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
|
||||
conn, err := net.ListenUDP("udp", addr)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
|
||||
defer conn.Close()
|
||||
|
||||
for {
|
||||
// Here must use make and give the lenth of buffer
|
||||
data := make([]byte, 4096)
|
||||
_, rAddr, err := conn.ReadFromUDP(data)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
continue
|
||||
}
|
||||
//file, _ := ioutil.ReadFile("data.bin")
|
||||
//_, err = conn.WriteToUDP(file, rAddr)
|
||||
_, err = conn.WriteToUDP([]byte{254, 239, 1, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 6, 58, 210, 98, 46, 174, 198, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, rAddr)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func wsHandler(w http.ResponseWriter, r *http.Request) {
|
||||
var (
|
||||
wsConn *websocket.Conn
|
||||
err error
|
||||
mutex sync.Mutex
|
||||
client *ClientInfo
|
||||
)
|
||||
//Upgrade websocket(返回给客户端的消息)
|
||||
if wsConn, err = upgrader.Upgrade(w, r, nil); err != nil {
|
||||
//报错了,直接返回底层的websocket链接就会终断掉
|
||||
return
|
||||
}
|
||||
go func() {
|
||||
for {
|
||||
mutex.Lock()
|
||||
err2 := wsConn.WriteMessage(websocket.PingMessage, []byte{})
|
||||
mutex.Unlock()
|
||||
if err2 != nil {
|
||||
wsConn.Close()
|
||||
return
|
||||
}
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
fmt.Printf("Runtime error caught: %v", r)
|
||||
}
|
||||
}()
|
||||
|
||||
}()
|
||||
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
fmt.Printf("Runtime error caught: %v", r)
|
||||
}
|
||||
if nil != client {
|
||||
managementService.setOffline(client.Client)
|
||||
}
|
||||
}()
|
||||
mutex.Lock()
|
||||
wsConn.WriteMessage(websocket.TextMessage, []byte("{\n \"event\": \"cookie_created\",\n \"data\": \"5f0389ae63c5c5962de0bf1fa7edbb9e7605da388a8ffb2f69af4c47b1fde020\"\n}"))
|
||||
mutex.Unlock()
|
||||
client = new(ClientInfo)
|
||||
for {
|
||||
messageType, p, err := wsConn.ReadMessage()
|
||||
if err != nil {
|
||||
fmt.Printf("WebSocket异常断开," + wsConn.RemoteAddr().String() + ",异常信息:" + err.Error() + "\n")
|
||||
wsConn.Close()
|
||||
return
|
||||
}
|
||||
if messageType == websocket.CloseMessage {
|
||||
fmt.Printf("WebSocket断开," + wsConn.RemoteAddr().String() + "\n")
|
||||
wsConn.Close()
|
||||
return
|
||||
}
|
||||
fmt.Printf(string(p) + "\n")
|
||||
mutex.Lock()
|
||||
tempClient := wsProcess(wsConn, p, client)
|
||||
mutex.Unlock()
|
||||
if tempClient != nil {
|
||||
client = tempClient
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func wsProcess(wsConn *websocket.Conn, data []byte, client *ClientInfo) *ClientInfo {
|
||||
|
||||
str := string(data)
|
||||
|
||||
if len(str) == 0 {
|
||||
return nil
|
||||
}
|
||||
if str[0:1] == "{" {
|
||||
|
||||
var request MonfloRequest
|
||||
json.Unmarshal(data, &request)
|
||||
|
||||
if request.Uri == "/" {
|
||||
if request.Headers.ApiKey != "" {
|
||||
client = managementService.getClientByApiKey(request.Headers.ApiKey)
|
||||
client.wsConn = wsConn
|
||||
client.ClientStatus = "online"
|
||||
response := WelcomeInfo{
|
||||
MonfloResponse: MonfloResponse{
|
||||
Event: "welcome",
|
||||
},
|
||||
Data: WelcomeData{
|
||||
Client: client.Client,
|
||||
Features: Features{
|
||||
MaxUserProfiles: 1,
|
||||
MaxStreams: 128,
|
||||
MaxDevices: 128,
|
||||
MaxP2pResolution: 2160,
|
||||
MaxP2pFrames: 60,
|
||||
MaxRelayResolution: 2160,
|
||||
MaxRelayFrames: 60,
|
||||
Hevc: true,
|
||||
SessionRecording: true,
|
||||
ManagementConsole: true,
|
||||
ConnectAnywhere: false,
|
||||
Support: false,
|
||||
CommercialUse: false,
|
||||
DeviceThumbnails: false,
|
||||
FileTransfer: true,
|
||||
},
|
||||
Peers: managementService.getPeers(client.UserName),
|
||||
Subscription: 3,
|
||||
Timestamp: time.Now().Unix(),
|
||||
},
|
||||
}
|
||||
wsConn.WriteMessage(websocket.TextMessage, formatJson(response))
|
||||
wsConn.WriteMessage(websocket.TextMessage, []byte("{\"status\":200}"))
|
||||
|
||||
//如果是客户端登陆,需要通知该用户下所有的服务端
|
||||
//if client.ClientType == "client" {
|
||||
// streamClients := managementService.getUserAllClient(client.UserName)
|
||||
// if streamClients != nil {
|
||||
// for _, streamClient := range streamClients {
|
||||
// if streamClient.ClientStatus == "online" && streamClient.ClientType == "server" {
|
||||
// eventResponse := &ClientConnectedEvent{
|
||||
// MonfloResponse: MonfloResponse{
|
||||
// Event: "client_connected",
|
||||
// },
|
||||
// Data: client.Client,
|
||||
// }
|
||||
// streamClient.wsConn.WriteMessage(websocket.TextMessage, formatJson(eventResponse))
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
return client
|
||||
} else {
|
||||
//服务端匿名登录
|
||||
uid, _ := uuid.NewV4()
|
||||
|
||||
response := WelcomeInfo{
|
||||
MonfloResponse: MonfloResponse{
|
||||
Event: "welcome",
|
||||
},
|
||||
Data: WelcomeData{
|
||||
Client: "client-" + uid.String(),
|
||||
Features: Features{
|
||||
MaxUserProfiles: 1,
|
||||
MaxStreams: 128,
|
||||
MaxDevices: 128,
|
||||
MaxP2pResolution: 2160,
|
||||
MaxP2pFrames: 60,
|
||||
MaxRelayResolution: 2160,
|
||||
MaxRelayFrames: 60,
|
||||
Hevc: true,
|
||||
SessionRecording: true,
|
||||
ManagementConsole: true,
|
||||
ConnectAnywhere: false,
|
||||
Support: false,
|
||||
CommercialUse: false,
|
||||
DeviceThumbnails: false,
|
||||
FileTransfer: false,
|
||||
},
|
||||
Subscription: 3,
|
||||
Peers: make(map[string]PeerInfo),
|
||||
Timestamp: time.Now().Unix(),
|
||||
},
|
||||
}
|
||||
client = managementService.addServer(response.Data.Client)
|
||||
client.wsConn = wsConn
|
||||
client.ClientType = "server"
|
||||
client.ClientStatus = "online"
|
||||
wsConn.WriteMessage(websocket.TextMessage, formatJson(response))
|
||||
wsConn.WriteMessage(websocket.TextMessage, []byte("{\"status\":200}"))
|
||||
return client
|
||||
}
|
||||
}
|
||||
|
||||
if request.Uri == "/devices/current" && request.Method == "PATCH" {
|
||||
client.Metadata = request.Data.Metadata
|
||||
response := PatchDeviceResponse{
|
||||
MonfloResponse: MonfloResponse{
|
||||
Status: 200,
|
||||
},
|
||||
Data: LoginResponse{
|
||||
Metadata: client.Metadata,
|
||||
Id: client.Id,
|
||||
},
|
||||
}
|
||||
wsConn.WriteMessage(websocket.TextMessage, formatJson(response))
|
||||
}
|
||||
|
||||
if request.Method == "PATCH" && strings.Contains(request.Uri, "/streams/stream-") {
|
||||
streamId := request.Uri[9:]
|
||||
client.Key = request.Data.Key
|
||||
client.PrivateAddr = request.Data.PrivateAddr
|
||||
client.PublicAddr = request.Data.PublicAddr
|
||||
client.StreamStatus = request.Data.Status
|
||||
response := MonfloResponse{
|
||||
Status: 200,
|
||||
}
|
||||
wsConn.WriteMessage(websocket.TextMessage, formatJson(response))
|
||||
|
||||
//通知所有该账号的客户端更新服务端信息
|
||||
|
||||
streamClients := managementService.getUserAllClient(client.UserName)
|
||||
if streamClients != nil {
|
||||
for _, streamClient := range streamClients {
|
||||
if streamClient.ClientStatus == "online" && streamClient.ClientType == "client" {
|
||||
response2 := &StreamResponse{
|
||||
MonfloResponse: MonfloResponse{
|
||||
Event: "stream_updated",
|
||||
},
|
||||
Data: StreamInfo{
|
||||
Id: streamId,
|
||||
Key: request.Data.Key,
|
||||
Status: request.Data.Status,
|
||||
OwnerClient: client.Client,
|
||||
PrivateAddr: request.Data.PrivateAddr,
|
||||
PublicAddr: request.Data.PublicAddr,
|
||||
},
|
||||
}
|
||||
wsConn.WriteMessage(websocket.TextMessage, formatJson(response2))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if request.Uri == "/devices" && request.Method == "GET" {
|
||||
response := DeviceResponse{
|
||||
MonfloResponse: MonfloResponse{
|
||||
Status: 200,
|
||||
},
|
||||
Data: LoginResponse{
|
||||
Metadata: client.Metadata,
|
||||
Id: client.Id,
|
||||
},
|
||||
}
|
||||
wsConn.WriteMessage(websocket.TextMessage, formatJson(response))
|
||||
}
|
||||
if request.Uri == "/peers" && request.Method == "GET" {
|
||||
peers := managementService.getPeers(client.UserName)
|
||||
response := PeersResponse{
|
||||
MonfloResponse: MonfloResponse{
|
||||
Status: 200,
|
||||
},
|
||||
Data: peers,
|
||||
}
|
||||
wsConn.WriteMessage(websocket.TextMessage, formatJson(response))
|
||||
}
|
||||
|
||||
if request.Method == "POST" && request.Uri == "/incognitos" {
|
||||
if request.Data.Stream != "" {
|
||||
//登录账户模式
|
||||
managementService.genId(client)
|
||||
} else {
|
||||
//服务端匿名模式
|
||||
client.PrivateAddr = request.Data.PrivateAddr
|
||||
client.PublicAddr = request.Data.PublicAddr
|
||||
client.Bitrate = request.Data.Bitrate
|
||||
client.Key = request.Data.Key
|
||||
client.Formats = request.Data.Formats
|
||||
//分配Id
|
||||
managementService.genId(client)
|
||||
client.Id = client.StreamId
|
||||
//分配StreamId
|
||||
managementService.genStream(client)
|
||||
}
|
||||
|
||||
response := &IncognitosResponse{
|
||||
MonfloResponse: MonfloResponse{
|
||||
Status: 200,
|
||||
},
|
||||
Data: IncognitosData{
|
||||
Id: client.StreamId,
|
||||
Stream: client.Stream,
|
||||
Client: client.Client,
|
||||
},
|
||||
}
|
||||
wsConn.WriteMessage(websocket.TextMessage, formatJson(response))
|
||||
}
|
||||
|
||||
if request.Method == "POST" && request.Uri == "/streams" {
|
||||
client.PrivateAddr = request.Data.PrivateAddr
|
||||
client.PublicAddr = request.Data.PublicAddr
|
||||
client.Bitrate = request.Data.Bitrate
|
||||
client.Key = request.Data.Key
|
||||
client.Formats = request.Data.Formats
|
||||
|
||||
managementService.genStream(client)
|
||||
|
||||
response := &StreamResponse{
|
||||
MonfloResponse: MonfloResponse{
|
||||
Status: 200,
|
||||
},
|
||||
Data: StreamInfo{
|
||||
Id: client.Stream,
|
||||
Status: "ready",
|
||||
OwnerClient: client.Client,
|
||||
Name: "0",
|
||||
PrivateAddr: client.PrivateAddr,
|
||||
PublicAddr: client.PublicAddr,
|
||||
Key: client.Key,
|
||||
Bitrate: client.Bitrate,
|
||||
Formats: client.Formats,
|
||||
},
|
||||
}
|
||||
wsConn.WriteMessage(websocket.TextMessage, formatJson(response))
|
||||
}
|
||||
|
||||
if request.Method == "GET" && (request.Uri == "/invitations/logins" || request.Uri == "/invitations" || request.Uri == "/shortcuts") {
|
||||
response := &MonfloResponse{
|
||||
Status: 200,
|
||||
}
|
||||
wsConn.WriteMessage(websocket.TextMessage, formatJson(response))
|
||||
}
|
||||
|
||||
if request.Method == "GET" && strings.Contains(request.Uri, "/streams/stream-") {
|
||||
streamCode := request.Uri[9:]
|
||||
stream := managementService.getClientStream(streamCode)
|
||||
if stream != nil {
|
||||
response := &StreamResponse{
|
||||
MonfloResponse: MonfloResponse{
|
||||
Status: 200,
|
||||
},
|
||||
Data: StreamInfo{
|
||||
Id: stream.Stream,
|
||||
Status: "ready",
|
||||
OwnerClient: stream.Client,
|
||||
Name: "0",
|
||||
PrivateAddr: stream.PrivateAddr,
|
||||
PublicAddr: stream.PublicAddr,
|
||||
Key: stream.Key,
|
||||
Bitrate: stream.Bitrate,
|
||||
Formats: stream.Formats,
|
||||
},
|
||||
}
|
||||
wsConn.WriteMessage(websocket.TextMessage, formatJson(response))
|
||||
|
||||
response2 := &StreamReadResponse{
|
||||
MonfloResponse: MonfloResponse{
|
||||
Event: "_stream_read",
|
||||
},
|
||||
Data: StreamReadData{
|
||||
Client: client.Client,
|
||||
Format: request.Headers.Format,
|
||||
Id: stream.Stream,
|
||||
PrivateAddr: request.Headers.PrivateAddr,
|
||||
PublicAddr: request.Headers.PublicAddr,
|
||||
Type: request.Headers.Type,
|
||||
},
|
||||
}
|
||||
stream.wsConn.WriteMessage(websocket.TextMessage, formatJson(response2))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if request.Method == "GET" && strings.Contains(request.Uri, "/incognitos/") {
|
||||
stream := managementService.getClientStreamId(request.Uri[12:])
|
||||
if stream != nil {
|
||||
response := &StreamResponse{
|
||||
MonfloResponse: MonfloResponse{
|
||||
Status: 200,
|
||||
},
|
||||
Data: StreamInfo{
|
||||
Id: stream.Stream,
|
||||
Status: "ready",
|
||||
OwnerClient: stream.Client,
|
||||
Name: stream.StreamId,
|
||||
PrivateAddr: stream.PrivateAddr,
|
||||
PublicAddr: stream.PublicAddr,
|
||||
Key: stream.Key,
|
||||
Bitrate: stream.Bitrate,
|
||||
Formats: stream.Formats,
|
||||
},
|
||||
}
|
||||
wsConn.WriteMessage(websocket.TextMessage, formatJson(response))
|
||||
|
||||
response2 := &StreamReadResponse{
|
||||
MonfloResponse: MonfloResponse{
|
||||
Event: "_stream_read",
|
||||
},
|
||||
Data: StreamReadData{
|
||||
Client: client.Client,
|
||||
Format: request.Headers.Format,
|
||||
Id: stream.Stream,
|
||||
PrivateAddr: request.Headers.PrivateAddr,
|
||||
PublicAddr: request.Headers.PublicAddr,
|
||||
Type: request.Headers.Type,
|
||||
},
|
||||
}
|
||||
|
||||
stream.wsConn.WriteMessage(websocket.TextMessage, formatJson(response2))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else if str[0:1] == "[" {
|
||||
var requests []MonfloRequest
|
||||
json.Unmarshal(data, &requests)
|
||||
|
||||
var datas []interface{}
|
||||
for _, request := range requests {
|
||||
if request.Uri == "/devices" && request.Method == "GET" {
|
||||
device := managementService.getDevices(client.UserName)
|
||||
response := DevicesResponse{
|
||||
MonfloResponse: MonfloResponse{
|
||||
Status: 200,
|
||||
},
|
||||
Data: device,
|
||||
}
|
||||
datas = append(datas, response)
|
||||
}
|
||||
if request.Uri == "/info" && request.Method == "GET" {
|
||||
|
||||
response := MonfloResponse{
|
||||
Status: 200,
|
||||
}
|
||||
datas = append(datas, response)
|
||||
}
|
||||
}
|
||||
wsConn.WriteMessage(websocket.TextMessage, formatJson(datas))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func verification(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Add("Server", "MonfloHTTPServer")
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
data, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
fmt.Print(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Print("verification:" + string(data) + "\n")
|
||||
var loginRequest LoginRequest
|
||||
json.Unmarshal(data, &loginRequest)
|
||||
|
||||
if !managementService.checkExist(loginRequest.Login, loginRequest.Fingerprint) {
|
||||
w.WriteHeader(404)
|
||||
return
|
||||
}
|
||||
client := managementService.getClient(loginRequest.Login, loginRequest.Fingerprint)
|
||||
client.UserName = loginRequest.Login
|
||||
response := LoginResponse{
|
||||
CreatedAt: client.CreatedAt,
|
||||
ApiKey: client.ApiKey,
|
||||
MacAddress: client.MacAddress,
|
||||
Metadata: client.Metadata,
|
||||
Fingerprint: client.Fingerprint,
|
||||
Id: client.Id,
|
||||
Client: client.Client,
|
||||
Name: client.Name,
|
||||
}
|
||||
|
||||
marshal, _ := json.Marshal(response)
|
||||
w.Write(marshal)
|
||||
}
|
||||
|
||||
func device(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Add("Server", "MonfloHTTPServer")
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
data, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
fmt.Print(err.Error())
|
||||
return
|
||||
}
|
||||
fmt.Print("Add Device:" + string(data) + "\n")
|
||||
var addDeviceRequest AddDeviceRequest
|
||||
json.Unmarshal(data, &addDeviceRequest)
|
||||
|
||||
userName := r.Header.Get("Monflo-login")
|
||||
managementService.addClient(userName, addDeviceRequest.Fingerprint)
|
||||
managementService.addDevice(addDeviceRequest)
|
||||
|
||||
client := managementService.getClientByFingerprint(addDeviceRequest.Fingerprint)
|
||||
|
||||
response := LoginResponse{
|
||||
CreatedAt: client.CreatedAt,
|
||||
ApiKey: client.ApiKey,
|
||||
MacAddress: client.MacAddress,
|
||||
Metadata: client.Metadata,
|
||||
Fingerprint: client.Fingerprint,
|
||||
Id: client.Id,
|
||||
Client: client.Client,
|
||||
Name: client.Name,
|
||||
}
|
||||
|
||||
marshal, _ := json.Marshal(response)
|
||||
w.Write(marshal)
|
||||
}
|
27
private.key
Normal file
27
private.key
Normal file
@ -0,0 +1,27 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEowIBAAKCAQEAwcf0gqkGW79baJ39995n1YirD4x5KtnC3CsD1gftE/va3GZM
|
||||
ToBsP3jdohi5TRvB/CnF6Ngv22kszDWTwLKg/K73D+5dfu8mxVyxx2kU4uzC0NR0
|
||||
Z2AtumWIS05N/S53PWESBbCgPBJLcGKqLULYXf9EvEPtXebhi68C4aGnCmWOcMCL
|
||||
H/VrCcwFT15eR6zsD3whv8Oqpdj5aneItpEaWd8dzBrHO69kbyfqK/GL14eLtPCl
|
||||
VoY0EQ8z6hNqNTil6eseBdEuwytND5LJnfzarXCBxdnh74CEu4nxZcgEIx3hoSpL
|
||||
JVtHiZfGXPZgtIech3LgcAcAmcaI6wtD94Z5pQIDAQABAoIBAAJmo9TqmzWPzWYi
|
||||
bv8fNlIi+1uZ9fZd9FgeAFIqjvlsaW3JprBiTvUKXlSf0cvuyByDt/wGkbE6QF/X
|
||||
WhlNHUmEMXN1FJt6AxT27Qz3dFbLcC5+M2MEggyJLYMhWT4F0VxlU3/WjGWyJFUk
|
||||
I8+jwGKJwyRCAzLipXDBnluFUTiDvBbw3SpS+C6zn6wcHCfO0waDUc6Gsn9/Von/
|
||||
4/AXx6tQfGYXhGYsBR/MxNQpbNol0CsAdTpi5wwZ5LUQf2Y/JlUGqQ1UwBouSZPu
|
||||
k/djzrzBqsFrMqxKE4+M1TuKluawlDWPEqKgcMooegFoopYfLavKtX8lLQFDE2xo
|
||||
7pIEvZECgYEA4nOc9W6iwP821p7rkUjnaaLth9jlt05t/sipN8eE8vX70ITHlNda
|
||||
vQVLsAbyY3BWzyEtg+KTsDinEyzdfKuqnBRbxda/7PwZ/VfOwSLVbgkXL2No68eV
|
||||
x1CzigJo7EERk+gx/zjCYlSpDVk3ycIimYkVWkIU9tmqtEXnFFdx1ocCgYEA2xEE
|
||||
Bi9jh3cY2QUCewz3Dz5rMKZkkEj3lBAD7pMTy53ZTbocL1ZTnWGyacW0byiOlnzd
|
||||
iny71iFAx4fdgXrhFmO/3x9duy25HJMlKyvG6U+6lD/Gr7JmX5WXGlgT61d+JfR3
|
||||
mtYwaM0f2ngxWYuwvfVq/WXaB7iESNOwfOHfzXMCgYADdXKbSRJRUlSbGJhOgseO
|
||||
FH/+SDDSCO+jKZt0D6cXMuyitbR6sINhSbhrOt/u5uNcjIwubIKG+YaLw26qndCg
|
||||
S6tPLUWHMB6RgQrWZlrOMHNbNPCAUW8XOUNUw06o9SF4md5RoKNPby2Z15gDi+SN
|
||||
Zcuesk2xq4dw83RhGijR9wKBgBiCGtUmUBhDtr/w04o4tRs7fHqA4xdRUoF6GTaD
|
||||
td891aXggG67VbdxyqgSulEFVI55gb+QnOMj7T9lb96ghLYgisLHm5DpWKBdxfbC
|
||||
ewp3JQSY7f2SE+n1rmYAHJpju3U7mHX2KIxRBpNGhx7hhfB6mHGpB299sS8En+YY
|
||||
zxUJAoGBAKXCJqyEwDkZfov312UNQ5S7PzkuM6eTNa0Lrbo/lrn/srdMN8Iawpqs
|
||||
R27AXbHEMuHjTFVIM77ju735XFn2gYdP3n5nPKWmiyd3GqSso07C3dxdTYjKPFT8
|
||||
wmIf+gNAN/0r/j7G0p+pIQQ6EWOfTGmXJvdYm1ZMyUvEkKZxmO6B
|
||||
-----END RSA PRIVATE KEY-----
|
29
request_struct.go
Normal file
29
request_struct.go
Normal file
@ -0,0 +1,29 @@
|
||||
package main
|
||||
|
||||
type MonfloRequest struct {
|
||||
Method string `json:"method,omitempty"`
|
||||
Uri string `json:"uri,omitempty"`
|
||||
Headers MonfloHeader `json:"headers,omitempty"`
|
||||
Data MonfloRequestData `json:"data,omitempty"`
|
||||
}
|
||||
|
||||
type MonfloHeader struct {
|
||||
ApiKey string `json:"apikey,omitempty"`
|
||||
PrivateAddr string `json:"private_addr,omitempty"`
|
||||
PublicAddr string `json:"public_addr,omitempty"`
|
||||
Type string `json:"type,omitempty"` //p2p
|
||||
Format string `json:"format,omitempty"` //h264
|
||||
}
|
||||
|
||||
type MonfloRequestData struct {
|
||||
Metadata string `json:"metadata,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
PrivateAddr string `json:"private_addr,omitempty"`
|
||||
PublicAddr string `json:"public_addr,omitempty"`
|
||||
Key string `json:"key,omitempty"`
|
||||
Bitrate int `json:"bitrate,omitempty"`
|
||||
Formats []string `json:"formats,omitempty"` //h264 h265
|
||||
Stream string `json:"stream,omitempty"`
|
||||
Status string `json:"status,omitempty"`
|
||||
Client string `json:"client,omitempty"`
|
||||
}
|
60
response_struct.go
Normal file
60
response_struct.go
Normal file
@ -0,0 +1,60 @@
|
||||
package main
|
||||
|
||||
type MonfloResponse struct {
|
||||
Event string `json:"event,omitempty"`
|
||||
Status int `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
type DevicesResponse struct {
|
||||
MonfloResponse
|
||||
Data []LoginResponse `json:"data"`
|
||||
}
|
||||
|
||||
type DeviceResponse struct {
|
||||
MonfloResponse
|
||||
Data LoginResponse `json:"data"`
|
||||
}
|
||||
|
||||
type PatchDeviceResponse struct {
|
||||
MonfloResponse
|
||||
Data LoginResponse `json:"data"`
|
||||
}
|
||||
|
||||
type PeersResponse struct {
|
||||
MonfloResponse
|
||||
Data map[string]PeerInfo `json:"data"`
|
||||
}
|
||||
|
||||
type IncognitosResponse struct {
|
||||
MonfloResponse
|
||||
Data IncognitosData `json:"data"`
|
||||
}
|
||||
type IncognitosData struct {
|
||||
Id string `json:"id"`
|
||||
Stream string `json:"stream"`
|
||||
Client string `json:"client"`
|
||||
}
|
||||
|
||||
type StreamResponse struct {
|
||||
MonfloResponse
|
||||
Data StreamInfo `json:"data"`
|
||||
}
|
||||
|
||||
type StreamReadResponse struct {
|
||||
MonfloResponse
|
||||
Data StreamReadData `json:"data"`
|
||||
}
|
||||
|
||||
type StreamReadData struct {
|
||||
Client string `json:"client"` //client-528591bf-bc07-59c5-8f24-a543bf383680
|
||||
Format string `json:"format"` //h264
|
||||
Id string `json:"id"` //stream-16f25ad7-be2b-5d45-a777-47d8f4c77179
|
||||
PrivateAddr string `json:"private_addr"` //172.19.10.175:58169
|
||||
PublicAddr string `json:"public_addr"` //58.210.98.46:44742
|
||||
Type string `json:"type"` //p2p
|
||||
}
|
||||
|
||||
type ClientConnectedEvent struct {
|
||||
MonfloResponse
|
||||
Data string `json:"data"`
|
||||
}
|
57
welcome_struct.go
Normal file
57
welcome_struct.go
Normal file
@ -0,0 +1,57 @@
|
||||
package main
|
||||
|
||||
|
||||
type Features struct {
|
||||
MaxUserProfiles int `json:"max_user_profiles"`
|
||||
MaxStreams int `json:"max_streams"`
|
||||
MaxDevices int `json:"max_devices"`
|
||||
MaxP2pResolution int `json:"max_p2p_resolution"`
|
||||
MaxP2pFrames int `json:"max_p2p_frames"`
|
||||
MaxRelayResolution int `json:"max_relay_resolution"`
|
||||
MaxRelayFrames int `json:"max_relay_frames"`
|
||||
Hevc bool `json:"hevc"`
|
||||
SessionRecording bool `json:"session_recording"`
|
||||
ManagementConsole bool `json:"management_console"`
|
||||
ConnectAnywhere bool `json:"connect_anywhere"`
|
||||
Support bool `json:"support"`
|
||||
CommercialUse bool `json:"commercial_use"`
|
||||
DeviceThumbnails bool `json:"device_thumbnails"`
|
||||
FileTransfer bool `json:"file_transfer"`
|
||||
}
|
||||
|
||||
type IPInfo struct {
|
||||
PrivateAddr string `json:"private_addr"`
|
||||
PublicAddr string `json:"public_addr"`
|
||||
}
|
||||
|
||||
type StreamInfo struct {
|
||||
Id string `json:"id,omitempty"`
|
||||
Status string `json:"status,omitempty"` //ready busy
|
||||
OwnerClient string `json:"owner_client,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
PrivateAddr string `json:"private_addr,omitempty"`
|
||||
PublicAddr string `json:"public_addr,omitempty"`
|
||||
Key string `json:"key,omitempty"`
|
||||
Bitrate int `json:"bitrate,omitempty"`
|
||||
Formats []string `json:"formats,omitempty"` //h264 h265
|
||||
}
|
||||
|
||||
type WelcomeData struct {
|
||||
Client string `json:"client,omitempty"`
|
||||
Features Features `json:"features,omitempty"`
|
||||
Peers map[string]PeerInfo `json:"peers,omitempty"`
|
||||
Subscription int `json:"subscription,omitempty"` //1=免费 2=专业 3=旗舰
|
||||
Timestamp int64 `json:"timestamp,omitempty"` //1599118479
|
||||
}
|
||||
|
||||
type WelcomeInfo struct {
|
||||
MonfloResponse
|
||||
Data WelcomeData `json:"data,omitempty"`
|
||||
}
|
||||
|
||||
type PeerInfo struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
Status string `json:"status,omitempty"`
|
||||
LastIP IPInfo `json:"last_ip,omitempty"`
|
||||
Streams map[string]StreamInfo `json:"streams"`
|
||||
}
|
Loading…
Reference in New Issue
Block a user