I have some problem. If I have old firmware (NodeMCU 0.9.5 build 20150318 powered by Lua 5.1.4) then it works and I receive back response to phone. But if I have new one ( build 2022-09-07 powered by Lua 5.1.4 on SDK 3.0.1-dev(fce080e)) then I do not receive response (but I get request “who” on ESP8266). What is the problem it could be?
Code:
srv = net.createServer(net.TCP)
srv:listen(80,function(conn)
conn:on("receive", function(client,request)
local buf = "";
buf = buf.."HTTP/1.1 200 OK\n\n"
local _, _, method, path, vars = string.find(request, "([A-Z]+) (.+)?(.+) HTTP");
if(method == nil)then
_, _, method, path = string.find(request, "([A-Z]+) (.+) HTTP");
end
local _GET = {}
if (vars ~= nil)then
for k, v in string.gmatch(vars, "(%w+)=(%w+)&*") do
_GET[k] = v
end
end
if(_GET.pin == "ON1")then
print(“On”)
elseif(_GET.pin == "OFF1") then
print(“Off”)
end
if(_GET.question == "who") then
buf=""
buf = buf.."HTTP/1.1 200 OK\n\n"
print(buf)
end
client:send(buf)
client:close()
collectgarbage()
end)
end)
Related
I just started studying Lua.
Every time I request, I want to check the name parameter in the request parameter. However, it is actually found that the self.name has changed occasionally.
For example,
request A with params: request_id = 123 & name = ABC,
request B with params: request_id = 321 & name = EFG,
in the log, I found that there are requests_id = 123, but name = EFG.
Why is that? Is my class incorrectly written?
Here is the sample code:
main.lua:
local checker = require "checker"
local ch = checker:new()
if ch:check_name() then
ngx.header["Content-Type"] = "application/json"
ngx.status = ngx.HTTP_FORBIDDEN
ngx.exit(ngx.HTTP_FORBIDDEN)
end
checker.lua:
local utils = require "utils"
local _M = {}
function _M:new()
local o = {}
setmetatable(o, self)
self.__index = self
self.args = utils.get_req_args() or {}
local name = self.args["name"] or ""
local request_id = self.args["request_id"] or ""
self.name = name
return o
end
function _M:check_name()
ngx.log(ngx.ERR, "request_id: ", self.request_id, " name: ", self.name)
-- do some check ...
end
utils.lua
local json = require "cjson"
local _M = {}
function _M.new(self)
return self
end
function _M.get_req_args()
-- GET
local args = nil
if ngx.var.request_method == "GET" then
args = ngx.req.get_uri_args()
-- POST
elseif ngx.var.request_method == "POST" then
ngx.req.read_body()
local data = ngx.req.get_body_data()
args = json.decode(data)
end
return args
end
I have written a go programme to query issues in github repository "golang:go".
The http.Get() responds with status "200 OK".
I then query for issues created in last 3 months and the http.Get() returns "422 Unprocessable Entity". Below is the programme
import(
"fmt"
"time"
"net/http"
"net/url"
)
func main() {
var ret error
var str string
q:=url.QueryEscape("repo:golang/go")
fmt.Println("q:", q)
urlStr := "https://api.github.com/search/issues" +"?q=" + q
fmt.Println("urlStr:", urlStr)
resp, ret:= http.Get(urlStr)
fmt.Println("ret :", ret, "resp.status :", resp.Status)
timeStr := "created:"
to := time.Now()
from := to.AddDate(0, -3, 0)
str = to.Format("2006-01-02")
timeStr = timeStr + str + ".."
fmt.Printf("time1 : %s\n", timeStr)
str = from.Format("2006-01-02")
timeStr = timeStr + str
fmt.Printf("time2 : %s\n", timeStr)
q=url.QueryEscape("repo:golang/go" + timeStr)
fmt.Println("q:", q)
urlStr = "https://api.github.com/search/issues" +"?q=" + q
fmt.Println("urlStr:", urlStr)
resp, ret = http.Get(urlStr)
fmt.Println("ret :", ret, "resp.status :", resp.Status)
}
I used this to form the query.
I am new to web programming and not able to understand where I went wrong in forming the second query.
two things that worked for me
1) reverse the "from" and "to" in your timeStr
2) don't use QueryEscape on the timeStr, just add it in like this
urlStr = "https://api.github.com/search/issues" + "?q=repo:golang/go+" + timeStr
Don't use an ampersand (I originally answered with this) use a plus sign or space. See https://help.github.com/articles/searching-issues-and-pull-requests/#search-by-when-an-issue-or-pull-request-was-created-or-last-updated for the syntax
update: on further consideration the QueryEscape is a good idea! It seems coincidentally to "just work"
I used like the following and it works for me if i don't escape the 2nd url:
package main
import(
"fmt"
"time"
"net/http"
"net/url"
)
func main() {
var ret error
var str string
q:=url.QueryEscape("repo:golang/go")
fmt.Println("q:", q)
urlStr := "https://api.github.com/search/issues" +"?q=" + q
fmt.Println("urlStr:", urlStr)
resp, ret:= http.Get(urlStr)
fmt.Println("ret :", ret, "resp.status :", resp.Status)
timeStr := "created:"
to := time.Now()
from := to.AddDate(0, -3, 0)
str = to.Format("2006-01-02")
timeStr = timeStr + str + ".."
fmt.Printf("time1 : %s\n", timeStr)
str = from.Format("2006-01-02")
timeStr = timeStr + str
fmt.Printf("time2 : %s\n", timeStr)
urlStr = "https://api.github.com/search/issues" +"?q=" + "repo:golang/go&created:2018-11-29..2018-08-29"
fmt.Println("urlStr:", urlStr)
resp, ret = http.Get(urlStr)
fmt.Println("ret :", ret, "resp.status :", resp.Status)
}
And the output is:
q: repo%3Agolang%2Fgo
urlStr: https://api.github.com/search/issues?q=repo%3Agolang%2Fgo
ret : <nil> resp.status : 200 OK
time1 : created:2018-11-29..
time2 : created:2018-11-29..2018-08-29
urlStr: https://api.github.com/search/issues?q=repo:golang/go&created:2018-11-29..2018-08-29
ret : <nil> resp.status : 200 OK
Many APIs including the one from github return the 422 status code when the client sends invalid input. In your code the bad input is generated by the line that concatenates the two qualifiers without a "separator".
So this "repo:golang/go" + timeStr will result in the q value containing a single "merged" qualifier that looks something like this:
"repo:golang/gocreated:2018-1...
To fix your code you just need to add a space between the two qualifiers and your query should work.
q=url.QueryEscape("repo:golang/go " + timeStr)
I did Server-Client Application with lua using one Esp8266. I wanna do this with two Esp8266. I wanna use one of these Esp8266 is Server and the other other one is Client. You can see below first code using for get RSSI from one AP and second code is using for writing these RSSI in a Server. How can i placed these two codes in two Esp8266?
i=5
tmr.alarm(1,10000,1, function()
print(wifi.sta.getap(scan_cfg, 1, listap))
if i>1 then
print(i)
i=i-1
else
tmr.stop(1)
print("Timer Durdu")
end
end
)
function listap(t)
for bssid,v in pairs(t) do
local ssid = string.match(v, "([^,]+)")
l=string.format("%-10s",ssid)
stringtoarray = {}
index = 1
for value in string.gmatch(v,"%w+") do
stringtoarray [index] = value
index = index + 1
end
print(l)
print(stringtoarray[2])
end
end
scan_cfg = {}
scan_cfg.ssid = "VSP250s"
scan_cfg.bssid = "00:09:df:8e:03:b4"
scan_cfg.channel = 0
scan_cfg.show_hidden = 1
Second code:
srv=net.createServer(net.TCP)
srv:listen(80,function(conn)
conn:on("receive", function(client,request)
local buf = "";
local _, _, method, path, vars = string.find(request, "([A-Z]+) (.+)?(.+) HTTP");
if(method == nil)then
_, _, method, path = string.find(request, "([A-Z]+) (.+) HTTP");
end
local _GET = {}
if (vars ~= nil)then
for k, v in string.gmatch(vars, "(%w+)=(%w+)&*") do
_GET[k] = v
end
end
buf = buf.."<!DOCTYPE html><html><div id='container'><font size='5'>"
buf = buf..'<style>body{width:auto;height:auto;background-color:#ffffff;}'
buf = buf..'.button {font-size: 20px;}</style>'
buf = buf.."<head> <meta http-equiv='refresh' content=3> "
buf = buf.."<p><h1>RSSI meter<br> ESP8266</h1>";
--buf = buf.."<p>Refresh : <button class='button'>ON</button> </p>";
--buf = buf.."<p>Relay Switch : <button class='button'>ON</button> "
--buf = buf.."<button class='button'>OFF</button><br>"
buf = buf..'<B>Voltage :<font color=red>'..string.format('%s',l)..' V</font></b><br>'
buf = buf..'<B>Current :<B><font color=blue>'..string.format('%g',stringtoarray[2])..' A</font></b><br>'
--buf = buf..'<B>Power Consumption :<B><font color=DeepSkyBlue>'..'Not Available'..'</font></b><br><BR>'
-- buf = buf..'<p>Function Button :<B><font color=BlueViolet>'..button_status..'</font></b><br></p>';
buf = buf..'</head>'
buf = buf..'<br><br><details><summary><font color=red>BURAK IPEK</font><p>'
buf = buf..'<summary><p>Vestel Electronics </p></details>'
buf = buf.."</body></font></div></html>"
client:send(buf);
client:close();
collectgarbage();
end)
end)
Put each code into a lua file. Include both from init.lua with typing
dofile("client.lua");
dofile("server.lua");
To make things easier, write methods.
Good luck.
I'm trying to create two HTTP requests with the same request body. Unfortunately, the second request sends an empty body.
w := httptest.NewRecorder()
w2 := httptest.NewRecorder()
pd := &postData{
Data: 5,
}
b := new(bytes.Buffer)
json.NewEncoder(b).Encode(pd)
req, _ := http.NewRequest("PUT", "/v1/jobs/echo", b)
server.ServeHTTP(w, req)
req, _ = http.NewRequest("PUT", "/v1/jobs/echo", b)
server.ServeHTTP(w2, req)
Reading through the documentation and the source code for bytes.Buffer, it looks like there's no way to reset the buffer to 0 - there's a Reset method, but this also wipes the buffer's internal state.
Is there a way to "replay" any reader in Go? A bytes.Buffer or any other Reader.
OK. So I wouldn't consider this ideal and it would be better to just init a reader in the first place but if you put your data in a bytes.Reader instead of bytes.Buffer then you'll be able to seek back to the beginning after the first call to NewRequest has read to the end.
w := httptest.NewRecorder()
w2 := httptest.NewRecorder()
pd := &postData{
Data: 5,
}
b := new(bytes.Buffer)
json.NewEncoder(b).Encode(pd)
r := bytes.NewReader(b.Bytes())
req, _ := http.NewRequest("PUT", "/v1/jobs/echo", r)
server.ServeHTTP(w, req)
r.Seek(0, 0)
req, _ = http.NewRequest("PUT", "/v1/jobs/echo", r)
server.ServeHTTP(w2, req)
I try a concurrent download with limited number of Workers using the AsyncSeq module.
Based on the FSharpX example of https://github.com/fsprojects/fsharpx/blob/master/samples/Crawler.fsx
let rec concurrentDownload concurrentWorkers download transform (urls:string list) =
asyncSeq {
let requests = BlockingQueueAgent<_>(1000)
let results = BlockingQueueAgent<_>(50)
let worker() = async {
while true do
let! url = requests.AsyncGet()
let! doc = download url
match doc with
| Some txt -> do! results.AsyncAdd( transform txt )
| _ -> ()
}
// fill in all the requests
for url in urls do
do! requests.AsyncAdd url
// create the workers and start them
for i in 1 .. concurrentWorkers do
worker() |> Async.Start
// get the results and yield them in the asynchronous sequence
while requests.Count > 0 && results.Count > 0 do
let! res = results.AsyncGet()
yield res
}
let rand = new System.Random()
let rnd() = rand.Next(0,4000)
// a simulated download, sleep time depends on random number
let download str = async {
let name = "dl " + str
let payload = rnd()
printfn "Started : %s (payload=%d)" name payload
do! Async.Sleep(1000 + payload)
printfn "Finished: %s" name
return Some name
}
let urls = [1..10] |> List.map (sprintf "URL %d")
let concurrentWorkers = 5
let transform = id
let ret = concurrentDownload concurrentWorkers download transform urls
//ret // val it : AsyncSeq<string> = Microsoft.FSharp.Control.FSharpAsync`1[FSI_0012.FSharp.Control.AsyncSeqInner`1[System.String]]
let z =
ret
|> AsyncSeq.toBlockingSeq
|> Seq.toList
I assumed that z gets something like seq ["dl URL 3"; "dl URL 5"; ... ]
because 'download' returns Some content.
The workers on the blocking queues working as expected:
Started : dl URL 1 (payload=2281)
Started : dl URL 3 (payload=741)
Started : dl URL 4 (payload=3283)
Started : dl URL 5 (payload=1117)
Started : dl URL 2 (payload=2435)
Finished: dl URL 3
Started : dl URL 6 (payload=263)
Finished: dl URL 5
Started : dl URL 7 (payload=1115)
Finished: dl URL 6
Started : dl URL 8 (payload=1041)
Finished: dl URL 1
Started : dl URL 9 (payload=959)
Finished: dl URL 2
Started : dl URL 10 (payload=604)
Finished: dl URL 7
Finished: dl URL 4
Finished: dl URL 10
Finished: dl URL 8
Finished: dl URL 9
The problem is, why is z an empty list?
And not as exprected seq ["dl URL 3"; "dl URL 5"; ... ]?
As a reference, here is the toBlockingSeq function:
// FSharpX AsyncSeq.toBlockingSeq
let toBlockingSeq (input : AsyncSeq<'T>) =
// Write all elements to a blocking buffer and then add None to denote end
let buf = new BlockingQueueAgent<_>(1)
async {
do! iterAsync (Some >> buf.AsyncAdd) input
do! buf.AsyncAdd None
} |> Async.Start
// Read elements from the blocking buffer & return a sequences
let rec loop () =
seq {
match buf.Get() with
| None -> ()
| Some v ->
yield v
yield! loop()
}
loop ()