socket.io troubles - 404 (Not Found) - sockets

Despite following the exact instructions of this video: https://www.youtube.com/watch?v=pNKNYLv2BpQ and changing details where necessary (e.g. I am using localhost:8888 as oppose to 3000), I am always getting error messages, no matter what I try. It is becoming extremely frustrating as I can't, for the life of me, figure out where I am going wrong.
I am currently getting the error message GET http://localhost:8888/socket.io/1/?t=1462670368869 404 (Not Found)after a massive struggle of continuously getting an error where it couldn't locate the 'socket.io.js' file. Can anyone shed some light on this devastatingly cryptic topic?
HTML:
<html>
<head>
<title>Chat with socket.io and node.js</title>
<style>
#chat{
height:500px;
}
</style>
</head>
<body>
<div id="chat"></div>
<form id="send-message">
<input size="35" id="message"></input>
<input type="submit"></input>
</form>
<script src="http://code.jquery.com/jquery-latest.min.js"></script>
<script src="socket.io.js"></script>
<script>
jQuery(function($){
var socket = io.connect();
var $messageForm = $('#send-message');
var $messageBox = $('#message');
var $chat = $('#chat');
$messageForm.submit(function(e){
e.preventDefault();
socket.emit('send message', $messageBox.val());
$messageBox.val('');
});
socket.on('new message', function(data){
$chat.append(data + "<br/>");
});
});
</script>
</body>
</html>
JavaScript:
var express = require('express');
app = express();
server = require('http').createServer(app);
io = require('socket.io').listen(server);
server.listen(8888);
app.get('/', function(req, res){
res.sendfile(__dirname + '/index.html');
});
io.sockets.on('connection', function(socket){
socket.on('send message', function(data){
io.sockets.emit('new message', data);
});
});
JSON:
{
"name": "chat",
"version": "0.0.1",
"private": "true",
"dependencies": {
"express": "^4.10.2",
"socket.io": "^0.9.16"
}
}

Related

Express Router .delete returns 404 Not Found?

Encountered a strange issue while using delete method in Express app.
Here is my app.js document. I am using elevatorRouter for "/elevators" routes.
app.js
app.use("/", indexRouter);
app.use("/users", usersRouter);
app.use("/passwordgenerator", passwordgeneratorRouter);
app.use("/elevators", elevatorRouter);
// catch 404 and forward to error handler
app.use(function (req, res, next) {
next(createError(404));
});
// error handler
app.use(function (err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get("env") === "development" ? err : {};
// render the error page
res.status(err.status || 500);
res.render("error");
});
module.exports = app;
Here is my route file. I am including the elevator router from app.js. It seems that edit route is working fine. I have only issue with "delete" method.
elevators.js
const express = require("express");
const router = express.Router();
const Elevator = require("../models/elevator");
const middleware = require("../middleware");
// Edit Elevator Route
router.get("/:id/edit", (req, res) => {
Elevator.findById(req.params.id, (err, foundElevator) => {
res.render("elevators/edit", { elevator: foundElevator });
});
});
// Delete Elevator Route
router.delete("/:id", (req, res) => {
Elevator.findByIdAndRemove(req.params.id, (err) => {
if (err) {
res.redirect("/elevators");
} else {
res.redirect("/elevators");
}
});
});
Here is my views. I didnt completely post the entire html. Instead, I have copied partially. I beleive this will be enough. I used postman to send "POST" method directly but still receiving the same 404 error. I beleive it is not related to the view
view
<div class="col-md-9">
<div class="card">
<img src="<%= elevator.image %>" class="card-img-top" alt="..." />
<div class="card-body">
<h4 class="card-title"><%= elevator.projectName%></h4>
<p><%= elevator.projectNumber %></p>
<% if(user) { %>
<form
class="delete-form"
action="/elevators/<%= elevator._id %>?_method=DELETE"
method="post"
>
<button class="btn btn-danger">Delete</button>
</form>
<% } %>
</div>
<div class="card-body">
Back
</div>
</div>
</div>
You cannot get response from a DELETE route with a POST HTTP request. It is a well-known issue of browsers, but HTML forms can only send FormData via POST and DELETE is not compatible.
Therefore, Express routing does not match and says POST:“/:id” route does not exist.
Try changing .delete to .post and it will work.
Edit: There is a method-overwrite module to convert POST requests to DELETE via a query param _method (or any other name you choose).

How to read data from mongodb by input value and display it using ejs?

I am trying to search mongodb on a post request for all products in my database. Everything is working except the post request. The request goes through but no data is given back. I do not see a problem with the database.
const express = require("express");
const bodyParser = require("body-parser");
const mongoose = require("mongoose");
const app = express();
app.set("view engine", "ejs");
app.use(bodyParser.urlencoded({ extended: true }));
app.use(express.static("public"));
mongoose.connect(
"mongodb+srv://x:origisgood#cluster0.d6rzu.mongodb.net/productsDB?
retryWrites=true&w=majority",
{
useNewUrlParser: true,
useUnifiedTopology: true,
}
);
const productsSchema = {
name: String,
price: Number,
img: String,
};
const Product = mongoose.model("product", productsSchema);
app.get("/", function (req, res) {
res.send(__dirname + "/index.html");
});
app.post("/", function (req, res) {
const productName = req.body.productName;
Product.find({ name: productName }, function (err, foundProducts) {
res.render("home", {
name: foundProducts.name,
price: foundProducts.price,
img: foundProducts.img,
});
});
});
app.listen(3001, function () {
console.log("Server started successfully");
});
index.html to be displayed before everything else
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8" />
<title>X</title>
</head>
<body>
<form action="/" method="post">
<input
type="text"
name="productName"
placeholder="Search for a product"
/>
<button type="submit" name="Search">Search</button>
</form>
</body>
</html>
home.ejs to be displayed when a product is searched up
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title>X</title>
</head>
<body>
<h1><%= name %></h1>
<% var imgwostr = img; %>
<% imgwostr = str.replace(/^"|"$/g, ""); %>
<img src="<%= imgwostr %>" alt="">
<p><%= price %></p>
</body>
</html>
Your problem is that the db returns a list of documents that you treat as one.
Your foundProducts object is actually an array of type Product, even if there is only one product it is still an array which means that if you want to get the value back you would need to specify an index of the item you want to get.
Something like this should work:
Product.find({ name: productName }, function (err, foundProducts) {
const product = foundProducts[0];
if (!product) {
res.render('notfound');
}
res.render("home", {
name: product.name,
price: product.price,
img: product.img,
});
}
Notice that if the product is not found you would need to render another page because you will have nothing to display.

Meteor server api using iron router returns HTML not the response

I have a simple Meteor app just the basic meteor create test. I want to be able to route traffic to the "/" directory to a template.
I want to be able to route data from a facebook web-hook to a simple js response.
My issue is that when I fire the web-hook URL using postman it returns HTML and not my response.
I've tried many different options for other posts I have read but now have the most basic version to just get it working.
Here is the code I've used
main.html
<head>
<title>test</title>
</head>
<body>
</body>
<template name="home">
<form class="new-message">
<input type="text" name="message" placeholder="Testing">
</form>
</template>
main.js:
import { Meteor } from 'meteor/meteor';
import { Router } from 'meteor/iron:router';
import { Template } from 'meteor/templating';
import './main.html';
Router.route('/', function () {
this.render('home');
});
Router.route('/webhooks/facebook', function() {
var request = this.request;
var response = this.response;
response.end('webhook was called');
}, {
where: 'server'
});
All other files are exactly how they are created with meteor create.
I'm on Meteor version 1.8.1
I'm using postman to test the web-hook this is the created GET URL:
https://------.ngrok.io/webhooks/facebook?hub.verify_token=mytoken&hub.challenge=1234567&hub.mode=subscribe
code omitted to keep ngrok from getting slammed.
This is the response I'm getting:
<html>
<head>
<link rel="stylesheet" type="text/css" class="__meteor-css__"
href="/merged-stylesheets.css?hash=6b1f9f6fb78291ae58da8ec4f36476931155453c">
<title>simplechat</title>
</head>
<body>
<script type="text/javascript">
__meteor_runtime_config__ = JSON.parse(decodeURIComponent("%7B%22meteorRelease%22%3A%22METEOR%401.8.1%22%2C%22meteorEnv%22%3A%7B%22NODE_ENV%22%3A%22development%22%2C%22TEST_METADATA%22%3A%22%7B%7D%22%7D%2C%22PUBLIC_SETTINGS%22%3A%7B%7D%2C%22ROOT_URL%22%3A%22http%3A%2F%2Flocalhost%3A3000%2F%22%2C%22ROOT_URL_PATH_PREFIX%22%3A%22%22%2C%22autoupdate%22%3A%7B%22versions%22%3A%7B%22web.browser%22%3A%7B%22version%22%3A%22b22f1ad86c0a904c992885256b7de72ed2863e1d%22%2C%22versionRefreshable%22%3A%22a580e09175421ec6994fc6da61a0413f3a15d2b1%22%2C%22versionNonRefreshable%22%3A%22fc4ded0006de942fe57524f94d500abeb4569d6f%22%7D%2C%22web.browser.legacy%22%3A%7B%22version%22%3A%222571a76ffc344fbc5b40ade303255cbbc59e2682%22%2C%22versionRefreshable%22%3A%22a580e09175421ec6994fc6da61a0413f3a15d2b1%22%2C%22versionNonRefreshable%22%3A%22dc1e886b7786e303655c010220e9f502e82dcf1c%22%7D%7D%2C%22autoupdateVersion%22%3Anull%2C%22autoupdateVersionRefreshable%22%3Anull%2C%22autoupdateVersionCordova%22%3Anull%2C%22appId%22%3A%22zqskgg1xifoj.hlnqbjmcma6f%22%7D%2C%22appId%22%3A%22zqskgg1xifoj.hlnqbjmcma6f%22%2C%22isModern%22%3Afalse%7D"))
</script>
<script type="text/javascript" src="/packages/meteor.js?hash=857dafb4b9dff17e29ed8498a22ea5b1a3d6b41d"></script>
<script type="text/javascript" src="/packages/meteor-base.js?hash=29010b127daf4ebacaaf9db9b8a61487e57d7d86">
</script>
<script type="text/javascript" src="/packages/mobile-experience.js?hash=2751f9ec11102d1106042c462b340c3fcfcb1990">
</script>
<script type="text/javascript" src="/packages/modules-runtime.js?hash=d3c3e5d67c95f97a60888bda7373292efad3be5e">
</script>
<script type="text/javascript" src="/packages/modules.js?hash=e8b7455d5562fec1444a3c6882cdc6639055cfca"></script>
<script type="text/javascript" src="/packages/modern-browsers.js?
<script type="text/javascript" src="/packages/autoupdate.js?hash=6d56c0f3a885390c688b4f3f893d96d1280fd0ee"></script>
---- Cut out all of the other script calls to keep this short -----
<script type="text/javascript" src="/app/global-imports.js?hash=1f8a1ae2e343994912f72f1dc6eec1ca7df24cae"></script>
<script type="text/javascript" src="/app/app.js?hash=70cfa37cd2f85e533f69d7312d02ef8984eae01a"></script>
</body>
</html>
So basically it returns HTML.
I'm sure I'm missing something simple.
Thanks in advance for you help. Usually I wait till I have exhausted all other options before posting here. And I'm sure I have tried every other example given here on StackOverflow.
My desired result is simple to just return a HTTP response "webhook was called" instead of the HTML garbage.
You could use somethings like this :
Router.map(function(){
this.route("routeName", {path: "/url/:param1/:optionalParam?,
where: "server",
action: function(){
var param = this.params.param1;
this.response.writeHead(200, {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*'
});
//authenticate call and decrypt body
if (this.request.method == 'POST') {
//do something
}
if (this.request.method == 'GET') {
//do something
}
}
});
this.route("abc", {path: "/api/get/user/activity/:temp1",
where: "server",
action: function(){
//proceed as above
}
});
});
For help, read through https://iron-meteor.github.io/iron-router/#server-routing
The router file should be saved inside the server folder (for server-side routes)
Haven't used iron route in a long time but from what I remember you want to change your server side route to the following as it is for restful routes.
Router.route('/webhooks/facebook', { where: 'server' })
.get(function () {
// GET
})
.post(function () {
// POST
})
.put(function () {
// PUT
})
For others who have been struggling getting both server and client routes to work on the same Meteor app here is the solution.
Iron routers newest version requires all server side routes to be on the server side and you must fire them from the startup.
All client routes are added on the client side and included in the main.js on the client side.
My simple test was this:
meteor create test
Then in clients/main.html replace the current code and add a simple template as follows:
<head>
<title>newroutetest</title>
</head>
<body>
</body>
<template name="home">
<h1>Home</h1>
</template>
Then in the client/main.js add your client routes as follows:
import { Template } from 'meteor/templating';
import './main.html';
Router.route('/', {
template: 'home'
});
Now we setup the server side route in the file server/main.js you add the route in the startup section as follows:
import { Meteor } from 'meteor/meteor';
Meteor.startup(() => {
Router.route('/webhook', function () {
var req = this.request;
var res = this.response;
res.end('hello from the server\n');
}, {where: 'server'});
});
That's It
I hope this helps others who have been struggling with this.

Socket.io event listener not working on client side

this is my index.html
<!doctype html>
<html>
<head>
<title>Socket.IO chat</title>
<script src="/socket.io/socket.io.js"></script>
<script src="http://code.jquery.com/jquery-1.11.1.js"></script>
</head>
<body>
<ul id="messages"></ul>
<script>
var socket = io();
socket.on('testerEvent', function(data){
console.log(data)
});
</script>
</body>
</html>
this is my index.js
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
app.get('/', function(req, res){
res.sendFile(__dirname + '/index.html');
});
io.on('connection', function(socket){
socket.emit('testerEvent', { description: 'A custom event named testerEvent!'});
});
http.listen(3000, function(){
console.log('listening on *:3000');
});
In index.html listener not working on client side but working on server side.
I don't know what's wrong.
It is not listening to any events because you are not telling it from where to listen to.
try this:
var connectionOptions = {
"force new connection": true,
"reconnectionAttempts": "infinity",
"timeout": 10000,
"transports": ["websocket"]
};
const socket = io(/*your server*/, connectionOptions);

Subscriptions via websockets in Orion

Is it possible to create a websockets subscription from a browser? We are using the branch feature/1181_websockets branch, git version 5ca6770aa401b52a31293fdcef4a9743fb1de2c4.
We made a PoC trying to subscribe a browser via websockets. We tried connecting some JS code running in the browser to the subscriptions url. The connection was established, but orion crashed when sending data from the client through the socket. Is this use case supported? Do you have a working example for it? The JS code:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<button id="send" type="button" name="button">send</button>
<script type="text/javascript">
var payload = `{"description": "One subscription to rule them all",
"subject": {
"entities": [{
"idPattern": ".*",
"type": "Room"
}],
"condition": {
"attrs": ["temperature"],
"expression": {
"q": "temperature>40"
}
}
},
"expires": "2016-04-05T14:00:00.00Z",
"throttling": 5
}`;
var ws = new WebSocket('ws://orion-url:9010/v2/subscriptions', 'ngsiv2-json');
var button = document.getElementById('send');
button.addEventListener('click', function(event) {
ws.send(payload)
});
</script>
</body>
</html>
As an alternative, we tried to create a subscription using the REST API, asking Orion to notify us via websockets. We POSTed the following JSON:
{
"description": "One subscription to rule them all",
"subject": {
"entities": [
{
"idPattern": ".*",
"type": "Room"
}
],
"condition": {
"attributes": [
"temperature"
],
"expression": {
"q": "temperature>40"
}
}
},
"notification": {
"callback": "ws://my-websocket-listener:8081"
},
"expires": "2016-04-05T14:00:00.00Z",
"throttling": 5
}
The subscription process fails and Orion returns a 422 status code with the message:
{
"error": "BadRequest",
"description": "Invalid URL"
}
Did we make any mistake in the subscription request? Is this use case supported?
Thanks!
Currently you can subscribe with your browser and receive notifications, the restriction are the following:
From WS you can create a WS or REST subscription.
From REST you cannot create a WS subscription.
Only in the REST subscriptions you can specify the callback, in WS always must be "ws://". If you create a WS subscription the creator will be the receiver.
WS subscription are deleted if a connection is closed.
Here I let a little code as example, you only need change the URL by your Orion's URL
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script type="text/javascript">
$(function() {
window.WebSocket = window.WebSocket || window.MozWebSocket;
// Here change with your URL
var websocket = new WebSocket('ws://127.0.0.1:9010', 'ngsiv2-json');
websocket.onopen = function () {
$('h1').css('color', 'green');
};
websocket.onerror = function () {
$('h1').css('color', 'red');
};
websocket.onmessage = function (message) {
console.log(message.data);
console.log(message);
$('div').append(message.data + '<br/>');
};
$('#send').click(function(e) {
e.preventDefault();
if ($('#txt').val().length > 0)
{
websocket.send($('#txt').val());
$('#txt').val('');
}
});
$('#new').click(function(e) {
e.preventDefault();
var msg = "{\"verb\":\"POST\",\"url\":\"/v2/entities\", \
\"params\":{\"options\":\"keyValues\"}, \
\"payload\":{\"type\":\"1\",\"id\":\"1\",\"temp\":1}}";
$('#txt').val(JSON.stringify(JSON.parse(msg), null, 2));
});
$('#upd').click(function(e) {
e.preventDefault();
var msg = "{\"verb\":\"POST\",\"url\":\"/v2/entities/1\", \
\"params\":{\"options\":\"keyValues\"},\"payload\":{\"temp\": 1}}";
$('#txt').val(JSON.stringify(JSON.parse(msg), null, 2));
});
$('#get').click(function(e) {
e.preventDefault();
var msg = "{\"verb\":\"GET\",\"url\":\"/v2/entities/1\"}";
$('#txt').val(JSON.stringify(JSON.parse(msg), null, 2));
});
$('#del').click(function(e) {
e.preventDefault();
var msg = "{\"verb\":\"DELETE\",\"url\":\"/v2/entities/1\"}";
$('#txt').val(JSON.stringify(JSON.parse(msg), null, 2));
});
$('#sub').click(function(e) {
e.preventDefault();
var msg = "{\"verb\":\"POST\",\"url\":\"/v2/subscriptions\", \
\"payload\":{\"description\":\"My subscription\", \
\"subject\":{\"entities\":[{\"id\":\"1\",\"type\":\"1\"}], \
\"condition\":{\"attributes\":[\"temp\"],\"expression\":{\"q\":\"temp>40\"}}}, \
\"notification\":{\"callback\":\"ws://\",\"attributes\":[\"temp\"], \
\"throttling\":5},\"expires\":\"2017-04-05T14:00:00.00Z\"}}";
$('#txt').val(JSON.stringify(JSON.parse(msg), null, 2));
});
});
</script>
</head>
<body>
<h1>WebSockets test</h1>
<form>
<table border="0">
<tr>
<td colspan="2">
<textarea rows="35" cols="70" id="txt"></textarea>
</td>
</tr>
<tr>
<td>
<button id="new">New</button>
<button id="upd">Update</button>
<button id="get">Show</button>
<button id="del">Delete</button>
<button id="sub">Subcription</button>
</td>
<td align="right">
<button id="send">Send</button>
</td>
</tr>
</table>
</form>
<br/>
<p>Server:</p>
<div></div>
</body>
</html>
I'm not a JS expert... but this work to me as a test when I work in the WS for Orion
Cheers