diff --git a/net/server/internal/api_relay.go b/net/server/internal/api_relay.go new file mode 100644 index 00000000..b049f653 --- /dev/null +++ b/net/server/internal/api_relay.go @@ -0,0 +1,59 @@ +package databag + +import ( + "errors" + "github.com/gorilla/websocket" + "net/http" +) + +var relayer = websocket.Upgrader{} +var left *websocket.Conn +var right *websocket.Conn +var cur bool = false + +//Status handler for websocket connection +func Relay(w http.ResponseWriter, r *http.Request) { + + // accept websocket connection + conn, err := relayer.Upgrade(w, r, nil) + if err != nil { + ErrMsg(err) + return + } + if (cur) { + right = conn; + PrintMsg("CONNECTED RIGHT"); + } else { + left = conn; + PrintMsg("CONNECTED LEFT"); + } + cur = !cur; + + defer conn.Close() + conn.SetReadLimit(APPBodyLimit) + + for true { + t, m, res := conn.ReadMessage() + if res != nil { + ErrMsg(res) + return + } + if t != websocket.TextMessage { + ErrMsg(errors.New("invalid websocket message type")) + return + } + if conn == left { + if err := right.WriteMessage(websocket.TextMessage, m); err != nil { + ErrMsg(err) + return + } + } + if conn == right { + if err := left.WriteMessage(websocket.TextMessage, m); err != nil { + ErrMsg(err) + return + } + } + } +} + diff --git a/net/server/internal/routers.go b/net/server/internal/routers.go index 5017fa99..a42fb5c0 100644 --- a/net/server/internal/routers.go +++ b/net/server/internal/routers.go @@ -796,4 +796,11 @@ var endpoints = routes{ "/status", Status, }, + + route{ + "Relay", + strings.ToUpper("Get"), + "/relay", + Relay, + }, } diff --git a/net/web/src/session/welcome/Welcome.jsx b/net/web/src/session/welcome/Welcome.jsx index afd6f76a..f2e6feb0 100644 --- a/net/web/src/session/welcome/Welcome.jsx +++ b/net/web/src/session/welcome/Welcome.jsx @@ -1,17 +1,152 @@ import { WelcomeWrapper } from './Welcome.styled'; import { RightOutlined } from '@ant-design/icons'; -import { Space } from 'antd'; +import { Input, Space } from 'antd'; + +import React, { createContext, useState, useRef, useEffect } from 'react'; import session from 'images/session.png'; export function Welcome() { + + const video = useRef(); + const vid = useRef(); + const peer = useRef(); + const ws = useRef(); + const candidates = useRef([]); + + const whiteNoise = () => { + const canvas = Object.assign(document.createElement("canvas"), {width: 320, height: 240}); + const ctx = canvas.getContext('2d'); + ctx.fillRect(0, 0, 320, 240); + const p = ctx.getImageData(0, 0, 320, 240); + requestAnimationFrame(function draw(){ + for (var i = 0; i < p.data.length; i++) { + p.data[i++] = p.data[i++] = p.data[i++] = Math.random() * 255; + } + ctx.putImageData(p, 0, 0); + requestAnimationFrame(draw); + }); + return canvas.captureStream(); + } + + const start = async () => { + const stream = await navigator.mediaDevices.getUserMedia({video: true}); + //const stream = await whiteNoise(); + peer.current.addTransceiver(stream.getTracks()[0], {streams: [stream]}); + }; + + const rtc = async () => { + const iceServers = [ + { + urls: 'stun:192.168.13.233:5001?transport=udp', + username: 'user', + credential: 'pass' + }, + { + urls: 'turn:192.168.13.233:5001?transport=udp', + username: 'user', + credential: 'pass' + }]; + + const pc = new RTCPeerConnection({ + iceServers + }); + + //const pc = new RTCPeerConnection(); + peer.current = pc; + + pc.onicecandidate = (e) => { + if (!e.candidate) return; + + ws.current.send(JSON.stringify({ candidate: e.candidate })); + console.log(JSON.stringify(e.candidate)); + + // If a srflx candidate was found, notify that the STUN server works! + if(e.candidate.type == "srflx"){ + console.log("The STUN server is reachable!"); + console.log(` Your Public IP Address is: ${e.candidate.address}`); + } + + // If a relay candidate was found, notify that the TURN server works! + if(e.candidate.type == "relay"){ + console.log("The TURN server is reachable !"); + } + }; + + pc.onicecandidateerror = (e) => { + console.error(e); + }; + + pc.ontrack = ({streams: [stream]}) => { + console.log("ON TRACK!"); + vid.current.srcObject = stream; + }; + + + const dc = pc.createDataChannel("both", {negotiated: true, id: 0}); + + pc.onnegotiationneeded = async () => { + console.log("NEGOTIATION"); + create(); + }; + + } + + const create = async () => { + const offer = await peer.current.createOffer(); + await peer.current.setLocalDescription(offer); + ws.current.send(JSON.stringify({ offer: offer })); + console.log(":: OFFER: ", offer); + } + + useEffect(() => { + rtc(); + ws.current = new WebSocket('wss://balzack.coredb.org/relay'); + ws.current.onmessage = async (ev) => { + const msg = JSON.parse(ev.data); + if (msg.candidate) { + console.log("> CANDIDATE: ", msg.candidate); + candidates.current.push(msg.candidate); + await peer.current.addIceCandidate(msg.candidate); + } + else if (msg.offer) { + console.log("> OFFER: ", msg.offer); + peer.current.setRemoteDescription(msg.offer); + await peer.current.setLocalDescription(await peer.current.createAnswer()); + ws.current.send(JSON.stringify({ answer: peer.current.localDescription })); + } + else if (msg.answer) { + console.log("> ANSWER: ", msg.answer); + peer.current.setRemoteDescription(msg.answer); + } + } + ws.current.onclose = (e) => { + console.log("CLOSED"); + } + ws.current.onopen = () => { + console.log("OPENED"); + } + ws.current.error = (e) => { + console.log("ERROR"); + } + + }, []); + return (
Databag
Communication for the decentralized web
- Session Background + +
+
+ +
Create
+
Start
+
Setup your profile
diff --git a/net/web/src/session/welcome/Welcome.styled.js b/net/web/src/session/welcome/Welcome.styled.js index 46bfa308..af3db296 100644 --- a/net/web/src/session/welcome/Welcome.styled.js +++ b/net/web/src/session/welcome/Welcome.styled.js @@ -9,6 +9,12 @@ export const WelcomeWrapper = styled.div` justify-content: center; color: #555555; + .video { + width: 640px; + height: 480px; + background-color: yellow; + } + .title { width: 100%; display: flex;