diff --git a/src/App.tsx b/src/App.tsx index 8a52dbf..a89acdd 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,6 +1,9 @@ import * as React from 'react'; import { render } from 'react-dom'; +import { initContext } from './context'; -import Counter from './Counter'; +import Home from './Home'; -render(, document.getElementById('main')); \ No newline at end of file +initContext(); + +render(, document.getElementById('main')); \ No newline at end of file diff --git a/src/Counter.tsx b/src/Counter.tsx deleted file mode 100644 index b20d0c9..0000000 --- a/src/Counter.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import * as React from 'react'; - -export default class Counter extends React.Component { - state = { - count: 0 - }; - - increment = () => { - this.setState({ - count: (this.state.count + 1) - }); - }; - - startConnection = () => { - const ws = new WebSocket("ws://localhost:5000"); - ws.onopen = (event : Event)=>{ - console.log("onopen"); - ws.send("Messgage from client"); - } - ws.onmessage = (event : MessageEvent) =>{ - console.log(event.data); - } - }; - - render () { - return ( -
-

{this.state.count}

- -
- ); - } -} \ No newline at end of file diff --git a/src/Home.tsx b/src/Home.tsx new file mode 100644 index 0000000..f10ae33 --- /dev/null +++ b/src/Home.tsx @@ -0,0 +1,35 @@ +import * as React from 'react'; +import { FunctionComponent, useState } from 'react'; +import {context} from './context' +import { RTMTWS } from './rtmt/rtmt_websocket'; + +const Home:FunctionComponent<{ initial?: number }> = ({ initial = 0 }) => { + const [clicks, setClicks] = useState(initial); + + React.useEffect(()=>{ + + + + const rtmtws = context.rtmt as RTMTWS + if(rtmtws){ + rtmtws.initWebSocket(onConnectionDone) + }else{ + console.log("context.rtmt is not RTMTWS"); + } + }) + + const onConnectionDone = ()=>{ + context.rtmt.sendMessage("new_game", "") + context.rtmt.listenMessage("new_game", (message)=>{ + console.log("new message"); + }) + } + + return <> +

Clicks: {clicks}

+ + + +} + +export default Home \ No newline at end of file diff --git a/src/context.tsx b/src/context.tsx new file mode 100644 index 0000000..481fc26 --- /dev/null +++ b/src/context.tsx @@ -0,0 +1,19 @@ +import { RTMT } from "./rtmt/rtmt" +import { RTMTWS } from "./rtmt/rtmt_websocket" +import { UserKeyStore, UserKeyStoreImpl } from "./store/key_store" + +type Context = { + rtmt : RTMT + userKeyStore : UserKeyStore +} + +export const initContext = ()=> { + const rtmt = new RTMTWS() + const userKeyStore = new UserKeyStoreImpl() + return { + rtmt : rtmt, + userKeyStore : userKeyStore, + } +} + +export const context : Context = initContext() diff --git a/src/rtmt/byte_util.ts b/src/rtmt/byte_util.ts new file mode 100644 index 0000000..a4e550a --- /dev/null +++ b/src/rtmt/byte_util.ts @@ -0,0 +1,12 @@ +import { Bytes } from "./rtmt" +const textEncoder = new TextEncoder() +const textDecoder = new TextDecoder("utf-8") + +export function encodeText(text : string) { + const bytes = textEncoder.encode(text) + return bytes +} + +export function decodeText(bytes : Bytes) { + return textDecoder.decode(bytes) +} \ No newline at end of file diff --git a/src/rtmt/encode_decode_message.ts b/src/rtmt/encode_decode_message.ts new file mode 100644 index 0000000..686c544 --- /dev/null +++ b/src/rtmt/encode_decode_message.ts @@ -0,0 +1,52 @@ +import { decodeText, encodeText } from "./byte_util"; +import { Bytes } from "./rtmt"; + +const headerLenght = 4 +// +// channel is string, message is byte array +// +export function encode(channel : string, message : Bytes) { + const channelLenght = channel.length + const messageLenght = message.length + const totalLenght = headerLenght + channelLenght + messageLenght + + const buffer = new ArrayBuffer(totalLenght); + const view = new DataView(buffer); + + view.setUint32(0, channelLenght); + + const channelBytes = encodeText(channel) + + let count = headerLenght + channelBytes.forEach((byte)=>{ + view.setUint8(count, byte) + count++ + }) + + for (const byte of message) { + view.setUint8(count, byte) + count++ + } + + return buffer +} + +// +// return { channel : string, message : byte array} +// +export function decode(bytes : Bytes) { + const view = new DataView(bytes); + + const channelLenght = view.getUint32(0) + + + const channel = decodeText( + bytes.slice(headerLenght, headerLenght + channelLenght)) + + const message = bytes.slice(headerLenght + channelLenght) + + return { + "channel": channel, + "message": message, + } +} diff --git a/src/rtmt/rtmt.ts b/src/rtmt/rtmt.ts new file mode 100644 index 0000000..2effa53 --- /dev/null +++ b/src/rtmt/rtmt.ts @@ -0,0 +1,7 @@ +export type Bytes = UInt8Array +export type OnMessage = (message : Bytes) => any + +export interface RTMT{ + sendMessage : (channel : string, message : Bytes) => any + listenMessage : (channel : string, callback : OnMessage) => any +} \ No newline at end of file diff --git a/src/rtmt/rtmt_websocket.ts b/src/rtmt/rtmt_websocket.ts new file mode 100644 index 0000000..6a464f6 --- /dev/null +++ b/src/rtmt/rtmt_websocket.ts @@ -0,0 +1,70 @@ +import { decode, encode } from "./encode_decode_message" +import { OnMessage, RTMT } from "./rtmt" +import { context } from '../context'; +import { wsServerAdress } from "../service/http_service"; + +export class RTMTWS implements RTMT{ + + private messageChannels : Map + private ws : WebSocket + + constructor() { + this.messageChannels = new Map() + } + + initWebSocket(onopen : ()=>any) { + context.userKeyStore.getUserKey((userKey : string)=>{ + const url = wsServerAdress + '?userKey=' + userKey + const ws = new WebSocket(url) + ws.binaryType = "arraybuffer"; //for firefox + ws.onopen = () => { + console.log('ws has opened') + this.ws = ws + onopen() + } + ws.onclose = () => { + console.log('ws has closed') + //this.ws = undefined + } + + ws.onmessage = (event : MessageEvent)=>{ + this.onWebSocketMessage(this, event) + } + + ws.addEventListener("error", ev => { + console.log({ ws_error: ev }); + }) + }) + } + + sendMessage(channel : string, message : Int8Array) { + if(this.ws === undefined){ + console.log('ws is undefined') + return + } + const data = encode(channel, message) + console.log("(RTMT) Sending message to channel " + channel); + this.ws.send(data) + } + + listenMessage(channel : string, callback : OnMessage) { + this.messageChannels.set(channel, callback) + } + + onWebSocketMessage(rtmt : RTMTWS, event : MessageEvent) { + console.log(event); + + const { channel, message } = decode(event.data) + rtmt.onMessage(channel, message) + } + + onMessage(channel : string, message : Int8Array){ + const callback = this.messageChannels.get(channel) + + if(callback){ + callback(message) + }else{ + console.log("Channel callback not found!" + channel); + } + } +} \ No newline at end of file