var body = JSON.stringify(params);
// Create an XMLHttpRequest 'POST' request w/ an optional callback handler
req.open('POST', '/rpc', async);
req.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
req.setRequestHeader("Content-length", body.length);
req.setRequestHeader("Connection", "close");
if (async) {
req.onreadystatechange = function() {
if(req.readyState == 4 && req.status == 200) {
var response = null;
try {
response = JSON.parse(req.responseText);
} catch (e) {
response = req.responseText;
}
callback(response);
}
};
}
// Make the actual request
req.send(body);
---- on the server side ----
class RPCHandler(BaseHandler):
'''#user_required'''
def post(self):
RPCmethods = ("UpdateScenario", "DeleteScenario")
logging.info(u'body ' + self.request.body)
args = simplejson.loads(self.request.body)
---- Get the following error on the server logs
body %5B%22UpdateScenario%22%2C%22c%22%2C%224.5%22%2C%2230frm%22%2C%22Refinance%22%2C%22100000%22%2C%22740%22%2C%2294538%22%2C%2250000%22%2C%22owner%22%2C%22sfr%22%2C%22Fremont%22%2C%22CA%22%5D=
No JSON object could be decoded: line 1 column 0 (char 0):
Traceback (most recent call last):
File "/base/python_runtime/python_lib/versions/1/google/appengine/ext/webapp/_webapp25.py", line 703, in call
handler.post(*groups)
File "/base/data/home/apps/s~mortgageratealert-staging/1.357912751535215625/main.py", line 418, in post
args = json.loads(self.request.body)
File "/base/python_runtime/python_lib/versions/1/simplejson/init.py", line 388, in loads
return _default_decoder.decode(s)
File "/base/python_runtime/python_lib/versions/1/simplejson/decoder.py", line 402, in decode
obj, end = self.raw_decode(s, idx=_w(s, 0).end())
File "/base/python_runtime/python_lib/versions/1/simplejson/decoder.py", line 420, in raw_decode
raise JSONDecodeError("No JSON object could be decoded", s, idx)
JSONDecodeError: No JSON object could be decoded: line 1 column 0 (char 0)
--- firebug shows the following ---
Parameters application/x-www-form-urlencoded
["UpdateScenario","c","4....
Source
["UpdateScenario","c","4.5","30frm","Refinance","100000","740","94538","50000","owner","sfr","Fremont","CA"]
Based on the firebug report and also the logs shows self.request.body as anticipated. However simplejson load doesn't like it.
Please help!
TWO OPTIONS:
It seems that you need to escape the contents of self.request.body.
Import urllib and change the last line of code in your sample to:
args = simplejson.loads(urllib.unquote(self.request.body))
Or you can try this other option: You are sending a complete json string in the POST body. You might not need to have the following line in your javascript:
req.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
Take it out, and see if you still need to use the urllib.unquote solution above.
You do not send JSON content. You have to add this header : contentType: 'application/json'
Related
so I'm having an issue while creating a discord music bot and I've been trying to solve it for a while now, but I can't find any solution.
Here's the constructor and three functions to search and play music that are necessary for the command to actually work (I'll only include the skip command since I get the same exception with the rest of the commands)
class music(commands.Cog):
def __init__(self, bot):
self.bot = bot
self.is_playing = False
self.is_paused = False
self.music_queue = []
self.YDL_OPTIONS = {"format": "bestaudio", "noplaylist": "True"}
self.FFMPEG_OPTIONS = {"before_options": "-reconnect 1 -reconnect_streamed 1 -reconnect_delay_max 5", "options": "-vn"}
self.vc = None
async def play_music(self, ctx):
if len(self.music_queue) > 0:
self.is_playing = True
m_url = self.music_queue[0][0]["source"]
if self.vc == None or not self.vc.is_connected():
self.vc == await self.music_queue[0][1].connect()
if self.vc == None:
await ctx.send("I'm sorry, but I can't join the voice channel")
return
else:
await self.vc.move_to(self.music_queue[0][1])
self.music_queue.pop(0)
self.vc.play(discord.FFmpegPCMAudio(m_url, **self.FFMPEG_OPTIONS), after=lambda e: self.play_next())
else:
self.is_playing = False
def play_next(self):
if len(self.music_queue) > 0:
self.is_playing = True
m_url = self.music_queue[0][0]["source"]
self.music_queue.pop(0)
self.vc.play(discord.FFmpegPCMAudio(m_url, **self.FFMPEG_OPTIONS), after=lambda e: self.play_next())
else:
self.is_playing = False
def search(self, item):
with YoutubeDL(self.YDL_OPTIONS) as ydl:
try:
info = ydl.extract_info("ytsearch:{0}".format(item), download=False)["entries"][0]
except Exception:
return False
return {"source": info["formats"][0]["url"], "title": info["title"]}
async def setup(client):
await client.add_cog(music(client))
bot.py with setup_hook and the command
class MyBot(commands.Bot):
async def setup_hook(self):
await self.load_extension("dustobot")
#commands.command(aliases=["s"], help="Skips the current song that is being played")
async def skip(self, ctx, *args):
if self.vc != None and self.vc:
self.vc.stop()
await self.play_music(ctx) #Calling a function that plays the next song in a queue
And this is the error I get:
2023-01-21 12:28:37 ERROR discord.ext.commands.bot Ignoring exception in command skip
Traceback (most recent call last):
File "C:\Users\private_path\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\discord\ext\commands\core.py", line 229, in wrapped
ret = await coro(*args, **kwargs)
TypeError: music.skip() missing 1 required positional argument: 'ctx'
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "C:\Users\private_path\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\discord\ext\commands\bot.py", line 1349, in invoke
await ctx.command.invoke(ctx)
File "C:\Users\private_path\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\discord\ext\commands\core.py", line 1023, in invoke
await injected(*ctx.args, **ctx.kwargs) # type: ignore
File "C:\Users\private_path\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\discord\ext\commands\core.py", line 238, in wrapped
raise CommandInvokeError(exc) from exc
discord.ext.commands.errors.CommandInvokeError: Command raised an exception: TypeError: music.skip() missing 1 required positional argument: 'ctx'
Is it because I'm using a deprecated discord.py syntax?
Thanks in advance for taking your time to help me, I really appreciate it.
Btw this is my main.py:
import os
import discord
from dustobot import music #This imports the music class
from dotenv import load_dotenv
from discord.ext import commands
load_dotenv()
TOKEN = os.getenv('DISCORD_TOKEN')
intents = discord.Intents.default()
intents.message_content = True
client = commands.Bot(command_prefix="!", intents=intents)
client.remove_command("help") #I have my own help command
if __name__ == "__main__":
client.run(TOKEN)
The issue is caused by the way you created the command:
#client refers to the bot
#client.command(aliases=["s"], help="Skips the current song that is being played")
The decorator doesn't expect this to be a method in a class. As such, it's not invoked as a method either, so self won't be passed automatically and the Context will be the first argument (self). As a result, the library won't pass a value for ctx, which results in your error.
In cogs, commands should be created using #commands.command instead of #<Bot_instance>.command, the reason being that you shouldn't have your Bot instance available to you in that scope.
You could've also gotten this by reading the manual for Cogs...
Every command is marked with the commands.command() decorator.
I was trying to set events for my bot, however, it always returns this error after trying to edit the nickname on my server:
#commands.Cog.listener()
async def on_member_update(self, ctx, member_before, member_after):
nickname_after = f"{member_after.nickname}" if not member_after.nickname else member_after.nickname
nickname_before = f"{member_before.nickname}" if not member_before.nickname else member_before.nickname
embed = discord.Embed(timestamp = ctx.message.created_at , color = discord.Colour.random() ,
title = "Member Update")
embed.add_field(name = "Nickname before:" , value = f"{nickname_before}" , inline = True)
embed.add_field(name = "Nickname after:" , value = f"{nickname_after}" , inline = True)
embed.set_thumbnail(url = f"{member_after.avatar.url}")
embed.set_author(name = f"{self.osamu.user}" , icon_url = f"{self.osamu.avatar.url}")
channel = self.osamu.get_channel(898199584726188042)
return await channel.send(embed = embed)
The following traceback has been detected:
Ignoring exception in on_member_update
Traceback (most recent call last):
File "/home/ohnezahn/.local/lib/python3.9/site-packages/discord/client.py", line 352, in _run_event
await coro(*args, **kwargs)
TypeError: on_member_update() missing 1 required positional argument: 'member_after'
What I'm trying to achieve: if the user is editing his nickname the bot shall send the embed in the Channel which I've set (channel = self.osamu.get_channel(898199584726188042)). However, the response is the traceback, no embed whatsoever...
According to the docs, on_member_update only takes 2 parameters: before and after. Since your listener seems to be in a class you also need to use self as the first argument.
So if you remove the ctx from your arguments it should work properly.
#commands.Cog.listener()
async def on_member_update(self, member_before, member_after):
https://discordpy.readthedocs.io/en/master/api.html?highlight=on_member_update#discord.on_member_update
I am using akka http fileUpload method that produces a Source[akka.util.ByteString, Any].
I would like to handle this source in 2 different threads such as:
----> Future(check first rows if ok) -> insert object in db -> HTTP response 201 / 400
|
source ---|
|
----> Future(upload file to S3) -> set object to ready / delete if error...
So far, I managed to do something like this:
val f = for {
uploadResult <- Future(sendFileToS3(filePath, source)) // uploads the file
(extractedLines, fileSize) <- Future(readFileFromS3(filePath)) // reads the uploaded file
} yield(uploadResult, extractedLines, fileSize)
oncomplete(f) {
case Success((uploadResult, extractedLines, fileSize)) => HTTP OK with id of the object created
case Success((uploadResult, extractedLines, fileSize)) if ... => HTTP KO
case Failure(ex) => HTTP KO
}
The problem here is that on large files, the HTTP response is returned when the upload is finished. But what I would like to have is to handle the uploadResult separately from checking the first lines.
Something like
val f = for {
(extractedLines, fileSize) <- Future(readSource(source))
} yield(extractedLines, fileSize)
oncomplete(f) {
case Success((extractedLines, fileSize)) =>
Future(sendFileToS3AndHandle(filePath, source)) //send in another thread
HTTP OK with id of the object created
case Success((extractedLines, fileSize)) if ... => HTTP KO
case Failure(ex) => HTTP KO
}
Did someone have a similar issue and managed to handle it like this?
I have read something about using the source twice but it seems over complicated for my use case (and did not managed to do what I want). Also, I tried to use akka-stream alsoTo but this does not solve the issue about returning the response as soon as the first line check is completed.
Thank you for your help or suggestion.
I'm working on AWS lambda + API Gateway, and I need to pass an array of numbers in the url (GET method) for a REST call. It seems a good way is to pass the numbers as string (comma separated) and then use JSON.parse for the conversion to an array of numbers.
Following is the AWS lambda code I'm using;
exports.handler = (event, context, callback) => {
var arr = JSON.parse('[' + event.numbers + ']');
console.log("array: " + arr);
// TODO implement
callback(null, 'Hello from Lambda');
};
I'm testing this function in AWS Lambda using this Input test event;
{
"numbers": "1,5"
}
And everything works as expected; no errors.
However, when I test it via API Gateway, and passing the numbers as string in the query, I get following error (observed via CloudWatch);
*19:19:02
START RequestId: eabab882-8cee-11e7-8e2f-79d3086e061f Version: $LATEST
19:19:02
2017-08-29T19:19:02.688Z eabab882-8cee-11e7-8e2f-79d3086e061f SyntaxError: Unexpected token u in JSON at position 1 at Object.parse (native) at exports.handler (/var/task/index.js:4:20)
19:19:02
END RequestId: eabab882-8cee-11e7-8e2f-79d3086e061f
19:19:02
REPORT RequestId: eabab882-8cee-11e7-8e2f-79d3086e061f Duration: 215.25 ms Billed Duration: 300 ms Memory Size: 128 MB Max Memory Used: 18 MB
19:19:02
RequestId: eabab882-8cee-11e7-8e2f-79d3086e061f Process exited before completing request*
This is the request passed to lambda as shown in the log;
"body-json" : {},
"params" : {
"path" : {
}
,"querystring" : {
"numbers" : "1,6"
}
,"header" : {
}
},
"stage-variables" : {
},
I can't figure out what the problem is, since I'm passing same string in both cases.
I would appreciate any help.
Thanks
Gus
With this input json informed, you need to get it like this:
var arr = JSON.parse('[' + event.params.querystring.numbers + ']');
rather than:
var arr = JSON.parse('[' + event.numbers + ']');
Or make a body mapping template to stay the way you want:
{ "number": "$input.params('number')" }
http://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-mapping-template-reference.html
I hope I have helped!
How do I get the full message and not just the metadata using gmail api?
I have a service account and I am able to retrieve a message but only in the metadata, raw and minimal formats. How do I retrieve the full message in the full format? The following code works fine
var request = service.Users.Messages.Get(userId, messageId);
request.Format = UsersResource.MessagesResource.GetRequest.FormatEnum.Metadata;
Message message = request.Execute();
However, when I omit the format (hence I use the default format which is FULL) or I change the format to UsersResource.MessagesResource.GetRequest.FormatEnum.Full
I get the error: Metadata scope doesn't allow format FULL
I have included the following scopes:
https://www.googleapis.com/auth/gmail.readonly,
https://www.googleapis.com/auth/gmail.metadata,
https://www.googleapis.com/auth/gmail.modify,
https://mail.google.com/
How do I get the full message?
I had to remove the scope for the metadata to be able to get the full message format.
The user from the SO post have the same error.
Try this out first.
Go to https://security.google.com/settings/security/permissions
Choose the app you are working with.
Click Remove > OK
Next time, just request exactly which permissions you need.
Another thing, try to use gmailMessage.payload.parts[0].body.dataand to decode it into readable text, do the following from the SO post:
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.StringUtils;
System.out.println(StringUtils.newStringUtf8(Base64.decodeBase64(gmailMessage.payload.parts[0].body.data)));
You can also check this for further reference.
try something like this
public String getMessage(string user_id, string message_id)
{
Message temp =service.Users.Messages.Get(user_id,message_id).Execute();
var parts = temp.Payload.Parts;
string s = "";
foreach (var part in parts) {
byte[] data = FromBase64ForUrlString(part.Body.Data);
s += Encoding.UTF8.GetString(data);
}
return s
}
public static byte[] FromBase64ForUrlString(string base64ForUrlInput)
{
int padChars = (base64ForUrlInput.Length % 4) == 0 ? 0 : (4 - (base64ForUrlInput.Length % 4));
StringBuilder result = new StringBuilder(base64ForUrlInput, base64ForUrlInput.Length + padChars);
result.Append(String.Empty.PadRight(padChars, '='));
result.Replace('-', '+');
result.Replace('_', '/');
return Convert.FromBase64String(result.ToString());
}