I am developing a Discord bot using the Discord.js API. So far so good, but I thought it would be nice to have the newest post on a relevant subreddit be announced in the chat by my bot every couple of minutes. Now I have managed to make the script pull the relevant data out of the Reddit JSON API, but this error is thrown:
TypeError: Cannot read property 'sendMessage' of undefined
at /data/app/app.js:810:7
at Array.forEach (native)
at IncomingMessage.<anonymous> (/data/app/app.js:808:36)
at emitNone (events.js:72:20)
at IncomingMessage.emit (events.js:166:7)
at endReadableNT (_stream_readable.js:913:12)
at nextTickCallbackWith2Args (node.js:442:9)
at process._tickCallback (node.js:356:17)
/data/app/app.js:810
bot.sendMessage(channel,"https://www.reddit.com" + child.data.permalink);
This is my code:
var Discord = require("discord.js");
var bot = new Discord.Client();
var redditSubModule = "pics";
function getRedditPosts(bot, msg) {
var url = "http://www.reddit.com/r/" + redditSubModule + "/new/.json?limit=2";
var request = http.get(url, function(response) {
var json = "";
response.on("data", function(chunk) {
json += chunk;
});
response.on("end", function() {
var redditResponse = JSON.parse(json);
redditResponse.data.children.forEach(function(child) {
console.log("https://www.reddit.com" + child.data.permalink);
bot.sendMessage(msg.channel,"https://www.reddit.com" + child.data.permalink);
});
});
});
request.on("error", function(err) {
console.log(err);
});
setTimeout(getRedditPosts, 60000);
}
getRedditPosts();
Why is bot undefined?
It seems like you're expecting getRedditPosts to be called with attributes (bot, msg), but you are calling it with no attributes getRedditPosts();
So basically you are passing undefined as the bot variable.
undefined has no functions on it and you are trying to call sendMessage
and that is the meaning of Cannot read property 'sendMessage' of undefined
You will also need to call the function getRedditPosts() when a user runs a command. Something like:
bot.on('message', (msg)=>{
if(message.content.toLowerCase().startsWith("!redditcommand")) {
getRedditPosts(msg.client, msg)
}
}
At the end of your code in place of the getRedditPosts(); should do the trick.
Related
I wrote a smart contract for creating simple database. It contains multiple functions , when i hit an REST api first time it gives me correct output but at further hits it make node server crash with a message --
F:\project\blockchain\node_modules\solc\soljson.js:1
(function (exports, require, module, __filename, __dirname) { var Module;if(!Module)Module=(typeof Module!=="undefined"?Module:null)||{};var moduleOverrides={};for(var key in Module){if(Module
.hasOwnProperty(key)){moduleOverrides[key]=Module[key]}}var ENVIRONMENT_IS_WEB=typeof window==="object";var ENVIRONMENT_IS_WORKER=typeof importScripts==="function";var ENVIRONMENT_IS_NODE=type
of process==="object"&&typeof require==="function"&&!ENVIRONMENT_IS_WEB&&!ENVIRONMENT_IS_WORKER;var ENVIRONMENT_IS_SHELL=!ENVIRONMENT_IS_WEB&&!ENVIRONMENT_IS_NODE&&!ENVIRONMENT_IS_WORKER;if(EN
VIRONMENT_IS_NODE){if(!Module["print"])Module["print"]=function print(x){process["stdout"].write(x+"\n")};if(!Module["printErr"])Module["printErr"]=function printErr(x){process["stderr"].write
(x+"\n")};var nodeFS=require("fs");var nodePath=require("path");Module["read"]=function read(filename,binary){filename=nodePath"normalize";var ret=nodeFS["readFileSync"](file
Error: Can't set headers after they are sent.
at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:344:11)
at ServerResponse.header (F:\project\blockchain\node_modules\express\lib\response.js:725:10)
at ServerResponse.send (F:\project\blockchain\node_modules\express\lib\response.js:170:12)
at ServerResponse.json (F:\project\blockchain\node_modules\express\lib\response.js:256:15)
at F:\project\blockchain\BlockchainDB\users\userFunction.js:37:47
at F:\project\blockchain\node_modules\web3\lib\web3\filter.js:120:21
at Array.forEach (native)
at F:\project\blockchain\node_modules\web3\lib\web3\filter.js:119:32
at Array.forEach (native)
at Object.onMessage [as callback] (F:\project\blockchain\node_modules\web3\lib\web3\filter.js:117:22)
my code for api
module.exports.creation=function(req,res){
var user_id = req.params.user_id || req.body.user_id;
var currency = req.params.user_id || req.body.currency ;
if(user_id == undefined || currency == undefined){
res.status(500).json({status:false,errors:"Empty parameters"});
}else{
isaccount().then(function(accountNumber){
if(accountNumber!=null){
var timestamp = Date.now();
var result = contract.createUser.sendTransaction(user_id,currency,accountNumber,timestamp,{from:web3.eth.coinbase,gas:600000});
var event = contract.CreatedUser(function(error, result) {
if (!error){
if(result.args.userId!= undefined && result.args.accountId!= undefined && result.args.categoryId!= undefined){
logger.info("user created with id :"+result);
res.status(200).json({status:true,data:{iduser:result.args.userId,accountId:result.args.accountId,created_at:timestamp}});
}else{
logger.info("user creation have problem :");
res.status(500).json({status:false,errors:"no response"});
}
}else{
logger.error(error);
res.status(500).send(false);
}
});
}else{
logger.debug("Problem in accountNumber generation");
res.status(500).send(false);
}
});
}
}
please help me to solve this problem
Thanks in advance
Try using return statement for all the res.status() calls. So, even though once the response status gets set to something, it is again getting res.status() somewhere after it.
I'm trying to port this simple PHP script to node.js.
The TV uses RS232 and the command is PON for on; POF for off.
This example successfully turns my TV On:
<?php
$rs232_sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
$result = socket_connect($rs232_sock, '10.0.1.155', '4999');
$rs232_in = pack("H*" ,'02'.bin2hex('PON').'03');
socket_write($rs232_sock, $rs232_in, strlen($rs232_in));
?>
I have this started for NodeJS:
var net = require('net');
var jspack = require('jspack/jspack.js').jspack;
client.connect('4999','10.0.1.155', function(){
console.log('CONNECTED');
// Send the RS232 command
client.write(jspack.Pack("H",'02'+bin2hex(command)+'03'));
}).on('data', function(data) {
// log the response
console.log('DATA: ' + data);
// Close the connection
client.destroy();
});
This is causing:
net.js:618
throw new TypeError('invalid data');
^
TypeError: invalid data
at Socket.write (net.js:618:11)
at Socket.<anonymous> (/Users/paul/Sites/homebridge-globalcache-gc100/test.js:79:10)
at Socket.g (events.js:261:16)
at emitNone (events.js:73:20)
at Socket.emit (events.js:167:7)
at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1051:10)
You don't need extra libraries to send binary data. Something like this should be sufficient:
var net = require('net');
var PON_MSG = new Buffer('\x02PON\x03', 'binary');
var POF_MSG = new Buffer('\x02POF\x03', 'binary');
client.connect('4999','10.0.1.155', function() {
console.log('CONNECTED');
// Replace `PON_MSG` with `POF_MSG` to do POF instead
client.write(PON_MSG);
}).on('data', function(data) {
console.log('DATA: %j', data);
});
Also be aware that the data event can fire multiple times, so when you can safely end the connection (if the remote side doesn't do so automatically) depends on the protocol (to make sure you have received the entire response).
I subscibe to laravel 5 event[channal] update.group and I recive message in console after I trigger event but on client side in browser I don't recive any message. Also after I trigger event I recive message in console and then node server stop working with message:
bash-4.2# node node.js
Listening on Port 3000
Message Recieved: testasdsa
/home/client/public_html/node_modules/ioredis/lib/parsers/javascript.js:216
throw err;
^
SyntaxError: Unexpected token e
at Object.parse (native)
at Redis.<anonymous> (/home/client/public_html/node_modules/node.js:10:20)
at Redis.emit (events.js:110:17)
at Redis.exports.returnReply (/home/client/public_html/node_modules/ioredis/lib/redis/parser.js:79:16)
at ReplyParser.<anonymous> (/home/client/public_html/node_modules/ioredis/lib/redis/parser.js:27:10)
at ReplyParser.emit (events.js:107:17)
at ReplyParser.send_reply (/home/client/public_html/node_modules/ioredis/lib/parsers/javascript.js:281:8)
at ReplyParser.execute (/home/client/public_html/node_modules/ioredis/lib/parsers/javascript.js:210:14)
at Socket.<anonymous> (/home/client/public_html/node_modules/ioredis/lib/redis/event_handler.js:90:22)
at Socket.emit (events.js:107:17)
at readableAddChunk (_stream_readable.js:163:16)
at Socket.Readable.push (_stream_readable.js:126:10)
at TCP.onread (net.js:538:20)
Here is my node.js file:
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var Redis = require('ioredis');
var redis = new Redis();
redis.subscribe('update.group', function(err, count) {
});
redis.on('message', function(channel, message) {
console.log('Message Recieved: ' + message);
message = JSON.parse(message);
io.sockets.emit(channel + ':' + message.event, message.data);
});
http.listen(3000, function(){
console.log('Listening on Port 3000');
});
And for client side:
var socket = io.connect('127.0.0.1:3000');
socket.on("update.group", function(message){
// increase the power everytime we load test route
console.log(message);
});
Anyone can find what is problem?
It's pretty obvious from your debug output: testasdsa is not valid JSON, so you cannot parse it as such. You will need to change the code that publishes the messages so that it's properly JSON encoded.
Since it looks like you're expecting event and data properties on an object, the publisher would need to be writing something like { "event": "foo", "data": "testasdsa" }.
To fix the problem of browser clients not getting the events, you need to change this in your server script:
io.sockets.emit(channel + ':' + message.event, message.data);
to:
io.sockets.emit(message.event, message.data);
Then just make sure the publisher sends out something like { "event": "update.group", "data": "somedata" }
I am receiving the error:
undefined:1
'{"completed_in":0.078,"max_id":333655176038719488,"max_id_str":"3336551760387
^
SyntaxError: Unexpected token '
at Object.parse (native)
at /home/tweets/10seconds.js:25:25
at passBackControl (/home/tweets/node_modules/oauth/lib/oauth.js:367:11)
at IncomingMessage.<anonymous> (/home/tweets/node_modules/oauth/lib/oauth.js:386:9)
at IncomingMessage.EventEmitter.emit (events.js:117:20)
at _stream_readable.js:895:16
at process._tickCallback (node.js:415:13)
When parsing Twitter API JSON from the Search API.
The code I am using the parse this JSON is:
MongoClient.connect("mongodb://localhost:27017/db", function(err, db) {
if(err) { return console.dir(err); }
var collection = db.collection("tweets");
while(run < 200){
oa.get("http://search.twitter.com/search.json?q=morning&rpp=100&include_entities=true&result_type=mixed", access_token, access_token_secret, function(error, data) {
var theTweets = JSON.parse(sys.inspect(data));
collection.insert(theTweets, {w:1}, function(err, result) {});
console.log(run);
});
run = run + 1;
}
});
What could cause this?
Probably, the output of sys.inspect is not JSON it adds the quote '.
Why are you using sys.inspect?
If data is a JSON string, then use JSON.parse(data); and if it's an object already, well you don't have to use JSON.parse at all...
The problem is on the sys.inspect() call as already stated by the other answers and comments.
As stated in the nodejs documentation (http://nodejs.org/api/util.html#util_util_inspect_object_options):
Return a string representation of object, which is useful for debugging.
By the way, it seems they changed the sys module name to util.
You can easily make a small test by running the following code on an older node version. It should throw your error:
var sys = require('sys');
var data = '{"test":1, "test2":2}';
sys.puts(JSON.parse(sys.inspect(data)));
And then remove the sys.inspect call. It should correctly parse the object:
var sys = require('sys');
var data = '{"test":1, "test2":2}';
sys.puts(JSON.parse(data));
I have the following code in server/statusboard.js;
var require = __meteor_bootstrap__.require,
request = require("request")
function getServices(services) {
services = [];
request('http://some-server/vshell/index.php?type=services&mode=json', function (error, response, body) {
var resJSON = JSON.parse(body);
_.each(resJSON, function(data) {
var host = data["host_name"];
var service = data["service_description"];
var hardState = data["last_hard_state"];
var currState = data["current_state"];
services+={host: host, service: service, hardState: hardState, currState: currState};
Services.insert({host: host, service: service, hardState: hardState, currState: currState});
});
});
}
Meteor.startup(function () {
var services = [];
getServices(services);
console.log(services);
});
Basically, it's pulling some data from a JSON feed and trying to push it into a collection.
When I start up Meteor I get the following exception;
app/packages/livedata/livedata_server.js:781
throw exception;
^
Error: Meteor code must always run within a Fiber
at [object Object].withValue (app/packages/meteor/dynamics_nodejs.js:22:15)
at [object Object].apply (app/packages/livedata/livedata_server.js:767:45)
at [object Object].insert (app/packages/mongo-livedata/collection.js:199:21)
at app/server/statusboard.js:15:16
at Array.forEach (native)
at Function.<anonymous> (app/packages/underscore/underscore.js:76:11)
at Request._callback (app/server/statusboard.js:9:7)
at Request.callback (/usr/local/meteor/lib/node_modules/request/main.js:108:22)
at Request.<anonymous> (/usr/local/meteor/lib/node_modules/request/main.js:468:18)
at Request.emit (events.js:67:17)
Exited with code: 1
I'm not too sure what that error means. Does anyone have any ideas, or can suggest a different approach?
Just wrapping your function in a Fiber might not be enough and can lead to unexpected behavior.
The reason is, along with Fiber, Meteor requires a set of variables attached to a fiber. Meteor uses data attached to a fiber as a dynamic scope and the easiest way to use it with 3rd party api is to use Meteor.bindEnvironment.
T.post('someurl', Meteor.bindEnvironment(function (err, res) {
// do stuff
// can access Meteor.userId
// still have MongoDB write fence
}, function () { console.log('Failed to bind environment'); }));
Watch these videos on evented mind if you want to know more:
https://www.eventedmind.com/posts/meteor-dynamic-scoping-with-environment-variables
https://www.eventedmind.com/posts/meteor-what-is-meteor-bindenvironment
As mentioned above it is because your executing code within a callback.
Any code you're running on the server-side needs to be contained within a Fiber.
Try changing your getServices function to look like this:
function getServices(services) {
Fiber(function() {
services = [];
request('http://some-server/vshell/index.php?type=services&mode=json', function (error, response, body) {
var resJSON = JSON.parse(body);
_.each(resJSON, function(data) {
var host = data["host_name"];
var service = data["service_description"];
var hardState = data["last_hard_state"];
var currState = data["current_state"];
services+={host: host, service: service, hardState: hardState, currState: currState};
Services.insert({host: host, service: service, hardState: hardState, currState: currState});
});
});
}).run();
}
I just ran into a similar problem and this worked for me. What I have to say though is that I am very new to this and I do not know if this is how this should be done.
You probably could get away with only wrapping your insert statement in the Fiber, but I am not positive.
Based on my tests you have to wrap the insert in code I tested that is similar to the above example.
For example, I did this and it still failed with Fibers error.
function insertPost(args) {
if(args) {
Fiber(function() {
post_text = args.text.slice(0,140);
T.post('statuses/update', { status: post_text },
function(err, reply) {
if(reply){
// TODO remove console output
console.log('reply: ' + JSON.stringify(reply,0,4));
console.log('incoming twitter string: ' + reply.id_str);
// TODO insert record
var ts = Date.now();
id = Posts.insert({
post: post_text,
twitter_id_str: reply.id_str,
created: ts
});
}else {
console.log('error: ' + JSON.stringify(err,0,4));
// TODO maybe store locally even though it failed on twitter
// and run service in background to push them later?
}
}
);
}).run();
}
}
I did this and it ran fine with no errors.
function insertPost(args) {
if(args) {
post_text = args.text.slice(0,140);
T.post('statuses/update', { status: post_text },
function(err, reply) {
if(reply){
// TODO remove console output
console.log('reply: ' + JSON.stringify(reply,0,4));
console.log('incoming twitter string: ' + reply.id_str);
// TODO insert record
var ts = Date.now();
Fiber(function() {
id = Posts.insert({
post: post_text,
twitter_id_str: reply.id_str,
created: ts
});
}).run();
}else {
console.log('error: ' + JSON.stringify(err,0,4));
// TODO maybe store locally even though it failed on twitter
// and run service in background to push them later?
}
}
);
}
}
I thought this might help others encountering this issue. I have not yet tested calling the asynchy type of external service after internal code and wrapping that in a Fiber. That might be worth testing as well. In my case I needed to know the remote action happened before I do my local action.
Hope this contributes to this question thread.