From 8c7df0f5abca35533b298dcc0c5f7bc2fe7d7125 Mon Sep 17 00:00:00 2001 From: Matthew Stratford Date: Sat, 11 Apr 2020 22:39:27 +0100 Subject: [PATCH] Add basis of webstudio selector server UI. --- .env | 1 + .env.prod | 1 + package.json | 1 + src/App.css | 14 ++++++++ src/api.ts | 30 ++++++++++++---- src/broadcast/state.ts | 80 +++++++++++++++++++++++++++++++++++++++++- src/navbar/index.tsx | 26 ++++++++++++-- yarn.lock | 29 ++++++++++++++- 8 files changed, 172 insertions(+), 10 deletions(-) diff --git a/.env b/.env index 98a640a..bf1edd2 100644 --- a/.env +++ b/.env @@ -2,4 +2,5 @@ HOST=local-development.ury.org.uk REACT_APP_VERSION=$npm_package_version REACT_APP_MYRADIO_NONAPI_BASE=https://ury.org.uk/myradio-staging REACT_APP_MYRADIO_BASE=https://ury.org.uk/api-staging/v2 +REACT_APP_BROADCAST_API_BASE=https://ury.org.uk/webstudio/api/v1 REACT_APP_WS_URL=wss://audio.ury.org.uk/webstudio/stream \ No newline at end of file diff --git a/.env.prod b/.env.prod index 50c6e4a..6abe627 100644 --- a/.env.prod +++ b/.env.prod @@ -1,4 +1,5 @@ REACT_APP_VERSION=$npm_package_version REACT_APP_MYRADIO_NONAPI_BASE=https://ury.org.uk/myradio REACT_APP_MYRADIO_BASE=https://ury.org.uk/api/v2 +REACT_APP_BROADCAST_API_BASE=https://ury.org.uk/webstudio/api/v1 REACT_APP_WS_URL=wss://audio.ury.org.uk/webstudio/stream \ No newline at end of file diff --git a/package.json b/package.json index eeec80c..32d0ba4 100644 --- a/package.json +++ b/package.json @@ -76,6 +76,7 @@ "react-dnd": "^9.4.0", "react-dnd-html5-backend": "^9.4.0", "react-dom": "^16.13.1", + "react-live-clock": "^4.0.5", "react-modal": "^3.11.2", "react-redux": "^7.1.3", "reactstrap": "^8.4.1", diff --git a/src/App.css b/src/App.css index 67f9db9..89abe90 100644 --- a/src/App.css +++ b/src/App.css @@ -21,6 +21,20 @@ color: #09d3ac; } +#timelord { + background: black; + border:red 1px solid; + padding:0; + margin:0; + color: white; + width: 300px; + max-width: 40vw; +} +#timelord .time { + font-weight: bold; + font-size: 1.1em; +} + .sp-container { display: flex; flex-direction: column; diff --git a/src/api.ts b/src/api.ts index 3c38e01..48ed382 100644 --- a/src/api.ts +++ b/src/api.ts @@ -4,19 +4,22 @@ export const MYRADIO_NON_API_BASE = process.env.REACT_APP_MYRADIO_NONAPI_BASE!; export const MYRADIO_BASE_URL = process.env.REACT_APP_MYRADIO_BASE!; +export const BROADCAST_API_BASE_URL = + process.env.REACT_APP_BROADCAST_API_BASE!; const MYRADIO_API_KEY = process.env.REACT_APP_MYRADIO_KEY!; class ApiException extends Error {} -export async function myradioRequest( +export async function apiRequest( url: string, method: "GET" | "POST" | "PUT", - params: any + params: any, + need_auth: boolean = true ): Promise { let req = null; if (method === "GET") { req = fetch(url + qs.stringify(params, { addQueryPrefix: true }), { - credentials: "include" + credentials: (need_auth ? "include" : "omit") }); } else { const body = JSON.stringify(params); @@ -27,7 +30,7 @@ export async function myradioRequest( headers: { "Content-Type": "application/json; charset=UTF-8" }, - credentials: "include" + credentials: (need_auth ? "include" : "omit") }); } return await req; @@ -38,7 +41,22 @@ export async function myradioApiRequest( method: "GET" | "POST" | "PUT", params: any ): Promise { - const res = await myradioRequest(MYRADIO_BASE_URL + endpoint, method, params); + const res = await apiRequest(MYRADIO_BASE_URL + endpoint, method, params); + const json = await res.json(); + if (json.status === "OK") { + return json.payload; + } else { + console.error(json.payload); + throw new ApiException("Request failed!"); + } +} + +export async function broadcastApiRequest( + endpoint: string, + method: "GET" | "POST" | "PUT", + params: any +): Promise { + const res = await apiRequest(BROADCAST_API_BASE_URL + endpoint, method, params, false); const json = await res.json(); if (json.status === "OK") { return json.payload; @@ -183,7 +201,7 @@ export function getAuxPlaylists(): Promise> { } export function loadAuxLibrary(libraryId: string): Promise { - return myradioRequest(MYRADIO_NON_API_BASE + "/NIPSWeb/load_aux_lib", "GET", { + return apiRequest(MYRADIO_NON_API_BASE + "/NIPSWeb/load_aux_lib", "GET", { libraryid: libraryId }).then(res => res.json()); } diff --git a/src/broadcast/state.ts b/src/broadcast/state.ts index 5c6d9a2..9198d82 100644 --- a/src/broadcast/state.ts +++ b/src/broadcast/state.ts @@ -1,6 +1,6 @@ import { createSlice, PayloadAction } from "@reduxjs/toolkit"; import { AppThunk } from "../store"; -import { myradioApiRequest } from "../api"; +import { myradioApiRequest, broadcastApiRequest } from "../api"; import { WebRTCStreamer } from "./rtc_streamer"; import * as MixerState from "../mixer/state"; import * as NavbarState from "../navbar/state"; @@ -9,15 +9,31 @@ import { RecordingStreamer } from "./recording_streamer"; export let streamer: WebRTCStreamer | null = null; +export type BroadcastStageEnum = +| "NOT_REGISTERED" +| "REGISTERED" +| "FAILED_REGISTRATION"; + + interface BroadcastState { + stage: BroadcastStageEnum; + connID: number | null; tracklisting: boolean; connectionState: ConnectionStateEnum; recordingState: ConnectionStateEnum; } +/* Overall states: +hasn't registered +registered +on air + +*/ const broadcastState = createSlice({ name: "Broadcast", initialState: { + stage: "NOT_REGISTERED", + connID: null, tracklisting: false, connectionState: "NOT_CONNECTED", recordingState: "NOT_CONNECTED" @@ -26,6 +42,14 @@ const broadcastState = createSlice({ toggleTracklisting(state) { state.tracklisting = !state.tracklisting; }, + setConnID(state, action: PayloadAction) { + state.connID = action.payload; + if (action.payload != null) { + state.stage = "REGISTERED" + } else { + state.stage = "NOT_REGISTERED" + } + }, setConnectionState(state, action: PayloadAction) { state.connectionState = action.payload; }, @@ -41,6 +65,60 @@ export interface TrackListItem { audiologid: number; } + + + + + +export const registerTimeslot = (): AppThunk => async (dispatch, getState) => { + if (getState().broadcast.stage === "NOT_REGISTERED") { + var state = getState().session; + const memberid = state.currentUser?.memberid; + const timeslotid = state.currentTimeslot?.timeslot_id; + console.log("Attempting to Register for Broadcast."); + var sourceid = 4; // TODO: make UI for this. + var connID = (await sendBroadcastRegister(timeslotid, memberid, sourceid)); + if (connID !== undefined) { + dispatch(broadcastState.actions.setConnID(connID["connid"])); + dispatch(startStreaming()); + } + + } +}; + +export const cancelTimeslot = (): AppThunk => async (dispatch, getState) => { + if (getState().broadcast.stage === "REGISTERED") { + console.log("Attempting to Cancel Broadcast."); + var response = (await sendBroadcastCancel(getState().broadcast.connID)); + dispatch(stopStreaming()); + if (response != null) { + dispatch(broadcastState.actions.setConnID(null)); + } + + } +}; + +export function sendBroadcastRegister(timeslotid: number | undefined, memberid: number | undefined, sourceid: number): Promise { + return broadcastApiRequest("/registerTimeslot", "POST", { + memberid: memberid, + timeslotid: timeslotid, + sourceid: sourceid + }); +} +export function sendBroadcastCancel(connid: number | null): Promise { + return broadcastApiRequest("/cancelTimeslot", "POST", { + connid: connid + }); +} + + + + + + + + + export const { toggleTracklisting } = broadcastState.actions; export const tracklistStart = ( diff --git a/src/navbar/index.tsx b/src/navbar/index.tsx index 3190701..ce41bfd 100644 --- a/src/navbar/index.tsx +++ b/src/navbar/index.tsx @@ -1,5 +1,7 @@ import React, { useRef, useEffect } from "react"; import { useDispatch, useSelector } from "react-redux"; +import Clock from 'react-live-clock'; + import { RootState } from "../rootReducer"; import * as BroadcastState from "../broadcast/state"; @@ -16,7 +18,7 @@ export function NavBar() { const redirect_url = encodeURIComponent(window.location.toString()); return ( <> -
+
Web Studio Logo +
{ + switch (broadcastState.stage) { + case "NOT_REGISTERED": + dispatch( + BroadcastState.registerTimeslot() + ) + break; + case "REGISTERED": + dispatch( + BroadcastState.cancelTimeslot() + ) + break; + } + }}> +
+
+ {broadcastState.stage === "NOT_REGISTERED" && "Register for show"} + {broadcastState.stage === "REGISTERED" && "Cancel show"} +
+
    @@ -193,7 +215,7 @@ export function CombinedNavAlertBar() { <>
    -