discord bot coding function calls - function

A good portion of the code right now is me trying to figure out what I am doing wrong, so I am printing a few things here and there.
My goal:
Retrieve number of messages in a specific discord channel, and delete any new messages that exceed the limit of 10 (haven't implemented deletion yet)
I want this to be an event (currently a command for testing) that is called whenever a member tries to post a message in said channel
Planning on using message.channel when I swap to an on_messege event, and hopefully I can figure it all out from there...
The msg counter function does work when I call it just using !numMsg (with both ctx and when I add the channel name myself i.e. !numMsg channel-name)
# delete new messages if 10 already exist in channel
#bot.command(name = 'test')
async def test(ctx):
print('in here')
print(ctx.channel.id)
num = await message_count(ctx.channel)
await ctx.send(num)
# msg counter
#bot.command(name = 'numMsg')
async def message_count(ctx, channel: discord.TextChannel=None):
print('in here 2')
print(channel)
channel = channel or ctx.channel
count = 0
async for _ in channel.history(limit=None):
count += 1
return count
#await ctx.send(count)
#await ctx.send("There were {} messages in {}".format(count, channel.mention))
Here is the output:
Here is how I change the code slightly to confirm the function itself works:
# msg counter
#bot.command(name = 'numMsg')
async def message_count(ctx, channel: discord.TextChannel=None):
print('in here 2')
print(channel)
channel = channel or ctx.channel
count = 0
async for _ in channel.history(limit=None):
count += 1
#return count
await ctx.send(count)
#await ctx.send("There were {} messages in {}".format(count, channel.mention))

Related

Stream parsing tweets

The bottom line is to listen to a specific user and transfer his tweets with minimal delay to the telegram bot.
To implement this task, I use the Twiipi library in which, as I understand it, there are 2 most important types of authentication for me:
On behalf of the user - 900 requests in 15 minutes (i.e. 1 request in 1 second)
On behalf of the application - 300 requests in 15 minutes (i.e. 1 request in 3 seconds)
I authenticate my script on behalf of the user using the OAuth1UserHandler function (listed below).
But despite this, the delay in speed appears after 7.5 minutes of work, given that the script for interacting with twitter resources runs once every 1.5 seconds. That is one way or another Authentication of my script takes place on behalf of the application. But despite this, I just made a second bot that starts after 7 minutes of the previous one, thereby updating the time for the previous one to work. My main problem is that the performance of parsing tweet data drops (acceptable speed is a maximum of 1.5 seconds, delays sometimes last 13 seconds).
Please tell me what I'm doing wrong or how can I solve my problem better?
code of one of 2 bots
import tweepy
import datetime
import time
from notifiers import get_notifier
from re import sub
TOKEN = 'telegram token here'
USER_ID = telegram user id here
ADMIN_ID = teelgram my id here for check work bots
auth = tweepy.OAuth1UserHandler(
consumer_key="consumer key",
consumer_secret="consumer secret",
access_token="access token",
access_token_secret="access token secret",
)
api = tweepy.API(auth)
# auth.set_access_token(access_token, access_token_secret)
print("############### Tokens connected ###############")
user = 'whose username we will listen to'
username_object = api.get_user(screen_name=user)
def listening_to_the_user():
print(' We start listening to the user...')
print(' When a user posts a tweet, you will hear an audio notification...')
seconds_left = 60*10
while seconds_left >= 0:
for i in api.user_timeline(user_id=username_object.id, screen_name=user, count=1):
tweet_post = i.created_at
tweet_text = sub(r"https?://t.co[^,\s]+,?", "", i.text)
tweet_time_information = [tweet_post.day, tweet_post.month, tweet_post.year, tweet_post.hour, tweet_post.minute]
now = datetime.datetime.now()
current_time = [now.day, now.month, now.year, now.hour, now.minute]
if tweet_time_information == current_time:
telegram = get_notifier('telegram')
notification_about_tweet = f'️{user}⬇️'
notification_about_tweet_time = f'{tweet_post.day}.{tweet_post.month}.{tweet_post.year}, {tweet_post.hour}:{tweet_post.minute}.{tweet_post.second}'
notification_about_current_time = f'{now.day}.{now.month}.{now.year}, {now.hour}:{now.minute}.{now.second}'
telegram.notify(token=TOKEN, chat_id=USER_ID, message=notification_about_tweet)
telegram.notify(token=TOKEN, chat_id=USER_ID, message=tweet_text)
try:
entities = i.extended_entities
itr = entities['media']
for img_dict in range(len(itr)):
telegram.notify(token=TOKEN, chat_id=ADMIN_ID, message=(entities['media'][img_dict]['media_url_https']))
except:
entities = 0
telegram.notify(token=TOKEN, chat_id=ADMIN_ID, message=notification_about_tweet)
telegram.notify(token=TOKEN, chat_id=ADMIN_ID, message=tweet_text)
telegram.notify(token=TOKEN, chat_id=ADMIN_ID, message=notification_about_tweet_time)
telegram.notify(token=TOKEN, chat_id=ADMIN_ID, message=notification_about_current_time)
try:
entities = i.extended_entities
itr = entities['media']
for img_dict in range(len(itr)):
telegram.notify(token=TOKEN, chat_id=USER_ID,
message=(entities['media'][img_dict]['media_url_https']))
except:
entities = 0
seconds_left -= 60
time.sleep(60)
seconds_left -= 1.5
time.sleep(1.5)
listening_to_the_user()
Initially, I tried to use bearer_token for authentication, but this literally did not affect the operation of my program in any way and I simply reduced it to those tokens that are now in it.
I rummaged through the documentation in search of an answer to my question, but in search I only thought of the script calling the second bot after 7 minutes of the previous one, and so they worked in turn

Express stops queries after 3-4 times

I'm creating a React game. In this game, the user can buy card packs. He has an amount of money (called essences) and can chose any type of packs he wants to purchase (mini packs cost 500, normal are 1500 and mega packs cost 3000).
For every type of pack, I have an onClick button that triggers a function (BuyPack) with a parameter (the cost of the selected pack).
⏫Here is the 500 essences pack.
The function then makes an axios call to my express server :
const BuyPack = (arg) => {
let nb = (document.getElementById('essences').innerText) // that obviously sucks lol
let nbInt = parseInt(nb) // converts innerText to int
const newSolde = (nbInt - arg) // The calculated amount after the purchase
// Update visually the amount of essences
localStorage.setItem('essences', newSolde)
document.getElementById('essences').innerHTML = newSolde; // Let's set the new amount
let datas = {id: localStorage.getItem('id'), typeOfPack: arg}; // id = the user id / arg = 500, 1500 or 3000, it's basically the pack price.
console.log('datas', datas) // Output : datas {id: '196', typeOfPack: 500}
Axios.post('http://localhost:3001/buyPack', {data: datas}) // The axios call that doesn't work as expected
}
The axios call is :
app.post('/buyPack', function (req, res) {
const userId = (req.body.data.id)
const typeOfPack = (req.body.data.typeOfPack)
console.log(typeOfPack)
// I make a first request to get the "pre-buy" amount of money
query("select essences FROM users WHERE id = ?", [userId], (err, rows) => {
const actualEssences = (rows[0].essences); // The amount we just got
// Second query where we update and decrease the amount of money for the user
query("update users set essences = " + (actualEssences - typeOfPack) + " where id = " + userId)
})
})
For some reason I don't get, after some purchases, my express server just doesn't respond anymore. (the 3000 below are the console.log(typeOfPack).
Client side, I have no problem, the money is decreasing and I get the console message that I clicked on the pack.
I've tryied many things, but I really can't see the the issue comes from.
Thanks a lot in advance.

How to search registered user on ejabberd server from client side using smack library?

I am using smack on the client-side. I tried to search registered users on the client-side because before creating a new user I want to know that the id is registered on server or not if not then create the user either log in the user but ejabberd server crashed with the error. Here are the crash logs of ejabberd server.
Failed to process iq:
#iq{
id = <<"Hh6AJ-28">>,type = set,lang = <<"en">>,
from =
#jid{
user = <<"admin">>,server = <<"faiqkhan-virtualbox">>,
resource = <<"92526029764259513741138">>,luser = <<"admin">>,
lserver = <<"faiqkhan-virtualbox">>,
lresource = <<"92526029764259513741138">>},
to =
#jid{
user = <<>>,server = <<"vjud.faiqkhan-virtualbox">>,resource = <<>>,
luser = <<>>,lserver = <<"vjud.faiqkhan-virtualbox">>,lresource = <<>>},
sub_els =
[#xmlel{
name = <<"query">>,
attrs = [{<<"xmlns">>,<<"jabber:iq:search">>}],
children =
[#xmlel{
name = <<"x">>,
attrs = [{<<"xmlns">>,<<"jabber:x:data">>},{<<"type">>,<<"submit">>}],
children =
[#xmlel{
name = <<"field">>,
attrs = [{<<"var">>,<<"user">>},{<<"type">>,<<"text-single">>}],
children =
[#xmlel{
name = <<"value">>,attrs = [],
children = [{xmlcdata,<<"wasiq#faiqkhan-virtualbox">>}]}]}]}]}],
meta = #{ip => {0,0,0,0,0,65535,49320,11092}}}
exception error: {module_not_loaded,mod_vcard_mnesia,
<<"faiqkhan-virtualbox">>}
in function gen_mod:get_module_opts/2 (src/gen_mod.erl, line 338)
in call from gen_mod:get_module_opt/3 (src/gen_mod.erl, line 318)
in call from mod_vcard_mnesia:filter_fields/3 (src/mod_vcard_mnesia.erl, line 200)
in call from mod_vcard_mnesia:search/4 (src/mod_vcard_mnesia.erl, line 78)
in call from mod_vcard:search_result/4 (src/mod_vcard.erl, line 479)
in call from mod_vcard:process_search/1 (src/mod_vcard.erl, line 264)
in call from gen_iq_handler:process_iq/3 (src/gen_iq_handler.erl, line 131)
in call from gen_iq_handler:process_iq/4 (src/gen_iq_handler.erl, line 109)
I used the following code to get a registered user from the client-side:
InetAddress address = InetAddress.getByName(HOST);
DomainBareJid serviceName = JidCreate.domainBareFrom("faiqkhan-VirtualBox"); XMPPTCPConnectionConfiguration.Builder builder = XMPPTCPConnectionConfiguration.builder();
builder.setPort(PORT);
builder.setSendPresence(true);
builder.setHostAddress(address);
builder.setServiceName(serviceName);
builder.setUsernameAndPassword("admin", "123456");
builder.setSecurityMode(ConnectionConfiguration.SecurityMode.disabled);
XMPPTCPConnection connection = new XMPPTCPConnection(builder.build());
try {
connection.connect();
connection.login("admin", "123456");
Logger.showError("21560-connection created to: " + connection.getHost());
Roster roster = Roster.getInstanceFor(connection);
Set<RosterEntry> entities = roster.getEntries();
UserSearchManager search = new UserSearchManager(connection);
DomainBareJid s = JidCreate.domainBareFrom("vjud.".concat("faiqkhan-VirtualBox"));
Form searchForm = search.getSearchForm(s);
Form answerForm = searchForm.createAnswerForm();
answerForm.setAnswer("user", "wasiq#faiqkhan-virtualbox");
ReportedData data = search.getSearchResults(answerForm, s);
if (data.getRows() != null) {
for (ReportedData.Row row : data.getRows()) {
for (CharSequence value : row.getValues("jid")) {
Log.i("Iteartor values......", " " + value);
}
}
}
} catch (SmackException | IOException | XMPPException | InterruptedException e) {
Logger.showError("21560-error on account creation: " + e.getMessage());
}
Server crashed on ReportedData data = search.getSearchResults(answerForm, s); line of code.
You found a bug in ejabberd:
It was already fixed in 2018 in
https://github.com/processone/ejabberd/commit/1be21126342d503205798605725ba5ceef9de42b
but the bug got reintroduced in 2019 in
https://github.com/processone/ejabberd/commit/a02cff0e780bb735531594c4ece81e8628f79782#diff-71f613241ed580c3e5dad2b4526503f2R12
and I've now applied a temporary fix in
https://github.com/processone/ejabberd/commit/92913389a51ddc564f11e0712b0d82fca8c9aecb
But even if that bug is fixed, the feature you want to use probably doesn't help: a user must set his vCard in order for his account to be provided in vJud search. In other words, vJUD searches in stored vCards, not in registered accounts. If I register an account but don't set a vCard, then vJUD will not find it.
before creating a new user I want to know that the id is registered on server or not
And why don't you simply attempt to register the account first?
On the other hand, if you would like to check in advance if an account is available for registration or not (like some web registration sites do, to allow the user modify the username until one is available), then I think XMPP doesn't provide that possibility for security reasons: it is not allowed to know if an account exists or not.
A solution for that would be to use the check_account ejabberd command
https://docs.ejabberd.im/developer/ejabberd-api/admin-api/#check-account
executing it with some frontend, like ejabberdctl, ReST or XMLRPC
https://docs.ejabberd.im/admin/guide/managing/#ejabberd-commands
$ ejabberdctl check_account user1 localhost
$ ejabberdctl check_account user6666 localhost
Error: false
~ 1

Add string from list to url for API get request

Hi I have an API get request that retrieves numbers that I put into a list. I then want to loop over that list, adding every number in the list to a separate new get request. The code I have so far is:
for evt in eventList:
main_api = 'https://api.matchbook.com/edge/rest/events/json?'
print (evt)
evt = str(evt)
url = main_api + urllib.parse.urlencode({evt})
print (url)
r15 = s.get('url')
r16 = r15.json()
print ('Event:' + ' ' + 'r16')
How can I get the number from eventList into the url of the get request like so:
s.get'https://api.matchbook.com/edge/rest/events/488990433530010'
Assuming you just need to format the new url and use it for the next request -
import requests
for evt in event_list:
...
new_url = 'https://api.matchbook.com/edge/rest/events/{0}'.format(evt)
new_request = requests.get(new_url)
# do something with new_request
...

Using ItemCollection on a BoxFolder type with Box API only returns 100 results and cannot retrieve the remaining ones

For a while now, I've been using the Box API to connect Acumatica ERP to Box and everything has been going fine until recently. Whenever I try to use a BoxCollection type with the property ItemCollection, I'll only get the first 100 results no matter the limit I set in the GetInformationAsync(). Here is the code snippet:
[PermissionSet(SecurityAction.Assert, Name = "FullTrust")]
public BoxCollection<BoxItem> GetFolderItems(string folderId, int limit = 500, int offset = 0)
{
var response = new BoxCollection<BoxItem>();
var fieldsToGet = new List<string>() { BoxItem.FieldName, BoxItem.FieldDescription, BoxItem.FieldParent, BoxItem.FieldEtag, BoxFolder.FieldItemCollection };
response = Task.Run(() => Client.FoldersManager.GetFolderItemsAsync(folderId, limit, offset)).Result;
return response;
}
I then pass that information on to a BoxFolder type variable, and then try to use the ItemCollection.Entries property, but this only returns 100 results at a time, with no visible way to extract the remaining 61 (in my case, the Count = 161, but Entries = 100 always)
Another code snippet of the used variable, I am basically trying to get the folder ID based on the name of the folder inside Box:
private static void SyncProcess(BoxFolder rootFolder, string folderName)
{
var boxFolder = rootFolder.ItemCollection.Entries.SingleOrDefault(ic => ic.Type == "folder" && ic.Name == folderName);
}
I wasn't able to find anything related to that limit = 100 in the documentation and it only started to give me problems recently.
I had to create a work around by using the following:
var boxCollection = client.GetFolderItems(rootFolder.Id);
var boxFolder = boxCollection.Entries.SingleOrDefault(ic => ic.Type == "folder" && ic.Name == folderName);
I was just wondering if there was a better way to get the complete collection using the property ItemCollection.Entries like I used to, instead of having to fetch them again.
Thanks!
Box pages folder items to keep response times short. The default page size is 100 items. You must iterate through the pages to get all of the items. Here's a code snippet that'll get 100 items at a time until all items in the folder are fetched. You can request up to 1000 items at a time.
var items = new List<BoxItem>();
BoxCollection<BoxItem> result;
do
{
result = await Client.FoldersManager.GetFolderItemsAsync(folderId, 100, items.Count());
items.AddRange(result.Entries);
} while (items.Count() < result.TotalCount);
John's answer can lead to a duplicate values in your items collection if there will be external/shared folders in your list. Those are being hidden when you are calling "GetFolderItemsAsync" with "asUser" header set.
There is a comment about it in the Box API's codeset itself (https://github.com/box/box-windows-sdk-v2/blob/main/Box.V2/Managers/BoxFoldersManager.cs)
Note: If there are hidden items in your previous response, your next offset should be = offset + limit, not the # of records you received back.
The total_count returned may not match the number of entries when using enterprise scope, because external folders are hidden the list of entries.
Taking this into account, it's better to not rely on comparing the number of items retrieved and the TotalCount property.
var items = new List<BoxItem>();
BoxCollection<BoxItem> result;
int limit = 100;
int offset = 0;
do
{
result = await Client.FoldersManager.GetFolderItemsAsync(folderId, limit, offset);
offset += limit;
items.AddRange(result.Entries);
} while (offset < result.TotalCount);