From a5e87334561dd10f1ba4c53d736bcaaed8b4df7f Mon Sep 17 00:00:00 2001 From: m1k1o Date: Sun, 21 Mar 2021 13:57:48 +0100 Subject: [PATCH] settings + stats. --- OpenApi.yml | 63 ++++++- client/src/api/api.ts | 257 +++++++++++++++++++++-------- client/src/components/RoomInfo.vue | 2 +- client/src/store/index.ts | 13 +- internal/api/manager.go | 4 +- internal/api/rooms.go | 19 ++- internal/http/manager.go | 3 +- internal/room/manager.go | 44 ++--- internal/types/room.go | 14 ++ 9 files changed, 317 insertions(+), 102 deletions(-) diff --git a/OpenApi.yml b/OpenApi.yml index 85c7591..57d0cae 100644 --- a/OpenApi.yml +++ b/OpenApi.yml @@ -47,11 +47,28 @@ paths: '500': description: Internal server error /api/rooms/{roomId}: + delete: + tags: + - rooms + summary: Remove room + operationId: roomRemove + parameters: + - in: path + name: roomId + required: true + schema: + type: string + responses: + '204': + description: OK + '500': + description: Internal server error + /api/rooms/{roomId}/settings: get: tags: - rooms summary: Get room settings - operationId: roomGet + operationId: roomSettings parameters: - in: path name: roomId @@ -69,11 +86,12 @@ paths: description: Bad request '500': description: Internal server error - delete: + /api/rooms/{roomId}/stats: + get: tags: - rooms - summary: Remove room - operationId: roomRemove + summary: Get room statistics + operationId: roomStats parameters: - in: path name: roomId @@ -81,8 +99,12 @@ paths: schema: type: string responses: - '204': + '200': description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/RoomStats' '500': description: Internal server error /api/rooms/{roomId}/stop: @@ -167,6 +189,7 @@ components: type: string format: datetime example: "2021-03-07T21:56:34Z" + RoomSettings: type: object properties: @@ -209,3 +232,33 @@ components: example: 128 audio_pipeline: type: string + + RoomStats: + type: object + properties: + connections: + type: number + example: 3 + host: + type: string + example: foobar + members: + type: array + items: + $ref: '#/components/schemas/RoomMember' + + RoomMember: + type: object + properties: + id: + type: string + example: foobar + displayname: + type: string + example: Foo Bar + admin: + type: boolean + example: true + muted: + type: boolean + example: false diff --git a/client/src/api/api.ts b/client/src/api/api.ts index df9387d..63e9977 100644 --- a/client/src/api/api.ts +++ b/client/src/api/api.ts @@ -76,6 +76,37 @@ export interface RoomEntry { */ created?: string; } +/** + * + * @export + * @interface RoomMember + */ +export interface RoomMember { + /** + * + * @type {string} + * @memberof RoomMember + */ + id?: string; + /** + * + * @type {string} + * @memberof RoomMember + */ + displayname?: string; + /** + * + * @type {boolean} + * @memberof RoomMember + */ + admin?: boolean; + /** + * + * @type {boolean} + * @memberof RoomMember + */ + muted?: boolean; +} /** * * @export @@ -161,6 +192,31 @@ export interface RoomSettings { */ audio_pipeline?: string; } +/** + * + * @export + * @interface RoomStats + */ +export interface RoomStats { + /** + * + * @type {number} + * @memberof RoomStats + */ + connections?: number; + /** + * + * @type {string} + * @memberof RoomStats + */ + host?: string; + /** + * + * @type {Array} + * @memberof RoomStats + */ + members?: Array; +} /** * RoomsApi - axios parameter creator @@ -202,40 +258,6 @@ export const RoomsApiAxiosParamCreator = function (configuration?: Configuration options: localVarRequestOptions, }; }, - /** - * - * @summary Get room settings - * @param {string} roomId - * @param {*} [options] Override http request option. - * @throws {RequiredError} - */ - roomGet: async (roomId: string, options: any = {}): Promise => { - // verify required parameter 'roomId' is not null or undefined - assertParamExists('roomGet', 'roomId', roomId) - const localVarPath = `/api/rooms/{roomId}` - .replace(`{${"roomId"}}`, encodeURIComponent(String(roomId))); - // use dummy base URL string because the URL constructor only accepts absolute URLs. - const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); - let baseOptions; - if (configuration) { - baseOptions = configuration.baseOptions; - } - - const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options}; - const localVarHeaderParameter = {} as any; - const localVarQueryParameter = {} as any; - - - - setSearchParams(localVarUrlObj, localVarQueryParameter, options.query); - let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; - localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; - - return { - url: toPathString(localVarUrlObj), - options: localVarRequestOptions, - }; - }, /** * * @summary Remove room @@ -295,6 +317,40 @@ export const RoomsApiAxiosParamCreator = function (configuration?: Configuration + setSearchParams(localVarUrlObj, localVarQueryParameter, options.query); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + /** + * + * @summary Get room settings + * @param {string} roomId + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + roomSettings: async (roomId: string, options: any = {}): Promise => { + // verify required parameter 'roomId' is not null or undefined + assertParamExists('roomSettings', 'roomId', roomId) + const localVarPath = `/api/rooms/{roomId}/settings` + .replace(`{${"roomId"}}`, encodeURIComponent(String(roomId))); + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + + setSearchParams(localVarUrlObj, localVarQueryParameter, options.query); let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; @@ -329,6 +385,40 @@ export const RoomsApiAxiosParamCreator = function (configuration?: Configuration + setSearchParams(localVarUrlObj, localVarQueryParameter, options.query); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + /** + * + * @summary Get room statistics + * @param {string} roomId + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + roomStats: async (roomId: string, options: any = {}): Promise => { + // verify required parameter 'roomId' is not null or undefined + assertParamExists('roomStats', 'roomId', roomId) + const localVarPath = `/api/rooms/{roomId}/stats` + .replace(`{${"roomId"}}`, encodeURIComponent(String(roomId))); + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + + setSearchParams(localVarUrlObj, localVarQueryParameter, options.query); let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; @@ -423,17 +513,6 @@ export const RoomsApiFp = function(configuration?: Configuration) { const localVarAxiosArgs = await localVarAxiosParamCreator.roomCreate(roomSettings, options); return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); }, - /** - * - * @summary Get room settings - * @param {string} roomId - * @param {*} [options] Override http request option. - * @throws {RequiredError} - */ - async roomGet(roomId: string, options?: any): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { - const localVarAxiosArgs = await localVarAxiosParamCreator.roomGet(roomId, options); - return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); - }, /** * * @summary Remove room @@ -456,6 +535,17 @@ export const RoomsApiFp = function(configuration?: Configuration) { const localVarAxiosArgs = await localVarAxiosParamCreator.roomRestart(roomId, options); return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); }, + /** + * + * @summary Get room settings + * @param {string} roomId + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async roomSettings(roomId: string, options?: any): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.roomSettings(roomId, options); + return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + }, /** * * @summary Start room @@ -467,6 +557,17 @@ export const RoomsApiFp = function(configuration?: Configuration) { const localVarAxiosArgs = await localVarAxiosParamCreator.roomStart(roomId, options); return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); }, + /** + * + * @summary Get room statistics + * @param {string} roomId + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async roomStats(roomId: string, options?: any): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.roomStats(roomId, options); + return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + }, /** * * @summary Stop room @@ -508,16 +609,6 @@ export const RoomsApiFactory = function (configuration?: Configuration, basePath roomCreate(roomSettings?: RoomSettings, options?: any): AxiosPromise { return localVarFp.roomCreate(roomSettings, options).then((request) => request(axios, basePath)); }, - /** - * - * @summary Get room settings - * @param {string} roomId - * @param {*} [options] Override http request option. - * @throws {RequiredError} - */ - roomGet(roomId: string, options?: any): AxiosPromise { - return localVarFp.roomGet(roomId, options).then((request) => request(axios, basePath)); - }, /** * * @summary Remove room @@ -538,6 +629,16 @@ export const RoomsApiFactory = function (configuration?: Configuration, basePath roomRestart(roomId: string, options?: any): AxiosPromise { return localVarFp.roomRestart(roomId, options).then((request) => request(axios, basePath)); }, + /** + * + * @summary Get room settings + * @param {string} roomId + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + roomSettings(roomId: string, options?: any): AxiosPromise { + return localVarFp.roomSettings(roomId, options).then((request) => request(axios, basePath)); + }, /** * * @summary Start room @@ -548,6 +649,16 @@ export const RoomsApiFactory = function (configuration?: Configuration, basePath roomStart(roomId: string, options?: any): AxiosPromise { return localVarFp.roomStart(roomId, options).then((request) => request(axios, basePath)); }, + /** + * + * @summary Get room statistics + * @param {string} roomId + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + roomStats(roomId: string, options?: any): AxiosPromise { + return localVarFp.roomStats(roomId, options).then((request) => request(axios, basePath)); + }, /** * * @summary Stop room @@ -589,18 +700,6 @@ export class RoomsApi extends BaseAPI { return RoomsApiFp(this.configuration).roomCreate(roomSettings, options).then((request) => request(this.axios, this.basePath)); } - /** - * - * @summary Get room settings - * @param {string} roomId - * @param {*} [options] Override http request option. - * @throws {RequiredError} - * @memberof RoomsApi - */ - public roomGet(roomId: string, options?: any) { - return RoomsApiFp(this.configuration).roomGet(roomId, options).then((request) => request(this.axios, this.basePath)); - } - /** * * @summary Remove room @@ -625,6 +724,18 @@ export class RoomsApi extends BaseAPI { return RoomsApiFp(this.configuration).roomRestart(roomId, options).then((request) => request(this.axios, this.basePath)); } + /** + * + * @summary Get room settings + * @param {string} roomId + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof RoomsApi + */ + public roomSettings(roomId: string, options?: any) { + return RoomsApiFp(this.configuration).roomSettings(roomId, options).then((request) => request(this.axios, this.basePath)); + } + /** * * @summary Start room @@ -637,6 +748,18 @@ export class RoomsApi extends BaseAPI { return RoomsApiFp(this.configuration).roomStart(roomId, options).then((request) => request(this.axios, this.basePath)); } + /** + * + * @summary Get room statistics + * @param {string} roomId + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof RoomsApi + */ + public roomStats(roomId: string, options?: any) { + return RoomsApiFp(this.configuration).roomStats(roomId, options).then((request) => request(this.axios, this.basePath)); + } + /** * * @summary Stop room diff --git a/client/src/components/RoomInfo.vue b/client/src/components/RoomInfo.vue index abcbe04..6b78aab 100644 --- a/client/src/components/RoomInfo.vue +++ b/client/src/components/RoomInfo.vue @@ -105,7 +105,7 @@ export default class RoomInfo extends Vue { this.loading = true try { - this.settings = await this.$store.dispatch('ROOMS_GET', roomId) + this.settings = await this.$store.dispatch('ROOMS_SETTINGS', roomId) } catch(e) { if (e.response) { this.$swal({ diff --git a/client/src/store/index.ts b/client/src/store/index.ts index 5e232ce..6cf852a 100644 --- a/client/src/store/index.ts +++ b/client/src/store/index.ts @@ -4,6 +4,7 @@ import Vuex, { ActionContext } from 'vuex' import { RoomEntry, RoomSettings, + RoomStats, RoomsApi, Configuration, } from '@/api/index' @@ -50,14 +51,18 @@ export default new Vuex.Store({ commit('ROOMS_ADD', res.data); return res.data }, - async ROOMS_GET(_: ActionContext, roomId: string): Promise { - const res = await api.roomGet(roomId) - return res.data - }, async ROOMS_REMOVE({ commit }: ActionContext, roomId: string) { await api.roomRemove(roomId) commit('ROOMS_DEL', roomId); }, + async ROOMS_SETTINGS(_: ActionContext, roomId: string): Promise { + const res = await api.roomSettings(roomId) + return res.data + }, + async ROOMS_STATS(_: ActionContext, roomId: string): Promise { + const res = await api.roomStats(roomId) + return res.data + }, async ROOMS_START({ commit }: ActionContext, roomId: string) { await api.roomStart(roomId) commit('ROOMS_PUT', { diff --git a/internal/api/manager.go b/internal/api/manager.go index a379893..c37eead 100644 --- a/internal/api/manager.go +++ b/internal/api/manager.go @@ -28,9 +28,11 @@ func (manager *ApiManagerCtx) Mount(r chi.Router) { r.Post("/rooms", manager.roomCreate) r.Route("/rooms/{roomId}", func(r chi.Router) { - r.Get("/", manager.roomGetSettings) r.Delete("/", manager.roomRemove) + r.Get("/settings", manager.roomGetSettings) + r.Get("/stats", manager.roomGetStats) + r.Post("/start", manager.roomGenericAction(manager.rooms.Start)) r.Post("/stop", manager.roomGenericAction(manager.rooms.Stop)) r.Post("/restart", manager.roomGenericAction(manager.rooms.Restart)) diff --git a/internal/api/rooms.go b/internal/api/rooms.go index 8d89aad..8b63239 100644 --- a/internal/api/rooms.go +++ b/internal/api/rooms.go @@ -43,6 +43,18 @@ func (manager *ApiManagerCtx) roomCreate(w http.ResponseWriter, r *http.Request) json.NewEncoder(w).Encode(response) } +func (manager *ApiManagerCtx) roomRemove(w http.ResponseWriter, r *http.Request) { + roomId := chi.URLParam(r, "roomId") + + err := manager.rooms.Remove(roomId) + if err != nil { + http.Error(w, err.Error(), 500) + return + } + + w.WriteHeader(http.StatusNoContent) +} + func (manager *ApiManagerCtx) roomGetSettings(w http.ResponseWriter, r *http.Request) { roomId := chi.URLParam(r, "roomId") @@ -56,16 +68,17 @@ func (manager *ApiManagerCtx) roomGetSettings(w http.ResponseWriter, r *http.Req json.NewEncoder(w).Encode(response) } -func (manager *ApiManagerCtx) roomRemove(w http.ResponseWriter, r *http.Request) { +func (manager *ApiManagerCtx) roomGetStats(w http.ResponseWriter, r *http.Request) { roomId := chi.URLParam(r, "roomId") - err := manager.rooms.Remove(roomId) + response, err := manager.rooms.GetStats(roomId) if err != nil { http.Error(w, err.Error(), 500) return } - w.WriteHeader(http.StatusNoContent) + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(response) } func (manager *ApiManagerCtx) roomGenericAction(action func(id string) error) func(http.ResponseWriter, *http.Request) { diff --git a/internal/http/manager.go b/internal/http/manager.go index 26219bc..3cd53e9 100644 --- a/internal/http/manager.go +++ b/internal/http/manager.go @@ -48,8 +48,7 @@ func New(ApiManager types.ApiManager, conf *config.Server) *HttpManagerCtx { if _, err := os.Stat(conf.Static + r.URL.Path); !os.IsNotExist(err) { fs.ServeHTTP(w, r) } else { - w.WriteHeader(http.StatusNotFound) - fmt.Fprint(w, "404 page not found") + http.NotFound(w, r) } }) } diff --git a/internal/room/manager.go b/internal/room/manager.go index 8bffe54..bcb5c3e 100644 --- a/internal/room/manager.go +++ b/internal/room/manager.go @@ -215,6 +215,28 @@ func (manager *RoomManagerCtx) GetEntry(id string) (*types.RoomEntry, error) { return manager.containerToEntry(*container) } +func (manager *RoomManagerCtx) Remove(id string) error { + _, err := manager.inspectContainer(id) + if err != nil { + return err + } + + // Stop the actual container + err = manager.client.ContainerStop(context.Background(), id, nil) + + if err != nil { + return err + } + + // Remove the actual container + err = manager.client.ContainerRemove(context.Background(), id, dockerTypes.ContainerRemoveOptions{ + RemoveVolumes: true, + Force: true, + }) + + return err +} + func (manager *RoomManagerCtx) GetSettings(id string) (*types.RoomSettings, error) { container, err := manager.inspectContainer(id) if err != nil { @@ -240,28 +262,12 @@ func (manager *RoomManagerCtx) GetSettings(id string) (*types.RoomSettings, erro return &settings, err } -func (manager *RoomManagerCtx) Remove(id string) error { - _, err := manager.inspectContainer(id) - if err != nil { - return err - } - // Stop the actual container - err = manager.client.ContainerStop(context.Background(), id, nil) - - if err != nil { - return err - } - - // Remove the actual container - err = manager.client.ContainerRemove(context.Background(), id, dockerTypes.ContainerRemoveOptions{ - RemoveVolumes: true, - Force: true, - }) - - return err +func (manager *RoomManagerCtx) GetStats(id string) (*types.RoomStats, error) { + return nil, fmt.Errorf("Not Implemented.") } + func (manager *RoomManagerCtx) Start(id string) error { _, err := manager.inspectContainer(id) if err != nil { diff --git a/internal/types/room.go b/internal/types/room.go index 08c617c..4cf5003 100644 --- a/internal/types/room.go +++ b/internal/types/room.go @@ -141,12 +141,26 @@ func (settings *RoomSettings) FromEnv(envs []string) error { return nil } +type RoomStats struct { + Connections uint32 `json:"connections"` + Host string `json:"host"` + Members []*RoomMember `json:"members"` +} + +type RoomMember struct { + ID string `json:"id"` + Name string `json:"displayname"` + Admin bool `json:"admin"` + Muted bool `json:"muted"` +} + type RoomManager interface { List() ([]RoomEntry, error) Create(settings RoomSettings) (string, error) GetEntry(id string) (*RoomEntry, error) GetSettings(id string) (*RoomSettings, error) + GetStats(id string) (*RoomStats, error) Remove(id string) error Start(id string) error