websocket is more stable

This commit is contained in:
vel 2022-01-31 12:29:06 -08:00
parent f52b9a9c53
commit 7a7e99337f
Signed by: velvox
GPG Key ID: 1C8200C1D689CEF5
12 changed files with 106 additions and 127 deletions

View File

@ -6,8 +6,6 @@
<component name="ChangeListManager"> <component name="ChangeListManager">
<list default="true" id="8a64704d-5500-41a6-aa4c-e275933fc58c" name="Changes" comment=""> <list default="true" id="8a64704d-5500-41a6-aa4c-e275933fc58c" name="Changes" comment="">
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" /> <change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/internal/ws/handlers.go" beforeDir="false" afterPath="$PROJECT_DIR$/internal/ws/handlers.go" afterDir="false" />
<change beforePath="$PROJECT_DIR$/internal/ws/state.go" beforeDir="false" afterPath="$PROJECT_DIR$/internal/ws/state.go" afterDir="false" />
<change beforePath="$PROJECT_DIR$/../frontend/src/components/Player.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/../frontend/src/components/Player.tsx" afterDir="false" /> <change beforePath="$PROJECT_DIR$/../frontend/src/components/Player.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/../frontend/src/components/Player.tsx" afterDir="false" />
<change beforePath="$PROJECT_DIR$/../frontend/src/pages/player.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/../frontend/src/pages/player.tsx" afterDir="false" /> <change beforePath="$PROJECT_DIR$/../frontend/src/pages/player.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/../frontend/src/pages/player.tsx" afterDir="false" />
</list> </list>
@ -100,15 +98,4 @@
<component name="VgoProject"> <component name="VgoProject">
<integration-enabled>true</integration-enabled> <integration-enabled>true</integration-enabled>
</component> </component>
<component name="XDebuggerManager">
<breakpoint-manager>
<breakpoints>
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
<url>file://$PROJECT_DIR$/internal/ws/handlers.go</url>
<line>61</line>
<option name="timeStamp" value="7" />
</line-breakpoint>
</breakpoints>
</breakpoint-manager>
</component>
</project> </project>

View File

@ -1,103 +1,85 @@
import { Box, css } from "@chakra-ui/react"; import { Box } from "@chakra-ui/react";
import React, { FC, useEffect, useRef, useState } from "react"; import React, { forwardRef } from "react";
import ReactPlayer, { Config, ReactPlayerProps } from "react-player"; import ReactPlayer, { Config, ReactPlayerProps } from "react-player";
import IdentityData from "../interfaces/Identity";
import { MessageTypes } from "../interfaces/IMessage";
import SocketEvents from "../interfaces/SocketEvents";
import Message from "../util/Message";
import MessageUtil from "../util/MessageUtil";
import PlayerSocket from "../ws/websocket";
type PlayerProps = { const Player = forwardRef<ReactPlayer, ReactPlayerProps>((props, ref) => {
id: string;
socket: PlayerSocket;
identity?: IdentityData;
} & ReactPlayerProps;
const Player: FC<PlayerProps> = (props) => {
const playerRef = useRef<ReactPlayer>(null);
const [paused, setPaused] = useState<boolean>(false);
const { socket } = props;
const config: Config = { const config: Config = {
file: { file: {
forceHLS: true, forceHLS: true,
}, },
}; };
useEffect(() => { // useEffect(() => {
if (playerRef.current && typeof props.identity !== "undefined") { // if (playerRef.current && typeof props.identity !== "undefined") {
console.log(props.identity.playhead); // console.log(props.identity.playhead);
playerRef.current.seekTo(props.identity.playhead); // playerRef.current.seekTo(props.identity.playhead);
setPaused(props.identity.paused); // setPaused(props.identity.paused);
} // }
}, []); // }, []);
socket.emitter.once(SocketEvents.SetPlayhead, (e) => { // socket.emitter.once(SocketEvents.SetPlayhead, (e) => {
console.log(e); // console.log(e);
playerRef.current.seekTo(e.playhead); // playerRef.current.seekTo(e.playhead);
setPaused(e.paused); // setPaused(e.paused);
}); // });
const onSeek = (playedSeconds: number) => { // const onSeek = (playedSeconds: number) => {
if (!props.identity.admin) return; // if (!props.identity.admin) return;
if (paused) { // if (paused) {
socket?.send( // socket?.send(
MessageUtil.encode( // MessageUtil.encode(
new Message(MessageTypes.SetPlayhead, { // new Message(MessageTypes.SetPlayhead, {
playhead: playedSeconds, // playhead: playedSeconds,
paused: true, // paused: true,
}) // })
) // )
); // );
return; // return;
} // }
socket?.send( // socket?.send(
MessageUtil.encode( // MessageUtil.encode(
new Message(MessageTypes.SetPlayhead, { // new Message(MessageTypes.SetPlayhead, {
playhead: playedSeconds, // playhead: playedSeconds,
paused: false, // paused: false,
}) // })
) // )
); // );
}; // };
const onPause = () => { // const onPause = () => {
if (!props.identity.admin) return; // if (!props.identity.admin) return;
setPaused(true); // setPaused(true);
socket?.send( // socket?.send(
MessageUtil.encode( // MessageUtil.encode(
new Message(MessageTypes.SetPlayhead, { // new Message(MessageTypes.SetPlayhead, {
playhead: playerRef.current.getCurrentTime(), // playhead: playerRef.current.getCurrentTime(),
paused: true, // paused: true,
}) // })
) // )
); // );
}; // };
const onPlay = () => { // const onPlay = () => {
if (!props.identity.admin) return; // if (!props.identity.admin) return;
setPaused(false); // setPaused(false);
socket?.send( // socket?.send(
MessageUtil.encode( // MessageUtil.encode(
new Message(MessageTypes.SetPlayhead, { // new Message(MessageTypes.SetPlayhead, {
playhead: playerRef.current.getCurrentTime(), // playhead: playerRef.current.getCurrentTime(),
paused: false, // paused: false,
}) // })
) // )
); // );
}; // };
return ( return (
<Box height="100vh" width="100vw"> <Box height="100vh" width="100vw">
<ReactPlayer <ReactPlayer
url={props.id} url={props.url}
width="100%" width="100%"
height="100%" height="100%"
config={config} config={config}
controls={props.identity.admin} controls
onPlay={onPlay} ref={ref}
onPause={onPause} playing={false}
onSeek={onSeek}
ref={playerRef}
playing={!paused}
{...props} {...props}
/> />
</Box> </Box>
); );
}; });
export default Player; export default Player;

View File

@ -7,17 +7,19 @@ interface useWSProps {
} }
// todo write websocket reconnector // todo write websocket reconnector
const useWS = ({ user }: useWSProps) => { const useWS = ({ user }: useWSProps): PlayerSocket | null => {
if (typeof window === "undefined") { if (typeof window === "undefined") {
return; return;
} }
// todo checkout usecallback // todo checkout usecallback
const [socket, setSocket] = useState<PlayerSocket>(); const [socket, setSocket] = useState<PlayerSocket>(null);
useEffect(() => { useEffect(() => {
let internalSocket = new PlayerSocket(user); let internalSocket = new PlayerSocket(user);
setSocket(internalSocket); setSocket(internalSocket);
return () => { return () => {
if (internalSocket.readyState !== WebSocket.OPEN) {
return internalSocket.close(); return internalSocket.close();
}
}; };
}, []); }, []);

View File

@ -0,0 +1,4 @@
export default interface SetPlayheadEvent {
playhead: number;
paused: boolean;
}

View File

@ -8,7 +8,7 @@ import { Container } from "../components/Container";
import { Footer } from "../components/Footer"; import { Footer } from "../components/Footer";
import { Hero } from "../components/Hero"; import { Hero } from "../components/Hero";
import { Main } from "../components/Main"; import { Main } from "../components/Main";
import isDev from "../util/isDev"; import { isDev } from "../util";
const Index: NextPage = () => { const Index: NextPage = () => {
return ( return (

View File

@ -1,16 +1,17 @@
import { GetServerSideProps, NextPage } from "next"; import { GetServerSideProps, NextPage } from "next";
import { User } from "next-auth"; import { User } from "next-auth";
import { getSession } from "next-auth/react"; import { getSession } from "next-auth/react";
import dynamic from "next/dynamic";
import Head from "next/head"; import Head from "next/head";
import React, { useState } from "react"; import React, { useEffect, useRef, useState } from "react";
import ReactPlayer from "react-player";
import { Container } from "../components/Container"; import { Container } from "../components/Container";
import Player from "../components/Player";
import useWS from "../hooks/useWS"; import useWS from "../hooks/useWS";
import IdentityData from "../interfaces/Identity"; import IdentityData from "../interfaces/Identity";
import SetPlayheadEvent from "../interfaces/Playhead";
import SocketEvents from "../interfaces/SocketEvents"; import SocketEvents from "../interfaces/SocketEvents";
import isBrowser from "../util/isBrowser"; import { isBrowser } from "../util";
import PlayerSocket from "../ws/websocket";
const Player = dynamic(() => import("../components/Player"), { ssr: false });
interface PlayerPageProps { interface PlayerPageProps {
user: User; user: User;
@ -18,25 +19,29 @@ interface PlayerPageProps {
// types for the function // types for the function
const PlayerPage: NextPage<PlayerPageProps> = ({ user }) => { const PlayerPage: NextPage<PlayerPageProps> = ({ user }) => {
// const playerRef = useRef<ReactPlayer>();
const socket = useWS({ user }); const socket = useWS({ user });
const playerRef = useRef<ReactPlayer>();
const [id, setID] = useState<string>(""); const [id, setID] = useState<string>("");
const [identity, setIdentity] = useState<IdentityData>(); const [identity, setIdentity] = useState<IdentityData>();
useEffect(() => {
if (isBrowser() && typeof socket !== "undefined") { if (isBrowser() && typeof socket !== "undefined") {
socket.emitter.on(SocketEvents.Identify, (e: IdentityData) => { socket?.emitter.once(SocketEvents.Identify, (e: IdentityData) => {
console.log(e);
setID(e.playlist); setID(e.playlist);
setIdentity(e); setIdentity(e);
}); });
console.log(identity); socket?.emitter.on(SocketEvents.SetPlayhead, (e: SetPlayheadEvent) => {
console.log(e);
});
} }
}, [socket]);
const onSeek = () => {};
return ( return (
<> <>
<Head> <Head>
<title>Watch Together</title> <title>Watch Together</title>
</Head> </Head>
<Container height="100vh" background={"#000"}> <Container height="100vh" background={"#000"}>
<Player id={id} socket={socket} identity={identity} /> <Player ref={playerRef} />
</Container> </Container>
</> </>
); );

View File

@ -1 +0,0 @@
export default class Handler {}

View File

@ -1,3 +0,0 @@
const useAPI = () => {};
export default useAPI;

View File

@ -0,0 +1,6 @@
export function isDev() {
return process.env.NODE_ENV === "development";
}
export function isBrowser() {
return typeof window !== "undefined";
}

View File

@ -1,3 +0,0 @@
export default function isBrowser() {
return typeof window !== "undefined";
}

View File

@ -1,3 +0,0 @@
export default function isDev() {
return process.env.NODE_ENV === "development";
}

View File

@ -25,6 +25,10 @@ export default class PlayerSocket extends Websocket {
this.onmessage = this.onMessage; this.onmessage = this.onMessage;
this.onclose = this.onClose; this.onclose = this.onClose;
} }
close(code?: number, reason?: string): void {
this.emitter.removeAllListeners();
super.close(code, reason);
}
onMessage(evt: MessageEvent<any>) { onMessage(evt: MessageEvent<any>) {
let message = MessageUtil.decode(evt.data); let message = MessageUtil.decode(evt.data);
if (message.type === MessageTypes["Ping"]) { if (message.type === MessageTypes["Ping"]) {
@ -65,7 +69,6 @@ export default class PlayerSocket extends Websocket {
} }
onClose(event: CloseEvent) { onClose(event: CloseEvent) {
console.log("[WS] socket connection closed"); console.log("[WS] socket connection closed");
console.log(event);
this.emitter.emit("closed"); this.emitter.emit("closed");
} }
get open() { get open() {