Hello i am new to peerjs. currently i am trying to code a video call app. i face a problem in it. it shows only my video.it is not showing video and audio of another user .please help i am stuck.
error on console(front end) is
websocket.js:87 WebSocket connection to 'ws://localhost:3000/socket.io/?EIO=4&transport=websocket&sid=uaFPNhLHfKuVgldiAAAA' failed: Invalid frame header
server.js (backend)
const express = require('express');
const app = express();
const server = require('http').Server(app);
const io = require('socket.io')(server);
const { v4: uuidV4 } = require('uuid');
const { ExpressPeerServer } = require('peer');
const peerServer = ExpressPeerServer(server, {
debug: true,
});
app.set('view engine', 'ejs');
app.use(express.static('public'));
app.use('/peerjs', peerServer);
app.get('/', (req, res) => {
res.redirect(`/${uuidV4()}`);
});
app.get('/:room', (req, res) => {
res.render('room', { roomId: req.params.room });
});
io.on('connection', (socket) => {
socket.on('join-room', (roomId, userId) => {
socket.join(roomId);
socket.to(roomId).emit('user-connected', userId);
});
});
server.listen(3000, () => {
console.log('running...');
});
room.ejs
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<script>
const ROOM_ID = '<%= roomId %>';
</script>
<script src="https://unpkg.com/peerjs#1.3.1/dist/peerjs.min.js"></script>
<script src="/socket.io/socket.io.js"></script>
<title>Document</title>
<link rel="stylesheet" href="style.css" />
<style>
#video-grid {
display: grid;
grid-template-columns: repeat(auto-fill, 250px);
grid-template-rows: 160px;
}
video {
height: 100%;
width: 100%;
object-fit: cover;
}
</style>
</head>
<body>
<div id="video-grid"></div>
<script src="script.js"></script>
</body>
</html>
script.js
const socket = io('/');
const videoGrid = document.getElementById('video-grid');
const myPeer = new Peer(undefined, {
host: '/',
port: '3000',
path: '/peerjs',
});
const myVideo = document.createElement('video');
myVideo.muted = true;
navigator.mediaDevices
.getUserMedia({
video: true,
audio: true,
})
.then((stream) => {
addVideoStream(myVideo, stream);
myPeer.on('call', (call) => {
call.answer(stream);
const video = document.createElement('video');
call.on('stream', (userVideoStream) => {
addVideoStream(video, userVideoStream);
});
});
socket.on('user-connected', (userId) => {
connectToNewUser(userId, stream);
});
});
myPeer.on('open', (id) => {
socket.emit('join-room', ROOM_ID, id);
});
function connectToNewUser(userId, stream) {
const call = myPeer.call(userId, stream);
const video = document.createElement('video');
call.on('stream', (userVideoStream) => {
addVideoStream(video, userVideoStream);
});
call.on('close', () => {
video.remove();
});
// peers[userId] = call
}
function addVideoStream(video, stream) {
video.srcObject = stream;
video.addEventListener('loadedmetadata', () => {
video.play();
});
videoGrid.append(video);
}
Related
I'm learning node express by making a to-do list. I'm having trouble with marking a to-do as complete/incomplete and deleting them. It's not giving me any errors so I'm trying to console log wherever I can.
The _id in the database is console logging so I think I have my variables correct? Please see below the server.js and main.js files for the comments where I think could be wrong.
I've been stuck on this problem for 3 days now...
EDIT: I just noticed findOneAndUpdate() is a mongoose function. I don't have mongoose yet... I think I'm on the right track...
server.js
const express = require("express");
const app = express();
const bodyParser = require("body-parser");
const MongoClient = require("mongodb").MongoClient;
const cors = require("cors");
const { request } = require("mongodb");
const PORT = process.env.PORT || 8000;
app.use(cors());
const username = "hidden";
const password = "hidden";
const connectionString = `mongodb+srv://${username}:${password}#cluster0.7k2ww.mongodb.net/myFirstDatabase?retryWrites=true&w=majority`;
MongoClient.connect(connectionString, { useUnifiedTopology: true }).then(
(client) => {
console.log("Connected to database");
const db = client.db("to-do-list");
const toDoCollection = db.collection("to-dos");
app.set("view engine", "ejs");
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(express.static("public"));
app.get("/", async (req, res) => {
const result = await toDoCollection.find().toArray();
const itemsLeft = await toDoCollection.countDocuments({
done: false,
});
res.render("index.ejs", { todos: result, left: itemsLeft });
});
app.post("/addtodo", (req, res) => {
toDoCollection
.insertOne({ todo: req.body.todo, done: false })
.then((result) => {
res.redirect("/");
})
.catch((error) => console.error(error));
});
app.put("/markComplete", async (req, res) => {
try {
await toDoCollection.findOneAndUpdate(
{
_id: req.body.todoId, // Is this line talking with my main.js file?
},
{
$set: { done: true },
},
{ sort: { _id: -1 }, upsert: false }
);
console.log(req.body.todoId);
res.json("Task completed");
} catch (err) {
console.log(err);
}
});
app.put("/markIncomplete", async (req, res) => {
try {
await toDoCollection.findOneAndUpdate(
{
_id: req.body.todoId,
},
{
$set: { done: false },
},
{ sort: { _id: -1 }, upsert: false }
);
console.log(req.body.todoId);
res.json("Task completed");
} catch (err) {
console.log(err);
}
});
app.delete("/deleteToDo", async (req, res) => {
console.log(req.body.todoId);
try {
await toDoCollection
.findOneAndDelete({ _id: req.body.todoId })
.then((result) => {
console.log("todo deleted");
res.json("todo deleted");
});
} catch {
console.log(err);
}
});
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
}
);
main.js
const deleteTask = document.querySelectorAll(".delete-todo");
const completeTask = document.querySelectorAll(".incomplete");
const incompleteTask = document.querySelectorAll(".complete");
Array.from(deleteTask).forEach((e) => {
e.addEventListener("click", deleteToDoFunc);
});
Array.from(completeTask).forEach((e) => {
e.addEventListener("click", completeToDoFunc);
});
Array.from(incompleteTask).forEach((e) => {
e.addEventListener("click", incompleteToDoFunc);
});
async function deleteToDoFunc() {
console.log("Delete working!");
const todoId = this.parentNode.dataset.id;
console.log(todoId);
try {
const res = await fetch("deleteToDo", {
method: "delete",
headers: { "Content-type": "application/json" },
body: JSON.stringify({
todoId: todoId,
}),
});
const data = await res.json();
console.log(data);
location.reload();
} catch (err) {
console.log(err);
}
}
async function completeToDoFunc() {
console.log("Update working!");
const todoId = this.parentNode.dataset.id;
console.log(todoId);
try {
const res = await fetch("markComplete", {
method: "put",
headers: { "Content-type": "application/json" },
body: JSON.stringify({
todoId: todoId, // Is this line talking with the server.js file?
}),
});
const data = await res.json();
console.log(data);
// location.reload();
} catch (err) {
console.log(err);
}
}
async function incompleteToDoFunc() {
console.log("Incomplete task");
const todoId = this.parentNode.dataset.id;
console.log(todoId);
try {
const res = await fetch("markIncomplete", {
method: "put",
headers: { "Content-type": "application/json" },
body: JSON.stringify({
todoId: todoId,
}),
});
const data = await res.json();
console.log(data);
location.reload();
} catch (err) {
console.log(err);
}
}
index.ejs
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
rel="stylesheet"
href="../css/font-awesome-4.7.0/css/font-awesome.min.css"
/>
<link rel="stylesheet" href="css/style.css" />
<link
href="https://fonts.googleapis.com/css2?family=Montserrat:wght#300;400&display=swap"
rel="stylesheet"
/>
<title>To Do</title>
</head>
<body>
<div class="container">
<header class="flexContainer">
<h1 class="title main-font center">To Do List</h1>
</header>
<form class="center" action="/addtodo" method="POST">
<input type="text" placeholder="Add a To Do" name="todo" />
<button type="submit" class="submitButton">
<i class="fa fa-plus-square"></i>
</button>
</form>
<div class="to-do-list flexContainer">
<ul class="task-list center">
<% todos.forEach(todo => { %>
<li class="todo-name main-font complete-task" data-id="<%=todo._id%>"> <!-- The route should know which to-do to update/delete based on _id -->
<% if (todo.done === true) { %>
<span class="complete"><%= todo.todo %></span>
<% } else { %>
<span class="incomplete"><%= todo.todo %></span>
<% } %>
<span class="fa fa-trash delete-todo"></span>
</li>
<%}) %>
</ul>
</div>
<h2 class="main-font center">Left to do: <%= left %></h2>
</div>
<script type="text/javascript" src="/js/main.js"></script>
</body>
</html>
When you try to update your To-Do List, does it override everything in your document? I see that your using a PUT request instead of a PATCH request, and a PUT request would replace your all your data instead of updating a single field
I've built a simple express app that uses child_process to run a command. I then need the output of each line sent to the browser using socket.io the following example app is partially working except it sends all of the output lines in a single string once the command has completed.
Is there a way to send each line and have it rendered in the client/browser?
//server.ts
var app = require('express')();
var http = require('http').createServer(app);
var io = require('socket.io')(http);
const { exec } = require('child_process');
app.get('/', (req, res) => {
res.sendFile(__dirname + '/index.html');
});
io.on('connection', (socket) => {
console.log('a user connected');
socket.on('disconnect', () => {
console.log('user disconnected');
});
socket.on('chat message', (msg) => {
console.log('message: ' + msg);
// io.emit('chat message', msg);
});
socket.on('chat message2', (msg) => {
console.log('message: ' + msg);
exec("kind create cluster", (error, stdout, stderr) => {
if (error) {
console.log(`error: ${error.message}`);
io.emit('chat message', `error: ${error.message}` );
return;
}
if (stderr) {
console.log(`stderr: ${stderr}`);
io.emit('chat message', `error: ${stderr}` );
return;
}
console.log(`stdout: ${stdout}`);
io.emit('chat message', new Buffer("> "+ `error: ${stdout}` ));
//ws.send(JSON.stringify({id:"shell",data:{stdout}}), function () {
//
// Ignore errors.
//
});
});
});
http.listen(3000, () => {
console.log('listening on *:3000');
});
Here's the client code:
//index.html
<!doctype html>
<html>
<head>
<title>Socket.IO chat</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font: 13px Helvetica, Arial; }
form { background: #000; padding: 3px; position: fixed; bottom: 0; width: 100%; }
form input { border: 0; padding: 10px; width: 90%; margin-right: 0.5%; }
form button { width: 9%; background: rgb(130, 224, 255); border: none; padding: 10px; }
#messages { list-style-type: none; margin: 0; padding: 0; }
#messages li { padding: 5px 10px; }
#messages li:nth-child(odd) { background: #eee; }
</style>
</head>
<body>
<ul id="messages"></ul>
<form action="">
<input id="m" autocomplete="off" /><button>Send</button>
</form>
</body>
<script src="/socket.io/socket.io.js"></script>
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
<script>
$(function () {
var socket = io();
$('form').submit(function(e){
e.preventDefault(); // prevents page reloading
socket.emit('chat message', $('#m').val());
socket.emit('chat message2', "Message 2 here!!");
$('#m').val('');
return false;
});
socket.on('chat message', function(msg){
$('#messages').append($('<li>').text(msg));
});
});
</script>
<script>
var socket = io();
</script>
</html>
OK for those interested solution is to use spawn instead of exec. e.g.
var app = require('express')();
var http = require('http').createServer(app);
var io = require('socket.io')(http);
//const { exec } = require('child_process');
const { spawn } = require('child_process');
app.get('/', (req, res) => {
res.sendFile(__dirname + '/index.html');
});
io.on('connection', (socket) => {
console.log('a user connected');
socket.on('disconnect', () => {
console.log('user disconnected');
});
socket.on('chat message', (msg) => {
console.log('message: ' + msg);
// io.emit('chat message', msg);
});
socket.on('chat message2', (msg) => {
console.log('message: ' + msg);
const sh = spawn('kind', ['create', 'cluster']);
sh.stdout.on('data', (data) => {
console.log(`stdout: ${data}`);
io.emit('chat message', `stdout: ${data}` );
});
sh.stderr.on('data', (data) => {
console.error(`stderr: ${data}`);
io.emit('chat message', `stderr: ${data}` );
});
sh.on('close', (code) => {
console.log(`child process exited with code ${code}`);
io.emit('chat message', `child process exited with code ${code}`);
});
});
});
http.listen(3000, () => {
console.log('listening on *:3000');
});
I am brand new to Express and Node.js, trying to build server-rendered app which will display some data from API.
This is my code
app.js
var express = require("express");
var app = express();
var request = require("request");
var apiKey = '****************************';
var bodyParser = require("body-parser");
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.set('viewEngine', 'ejs');
const options = {
method: 'POST',
url: 'http://api.somethingsomething.com/content/search/v1?',
headers: {
'X-Api-Key': `${apiKey}`,
'Content-Type': 'application/json'
},
body: {
'queryString': 'pigs',
'resultContext' : {
'aspects' :['title','lifecycle','location','summary','editorial' ]
}
},
json: true
}
app.get('/', function(req, res) {
request(options, function(error, response, body) {
if (!error && response.statusCode == 200) {
var info = JSON.stringify(body);
console.log(info);
res.render('index', { results: info}); // this does not render anything
}
})
});
app.listen(3000, function() {
console.log("Listening on port 3000");
})
index.ejs
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<div id="searchResults">
<%= results %>
</div>
</body>
</html>
It does not render index.ejs and cannot display data.
Error: No default engine was specified and no extension was provided.
I tried googling it, but no luck. Any help will be appreciated; Thank you
problem was simple app.set('viewEngine', 'ejs'); was wrong, should be pp.set('view engine', 'ejs');
I'm trying to POST a token and display the results as an ordered list. I would like the list to update onchange of the input. On page load the request POST is infinitely looping with error:
TypeError: ctrl.keys(...) is undefined
I suspect that my assumptions of how the data binding on the controller works are completely wrong.
//component
var tISM = {};
//model
tISM = {
Key: function(data) {
this.Id = m.prop(data.Id);
this.Name = m.prop(data.Name);
this.CreationTime = m.prop(data.CreationTime);
},
keys: function(token) {
return m.request({
method: "POST",
url: "key/list",
data: { "token": token },
type: tISM.Key
})
},
};
//controller
tISM.controller = function() {
// when this controller is updated perform a new POST for data by calling message?
var token = m.prop("xxx")
var keys = function() {
tISM.keys(this.token)
}
return { token, keys }
};
//view
tISM.view = function(ctrl) {
return m("div"), [
m("ol", ctrl.keys().map( function(key, index) {
return m("li", key.Id, key.Name, key.CreationTime)
})),
m("input", {
onchange: m.withAttr("value", ctrl.token)
})
]
};
//initialize
m.mount(document.getElementById("app"), tISM);
<script src="http://cdnjs.cloudflare.com/ajax/libs/mithril/0.2.5/mithril.min.js"></script>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Mithril App</title>
<script src="mithril.js"></script>
</head>
<body>
<div id="app"></div>
</body>
</html>
m.request() returns a deferred, not the value itself. I have a snippet below that shows one way of getting the values out. I explicitly replaced the m.request() with deferred calls under the hood, and a timeout rather than a post.
//component
var tISM = {};
//model
tISM = {
Key: function(data) {
this.Id = m.prop(data.Id);
this.Name = m.prop(data.Name);
this.CreationTime = m.prop(data.CreationTime);
},
keys: function(token) {
m.startComputation()
var d = m.deferred();
setTimeout(function() {
d.resolve([1,2,3]);
m.endComputation();
}, 1000);
return d.promise;
}
};
//controller
tISM.controller = function() {
// when this controller is updated perform a new POST for data by calling message?
var token = m.prop("xxx")
var keys = m.prop([]);
tISM.keys(this.token).then(keys)
return {
token: token,
keys: keys
}
return { token, keys }
};
//view
tISM.view = function(ctrl) {
return m("div"), [
m("ol", ctrl.keys().map( function(key, index) {
return m("li", key.Id, key.Name, key.CreationTime)
})),
m("input", {
onchange: m.withAttr("value", ctrl.token)
})
]
};
//initialize
m.mount(document.getElementById("app"), tISM);
<script src="http://cdnjs.cloudflare.com/ajax/libs/mithril/0.2.5/mithril.min.js"></script>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Mithril App</title>
<script src="mithril.js"></script>
</head>
<body>
<div id="app"></div>
</body>
</html>
My problem was I don't know javascript. This works:
//component
var tISM = {};
//model
tISM.Key = function(data) {
this.Id = m.prop(data.Id);
this.Name = m.prop(data.Name);
this.CreationTime = m.prop(data.CreationTime);
}
tISM = {
keys: function(token) {
return m.request({
method: "POST",
url: "key/list",
data: { "token": token },
type: tISM.Key
})
},
};
//controller
tISM.controller = function() {
this.token = m.prop("")
this.keys = m.prop([])
this.updateToken = function(token) {
this.token(token)
tISM.keys(this.token).then(this.keys)
}.bind(this)
};
//view
tISM.view = function(ctrl) {
return m("div"), [
m("input", {
oninput: m.withAttr("value", ctrl.updateToken)
}),
m("ol", ctrl.keys().map( function(key, index) {
return m("li", key.Id, key.Name, key.CreationTime)
})),
]
};
//initialize
m.mount(document.getElementById("app"), tISM);
I created an element with class foo. Then I intended to swap its class with bar after an click event was occurred. However, when I clicked the element, streams that subscribes the click events of the foo and bar were triggered successively. As a result, element's class didn't change.
How can I subscribe events of the same element where its classes change in time?
Here's the link:
https://jsbin.com/kanomonexa/edit?html,js,console,output
Here's the sample code:
const {div, button, makeDOMDriver} = CycleDOM;
const toggleDriver = (data$)=> {
data$.subscribe(function(data) {
if (data.operation === 'remove' ) {
$(data.selector).removeClass(data.className);
}
else if (data.operation === 'add') {
$(data.selector).addClass(data.className);
}
else {
$(data.selector).toggle(data.className);
}
});
return Rx.Observable.empty();
};
const consoleLogDriver = (data$)=>{
data$.subscribe(data=> {
console.log(data);
});
return Rx.Observable.empty();
};
const main = (sources) =>{
const fooClick$ = sources.DOM
.select('.foo')
.events('click');
const fooLog$ = fooClick$.map(_ =>'.foo is Clicked');
const toggleFoo$ = fooClick$.flatMap(_ => {
const result = [
{
operation: 'remove',
selector: 'button',
className: 'foo'
},
{
operation: 'add',
selector: 'button',
className: 'bar'
}
];
return Rx.Observable.fromArray(result);
});
const barClick$ = sources.DOM
.select('.bar')
.events('click');
const barLog$ = barClick$.map(_ => '.bar is Clicked');
const toggleBar$ = barClick$.flatMap(_ =>{
const result = [
{
operation: 'remove',
selector: 'button',
className: 'bar'
},
{
operation: 'add',
selector: 'button',
className: 'foo'
}
];
return Rx.Observable.fromArray(result);
});
const log$ = Rx.Observable.merge(
fooLog$,
barLog$
);
const toggle$ = Rx.Observable.merge(
toggleFoo$,
toggleBar$
);
const vTree$ = Rx.Observable.of(div([
button('#button.foo',['Click me'])
]));
return {
DOM: vTree$,
consoleLogDriver: log$,
toggleDriver:toggle$
};
};
var drivers = {
DOM: makeDOMDriver('#app'),
toggleDriver: toggleDriver,
consoleLogDriver: consoleLogDriver
};
Cycle.run(main, drivers);
<!DOCTYPE html>
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/4.0.6/rx.all.js"></script>
<script src="https://code.jquery.com/jquery-2.1.4.js"></script>
<script src="https://rawgit.com/cyclejs/cycle-core/v6.0.3/dist/cycle.js"></script>
<script src="https://rawgit.com/cyclejs/cycle-dom/v9.4.0/dist/cycle-dom.js"></script>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<div id="app"></div>
</body>
</html>
You may delay(0) your toggle$ stream to schedule its values to the next event loop and then successfully change your className:
...
const toggle$ = Observable.merge(...)
.delay(0)
...
I see that you are using Jquery to toggle your class. Depending on what you want to do, I imagine it can have some usefull cases (eg: toggle a class somewhere else in the page out of scope from virtual dom).
But there your cycle app is handled by virtual dom so I suggest you to use the right tool for the job and instead rebuild your vtree$ on each change:
...
const currentClassName$ = Rx.Observable
.merge(
fooClick$.map(_ => '.bar'),
barClick$.map(_ => '.foo')
)
.delay(0) // fix the bug
.startWith('.foo');
const vTree$ = currentClassName$
.map(currentClassName =>
div([
button(
'#button' + currentClassName, ['Click me']
)
]));
...
Working demo