diff --git a/frontend/app/components/Session_/Player/Player.js b/frontend/app/components/Session_/Player/Player.js index 87d86d312..eda7cac41 100644 --- a/frontend/app/components/Session_/Player/Player.js +++ b/frontend/app/components/Session_/Player/Player.js @@ -18,7 +18,7 @@ const ScreenWrapper = withOverlay()(React.memo(() =>
{ // TODO: solve classes inheritance issues in typescript + this._scale(); } - scale = () => this._scale() clean() { diff --git a/frontend/app/player/MessageDistributor/managers/AssistManager.ts b/frontend/app/player/MessageDistributor/managers/AssistManager.ts index 6affb05dd..6aa6a77ad 100644 --- a/frontend/app/player/MessageDistributor/managers/AssistManager.ts +++ b/frontend/app/player/MessageDistributor/managers/AssistManager.ts @@ -8,8 +8,74 @@ import { ID_TP_MAP } from '../messages'; import { update, getState } from '../../store'; +export enum CallingState { + Requesting, + True, + False, +}; + + export const INITIAL_STATE = { - calling: false; + calling: CallingState.False, +} + + +function resolveURL(baseURL: string, relURL: string): string { + if (relURL.startsWith('#') || relURL === "") { + return relURL; + } + return new URL(relURL, baseURL).toString(); +} + + +var match = /bar/.exec("foobar"); +const re1 = /url\(("[^"]*"|'[^']*'|[^)]*)\)/g +const re2 = /@import "(.*?)"/g +function cssUrlsIndex(css: string): Array<[number, number]> { + const idxs: Array<[number, number]> = []; + const i1 = css.matchAll(re1); + // @ts-ignore + for (let m of i1) { + // @ts-ignore + const s: number = m.index + m[0].indexOf(m[1]); + const e: number = s + m[1].length; + idxs.push([s, e]); + } + const i2 = css.matchAll(re2); + // @ts-ignore + for (let m of i2) { + // @ts-ignore + const s = m.index + m[0].indexOf(m[1]); + const e = s + m[1].length; + idxs.push([s, e]) + } + return idxs; +} +function unquote(str: string): [string, string] { + str = str.trim(); + if (str.length <= 2) { + return [str, ""] + } + if (str[0] == '"' && str[str.length-1] == '"') { + return [ str.substring(1, str.length-1), "\""]; + } + if (str[0] == '\'' && str[str.length-1] == '\'') { + return [ str.substring(1, str.length-1), "'" ]; + } + return [str, ""] +} +function rewriteCSSLinks(css: string, rewriter: (rawurl: string) => string): string { + for (let idx of cssUrlsIndex(css)) { + const f = idx[0] + const t = idx[1] + const [ rawurl, q ] = unquote(css.substring(f, t)); + css = css.substring(0,f) + q + rewriter(rawurl) + q + css.substring(t); + } + return css +} + +function resolveCSS(baseURL: string, css: string): string { + return rewriteCSSLinks(css, rawurl => resolveURL(baseURL, rawurl)); } @@ -33,7 +99,7 @@ export default class AssistManager { // @ts-ignore host: new URL(window.ENV.API_EDP).host, path: '/assist', - port: 80, + port: 443 //location.protocol === 'https:' ? 443 : 80, }); this.peer = peer; this.peer.on('error', e => { @@ -54,7 +120,7 @@ export default class AssistManager { if (!this.peer) { return; } const id = this.peerID; console.log("trying to connect to", id) - const conn = this.peer.connect(id); + const conn = this.peer.connect(id, { serialization: 'json'}); conn.on('open', () => { this.md.setMessagesLoading(false); @@ -67,6 +133,30 @@ export default class AssistManager { let time = 0; let ts0 = 0; (data as Array).forEach(msg => { + + // TODO: more appropriate way to do it. + if (msg._id === 60) { + // @ts-ignore + if (msg.name === 'src' || msg.name === 'href') { + // @ts-ignore + msg.value = resolveURL(msg.baseURL, msg.value); + // @ts-ignore + } else if (msg.name === 'style') { + // @ts-ignore + msg.value = resolveCSS(msg.baseURL, msg.value); + } + msg._id = 12; + } else if (msg._id === 61) { // "SetCSSDataURLBased" + // @ts-ignore + msg.data = resolveCSS(msg.baseURL, msg.data); + msg._id = 15; + } else if (msg._id === 67) { // "insert_rule" + // @ts-ignore + msg.rule = resolveCSS(msg.baseURL, msg.rule); + msg._id = 37; + } + + msg.tp = ID_TP_MAP[msg._id]; // _id goes from tracker if (msg.tp === "timestamp") { ts0 = ts0 || msg.timestamp @@ -115,31 +205,40 @@ export default class AssistManager { } } - private onMouseMoveShare = (e: MouseEvent ): void => { + //private blocked: boolean = false; + private onMouseMove = (e: MouseEvent ): void => { + //if (this.blocked) { return; } + //this.blocked = true; + //setTimeout(() => this.blocked = false, 200); const conn = this.dataConnection; if (!conn || !conn.open) { return; } // @ts-ignore ??? - const data = this.md._getInternalCoordinates(e); - conn.send({ x: Math.round(data.x), y: Math.round(data.y) }); // debounce? + const data = this.md.getInternalCoordinates(e); + conn.send({ x: Math.round(data.x), y: Math.round(data.y) }); } - call(localStream: MediaStream, onStream: (s: MediaStream)=>void, onClose: () => void, onError?: ()=> void): null | Function { + call(localStream: MediaStream, onStream: (s: MediaStream)=>void, onClose: () => void, onReject: () => void, onError?: ()=> void): null | Function { if (!this.peer || getState().calling) { return null; } + update({ calling: CallingState.Requesting }); + console.log('calling...') const call = this.peer.call(this.peerID, localStream); - - console.log('calling...') - - update({ calling: true}); + + let requesting = true; call.on('stream', stream => { + update({ calling: CallingState.True }); onStream(stream); // @ts-ignore ?? - this.md.overlay.addEventListener("mousemove", this.onMouseMoveShare) + this.md.overlay.addEventListener("click", this.onMouseMove) }); this.onCallEnd = () => { + if (requesting) { + requesting = false; + onReject(); + } // @ts-ignore ?? - this.md.overlay.removeEventListener("mousemove", this.onMouseMoveShare); - update({ calling: false}); + this.md.overlay.removeEventListener("click", this.onMouseMove); + update({ calling: CallingState.True }); onClose(); } call.on("close", this.onCallEnd); @@ -155,5 +254,6 @@ export default class AssistManager { clear() { this.peer?.destroy(); } - } + + diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json index e2b8fa997..f229f5cae 100644 --- a/frontend/tsconfig.json +++ b/frontend/tsconfig.json @@ -5,6 +5,7 @@ "moduleResolution": "node", //? //"allowJs": true, "allowSyntheticDefaultImports": true, + "downlevelIteration": true, //"sourceMap": false, "lib": [ "es2020", "dom" ], "jsx": "react",