feat(ws): barebones SetPlayhead event

This commit is contained in:
vel 2022-01-27 22:48:21 -08:00
parent 5f81ed1756
commit 728f2d67d0
Signed by: velvox
GPG Key ID: 1C8200C1D689CEF5
11 changed files with 162 additions and 31 deletions

View File

@ -5,14 +5,17 @@
</component>
<component name="ChangeListManager">
<list default="true" id="8a64704d-5500-41a6-aa4c-e275933fc58c" name="Changes" comment="">
<change beforePath="$PROJECT_DIR$/../.vscode/settings.json" beforeDir="false" afterPath="$PROJECT_DIR$/../.vscode/settings.json" afterDir="false" />
<change afterPath="$PROJECT_DIR$/cmd/watchtogether/build.sh" afterDir="false" />
<change afterPath="$PROJECT_DIR$/../frontend/src/interfaces/SocketEvents.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/cmd/watchtogether/main.go" beforeDir="false" afterPath="$PROJECT_DIR$/cmd/watchtogether/main.go" 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$/../frontend/package.json" beforeDir="false" afterPath="$PROJECT_DIR$/../frontend/package.json" afterDir="false" />
<change beforePath="$PROJECT_DIR$/../frontend/src/hooks/useWS.ts" beforeDir="false" afterPath="$PROJECT_DIR$/../frontend/src/hooks/useWS.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/internal/ws/hub.go" beforeDir="false" afterPath="$PROJECT_DIR$/internal/ws/hub.go" afterDir="false" />
<change beforePath="$PROJECT_DIR$/internal/ws/message.go" beforeDir="false" afterPath="$PROJECT_DIR$/internal/ws/message.go" afterDir="false" />
<change beforePath="$PROJECT_DIR$/../frontend/src/components/Container.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/../frontend/src/components/Container.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/interfaces/Identity.ts" beforeDir="false" afterPath="$PROJECT_DIR$/../frontend/src/interfaces/Identity.ts" 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/ws/websocket.ts" beforeDir="false" afterPath="$PROJECT_DIR$/../frontend/src/ws/websocket.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/../frontend/yarn.lock" beforeDir="false" afterPath="$PROJECT_DIR$/../frontend/yarn.lock" afterDir="false" />
</list>
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />

View File

@ -0,0 +1,12 @@
#!/bin/bash
VERSION=v1.0.0
COMMIT_HASH=$(git rev-parse --short HEAD)
ENVIRONMENT=$ENV
BUILDSTRING="$VERSION-$COMMIT_HASH-$ENVIRONMENT"
echo The environment is "$ENVIRONMENT"
echo Building watch together backend "$VERSION-$COMMIT_HASH"
if [[ "$ENVIRONMENT" == "dev" ]]; then
go build -gcflags="all=-N -l" -ldflags "-X github.com/qpixel/watchtogether/cmd/watchtogether/main.VERSION=${BUILDSTRING} -X github.com/qpixel/watchtogether/cmd/watchtogether/main.ENVIRONMENT=${ENVIRONMENT}";
else
go build -ldflags "-X github.com/qpixel/watchtogether/cmd/watchtogether/main.VERSION=${BUILDSTRING} -X github.com/ubergeek77/uberbot/v2/core.ENVIRONMENT=${ENVIRONMENT}";
fi

View File

@ -10,6 +10,11 @@ import (
var log = tlog.NewTaggedLogger("Logger", tlog.NewColor("38;5;111"))
var (
VERSION string
ENVIRONMENT string
)
func main() {
r := mux.NewRouter()
hub := ws.NewHub()
@ -47,7 +52,8 @@ func main() {
}
return
})
log.Infof("starting backend")
log.Infof("running version %s. environment: %s", VERSION, ENVIRONMENT)
err := http.ListenAndServe(":8080", r)
if err != nil {
log.Errorf("%s", err.Error())

View File

@ -16,10 +16,11 @@ func handleIdentifyEvent(message *Message) {
MessageData: MessageData{
Type: Identify,
Data: map[string]interface{}{
"admin": true,
"playlist": "http://cdnapi.kaltura.com/p/1878761/sp/187876100/playManifest/entryId/1_usagz19w/flavorIds/1_5spqkazq,1_nslowvhp,1_boih5aji,1_qahc37ag/format/applehttp/protocol/http/a.m3u8",
"playhead": 0,
"user": d["user"],
"admin": true,
"playlist": "http://localhost:8081/BelleOpening.m3u8",
"controller": true,
"playhead": 0,
"user": d["user"],
},
},
}
@ -42,5 +43,21 @@ func handleGetPlayhead(message *Message) {
}
func handleSetPlayhead(message *Message) {
d := message.Data.(map[string]interface{})
m := Message{
MessageData: MessageData{
Type: SetPlayhead,
Data: map[string]interface{}{
"playhead": d["playhead"],
"paused": d["paused"],
},
},
}
log.Infof("Received SetPlayhead event. playhead is at %s", d["playhead"])
for client := range message.Client.hub.Clients {
if client == message.Client {
continue
}
client.send <- m.SerializeMessage().Data
}
}

View File

@ -30,9 +30,9 @@ func (h *Hub) handleMessage(rm RawMessage) {
handleIdentifyEvent(&m)
case Ping:
handlePingEvent(&m)
case Position:
case GetPlayhead:
handleGetPlayhead(&m)
case SetPosition:
case SetPlayhead:
handleSetPlayhead(&m)
default:
return

View File

@ -14,8 +14,8 @@ const (
Ping MessageTypes = iota
Pong
Identify
Position
SetPosition
GetPlayhead
SetPlayhead
)
type MessageData struct {

View File

@ -1,19 +1,23 @@
import { Flex, useColorMode, FlexProps } from '@chakra-ui/react'
import React, { FC } from "react";
import { Flex, useColorMode, FlexProps } from "@chakra-ui/react";
export const Container = (props: FlexProps) => {
const { colorMode } = useColorMode()
export const Container: FC<FlexProps> = (props: FlexProps) => {
const { colorMode } = useColorMode();
const bgColor = { light: 'gray.50', dark: 'gray.900' }
const bgColor = { light: "gray.50", dark: "gray.900" };
const color = { light: 'black', dark: 'white' }
const color = { light: "black", dark: "white" };
return (
<Flex
direction="column"
alignItems="center"
justifyContent="flex-start"
bg={bgColor[colorMode]}
color={color[colorMode]}
{...props}
/>
)
}
);
};
Container.defaultProps = {
alignItems: "center",
};

View File

@ -1,15 +1,90 @@
import React, { FC } from "react";
import { Box, css } from "@chakra-ui/react";
import React, { FC, useRef, useState } from "react";
import ReactPlayer, { Config, ReactPlayerProps } from "react-player";
import { MessageTypes } from "../interfaces/IMessage";
import Message from "../util/Message";
import MessageUtil from "../util/MessageUtil";
import PlayerSocket from "../ws/websocket";
type PlayerProps = { id: string } & ReactPlayerProps;
type PlayerProps = {
id: string;
socket: PlayerSocket;
} & ReactPlayerProps;
interface ProgressProps {
played: number;
playedSeconds: number;
loaded: number;
loadedSeconds: number;
}
const Player: FC<PlayerProps> = (props) => {
const playerRef = useRef<ReactPlayer>(null);
const [paused, setPaused] = useState<boolean>(false);
const { socket } = props;
const config: Config = {
file: {
forceHLS: true,
},
};
return <ReactPlayer url={props.id} config={config} {...props} />;
const onProgress = (state: ProgressProps) => {
if (paused) {
socket?.send(
MessageUtil.encode(
new Message(MessageTypes.SetPlayhead, {
playhead: state.playedSeconds,
paused: true,
})
)
);
}
socket?.send(
MessageUtil.encode(
new Message(MessageTypes.SetPlayhead, {
playhead: state.playedSeconds,
paused: false,
})
)
);
};
const onPause = () => {
setPaused(true);
socket?.send(
MessageUtil.encode(
new Message(MessageTypes.SetPlayhead, {
playhead: playerRef.current.getCurrentTime(),
paused: true,
})
)
);
};
const onPlay = () => {
setPaused(false);
socket?.send(
MessageUtil.encode(
new Message(MessageTypes.SetPlayhead, {
playhead: playerRef.current.getCurrentTime(),
paused: false,
})
)
);
};
return (
<Box height="100vh" width="100vw">
<ReactPlayer
url={props.id}
width="100%"
height="100%"
config={config}
controls
onPlay={onPlay}
onPause={onPause}
onProgress={onProgress}
ref={playerRef}
{...props}
/>
</Box>
);
};
export default Player;

View File

@ -1,6 +1,8 @@
import IUser from "./IUser";
interface IdentityData {
admin?: boolean;
controller?: boolean;
clientID?: string;
playlist?: string;
playHead?: number;

View File

@ -0,0 +1,5 @@
enum SocketEvents {
Identify = "Identify",
}
export default SocketEvents;

View File

@ -1,3 +1,4 @@
import { Socket } from "dgram";
import { GetServerSideProps, NextPage } from "next";
import { User } from "next-auth";
import { getSession } from "next-auth/react";
@ -5,36 +6,42 @@ import dynamic from "next/dynamic";
import Head from "next/head";
import React, { useRef, useState } from "react";
import ReactPlayer from "react-player";
import { BaseReactPlayerProps } from "react-player/base";
import { Container } from "../components/Container";
import useWS from "../hooks/useWS";
import IdentityData from "../interfaces/Identity";
import { MessageTypes } from "../interfaces/IMessage";
import SocketEvents from "../interfaces/SocketEvents";
import isBrowser from "../util/isBrowser";
import Message from "../util/Message";
import MessageUtil from "../util/MessageUtil";
const Player = dynamic(() => import("../components/Player"), { ssr: false });
interface PlayerPageProps {
user: User;
}
// types for the function
const PlayerPage: NextPage<PlayerPageProps> = ({ user }) => {
const playerRef = useRef<ReactPlayer>();
// const playerRef = useRef<ReactPlayer>();
const socket = useWS({ user });
const [id, setID] = useState<string>("");
const [identity, setIdentity] = useState<IdentityData>();
if (isBrowser() && typeof socket !== "undefined") {
socket.emitter.on("Identify", (e: IdentityData) => {
socket.emitter.on(SocketEvents.Identify, (e: IdentityData) => {
console.log(e);
setID(e.playlist);
setIdentity(e);
});
}
return (
<>
<Head>
<title>Watch Together</title>
</Head>
<Container height="100vh">
<Player id={id} ref={playerRef} />
<Container height="100vh" background={"#000"}>
<Player id={id} socket={socket} />
</Container>
</>
);