From 3134b95e80676025bf469b84de5da7989b8ba90f Mon Sep 17 00:00:00 2001 From: aler9 <46489434+aler9@users.noreply.github.com> Date: Sat, 7 Aug 2021 18:28:27 +0200 Subject: [PATCH] api: add documentation --- .github/workflows/lint.yml | 12 +- Makefile | 25 ++- apidocs/.redocly.yaml | 3 + apidocs/openapi.yaml | 417 +++++++++++++++++++++++++++++++++++++ internal/core/api.go | 20 +- internal/core/api_test.go | 4 +- 6 files changed, 461 insertions(+), 20 deletions(-) create mode 100644 apidocs/.redocly.yaml create mode 100644 apidocs/openapi.yaml diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 2554306e..0f73ff83 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -7,7 +7,7 @@ on: branches: [ main ] jobs: - golangci-lint: + code: runs-on: ubuntu-20.04 steps: @@ -17,7 +17,7 @@ jobs: with: version: v1.38 - go-mod-tidy: + mod-tidy: runs-on: ubuntu-20.04 steps: @@ -31,3 +31,11 @@ jobs: go mod download go mod tidy git diff --exit-code + + api: + runs-on: ubuntu-20.04 + + steps: + - uses: actions/checkout@v2 + + - run: make api-lint diff --git a/Makefile b/Makefile index c23a6a9a..865ff053 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,7 @@ BASE_IMAGE = golang:1.16-alpine3.13 LINT_IMAGE = golangci/golangci-lint:v1.38.0 +NODE_IMAGE = node:14-alpine3.13 .PHONY: $(shell ls) @@ -14,8 +15,9 @@ help: @echo " test run tests" @echo " test32 run tests on a 32-bit system" @echo " lint run linters" - @echo " bench NAME=n run bench environment" + @echo " bench NAME=n run bench environment" @echo " run run app" + @echo " api-lint" run api linters" @echo " release build release assets" @echo " dockerhub build and push docker hub images" @echo "" @@ -27,7 +29,7 @@ $(blank) endef mod-tidy: - docker run --rm -it -v $(PWD):/s -w /s amd64/$(BASE_IMAGE) \ + docker run --rm -it -v $(PWD):/s -w /s $(BASE_IMAGE) \ sh -c "apk add git && GOPROXY=direct go get && go mod tidy" define DOCKERFILE_FORMAT @@ -106,7 +108,7 @@ bench: docker run --rm -it -p 9999:9999 temp define DOCKERFILE_RUN -FROM amd64/$(BASE_IMAGE) +FROM $(BASE_IMAGE) RUN apk add --no-cache ffmpeg WORKDIR /s COPY go.mod go.sum ./ @@ -153,8 +155,19 @@ run: temp \ sh -c "/out" +define DOCKERFILE_API_LINT +FROM $(NODE_IMAGE) +RUN yarn global add @redocly/openapi-cli@1.0.0-beta.54 +endef +export DOCKERFILE_API_LINT + +api-lint: + echo "$$DOCKERFILE_API_LINT" | docker build . -f - -t temp + docker run --rm -v $(PWD)/apidocs:/s -w /s temp \ + sh -c "openapi lint openapi.yaml" + define DOCKERFILE_RELEASE -FROM amd64/$(BASE_IMAGE) +FROM $(BASE_IMAGE) RUN apk add --no-cache zip make git tar WORKDIR /s COPY go.mod go.sum ./ @@ -165,8 +178,8 @@ endef export DOCKERFILE_RELEASE release: - echo "$$DOCKERFILE_RELEASE" | docker build . -f - -t temp \ - && docker run --rm -v $(PWD):/out \ + echo "$$DOCKERFILE_RELEASE" | docker build . -f - -t temp + docker run --rm -v $(PWD):/out \ temp sh -c "rm -rf /out/release && cp -r /s/release /out/" release-nodocker: diff --git a/apidocs/.redocly.yaml b/apidocs/.redocly.yaml new file mode 100644 index 00000000..8a8d8ee0 --- /dev/null +++ b/apidocs/.redocly.yaml @@ -0,0 +1,3 @@ +lint: + extends: + - recommended diff --git a/apidocs/openapi.yaml b/apidocs/openapi.yaml new file mode 100644 index 00000000..1449c5ac --- /dev/null +++ b/apidocs/openapi.yaml @@ -0,0 +1,417 @@ +openapi: 3.0.0 + +info: + version: 1.0.0 + title: rtsp-simple-server API + description: API of rtsp-simple-server, a RTSP / RTMP / HLS server and proxy. + license: + name: MIT + url: https://opensource.org/licenses/MIT + +servers: + - url: http://localhost:9997/v1 + +components: + schemas: + Conf: + type: object + properties: + # general + logLevel: + type: string + logDestinations: + type: array + items: + type: string + logFile: + type: string + readTimeout: + type: integer + writeTimeout: + type: integer + readBufferCount: + type: integer + api: + type: boolean + apiAddress: + type: string + metrics: + type: boolean + metricsAddress: + type: string + pprof: + type: boolean + pprofAddress: + type: string + runOnConnect: + type: string + runOnConnectRestart: + type: boolean + + # rtsp + rtspDisable: + type: boolean + protocols: + type: array + items: + type: string + encryption: + type: string + rtspAddress: + type: string + rtspsAddress: + type: string + rtpAddress: + type: string + rtcpAddress: + type: string + multicastIPRange: + type: string + multicastRTPPort: + type: integer + multicastRTCPPort: + type: integer + serverKey: + type: string + serverCert: + type: string + authMethods: + type: array + items: + type: string + readBufferSize: + type: integer + + # rtmp + rtmpDisable: + type: boolean + rtmpAddress: + type: string + + # hls + hlsDisable: + type: boolean + hlsAddress: + type: string + hlsAlwaysRemux: + type: boolean + hlsSegmentCount: + type: integer + hlsSegmentDuration: + type: integer + hlsAllowOrigin: + type: string + + paths: + type: object + additionalProperties: + $ref: '#/components/schemas/PathConf' + + PathConf: + type: object + properties: + # source + source: + type: string + sourceProtocol: + type: string + sourceAnyPortEnable: + type: boolean + sourceFingerprint: + type: string + sourceOnDemand: + type: boolean + sourceOnDemandStartTimeout: + type: integer + sourceOnDemandCloseAfter: + type: integer + sourceRedirect: + type: string + disablePublisherOverride: + type: boolean + fallback: + type: string + + # authentication + publishUser: + type: string + publishPass: + type: string + publishIPs: + type: array + items: + type: string + readUser: + type: string + readPass: + type: string + readIPs: + type: array + items: + type: string + + # custom commands + runOnInit: + type: string + runOnInitRestart: + type: boolean + runOnDemand: + type: string + runOnDemandRestart: + type: boolean + runOnDemandStartTimeout: + type: integer + runOnDemandCloseAfter: + type: integer + runOnPublish: + type: string + runOnPublishRestart: + type: boolean + runOnRead: + type: string + runOnReadRestart: + type: boolean + + Path: + type: object + properties: + confName: + type: string + conf: + $ref: '#/components/schemas/PathConf' + source: + oneOf: + - type: object + properties: + type: + type: string + enum: ['rtspsession'] + id: + type: string + - type: object + properties: + type: + type: string + enum: ['rtmpconn'] + id: + type: string + sourceReady: + type: boolean + readers: + type: array + items: + oneOf: + - type: object + properties: + type: + type: string + enum: ['rtspsession'] + id: + type: string + - type: object + properties: + type: + type: string + enum: ['rtmpconn'] + id: + type: string + + RTSPSession: + type: object + properties: + remoteAddr: + type: string + + RTMPConn: + type: object + properties: + remoteAddr: + type: string + +paths: + /config/get: + get: + operationId: configGet + summary: returns the current configuration. + description: '' + responses: + '200': + description: the request was successful. + content: + application/json: + schema: + $ref: '#/components/schemas/Conf' + '500': + description: internal server error. + + /config/set: + post: + operationId: configSet + summary: changes the current configuration. + responses: + '200': + description: the request was successful. + '400': + description: invalid request. + '500': + description: internal server error. + + /config/paths/add/{name}: + post: + operationId: configPathsAdd + summary: adds the configuration of a path. + description: '' + parameters: + - name: name + in: path + required: true + description: the name of the path. + schema: + type: string + responses: + '200': + description: the request was successful. + '400': + description: invalid request. + '500': + description: internal server error. + + /config/paths/edit/{name}: + post: + operationId: configPathsEdit + summary: changes the configuration of a path. + description: '' + parameters: + - name: name + in: path + required: true + description: the name of the path. + schema: + type: string + responses: + '200': + description: the request was successful. + '400': + description: invalid request. + '500': + description: internal server error. + + /config/paths/remove/{name}: + post: + operationId: configPathsRemove + summary: removes the configuration of a path. + description: '' + parameters: + - name: name + in: path + required: true + description: the name of the path. + schema: + type: string + responses: + '200': + description: the request was successful. + '400': + description: invalid request. + '500': + description: internal server error. + + /paths/list: + get: + operationId: pathsList + summary: returns all active paths. + description: '' + responses: + '200': + description: the request was successful. + content: + application/json: + schema: + items: + type: object + additionalProperties: + $ref: '#/components/schemas/Path' + '400': + description: invalid request. + '500': + description: internal server error. + + /rtspsessions/list: + get: + operationId: rtspSessionsList + summary: returns all active RTSP sessions. + description: '' + responses: + '200': + description: the request was successful. + content: + application/json: + schema: + items: + type: object + additionalProperties: + $ref: '#/components/schemas/RTSPSession' + '400': + description: invalid request. + '500': + description: internal server error. + + /rtspsessions/kick/{id}: + post: + operationId: rtspSessionsKick + summary: kicks out a RTSP session from the server. + description: '' + parameters: + - name: id + in: path + required: true + description: the ID of the session. + schema: + type: string + responses: + '200': + description: the request was successful. + '400': + description: invalid request. + '500': + description: internal server error. + + /rtmpconns/list: + get: + operationId: rtmpConnsList + summary: returns all active RTMP connections. + description: '' + responses: + '200': + description: the request was successful. + content: + application/json: + schema: + items: + type: object + additionalProperties: + $ref: '#/components/schemas/RTMPConn' + '400': + description: invalid request. + '500': + description: internal server error. + + /rtmpconns/kick/{id}: + post: + operationId: rtmpConnsKick + summary: kicks out a RTMP connection from the server. + description: '' + parameters: + - name: id + in: path + required: true + description: the ID of the connection. + schema: + type: string + responses: + '200': + description: the request was successful. + '400': + description: invalid request. + '500': + description: internal server error. diff --git a/internal/core/api.go b/internal/core/api.go index 4d7c64e8..725246e5 100644 --- a/internal/core/api.go +++ b/internal/core/api.go @@ -259,16 +259,16 @@ func newAPI( gin.SetMode(gin.ReleaseMode) router := gin.New() group := router.Group("/", a.mwLog) - group.GET("/config/get", a.onConfigGet) - group.POST("/config/set", a.onConfigSet) - group.POST("/config/paths/add/:name", a.onConfigPathsAdd) - group.POST("/config/paths/edit/:name", a.onConfigPathsEdit) - group.POST("/config/paths/delete/:name", a.onConfigPathsDelete) - group.GET("/paths/list", a.onPathsList) - group.GET("/rtspsessions/list", a.onRTSPSessionsList) - group.POST("/rtspsessions/kick/:id", a.onRTSPSessionsKick) - group.GET("/rtmpconns/list", a.onRTMPConnsList) - group.POST("/rtmpconns/kick/:id", a.onRTMPConnsKick) + group.GET("/v1/config/get", a.onConfigGet) + group.POST("/v1/config/set", a.onConfigSet) + group.POST("/v1/config/paths/add/:name", a.onConfigPathsAdd) + group.POST("/v1/config/paths/edit/:name", a.onConfigPathsEdit) + group.POST("/v1/config/paths/remove/:name", a.onConfigPathsDelete) + group.GET("/v1/paths/list", a.onPathsList) + group.GET("/v1/rtspsessions/list", a.onRTSPSessionsList) + group.POST("/v1/rtspsessions/kick/:id", a.onRTSPSessionsKick) + group.GET("/v1/rtmpconns/list", a.onRTMPConnsList) + group.POST("/v1/rtmpconns/kick/:id", a.onRTMPConnsKick) a.s = &http.Server{ Handler: router, diff --git a/internal/core/api_test.go b/internal/core/api_test.go index d627718b..58672290 100644 --- a/internal/core/api_test.go +++ b/internal/core/api_test.go @@ -125,7 +125,7 @@ func TestAPIConfigPathsEdit(t *testing.T) { require.Equal(t, "rtsp://127.0.0.1:9998/mypath", out.Paths["mypath"].Source) } -func TestAPIConfigPathsDelete(t *testing.T) { +func TestAPIConfigPathsRemove(t *testing.T) { p, ok := newInstance("api: yes\n") require.Equal(t, true, ok) defer p.close() @@ -136,7 +136,7 @@ func TestAPIConfigPathsDelete(t *testing.T) { }, nil) require.NoError(t, err) - err = httpRequest(http.MethodPost, "http://localhost:9997/config/paths/delete/mypath", nil, nil) + err = httpRequest(http.MethodPost, "http://localhost:9997/config/paths/remove/mypath", nil, nil) require.NoError(t, err) var out struct {