api: improve openapi definition (#5380)

add uint64, uint, uuid, move WebRTCICEServer into dedicated schema
This commit is contained in:
Alessandro Ros
2026-01-25 19:35:43 +01:00
committed by GitHub
parent 1a53e40bdc
commit 46b4293e35
41 changed files with 379 additions and 287 deletions
+96 -87
View File
@@ -91,7 +91,7 @@ components:
format: int64
udpReadBufferSize:
type: integer
format: int64
format: uint64
runOnConnect:
type: string
runOnConnectRestart:
@@ -336,16 +336,7 @@ components:
webrtcICEServers2:
type: array
items:
type: object
properties:
url:
type: string
username:
type: string
password:
type: string
clientOnly:
type: boolean
$ref: '#/components/schemas/WebRTCICEServer'
webrtcHandshakeTimeout:
type: string
webrtcTrackGatherTimeout:
@@ -429,15 +420,15 @@ components:
# Raspberry Pi Camera source
rpiCameraCamID:
type: integer
format: int64
format: uint64
rpiCameraSecondary:
type: boolean
rpiCameraWidth:
type: integer
format: int64
format: uint64
rpiCameraHeight:
type: integer
format: int64
format: uint64
rpiCameraHFlip:
type: boolean
rpiCameraVFlip:
@@ -469,7 +460,7 @@ components:
type: string
rpiCameraShutter:
type: integer
format: int64
format: uint64
rpiCameraMetering:
type: string
rpiCameraGain:
@@ -502,7 +493,7 @@ components:
type: string
rpiCameraFlickerPeriod:
type: integer
format: int64
format: uint64
rpiCameraTextOverlayEnable:
type: boolean
rpiCameraTextOverlay:
@@ -511,10 +502,10 @@ components:
type: string
rpiCameraIDRPeriod:
type: integer
format: int64
format: uint64
rpiCameraBitrate:
type: integer
format: int64
format: uint64
rpiCameraHardwareH264Profile:
type: string
rpiCameraHardwareH264Level:
@@ -525,7 +516,7 @@ components:
type: string
rpiCameraMJPEGQuality:
type: integer
format: int64
format: uint64
# Hooks
runOnInit:
@@ -594,10 +585,10 @@ components:
type: string
bytesReceived:
type: integer
format: int64
format: uint64
bytesSent:
type: integer
format: int64
format: uint64
readers:
type: array
items:
@@ -666,7 +657,7 @@ components:
type: string
bytesSent:
type: integer
format: int64
format: uint64
HLSMuxerList:
type: object
@@ -717,6 +708,7 @@ components:
properties:
id:
type: string
format: uuid
created:
type: string
remoteAddr:
@@ -730,10 +722,10 @@ components:
type: string
bytesReceived:
type: integer
format: int64
format: uint64
bytesSent:
type: integer
format: int64
format: uint64
RTMPConnList:
type: object
@@ -754,18 +746,20 @@ components:
properties:
id:
type: string
format: uuid
created:
type: string
remoteAddr:
type: string
bytesReceived:
type: integer
format: int64
format: uint64
bytesSent:
type: integer
format: int64
format: uint64
session:
type: string
format: uuid
nullable: true
tunnel:
type: string
@@ -789,6 +783,7 @@ components:
properties:
id:
type: string
format: uuid
created:
type: string
remoteAddr:
@@ -808,34 +803,34 @@ components:
nullable: true
bytesReceived:
type: integer
format: int64
format: uint64
bytesSent:
type: integer
format: int64
format: uint64
rtpPacketsReceived:
type: integer
format: int64
format: uint64
rtpPacketsSent:
type: integer
format: int64
format: uint64
rtpPacketsLost:
type: integer
format: int64
format: uint64
rtpPacketsInError:
type: integer
format: int64
format: uint64
rtpPacketsJitter:
type: number
format: double
rtcpPacketsReceived:
type: integer
format: int64
format: uint64
rtcpPacketsSent:
type: integer
format: int64
format: uint64
rtcpPacketsInError:
type: integer
format: int64
format: uint64
RTSPSessionList:
type: object
@@ -856,6 +851,7 @@ components:
properties:
id:
type: string
format: uuid
created:
type: string
remoteAddr:
@@ -869,121 +865,121 @@ components:
type: string
packetsSent:
type: integer
format: int64
format: uint64
description: The total number of sent DATA packets, including retransmitted packets
packetsReceived:
type: integer
format: int64
format: uint64
description: The total number of received DATA packets, including retransmitted packets
packetsReceivedBelated:
type: integer
format: int64
format: uint64
packetsSentUnique:
type: integer
format: int64
format: uint64
description: The total number of unique DATA packets sent by the SRT sender
packetsReceivedUnique:
type: integer
format: int64
format: uint64
description: The total number of unique original, retransmitted or recovered by the packet filter DATA packets received in time, decrypted without errors and, as a result, scheduled for delivery to the upstream application by the SRT receiver.
packetsSendLoss:
type: integer
format: int64
format: uint64
description: The total number of data packets considered or reported as lost at the sender side. Does not correspond to the packets detected as lost at the receiver side.
packetsReceivedLoss:
type: integer
format: int64
format: uint64
description: The total number of SRT DATA packets detected as presently missing (either reordered or lost) at the receiver side
packetsRetrans:
type: integer
format: int64
format: uint64
description: The total number of retransmitted packets sent by the SRT sender
packetsReceivedRetrans:
type: integer
format: int64
format: uint64
description: The total number of retransmitted packets registered at the receiver side
packetsSentACK:
type: integer
format: int64
format: uint64
description: The total number of sent ACK (Acknowledgement) control packets
packetsReceivedACK:
type: integer
format: int64
format: uint64
description: The total number of received ACK (Acknowledgement) control packets
packetsSentNAK:
type: integer
format: int64
format: uint64
description: The total number of sent NAK (Negative Acknowledgement) control packets
packetsReceivedNAK:
type: integer
format: int64
format: uint64
description: The total number of received NAK (Negative Acknowledgement) control packets
packetsSentKM:
type: integer
format: int64
format: uint64
description: The total number of sent KM (Key Material) control packets
packetsReceivedKM:
type: integer
format: int64
format: uint64
description: The total number of received KM (Key Material) control packets
usSndDuration:
type: integer
format: int64
format: uint64
description: The total accumulated time in microseconds, during which the SRT sender has some data to transmit, including packets that have been sent, but not yet acknowledged
packetsSendDrop:
type: integer
format: int64
format: uint64
description: The total number of dropped by the SRT sender DATA packets that have no chance to be delivered in time
packetsReceivedDrop:
type: integer
format: int64
format: uint64
description: The total number of dropped by the SRT receiver and, as a result, not delivered to the upstream application DATA packets
packetsReceivedUndecrypt:
type: integer
format: int64
format: uint64
description: The total number of packets that failed to be decrypted at the receiver side
bytesSent:
type: integer
format: int64
format: uint64
description: Same as packetsSent, but expressed in bytes, including payload and all the headers (IP, TCP, SRT)
bytesReceived:
type: integer
format: int64
format: uint64
description: Same as packetsReceived, but expressed in bytes, including payload and all the headers (IP, TCP, SRT)
bytesReceivedBelated:
type: integer
format: int64
format: uint64
bytesSentUnique:
type: integer
format: int64
format: uint64
description: Same as packetsSentUnique, but expressed in bytes, including payload and all the headers (IP, TCP, SRT)
bytesReceivedUnique:
type: integer
format: int64
format: uint64
description: Same as packetsReceivedUnique, but expressed in bytes, including payload and all the headers (IP, TCP, SRT)
bytesReceivedLoss:
type: integer
format: int64
format: uint64
description: Same as packetsReceivedLoss, but expressed in bytes, including payload and all the headers (IP, TCP, SRT), bytes for the presently missing (either reordered or lost) packets' payloads are estimated based on the average packet size
bytesRetrans:
type: integer
format: int64
format: uint64
description: Same as packetsRetrans, but expressed in bytes, including payload and all the headers (IP, TCP, SRT)
bytesReceivedRetrans:
type: integer
format: int64
format: uint64
description: Same as packetsReceivedRetrans, but expressed in bytes, including payload and all the headers (IP, TCP, SRT)
bytesSendDrop:
type: integer
format: int64
format: uint64
description: Same as packetsSendDrop, but expressed in bytes, including payload and all the headers (IP, TCP, SRT)
bytesReceivedDrop:
type: integer
format: int64
format: uint64
description: Same as packetsReceivedDrop, but expressed in bytes, including payload and all the headers (IP, TCP, SRT)
bytesReceivedUndecrypt:
type: integer
format: int64
format: uint64
description: Same as packetsReceivedUndecrypt, but expressed in bytes, including payload and all the headers (IP, TCP, SRT)
usPacketsSendPeriod:
type: number
@@ -991,11 +987,11 @@ components:
description: Current minimum time interval between which consecutive packets are sent, in microseconds
packetsFlowWindow:
type: integer
format: int64
format: uint64
description: The maximum number of packets that can be "in flight"
packetsFlightSize:
type: integer
format: int64
format: uint64
description: The number of packets in flight
msRTT:
type: number
@@ -1015,11 +1011,11 @@ components:
description: Estimated capacity of the network link, in Mbps
bytesAvailSendBuf:
type: integer
format: int64
format: uint64
description: The available space in the sender's buffer, in bytes
bytesAvailReceiveBuf:
type: integer
format: int64
format: uint64
description: The available space in the receiver's buffer, in bytes
mbpsMaxBW:
type: number
@@ -1027,47 +1023,47 @@ components:
description: Transmission bandwidth limit, in Mbps
byteMSS:
type: integer
format: int64
format: uint64
description: Maximum Segment Size (MSS), in bytes
packetsSendBuf:
type: integer
format: int64
format: uint64
description: The number of packets in the sender's buffer that are already scheduled for sending or even possibly sent, but not yet acknowledged
bytesSendBuf:
type: integer
format: int64
format: uint64
description: Instantaneous (current) value of packetsSndBuf, but expressed in bytes, including payload and all headers (IP, TCP, SRT)
msSendBuf:
type: integer
format: int64
format: uint64
description: The timespan (msec) of packets in the sender's buffer (unacknowledged packets)
msSendTsbPdDelay:
type: integer
format: int64
format: uint64
description: Timestamp-based Packet Delivery Delay value of the peer
packetsReceiveBuf:
type: integer
format: int64
format: uint64
description: The number of acknowledged packets in receiver's buffer
bytesReceiveBuf:
type: integer
format: int64
format: uint64
description: Instantaneous (current) value of packetsRcvBuf, expressed in bytes, including payload and all headers (IP, TCP, SRT)
msReceiveBuf:
type: integer
format: int64
format: uint64
description: The timespan (msec) of acknowledged packets in the receiver's buffer
msReceiveTsbPdDelay:
type: integer
format: int64
format: uint64
description: Timestamp-based Packet Delivery Delay value set on the socket via SRTO_RCVLATENCY or SRTO_LATENCY
packetsReorderTolerance:
type: integer
format: int64
format: uint64
description: Instant value of the packet reorder tolerance
packetsReceivedAvgBelatedTime:
type: integer
format: int64
format: uint64
description: Accumulated difference between the current time and the time-to-play of a packet that is received late
packetsSendLossRate:
type: number
@@ -1092,11 +1088,24 @@ components:
items:
$ref: '#/components/schemas/SRTConn'
WebRTCICEServer:
type: object
properties:
url:
type: string
username:
type: string
password:
type: string
clientOnly:
type: boolean
WebRTCSession:
type: object
properties:
id:
type: string
format: uuid
created:
type: string
remoteAddr:
@@ -1116,28 +1125,28 @@ components:
type: string
bytesReceived:
type: integer
format: int64
format: uint64
bytesSent:
type: integer
format: int64
format: uint64
rtpPacketsReceived:
type: integer
format: int64
format: uint64
rtpPacketsSent:
type: integer
format: int64
format: uint64
rtpPacketsLost:
type: integer
format: int64
format: uint64
rtpPacketsJitter:
type: number
format: double
rtcpPacketsReceived:
type: integer
format: int64
format: uint64
rtcpPacketsSent:
type: integer
format: int64
format: uint64
WebRTCSessionList:
type: object
+2 -2
View File
@@ -54,10 +54,10 @@ func recordingsOfPath(
segments, _ := recordstore.FindSegments(pathConf, pathName, nil, nil)
ret.Segments = make([]*defs.APIRecordingSegment, len(segments))
ret.Segments = make([]defs.APIRecordingSegment, len(segments))
for i, seg := range segments {
ret.Segments[i] = &defs.APIRecordingSegment{
ret.Segments[i] = defs.APIRecordingSegment{
Start: seg.Start,
}
}
+2 -2
View File
@@ -17,11 +17,11 @@ func (a *API) onConfigPathsList(ctx *gin.Context) {
a.mutex.RUnlock()
data := &defs.APIPathConfList{
Items: make([]*conf.Path, len(c.Paths)),
Items: make([]conf.Path, len(c.Paths)),
}
for i, key := range sortedKeys(c.Paths) {
data.Items[i] = c.Paths[key]
data.Items[i] = *c.Paths[key]
}
data.ItemCount = len(data.Items)
+2 -2
View File
@@ -17,9 +17,9 @@ type testHLSServer struct {
}
func (s *testHLSServer) APIMuxersList() (*defs.APIHLSMuxerList, error) {
items := make([]*defs.APIHLSMuxer, 0, len(s.muxers))
items := make([]defs.APIHLSMuxer, 0, len(s.muxers))
for _, muxer := range s.muxers {
items = append(items, muxer)
items = append(items, *muxer)
}
return &defs.APIHLSMuxerList{Items: items}, nil
}
+7 -7
View File
@@ -16,9 +16,9 @@ type testPathManager struct {
}
func (m *testPathManager) APIPathsList() (*defs.APIPathList, error) {
items := make([]*defs.APIPath, 0, len(m.paths))
items := make([]defs.APIPath, 0, len(m.paths))
for _, path := range m.paths {
items = append(items, path)
items = append(items, *path)
}
return &defs.APIPathList{Items: items}, nil
}
@@ -38,13 +38,13 @@ func TestPathsList(t *testing.T) {
"test1": {
Name: "test1",
ConfName: "test1",
Source: &defs.APIPathSourceOrReader{Type: "publisher", ID: "pub1"},
Source: &defs.APIPathSource{Type: "publisher", ID: "pub1"},
Ready: true,
ReadyTime: &now,
Tracks: []string{"H264", "Opus"},
BytesReceived: 1000,
BytesSent: 2000,
Readers: []defs.APIPathSourceOrReader{
Readers: []defs.APIPathReader{
{Type: "reader", ID: "reader1"},
},
},
@@ -55,7 +55,7 @@ func TestPathsList(t *testing.T) {
Tracks: []string{},
BytesReceived: 500,
BytesSent: 100,
Readers: []defs.APIPathSourceOrReader{},
Readers: []defs.APIPathReader{},
},
},
}
@@ -91,13 +91,13 @@ func TestPathsGet(t *testing.T) {
"mystream": {
Name: "mystream",
ConfName: "mystream",
Source: &defs.APIPathSourceOrReader{Type: "rtspSession", ID: "session123"},
Source: &defs.APIPathSource{Type: "rtspSession", ID: "session123"},
Ready: true,
ReadyTime: &now,
Tracks: []string{"H264", "Opus"},
BytesReceived: 123456,
BytesSent: 789012,
Readers: []defs.APIPathSourceOrReader{
Readers: []defs.APIPathReader{
{Type: "hlsMuxer", ID: "muxer1"},
{Type: "webRTCSession", ID: "session456"},
},
+2 -2
View File
@@ -30,11 +30,11 @@ func (a *API) onRecordingsList(ctx *gin.Context) {
}
data.PageCount = pageCount
data.Items = make([]*defs.APIRecording, len(pathNames))
data.Items = make([]defs.APIRecording, len(pathNames))
for i, pathName := range pathNames {
pathConf, _, _ := conf.FindPathConf(c.Paths, pathName)
data.Items[i] = recordingsOfPath(pathConf, pathName)
data.Items[i] = *recordingsOfPath(pathConf, pathName)
}
ctx.JSON(http.StatusOK, data)
+2 -2
View File
@@ -19,9 +19,9 @@ type testRTMPServer struct {
}
func (s *testRTMPServer) APIConnsList() (*defs.APIRTMPConnList, error) {
items := make([]*defs.APIRTMPConn, 0, len(s.conns))
items := make([]defs.APIRTMPConn, 0, len(s.conns))
for _, conn := range s.conns {
items = append(items, conn)
items = append(items, *conn)
}
return &defs.APIRTMPConnList{Items: items}, nil
}
+4 -4
View File
@@ -21,9 +21,9 @@ type testRTSPServer struct {
}
func (s *testRTSPServer) APIConnsList() (*defs.APIRTSPConnsList, error) {
items := make([]*defs.APIRTSPConn, 0, len(s.conns))
items := make([]defs.APIRTSPConn, 0, len(s.conns))
for _, conn := range s.conns {
items = append(items, conn)
items = append(items, *conn)
}
return &defs.APIRTSPConnsList{Items: items}, nil
}
@@ -37,9 +37,9 @@ func (s *testRTSPServer) APIConnsGet(id uuid.UUID) (*defs.APIRTSPConn, error) {
}
func (s *testRTSPServer) APISessionsList() (*defs.APIRTSPSessionList, error) {
items := make([]*defs.APIRTSPSession, 0, len(s.sessions))
items := make([]defs.APIRTSPSession, 0, len(s.sessions))
for _, session := range s.sessions {
items = append(items, session)
items = append(items, *session)
}
return &defs.APIRTSPSessionList{Items: items}, nil
}
+2 -2
View File
@@ -19,9 +19,9 @@ type testSRTServer struct {
}
func (s *testSRTServer) APIConnsList() (*defs.APISRTConnList, error) {
items := make([]*defs.APISRTConn, 0, len(s.conns))
items := make([]defs.APISRTConn, 0, len(s.conns))
for _, conn := range s.conns {
items = append(items, conn)
items = append(items, *conn)
}
return &defs.APISRTConnList{Items: items}, nil
}
+2 -2
View File
@@ -19,9 +19,9 @@ type testWebRTCServer struct {
}
func (s *testWebRTCServer) APISessionsList() (*defs.APIWebRTCSessionList, error) {
items := make([]*defs.APIWebRTCSession, 0, len(s.sessions))
items := make([]defs.APIWebRTCSession, 0, len(s.sessions))
for _, session := range s.sessions {
items = append(items, session)
items = append(items, *session)
}
return &defs.APIWebRTCSessionList{Items: items}, nil
}
+6 -6
View File
@@ -550,12 +550,12 @@ func (pa *path) doAPIPathsGet(req pathAPIPathsGetReq) {
data: &defs.APIPath{
Name: pa.name,
ConfName: pa.conf.Name,
Source: func() *defs.APIPathSourceOrReader {
Source: func() *defs.APIPathSource {
if pa.source == nil {
return nil
}
v := pa.source.APISourceDescribe()
return &v
return v
}(),
Ready: pa.isReady(),
ReadyTime: func() *time.Time {
@@ -583,11 +583,11 @@ func (pa *path) doAPIPathsGet(req pathAPIPathsGetReq) {
}
return pa.stream.BytesSent()
}(),
Readers: func() []defs.APIPathSourceOrReader {
ret := make([]defs.APIPathSourceOrReader, len(pa.readers))
Readers: func() []defs.APIPathReader {
ret := make([]defs.APIPathReader, len(pa.readers))
i := 0
for r := range pa.readers {
ret[i] = r.APIReaderDescribe()
ret[i] = *r.APIReaderDescribe()
i++
}
return ret
@@ -713,7 +713,7 @@ func (pa *path) setReady(desc *description.Session, useRTPPackets bool, replaceN
ExternalCmdPool: pa.externalCmdPool,
Conf: pa.conf,
ExternalCmdEnv: pa.ExternalCmdEnv(),
Desc: pa.source.APISourceDescribe(),
Desc: *pa.source.APISourceDescribe(),
Query: pa.publisherQuery,
})
+2 -2
View File
@@ -594,13 +594,13 @@ func (pm *pathManager) APIPathsList() (*defs.APIPathList, error) {
res := <-req.res
res.data = &defs.APIPathList{
Items: []*defs.APIPath{},
Items: []defs.APIPath{},
}
for _, pa := range res.paths {
item, err := pa.APIPathsGet(pathAPIPathsGetReq{})
if err == nil {
res.data.Items = append(res.data.Items, item)
res.data.Items = append(res.data.Items, *item)
}
}
+2 -2
View File
@@ -12,8 +12,8 @@ func (*sourceRedirect) Log(logger.Level, string, ...any) {
}
// APISourceDescribe implements source.
func (*sourceRedirect) APISourceDescribe() defs.APIPathSourceOrReader {
return defs.APIPathSourceOrReader{
func (*sourceRedirect) APISourceDescribe() *defs.APIPathSource {
return &defs.APIPathSource{
Type: "redirect",
ID: "",
}
+46 -40
View File
@@ -69,35 +69,41 @@ type APIInfo struct {
// APIPathConfList is a list of path configurations.
type APIPathConfList struct {
ItemCount int `json:"itemCount"`
PageCount int `json:"pageCount"`
Items []*conf.Path `json:"items"`
ItemCount int `json:"itemCount"`
PageCount int `json:"pageCount"`
Items []conf.Path `json:"items"`
}
// APIPathSourceOrReader is a source or a reader.
type APIPathSourceOrReader struct {
// APIPathSource is a source.
type APIPathSource struct {
Type string `json:"type"`
ID string `json:"id"`
}
// APIPathReader is a reader.
type APIPathReader struct {
Type string `json:"type"`
ID string `json:"id"`
}
// APIPath is a path.
type APIPath struct {
Name string `json:"name"`
ConfName string `json:"confName"`
Source *APIPathSourceOrReader `json:"source"`
Ready bool `json:"ready"`
ReadyTime *time.Time `json:"readyTime"`
Tracks []string `json:"tracks"`
BytesReceived uint64 `json:"bytesReceived"`
BytesSent uint64 `json:"bytesSent"`
Readers []APIPathSourceOrReader `json:"readers"`
Name string `json:"name"`
ConfName string `json:"confName"`
Source *APIPathSource `json:"source"`
Ready bool `json:"ready"`
ReadyTime *time.Time `json:"readyTime"`
Tracks []string `json:"tracks"`
BytesReceived uint64 `json:"bytesReceived"`
BytesSent uint64 `json:"bytesSent"`
Readers []APIPathReader `json:"readers"`
}
// APIPathList is a list of paths.
type APIPathList struct {
ItemCount int `json:"itemCount"`
PageCount int `json:"pageCount"`
Items []*APIPath `json:"items"`
ItemCount int `json:"itemCount"`
PageCount int `json:"pageCount"`
Items []APIPath `json:"items"`
}
// APIHLSMuxer is an HLS muxer.
@@ -110,9 +116,9 @@ type APIHLSMuxer struct {
// APIHLSMuxerList is a list of HLS muxers.
type APIHLSMuxerList struct {
ItemCount int `json:"itemCount"`
PageCount int `json:"pageCount"`
Items []*APIHLSMuxer `json:"items"`
ItemCount int `json:"itemCount"`
PageCount int `json:"pageCount"`
Items []APIHLSMuxer `json:"items"`
}
// APIRTMPConnState is the state of a RTMP connection.
@@ -139,9 +145,9 @@ type APIRTMPConn struct {
// APIRTMPConnList is a list of RTMP connections.
type APIRTMPConnList struct {
ItemCount int `json:"itemCount"`
PageCount int `json:"pageCount"`
Items []*APIRTMPConn `json:"items"`
ItemCount int `json:"itemCount"`
PageCount int `json:"pageCount"`
Items []APIRTMPConn `json:"items"`
}
// APIRTSPConn is a RTSP connection.
@@ -157,9 +163,9 @@ type APIRTSPConn struct {
// APIRTSPConnsList is a list of RTSP connections.
type APIRTSPConnsList struct {
ItemCount int `json:"itemCount"`
PageCount int `json:"pageCount"`
Items []*APIRTSPConn `json:"items"`
ItemCount int `json:"itemCount"`
PageCount int `json:"pageCount"`
Items []APIRTSPConn `json:"items"`
}
// APIRTSPSessionState is the state of a RTSP session.
@@ -196,9 +202,9 @@ type APIRTSPSession struct {
// APIRTSPSessionList is a list of RTSP sessions.
type APIRTSPSessionList struct {
ItemCount int `json:"itemCount"`
PageCount int `json:"pageCount"`
Items []*APIRTSPSession `json:"items"`
ItemCount int `json:"itemCount"`
PageCount int `json:"pageCount"`
Items []APIRTSPSession `json:"items"`
}
// APISRTConnState is the state of a SRT connection.
@@ -344,9 +350,9 @@ type APISRTConn struct {
// APISRTConnList is a list of SRT connections.
type APISRTConnList struct {
ItemCount int `json:"itemCount"`
PageCount int `json:"pageCount"`
Items []*APISRTConn `json:"items"`
ItemCount int `json:"itemCount"`
PageCount int `json:"pageCount"`
Items []APISRTConn `json:"items"`
}
// APIWebRTCSessionState is the state of a WebRTC connection.
@@ -381,9 +387,9 @@ type APIWebRTCSession struct {
// APIWebRTCSessionList is a list of WebRTC sessions.
type APIWebRTCSessionList struct {
ItemCount int `json:"itemCount"`
PageCount int `json:"pageCount"`
Items []*APIWebRTCSession `json:"items"`
ItemCount int `json:"itemCount"`
PageCount int `json:"pageCount"`
Items []APIWebRTCSession `json:"items"`
}
// APIRecordingSegment is a recording segment.
@@ -393,13 +399,13 @@ type APIRecordingSegment struct {
// APIRecording is a recording.
type APIRecording struct {
Name string `json:"name"`
Segments []*APIRecordingSegment `json:"segments"`
Name string `json:"name"`
Segments []APIRecordingSegment `json:"segments"`
}
// APIRecordingList is a list of recordings.
type APIRecordingList struct {
ItemCount int `json:"itemCount"`
PageCount int `json:"pageCount"`
Items []*APIRecording `json:"items"`
ItemCount int `json:"itemCount"`
PageCount int `json:"pageCount"`
Items []APIRecording `json:"items"`
}
+1 -1
View File
@@ -3,5 +3,5 @@ package defs
// Reader is an entity that can read a stream.
type Reader interface {
Close()
APIReaderDescribe() APIPathSourceOrReader
APIReaderDescribe() *APIPathReader
}
+1 -1
View File
@@ -17,7 +17,7 @@ import (
// - core.sourceRedirect
type Source interface {
logger.Writer
APISourceDescribe() APIPathSourceOrReader
APISourceDescribe() *APIPathSource
}
// FormatsToCodecs returns the name of codecs of given formats.
+1 -1
View File
@@ -16,7 +16,7 @@ type OnConnectParams struct {
RunOnConnectRestart bool
RunOnDisconnect string
RTSPAddress string
Desc defs.APIPathSourceOrReader
Desc defs.APIPathReader
}
// OnConnect is the OnConnect hook.
+1 -1
View File
@@ -13,7 +13,7 @@ type OnReadParams struct {
ExternalCmdPool *externalcmd.Pool
Conf *conf.Path
ExternalCmdEnv externalcmd.Environment
Reader defs.APIPathSourceOrReader
Reader defs.APIPathReader
Query string
}
+1 -1
View File
@@ -13,7 +13,7 @@ type OnReadyParams struct {
ExternalCmdPool *externalcmd.Pool
Conf *conf.Path
ExternalCmdEnv externalcmd.Environment
Desc defs.APIPathSourceOrReader
Desc defs.APIPathSource
Query string
}
+8 -8
View File
@@ -26,10 +26,10 @@ func (dummyPathManager) APIPathsList() (*defs.APIPathList, error) {
return &defs.APIPathList{
ItemCount: 1,
PageCount: 1,
Items: []*defs.APIPath{{
Items: []defs.APIPath{{
Name: "mypath",
ConfName: "mypathconf",
Source: &defs.APIPathSourceOrReader{
Source: &defs.APIPathSource{
Type: "testing",
ID: "123324354",
},
@@ -38,7 +38,7 @@ func (dummyPathManager) APIPathsList() (*defs.APIPathList, error) {
Tracks: []string{"H264", "H265"},
BytesReceived: 123,
BytesSent: 456,
Readers: []defs.APIPathSourceOrReader{
Readers: []defs.APIPathReader{
{
Type: "testing",
ID: "345234423",
@@ -58,7 +58,7 @@ func (dummyHLSServer) APIMuxersList() (*defs.APIHLSMuxerList, error) {
return &defs.APIHLSMuxerList{
ItemCount: 1,
PageCount: 1,
Items: []*defs.APIHLSMuxer{{
Items: []defs.APIHLSMuxer{{
Path: "mypath",
Created: time.Date(2003, 11, 4, 23, 15, 7, 0, time.UTC),
LastRequest: time.Date(2003, 11, 4, 23, 15, 7, 0, time.UTC),
@@ -77,7 +77,7 @@ func (dummyRTSPServer) APIConnsList() (*defs.APIRTSPConnsList, error) {
return &defs.APIRTSPConnsList{
ItemCount: 1,
PageCount: 1,
Items: []*defs.APIRTSPConn{{
Items: []defs.APIRTSPConn{{
ID: uuid.MustParse("18294761-f9d1-4ea9-9a35-fe265b62eb41"),
Created: time.Date(2003, 11, 4, 23, 15, 7, 0, time.UTC),
RemoteAddr: "124.5.5.5:34542",
@@ -96,7 +96,7 @@ func (dummyRTSPServer) APISessionsList() (*defs.APIRTSPSessionList, error) {
return &defs.APIRTSPSessionList{
ItemCount: 1,
PageCount: 1,
Items: []*defs.APIRTSPSession{{
Items: []defs.APIRTSPSession{{
ID: uuid.MustParse("124b22ce-9c34-4387-b045-44caf98049f7"),
Created: time.Date(2003, 11, 4, 23, 15, 7, 0, time.UTC),
RemoteAddr: "124.5.5.5:34542",
@@ -132,7 +132,7 @@ func (dummyRTMPServer) APIConnsList() (*defs.APIRTMPConnList, error) {
return &defs.APIRTMPConnList{
ItemCount: 1,
PageCount: 1,
Items: []*defs.APIRTMPConn{{
Items: []defs.APIRTMPConn{{
ID: uuid.MustParse("9a07afe4-fc07-4c9b-be6e-6255720c36d0"),
Created: time.Date(2003, 11, 4, 23, 15, 7, 0, time.UTC),
RemoteAddr: "3.3.3.3:5678",
@@ -159,7 +159,7 @@ func (dummyWebRTCServer) APISessionsList() (*defs.APIWebRTCSessionList, error) {
return &defs.APIWebRTCSessionList{
ItemCount: 1,
PageCount: 1,
Items: []*defs.APIWebRTCSession{{
Items: []defs.APIWebRTCSession{{
ID: uuid.MustParse("f47ac10b-58cc-4372-a567-0e02b2c3d479"),
Created: time.Date(2003, 11, 4, 23, 15, 7, 0, time.UTC),
RemoteAddr: "127.0.0.1:3455",
+2 -2
View File
@@ -245,8 +245,8 @@ func (m *muxer) getInstance() *muxerInstance {
}
// APIReaderDescribe implements reader.
func (m *muxer) APIReaderDescribe() defs.APIPathSourceOrReader {
return defs.APIPathSourceOrReader{
func (m *muxer) APIReaderDescribe() *defs.APIPathReader {
return &defs.APIPathReader{
Type: "hlsMuxer",
ID: "",
}
+2 -2
View File
@@ -217,11 +217,11 @@ outer:
case req := <-s.chAPIMuxerList:
data := &defs.APIHLSMuxerList{
Items: []*defs.APIHLSMuxer{},
Items: []defs.APIHLSMuxer{},
}
for _, muxer := range s.muxers {
data.Items = append(data.Items, muxer.apiItem())
data.Items = append(data.Items, *muxer.apiItem())
}
sort.Slice(data.Items, func(i, j int) bool {
+14 -6
View File
@@ -89,7 +89,7 @@ func (c *conn) run() { //nolint:dupl
RunOnConnectRestart: c.runOnConnectRestart,
RunOnDisconnect: c.runOnDisconnect,
RTSPAddress: c.rtspAddress,
Desc: c.APIReaderDescribe(),
Desc: *c.APIReaderDescribe(),
})
defer onDisconnectHook()
@@ -198,7 +198,7 @@ func (c *conn) runRead() error {
ExternalCmdPool: c.externalCmdPool,
Conf: path.SafeConf(),
ExternalCmdEnv: path.ExternalCmdEnv(),
Reader: c.APISourceDescribe(),
Reader: *c.APIReaderDescribe(),
Query: c.rconn.URL.RawQuery,
})
defer onUnreadHook()
@@ -285,8 +285,8 @@ func (c *conn) runPublish() error {
}
// APIReaderDescribe implements reader.
func (c *conn) APIReaderDescribe() defs.APIPathSourceOrReader {
return defs.APIPathSourceOrReader{
func (c *conn) APIReaderDescribe() *defs.APIPathReader {
return &defs.APIPathReader{
Type: func() string {
if c.isTLS {
return "rtmpsConn"
@@ -298,8 +298,16 @@ func (c *conn) APIReaderDescribe() defs.APIPathSourceOrReader {
}
// APISourceDescribe implements source.
func (c *conn) APISourceDescribe() defs.APIPathSourceOrReader {
return c.APIReaderDescribe()
func (c *conn) APISourceDescribe() *defs.APIPathSource {
return &defs.APIPathSource{
Type: func() string {
if c.isTLS {
return "rtmpsConn"
}
return "rtmpConn"
}(),
ID: c.uuid.String(),
}
}
func (c *conn) apiItem() *defs.APIRTMPConn {
+2 -2
View File
@@ -227,11 +227,11 @@ outer:
case req := <-s.chAPIConnsList:
data := &defs.APIRTMPConnList{
Items: []*defs.APIRTMPConn{},
Items: []defs.APIRTMPConn{},
}
for c := range s.conns {
data.Items = append(data.Items, c.apiItem())
data.Items = append(data.Items, *c.apiItem())
}
sort.Slice(data.Items, func(i, j int) bool {
+9 -11
View File
@@ -78,16 +78,6 @@ func (c *conn) initialize() {
c.Log(logger.Info, "opened")
desc := defs.APIPathSourceOrReader{
Type: func() string {
if c.isTLS {
return "rtspsConn"
}
return "rtspConn"
}(),
ID: c.uuid.String(),
}
c.onDisconnectHook = hooks.OnConnect(hooks.OnConnectParams{
Logger: c,
ExternalCmdPool: c.externalCmdPool,
@@ -95,7 +85,15 @@ func (c *conn) initialize() {
RunOnConnectRestart: c.runOnConnectRestart,
RunOnDisconnect: c.runOnDisconnect,
RTSPAddress: c.rtspAddress,
Desc: desc,
Desc: defs.APIPathReader{
Type: func() string {
if c.isTLS {
return "rtspsConn"
}
return "rtspConn"
}(),
ID: c.uuid.String(),
},
})
}
+4 -4
View File
@@ -407,11 +407,11 @@ func (s *Server) APIConnsList() (*defs.APIRTSPConnsList, error) {
defer s.mutex.RUnlock()
data := &defs.APIRTSPConnsList{
Items: []*defs.APIRTSPConn{},
Items: []defs.APIRTSPConn{},
}
for _, c := range s.conns {
data.Items = append(data.Items, c.apiItem())
data.Items = append(data.Items, *c.apiItem())
}
sort.Slice(data.Items, func(i, j int) bool {
@@ -452,11 +452,11 @@ func (s *Server) APISessionsList() (*defs.APIRTSPSessionList, error) {
defer s.mutex.RUnlock()
data := &defs.APIRTSPSessionList{
Items: []*defs.APIRTSPSession{},
Items: []defs.APIRTSPSession{},
}
for _, s := range s.sessions {
data.Items = append(data.Items, s.apiItem())
data.Items = append(data.Items, *s.apiItem())
}
sort.Slice(data.Items, func(i, j int) bool {
+13 -5
View File
@@ -297,7 +297,7 @@ func (s *session) onPlay(_ *gortsplib.ServerHandlerOnPlayCtx) (*base.Response, e
ExternalCmdPool: s.externalCmdPool,
Conf: s.path.SafeConf(),
ExternalCmdEnv: s.path.ExternalCmdEnv(),
Reader: s.APIReaderDescribe(),
Reader: *s.APIReaderDescribe(),
Query: s.rsession.Query(),
})
}
@@ -360,8 +360,8 @@ func (s *session) onPause(_ *gortsplib.ServerHandlerOnPauseCtx) (*base.Response,
}
// APIReaderDescribe implements reader.
func (s *session) APIReaderDescribe() defs.APIPathSourceOrReader {
return defs.APIPathSourceOrReader{
func (s *session) APIReaderDescribe() *defs.APIPathReader {
return &defs.APIPathReader{
Type: func() string {
if s.isTLS {
return "rtspsSession"
@@ -373,8 +373,16 @@ func (s *session) APIReaderDescribe() defs.APIPathSourceOrReader {
}
// APISourceDescribe implements source.
func (s *session) APISourceDescribe() defs.APIPathSourceOrReader {
return s.APIReaderDescribe()
func (s *session) APISourceDescribe() *defs.APIPathSource {
return &defs.APIPathSource{
Type: func() string {
if s.isTLS {
return "rtspsSession"
}
return "rtspSession"
}(),
ID: s.uuid.String(),
}
}
// onPacketLost is called by rtspServer.
+9 -6
View File
@@ -103,7 +103,7 @@ func (c *conn) run() { //nolint:dupl
RunOnConnectRestart: c.runOnConnectRestart,
RunOnDisconnect: c.runOnDisconnect,
RTSPAddress: c.rtspAddress,
Desc: c.APIReaderDescribe(),
Desc: *c.APIReaderDescribe(),
})
defer onDisconnectHook()
@@ -317,7 +317,7 @@ func (c *conn) runRead(streamID *streamID) error {
ExternalCmdPool: c.externalCmdPool,
Conf: path.SafeConf(),
ExternalCmdEnv: path.ExternalCmdEnv(),
Reader: c.APIReaderDescribe(),
Reader: *c.APIReaderDescribe(),
Query: streamID.query,
})
defer onUnreadHook()
@@ -338,16 +338,19 @@ func (c *conn) runRead(streamID *streamID) error {
}
// APIReaderDescribe implements reader.
func (c *conn) APIReaderDescribe() defs.APIPathSourceOrReader {
return defs.APIPathSourceOrReader{
func (c *conn) APIReaderDescribe() *defs.APIPathReader {
return &defs.APIPathReader{
Type: "srtConn",
ID: c.uuid.String(),
}
}
// APISourceDescribe implements source.
func (c *conn) APISourceDescribe() defs.APIPathSourceOrReader {
return c.APIReaderDescribe()
func (c *conn) APISourceDescribe() *defs.APIPathSource {
return &defs.APIPathSource{
Type: "srtConn",
ID: c.uuid.String(),
}
}
func (c *conn) apiItem() *defs.APISRTConn {
+2 -2
View File
@@ -195,11 +195,11 @@ outer:
case req := <-s.chAPIConnsList:
data := &defs.APISRTConnList{
Items: []*defs.APISRTConn{},
Items: []defs.APISRTConn{},
}
for c := range s.conns {
data.Items = append(data.Items, c.apiItem())
data.Items = append(data.Items, *c.apiItem())
}
sort.Slice(data.Items, func(i, j int) bool {
+2 -2
View File
@@ -399,11 +399,11 @@ outer:
case req := <-s.chAPISessionsList:
data := &defs.APIWebRTCSessionList{
Items: []*defs.APIWebRTCSession{},
Items: []defs.APIWebRTCSession{},
}
for sx := range s.sessions {
data.Items = append(data.Items, sx.apiItem())
data.Items = append(data.Items, *sx.apiItem())
}
sort.Slice(data.Items, func(i, j int) bool {
+8 -5
View File
@@ -373,7 +373,7 @@ func (s *session) runRead() (int, error) {
ExternalCmdPool: s.externalCmdPool,
Conf: path.SafeConf(),
ExternalCmdEnv: path.ExternalCmdEnv(),
Reader: s.APIReaderDescribe(),
Reader: *s.APIReaderDescribe(),
Query: s.req.httpRequest.URL.RawQuery,
})
defer onUnreadHook()
@@ -443,16 +443,19 @@ func (s *session) addCandidates(
}
// APIReaderDescribe implements reader.
func (s *session) APIReaderDescribe() defs.APIPathSourceOrReader {
return defs.APIPathSourceOrReader{
func (s *session) APIReaderDescribe() *defs.APIPathReader {
return &defs.APIPathReader{
Type: "webRTCSession",
ID: s.uuid.String(),
}
}
// APISourceDescribe implements source.
func (s *session) APISourceDescribe() defs.APIPathSourceOrReader {
return s.APIReaderDescribe()
func (s *session) APISourceDescribe() *defs.APIPathSource {
return &defs.APIPathSource{
Type: "webRTCSession",
ID: s.uuid.String(),
}
}
func (s *session) apiItem() *defs.APIWebRTCSession {
+2 -2
View File
@@ -47,7 +47,7 @@ func resolveSource(s string, matches []string, query string) string {
type staticSource interface {
logger.Writer
Run(defs.StaticSourceRunParams) error
APISourceDescribe() defs.APIPathSourceOrReader
APISourceDescribe() *defs.APIPathSource
}
type handlerPathManager interface {
@@ -300,7 +300,7 @@ func (s *Handler) ReloadConf(newConf *conf.Path) {
}
// APISourceDescribe instanceements source.
func (s *Handler) APISourceDescribe() defs.APIPathSourceOrReader {
func (s *Handler) APISourceDescribe() *defs.APIPathSource {
return s.instance.APISourceDescribe()
}
+2 -2
View File
@@ -138,8 +138,8 @@ func (s *Source) Run(params defs.StaticSourceRunParams) error {
}
// APISourceDescribe implements StaticSource.
func (*Source) APISourceDescribe() defs.APIPathSourceOrReader {
return defs.APIPathSourceOrReader{
func (*Source) APISourceDescribe() *defs.APIPathSource {
return &defs.APIPathSource{
Type: "hlsSource",
ID: "",
}
+2 -2
View File
@@ -143,8 +143,8 @@ func (s *Source) runReader(nc net.Conn) error {
}
// APISourceDescribe implements StaticSource.
func (*Source) APISourceDescribe() defs.APIPathSourceOrReader {
return defs.APIPathSourceOrReader{
func (*Source) APISourceDescribe() *defs.APIPathSource {
return &defs.APIPathSource{
Type: "mpegtsSource",
ID: "",
}
+4 -4
View File
@@ -93,8 +93,8 @@ func (r *secondaryReader) Close() {
}
// APIReaderDescribe implements reader.
func (*secondaryReader) APIReaderDescribe() defs.APIPathSourceOrReader {
return defs.APIPathSourceOrReader{
func (*secondaryReader) APIReaderDescribe() *defs.APIPathReader {
return &defs.APIPathReader{
Type: "rpiCameraSecondary",
ID: "",
}
@@ -359,8 +359,8 @@ func (s *Source) waitForPrimary(
}
// APISourceDescribe implements StaticSource.
func (*Source) APISourceDescribe() defs.APIPathSourceOrReader {
return defs.APIPathSourceOrReader{
func (*Source) APISourceDescribe() *defs.APIPathSource {
return &defs.APIPathSource{
Type: "rpiCameraSource",
ID: "",
}
+2 -2
View File
@@ -137,8 +137,8 @@ func (s *Source) runReader(conn *gortmplib.Client) error {
}
// APISourceDescribe implements StaticSource.
func (*Source) APISourceDescribe() defs.APIPathSourceOrReader {
return defs.APIPathSourceOrReader{
func (*Source) APISourceDescribe() *defs.APIPathSource {
return &defs.APIPathSource{
Type: "rtmpSource",
ID: "",
}
+2 -2
View File
@@ -217,8 +217,8 @@ func (s *Source) runReader(desc *description.Session, nc net.Conn) error {
}
// APISourceDescribe implements StaticSource.
func (*Source) APISourceDescribe() defs.APIPathSourceOrReader {
return defs.APIPathSourceOrReader{
func (*Source) APISourceDescribe() *defs.APIPathSource {
return &defs.APIPathSource{
Type: "rtpSource",
ID: "",
}
+2 -2
View File
@@ -270,8 +270,8 @@ func (s *Source) runInner(c *gortsplib.Client, u *base.URL, pathConf *conf.Path)
}
// APISourceDescribe implements StaticSource.
func (*Source) APISourceDescribe() defs.APIPathSourceOrReader {
return defs.APIPathSourceOrReader{
func (*Source) APISourceDescribe() *defs.APIPathSource {
return &defs.APIPathSource{
Type: "rtspSource",
ID: "",
}
+2 -2
View File
@@ -128,8 +128,8 @@ func (s *Source) runReader(sconn srt.Conn) error {
}
// APISourceDescribe implements StaticSource.
func (*Source) APISourceDescribe() defs.APIPathSourceOrReader {
return defs.APIPathSourceOrReader{
func (*Source) APISourceDescribe() *defs.APIPathSource {
return &defs.APIPathSource{
Type: "srtSource",
ID: "",
}
+2 -2
View File
@@ -114,8 +114,8 @@ func (s *Source) Run(params defs.StaticSourceRunParams) error {
}
// APISourceDescribe implements StaticSource.
func (*Source) APISourceDescribe() defs.APIPathSourceOrReader {
return defs.APIPathSourceOrReader{
func (*Source) APISourceDescribe() *defs.APIPathSource {
return &defs.APIPathSource{
Type: "webRTCSource",
ID: "",
}
+102 -45
View File
@@ -1,15 +1,19 @@
package main
import (
"net"
"os"
"reflect"
"strings"
"testing"
"time"
"github.com/bluenviron/gortsplib/v5/pkg/auth"
"github.com/bluenviron/mediamtx/internal/conf"
"github.com/bluenviron/mediamtx/internal/conf/yamlwrapper"
"github.com/bluenviron/mediamtx/internal/defs"
"github.com/bluenviron/mediamtx/internal/logger"
"github.com/google/uuid"
"github.com/stretchr/testify/require"
)
@@ -32,6 +36,98 @@ type openAPI struct {
} `json:"components"`
}
func fillProperty(t *testing.T, rt reflect.Type, existing openAPIProperty) openAPIProperty {
switch {
case rt == reflect.TypeOf(""):
return openAPIProperty{Type: "string"}
case rt == reflect.PointerTo(reflect.TypeOf("")):
return openAPIProperty{
Type: "string",
Nullable: true,
}
case rt == reflect.TypeOf(int(0)):
return openAPIProperty{Type: "integer", Format: "int64"}
case rt == reflect.TypeOf(uint(0)):
return openAPIProperty{Type: "integer", Format: "uint64"}
case rt == reflect.TypeOf(uint64(0)):
return openAPIProperty{Type: "integer", Format: "uint64"}
case rt == reflect.TypeOf(float64(0)):
return openAPIProperty{Type: "number", Format: "double"}
case rt == reflect.TypeOf(false):
return openAPIProperty{Type: "boolean"}
case rt == reflect.TypeOf(&time.Time{}):
return openAPIProperty{Type: "string", Nullable: true}
case rt == reflect.TypeOf(uuid.UUID{}):
return openAPIProperty{Type: "string", Format: "uuid"}
case rt == reflect.PointerTo(reflect.TypeOf(uuid.UUID{})):
return openAPIProperty{Type: "string", Format: "uuid", Nullable: true}
case rt == reflect.TypeOf(time.Time{}) ||
rt == reflect.TypeOf(conf.Duration(0)) ||
rt == reflect.TypeOf(net.IPNet{}) ||
rt == reflect.TypeOf(conf.Credential("")) ||
rt == reflect.TypeOf(conf.RecordFormat(0)) ||
rt == reflect.TypeOf(conf.AuthAction("")) ||
rt == reflect.TypeOf(conf.Encryption(0)) ||
rt == reflect.TypeOf(conf.RTSPTransport{}) ||
rt == reflect.TypeOf(conf.StringSize(0)) ||
rt == reflect.TypeOf(conf.RTSPRangeType(0)) ||
rt == reflect.TypeOf(conf.LogLevel(0)) ||
rt == reflect.TypeOf(conf.AuthMethod(0)) ||
rt == reflect.TypeOf(logger.Destination(0)) ||
rt == reflect.TypeOf(auth.VerifyMethod(0)) ||
rt == reflect.TypeOf(conf.HLSVariant(0)) ||
rt == reflect.TypeOf(defs.APIRTMPConnState("")) ||
rt == reflect.TypeOf(defs.APIWebRTCSessionState("")) ||
rt == reflect.TypeOf(defs.APISRTConnState("")) ||
rt == reflect.TypeOf(defs.APIRTSPSessionState("")):
return openAPIProperty{Type: "string"}
case rt == reflect.TypeOf(conf.RTSPTransports{}):
return openAPIProperty{
Type: "array",
Items: &openAPIProperty{
Type: "string",
},
}
case rt.Kind() == reflect.Struct:
schemaName := strings.TrimPrefix(rt.Name(), "API")
if rt.PkgPath() == "github.com/bluenviron/mediamtx/internal/conf" && schemaName == "Path" {
schemaName = "PathConf"
}
return openAPIProperty{
Ref: "#/components/schemas/" + schemaName,
}
case rt.Kind() == reflect.Pointer && rt.Elem().Kind() == reflect.Struct:
prop := fillProperty(t, rt.Elem(), existing)
prop.Nullable = true
return prop
case rt.Kind() == reflect.Slice:
items := fillProperty(t, rt.Elem(), *existing.Items)
return openAPIProperty{
Type: "array",
Items: &items,
}
default:
t.Errorf("unhandled type: %v", rt)
return openAPIProperty{}
}
}
func TestAPIDocs(t *testing.T) {
byts, err := os.ReadFile("../../api/openapi.yaml")
require.NoError(t, err)
@@ -78,11 +174,11 @@ func TestAPIDocs(t *testing.T) {
},
{
"PathSource",
defs.APIPathSourceOrReader{},
defs.APIPathSource{},
},
{
"PathReader",
defs.APIPathSourceOrReader{},
defs.APIPathReader{},
},
{
"HLSMuxer",
@@ -152,54 +248,15 @@ func TestAPIDocs(t *testing.T) {
Type: "object",
Properties: make(map[string]openAPIProperty),
}
ty := reflect.TypeOf(ca.goStruct)
for i := range ty.NumField() {
sf := ty.Field(i)
js := sf.Tag.Get("json")
if js != "-" && js != "paths" && js != "pathDefaults" && !strings.Contains(js, ",omitempty") {
switch {
case sf.Type == reflect.TypeOf(""):
content2.Properties[js] = openAPIProperty{Type: "string"}
case sf.Type == reflect.PointerTo(reflect.TypeOf("")):
content2.Properties[js] = openAPIProperty{
Type: "string",
Nullable: true,
}
case sf.Type == reflect.TypeOf(int(0)):
content2.Properties[js] = openAPIProperty{Type: "integer", Format: "int64"}
case sf.Type == reflect.TypeOf(float64(0)):
content2.Properties[js] = openAPIProperty{Type: "number", Format: "double"}
case sf.Type == reflect.TypeOf(false):
content2.Properties[js] = openAPIProperty{Type: "boolean"}
case sf.Type == reflect.TypeOf(time.Time{}):
content2.Properties[js] = openAPIProperty{Type: "string"}
case sf.Type == reflect.TypeOf(&time.Time{}):
content2.Properties[js] = openAPIProperty{
Type: "string",
Nullable: true,
}
case sf.Type == reflect.TypeOf(conf.AuthInternalUserPermissions{}):
content2.Properties[js] = openAPIProperty{
Type: "array",
Items: &openAPIProperty{
Ref: "#/components/schemas/AuthInternalUserPermission",
},
}
default:
if existing, ok := content1.Properties[js]; ok {
content2.Properties[js] = existing
} else {
t.Errorf("missing item: '%s'", js)
}
}
content2.Properties[js] = fillProperty(t, sf.Type, content1.Properties[js])
}
}