websocket stuff

This commit is contained in:
vel 2022-01-26 22:30:05 -08:00
parent 013e6c5b01
commit cad2d85ce4
Signed by: velvox
GPG Key ID: 1C8200C1D689CEF5
16 changed files with 195 additions and 89 deletions

3
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,3 @@
{
"editor.defaultFormatter": "esbenp.prettier-vscode"
}

View File

@ -5,8 +5,19 @@
</component>
<component name="ChangeListManager">
<list default="true" id="8a64704d-5500-41a6-aa4c-e275933fc58c" name="Changes" comment="">
<change beforePath="$PROJECT_DIR$/../frontend/src/components/Player.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/../frontend/src/components/Player.tsx" afterDir="false" />
<change afterPath="$PROJECT_DIR$/Caddyfile" afterDir="false" />
<change afterPath="$PROJECT_DIR$/docker-compose.yml" 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$/../frontend/.env.example" beforeDir="false" afterPath="$PROJECT_DIR$/../frontend/.env.example" 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/interfaces/IMessage.ts" beforeDir="false" afterPath="$PROJECT_DIR$/../frontend/src/interfaces/IMessage.ts" 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/index.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/../frontend/src/pages/index.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/util/Message.ts" beforeDir="false" afterPath="$PROJECT_DIR$/../frontend/src/util/Message.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/../frontend/types/environment.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/../frontend/types/environment.d.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" />

4
backend/Caddyfile Normal file
View File

@ -0,0 +1,4 @@
localhost:3001
file_server
reverse_proxy 127.0.0.1:8080

View File

@ -0,0 +1,3 @@
version: "3.9"
services:
caddy:

View File

@ -3,12 +3,15 @@ package ws
//todo better data deserialization
type IdentityData struct {
ClientID string `json:"clientId"`
ClientID string `json:"clientID"`
User User `json:"user"`
}
func handleIdentifyEvent(message *Message) {
d := message.Data.(map[string]interface{})
if id, ok := d["clientID"]; ok {
log.Infof("Client %s has sent identify event", id.(string))
}
m := Message{
MessageData: MessageData{
Type: Identify,

View File

@ -1,5 +1,6 @@
DISCORD_ID=
DISCORD_SECRET=
SECRET=
CLIENT_ID=
NEXT_PUBLIC_CLIENT_ID=
NEXTAUTH_URL=
NEXT_PUBLIC_WS_URI=

View File

@ -22,7 +22,8 @@
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-player": "^2.9.0",
"uuid": "^8.3.2"
"uuid": "^8.3.2",
"ws": "^8.4.2"
},
"devDependencies": {
"@next/bundle-analyzer": "^12.0.8",
@ -31,6 +32,7 @@
"@types/react-dom": "^17.0.3",
"@types/uuid": "^8.3.4",
"@types/websocket": "^1.0.4",
"@types/ws": "^8.2.2",
"cross-env": "^7.0.3",
"typescript": "4.3.2"
},

View File

@ -0,0 +1,23 @@
import { User } from "next-auth";
import { useEffect, useState } from "react";
import PlayerSocket from "../ws/websocket";
interface useWSProps {
user: User;
}
// todo write websocket reconnector
const useWS = ({ user }: useWSProps) => {
// todo checkout usecallback
const [socket, setSocket] = useState<PlayerSocket>();
useEffect(() => {
let socket = new PlayerSocket(user);
setSocket(socket);
return () => {
return socket.close();
};
}, []);
return socket;
};
export default useWS;

View File

@ -8,7 +8,7 @@ export enum MessageTypes {
interface IMessage {
type: MessageTypes;
data?: Record<string, unknown>;
data?: unknown;
}
export default IMessage;

View File

@ -6,3 +6,5 @@ interface IdentityData {
playHead?: number;
user: IUser;
}
export default IdentityData;

View File

@ -1,6 +1,7 @@
import { Button, Link as ChakraLink, Text } from "@chakra-ui/react";
import { GetServerSideProps, NextPage } from "next";
import { getSession, signIn } from "next-auth/react";
import Head from "next/head";
import Link from "next/link";
import React from "react";
import { Container } from "../components/Container";
@ -10,6 +11,10 @@ import { Main } from "../components/Main";
const Index: NextPage = () => {
return (
<>
<Head>
<title>Watch Together</title>
</Head>
<Container height="100vh">
<Hero />
<Main>
@ -17,7 +22,6 @@ const Index: NextPage = () => {
maxWidth="200"
alignSelf="center"
onClick={() => signIn("discord")}
disabled
>
Login With Discord
</Button>
@ -30,6 +34,7 @@ const Index: NextPage = () => {
</ChakraLink>
</Footer>
</Container>
</>
);
};

View File

@ -1,14 +1,12 @@
import consola from "consola";
import { GetServerSideProps, NextPage } from "next";
import { Session, User } from "next-auth";
import { getSession, useSession } from "next-auth/react";
import { User } from "next-auth";
import { getSession } from "next-auth/react";
import dynamic from "next/dynamic";
import React, { useEffect, useRef } from "react";
import Head from "next/head";
import React, { useRef } from "react";
import ReactPlayer from "react-player";
import { Container } from "../components/Container";
import { MessageTypes } from "../interfaces/IMessage";
import Message from "../util/Message";
import MessageUtil from "../util/MessageUtil";
import useWS from "../hooks/useWS";
const Player = dynamic(() => import("../components/Player"), { ssr: false });
@ -17,58 +15,52 @@ interface PlayerPageProps {
user: User;
}
const pingEvent = (ws: WebSocket) => {
let interval = setInterval(() => {
if (ws.readyState === ws.CLOSED) {
clearInterval(interval);
return;
}
console.log("running ping event");
ws.send(MessageUtil.encode(new Message(MessageTypes.Ping)));
}, 20000);
};
const PlayerPage: NextPage<PlayerPageProps> = ({ URI, user }) => {
const playerRef = useRef<ReactPlayer>();
consola.wrapAll();
useEffect(() => {
if (typeof window === "undefined") return;
const ws = new WebSocket(URI);
ws.onopen = () => {
ws.send(
MessageUtil.encode(
new Message(MessageTypes.Identify, {
clientID: process.env.CLIENT_ID,
user: {
ID: user.id,
Name: user.name,
},
})
)
);
pingEvent(ws);
};
ws.onmessage = (event) => {
console.log(event);
console.log(JSON.parse(event.data));
};
ws.onclose = () => {
ws.close();
};
ws.onerror = (err) => {
console.log(err);
return () => {
ws.close();
};
};
return () => {
ws.close();
};
}, []);
const socket = useWS({ user });
// useEffect(() => {
// if (typeof window === "undefined") return;
// const ws = new WebSocket(URI);
// ws.onopen = () => {
// ws.send(
// MessageUtil.encode(
// new Message(MessageTypes.Identify, {
// clientID: process.env.CLIENT_ID,
// user: {
// ID: user.id,
// Name: user.name,
// },
// })
// )
// );
// pingEvent(ws);
// };
// ws.onmessage = (event) => {
// console.log(event);
// console.log(JSON.parse(event.data));
// };
// ws.onclose = () => {
// ws.close();
// };
// ws.onerror = (err) => {
// console.log(err);
// return () => {
// ws.close();
// };
// };
// return () => {
// ws.close();
// };
// }, []);
return (
<>
<Head>
<title>Watch Together</title>
</Head>
<Container height="100vh">
<Player id="" ref={playerRef} />
</Container>
</>
);
};
@ -84,7 +76,6 @@ export const getServerSideProps: GetServerSideProps = async (context) => {
}
return {
props: {
URI: process.env.WS_URI,
user: session.user,
},
};

View File

@ -1,10 +1,7 @@
import IMessage, { MessageTypes } from "../interfaces/IMessage";
export default class Message implements IMessage {
constructor(
public type: MessageTypes,
public data?: Record<string, unknown>
) {}
constructor(public type: MessageTypes, public data?: unknown) {}
toJSON(): Record<string, unknown> {
return {

View File

@ -0,0 +1,49 @@
// nice and easy way to get types for the
import { User } from "next-auth";
import IdentityData from "../interfaces/Identity";
import { MessageTypes } from "../interfaces/IMessage";
import Message from "../util/Message";
import MessageUtil from "../util/MessageUtil";
// browser socket
let Websocket: typeof WebSocket;
if (typeof window !== "undefined") {
Websocket = window.WebSocket;
} else {
Websocket = require("ws");
}
export default class PlayerSocket extends Websocket {
constructor(private user: User) {
super(process.env.NEXT_PUBLIC_WS_URI);
this.onopen = this.onOpen;
}
onOpen() {
this.send(
MessageUtil.encode(
new Message(MessageTypes.Identify, {
clientID: process.env.NEXT_PUBLIC_CLIENT_ID,
user: {
id: this.user.id,
name: this.user.name,
},
} as IdentityData)
)
);
this.pingEvent();
}
pingEvent() {
let interval = setInterval(() => {
if (!this.open) {
clearInterval(interval);
return;
}
console.log("[WS] running ping event");
this.send(MessageUtil.encode(new Message(MessageTypes.Ping)));
}, 20000);
}
get open() {
return this.readyState === this.OPEN;
}
}

View File

@ -3,7 +3,7 @@ declare namespace NodeJS {
DISCORD_ID: string;
DISCORD_SECRET: string;
SECRET: string;
CLIENT_ID: string;
WS_URI: string;
NEXT_PUBLIC_CLIENT_ID: string;
NEXT_PUBLIC_WS_URI: string;
}
}

View File

@ -1029,6 +1029,13 @@
dependencies:
"@types/node" "*"
"@types/ws@^8.2.2":
version "8.2.2"
resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.2.2.tgz#7c5be4decb19500ae6b3d563043cd407bf366c21"
integrity sha512-NOn5eIcgWLOo6qW8AcuLZ7G8PycXu0xTxxkS6Q18VWFxgPUSOwV0pBj2a/4viNZVu25i7RIB7GttdkAIUUXOOg==
dependencies:
"@types/node" "*"
acorn-walk@^8.0.0:
version "8.2.0"
resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1"
@ -3227,6 +3234,11 @@ ws@^7.3.1:
resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.6.tgz#e59fc509fb15ddfb65487ee9765c5a51dec5fe7b"
integrity sha512-6GLgCqo2cy2A2rjCNFlxQS6ZljG/coZfZXclldI8FB/1G3CCI36Zd8xy2HrFVACi8tfk5XrgLQEk+P0Tnz9UcA==
ws@^8.4.2:
version "8.4.2"
resolved "https://registry.yarnpkg.com/ws/-/ws-8.4.2.tgz#18e749868d8439f2268368829042894b6907aa0b"
integrity sha512-Kbk4Nxyq7/ZWqr/tarI9yIt/+iNNFOjBXEWgTb4ydaNHBNGgvf2QHbS9fdfsndfjFlFwEd4Al+mw83YkaD10ZA==
xtend@^4.0.2:
version "4.0.2"
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"