How do you use lua in redis to return usable result to nodejs - node.js

one of the module i am implementing for my mobile app api is to get all outstanding notifications from , submitting username.
i used a list called username:notifications to store all outstanding id of notifications.
For example, in my test case, ['9','10',11'] is the result after calling for
lrange username:notifications 0 -1
So i wrote a lua script to get lrange and for each result,
hgetall notification:id
And for some reason, lua could not send the table, result to nodejs in usable state. Wondering if anyone
has a solution for multiple hgetall requests and returning them to nodejs
Here goes the rest of the code:
-- #KEYS: "username"
-- #ARGV: username
-- gets all fields from a hash as a dictionary
local hgetall = function (key)
local bulk = redis.call('HGETALL', key)
local result = {}
local nextkey
for i, v in ipairs(bulk) do
if i % 2 == 1 then
nextkey = v
else
result[nextkey] = v
end
end
end
local result = {}
local fields = redis.call('LRANGE' , ARGV[1], 0,-1)
for i, field in ipairs(fields) do
result[field] = hgetall('notification:'..field)
end
return result

You cannot return a "dictionary" from a Lua script, it is not a valid Redis type (see here).
What you can do is something like this:
local result = {}
local fields = redis.call('LRANGE' , ARGV[1], 0, -1)
for i=1,#fields do
local t = hgetall('notification:' .. fields[i])
result[#result+1] = fields[i]
result[#result+1] = #t/2
for j=1,#t do
result[#result+1] = t[j]
end
end
return result
The result is a simple list with this format:
[ field_1, nb_pairs_1, pairs..., field_2, nb_pairs_2, ... ]
You will need to decode it in your Node program.
EDIT: there is another solution, probably simpler in your case: encode the result in JSON and return it as a string.
Just replace the last line of your code by:
return cjson.encode(result)
and decode from JSON in your Node code.

Related

Smiles bot in Lua: matching text

This is my bot, who copies smilies in game chat.
The smiles it copies are saved in the table called "emoticons". If someone writes ":)", the bot writes ":)" and so on
The code inside the loop is for this: if someone writes, for example, ">:)", you have to make the script copy ">:)" and not just ":)"
CreateFrame, RegisterEvent, SetScript and SendChatMessage are in-game built Lua API
local emoticons = {
":)", "(:", ":))", ">:)", "0:)", ":D", ":]", ":)))", "=]", "?_?", "+.+", ":P", ":3", "^^", "roar", ":V", "D:", ":C", ".D", ".)", "o_o",
"^-^", ":PPP", ":DDD", ":D:D:D", ":DDDD", ":D:D:D:D", ":DDDDD", ":d", ":L", "<O>_<O>", "o/", "+_+", "?_?", "*0*", ":}", ";)", ":))))", "o.o", "<.<''", ":|",
":-)", "^^^^", ":D:D:D:D:D:D", ":D :D :D", "^^^", ":c", ";]", ":9", ">:|", ">.<", ";3", ";P", "T_T", ":3c", ":)))))",
"^^^^^" }
local f = CreateFrame("Frame")
f:RegisterEvent("CHAT_MSG_GUILD")
f:SetScript("OnEvent", function(self, event, text, playerName, _, channelName, playerName2, _, _, channelIndex)
local msg
local n = 0
for x, key in ipairs(emoticons) do
local l = string.len(emoticons[x])
if (string.sub(text, -l) == emoticons[x]) then
if (l > n) then
msg = emoticons[x]
n = l
end
end
end
if (msg) and (playerName ~= UnitName("player")) then
if (event == "CHAT_MSG_GUILD") then SendChatMessage(msg, "GUILD", nil, channelIndex) end
end
end)
Is there any way to improve it? For example, if someone writes
"^^^^^^"
the bot copies
"^^^^^"
which would be the same with one less "^" as it was stored in the table
My goal is that if someone writes, for example, "^^^^^^" and it is not registered in the table, the script will not respond
You're probably better off learning how to use string.gmatch
As an example, let's say you only store one instance of ':D' in your emoticons table. You can iterate through the matches and respond in kind. Here's a small example:
local text = ':D:D:D'
local count = 0
for w in string.gmatch(text, ':D') do
count = count + 1
end
if count > 0 then
local response = ''
for i = 1, count do
response = response .. ':D'
end
print(response) -- prints ':D:D:D'
end
This doesn't handle every case, but hopefully it can help you get started
:D

XGetWindowProperty and ctypes

Question
I'm trying to find NET_WM_NAME property for each of the window/client that X11 reports. Problem is that there's nothing returned - number of items is 0 and returned data results in empty string. I've looked at multiple code examples through out github and examples written in C and C++ , specifically Why is XGetWindowProperty returning null? as well as Xlib XGetWindowProperty Zero items returned , however I cannot find where is the problem with my code. Seemingly everything is fine, order of parameters passed to XGetWindowProperty function is in accordance with documentation, and the function returns success status, but results are empty. Where is the problem with my code ?
Code
Below is the code I am working with. The issue is xgetwindowproperty function. The other parts below it work fine, and are provided only for completeness.
#! /usr/bin/env python3
import sys
from ctypes import *
def xgetwindowproperty(display,w):
actual_type_return = c_ulong()
actual_format_return = c_int()
nitems_return = c_ulong()
bytes_after_return = c_ulong()
prop_return = POINTER(c_ubyte)()
wm_name = Xlib.XInternAtom(display,'_NET_WM_NAME',False)
utf8atom = Xlib.XInternAtom(display,'UTF8_STRING',False)
print('_NET_WM_NAME',wm_name, 'UTF8_STRING',utf8atom)
# AnyPropertyType = c_long(0)
status = Xlib.XGetWindowProperty(
display,
w,
wm_name,
0,
65536,
False,
utf8atom,
byref(actual_type_return),
byref(actual_format_return),
byref(nitems_return),
byref(bytes_after_return),
byref(prop_return)
)
print(nitems_return.value) # returns 0
# empty string as result
print( 'Prop', ''.join([ chr(c) for c in prop_return[:bytes_after_return.value] ]) )
Xlib.XFree(prop_return)
print('#'*10)
# -------
Xlib = CDLL("libX11.so.6")
display = Xlib.XOpenDisplay(None)
if display == 0:
sys.exit(2)
w = Xlib.XRootWindow(display, c_int(0))
root = c_ulong()
children = POINTER(c_ulong)()
parent = c_ulong()
nchildren = c_uint()
Xlib.XQueryTree(display, w, byref(root), byref(parent), byref(children), byref(nchildren))
for i in range(nchildren.value):
print("Child:",children[i])
xgetwindowproperty(display,children[i])

why would python3 recursive function return null

I have this function that when hitting a rate limit will call itself again. It should eventually succeed and return the working data. It works normally then rate limiting works as expected, and finally when the data goes back to normal I get:
TypeError: 'NoneType' object is not subscriptable
def grabPks(pageNum):
# cloudflare blocks bots...use scraper library to get around this or build your own logic to store and use a manually generated cloudflare session cookie... I don't care 😎
req = scraper.get("sumurl.com/"+str(pageNum)).content
if(req == b'Rate Limit Exceeded'):
print("adjust the rate limiting because they're blocking us :(")
manPenalty = napLength * 3
print("manually sleeping for {} seconds".format(manPenalty))
time.sleep(manPenalty)
print("okay let's try again... NOW SERVING {}".format(pageNum))
grabPks(pageNum)
else:
tree = html.fromstring(req)
pk = tree.xpath("/path/small/text()")
resCmpress = tree.xpath("path/a//text()")
resXtend = tree.xpath("[path/td[2]/small/a//text()")
balance = tree.xpath("path/font//text()")
return pk, resCmpress, resXtend, balance
I've tried to move the return to outside of the else scope but then it throws:
UnboundLocalError: local variable 'pk' referenced before assignment
Your top level grabPks doesnt return anything if it is rate limited.
Think about this:
Call grabPks()
You're rate limited so you go into the if statement and call grabPks() again.
This time it succeeds so grabPks() returns the value to the function above it.
The first function now falls out of the if statement, gets to the end of the function and returns nothing.
Try return grabPks(pageNum) instead inside your if block.
well okay... I needed to return grabPKs to make it play nice...:
def grabPks(pageNum):
# cloudflare blocks bots...use scraper library to get around this or build your own logic to store and use a manually generated cloudflare session cookie... I don't care 😎
req = scraper.get("sumurl.com/"+str(pageNum)).content
if(req == b'Rate Limit Exceeded'):
print("adjust the rate limiting because they're blocking us :(")
manPenalty = napLength * 3
print("manually sleeping for {} seconds".format(manPenalty))
time.sleep(manPenalty)
print("okay let's try again... NOW SERVING {}".format(pageNum))
return grabPks(pageNum)
else:
tree = html.fromstring(req)
pk = tree.xpath("/path/small/text()")
resCmpress = tree.xpath("path/a//text()")
resXtend = tree.xpath("[path/td[2]/small/a//text()")
balance = tree.xpath("path/font//text()")
return pk, resCmpress, resXtend, balance

Aerospike Query read all the records with Bin1 == Bin2

I have a nodejs and aerospike set up. I want to know how run a query where Bin1 == Bin2.
In SQL
SELECT * FROM [test]t where t.EmployeeId == t.shipperid
Can it be done ? I can always query all the values from test set and filter it in nodejs. However I think it will be highly inefficient. Please let me know if there is an aerospike way to doing it?
You can create an extra bin, "equal_ids", which is set to true when the IDs are equal. This bin is to have a secondary index. Then, you can do a secondary index query for equal_ids==true
This is not supported through the existing query predicates, but you can express this as a stream UDF.
local function bin_match_filter(bin1, bin2)
return function(rec)
if rec[bin1] and rec[bin2] and
(type(rec[bin1]) == type(rec[bin2])) and
rec[bin1] == rec[bin2] then
return true
end
return false
end
end
local function map_record(rec)
local ret = map()
for i, bin_name in ipairs(record.bin_names(rec)) do
ret[bin_name] = rec[bin_name]
end
return ret
end
function check_bins_match(stream, bin1, bin2)
return stream : filter(bin_match_filter(bin1, bin2)) : map(map_record)
end
You can now run the records matched by a secondary index query, or a scan through this stream UDF.

Split a string on sqlite

i don't know sqlite but I have to implement a database already done. I'm programming with Corona SDK. The problem: i have a column called "answers" in this format: House,40|Bed,20|Mirror,10 ecc.
I want to split the string and remove "," "|" like this:
VARIABLE A=House
VARIABLE A1=40
VARIABLE B=Bed
VARIABLE B1=20
VARIABLE C=Mirror
VARIABLE C1=10
I'm sorry for my english. Thanks to everybody.
Try this:
If you want to simply remove the characters, then you can use the following:
Update 3 :
local myString = "House;home;flat,40|Bed;bunk,20|Mirror,10"
local myTable = {}
local tempTable = {}
local count_1 = 0
for word in string.gmatch(myString, "([^,|]+)") do
myTable[#myTable+1]=word
count_1=count_1+1
tempTable[count_1] = {} -- Multi Dimensional Array
local count_2 = 0
for word_ in string.gmatch(myTable[#myTable], "([^,|,;]+)") do
count_2=count_2+1
local str_ = word_
tempTable[count_1][count_2] = str_
--print(count_1.."|"..count_2.."|"..str_)
end
end
print("------------------------")
local myTable = {} -- Resetting my table, just for using it again :)
for i=1,count_1 do
for j=1,#tempTable[i] do
print("tempTable["..i.."]["..j.."] = "..tempTable[i][j])
if(j==1)then myTable[i] = tempTable[i][j] end
end
end
print("------------------------")
for i=1,#myTable do
print("myTable["..i.."] = "..myTable[i])
end
--[[ So now you will have a multidimensional array tempTable with
elements as:
tempTable = {{House,home,flat},
{40},
{Bed,bunk},
{20},
{Mirror},
{10}}
So you can simply take any random/desired value from each.
I am taking any of the 3 from the string "House,home,flat" and
assigning it to var1 below:
--]]
var1 = tempTable[1][math.random(3)]
print("var1 ="..var1)
-- So, as per your need, you can check var1 as:
for i=1,#tempTable[1] do -- #tempTable[1] means the count of array 'tempTable[1]'
if(var1==tempTable[1][i])then
print("Ok")
break;
end
end
----------------------------------------------------------------
-- Here you can print myTable(if needed) --
----------------------------------------------------------------
for i=1,#myTable do
print("myTable["..i.."]="..myTable[i])
end
--[[ The output is as follows:
myTable[1]=House
myTable[2]=40
myTable[3]=Bed
myTable[4]=20
myTable[5]=Mirror
myTable[6]=10
Is it is what you are looking for..?
]]--
----------------------------------------------------------------
Keep coding............. :)

Resources