Browse Source

Add sjson streaming example

Fixes #2209.
Marcel Stör 6 years ago
parent
commit
555b5574a2
2 changed files with 77 additions and 2 deletions
  1. 7 2
      docs/en/modules/sjson.md
  2. 70 0
      lua_examples/sjson-streaming.lua

+ 7 - 2
docs/en/modules/sjson.md

@@ -21,6 +21,10 @@ anywhere else in your data structures. A suitable value might be `"\0"`.
 
 
 When encoding a Lua object, if a function is found, then it is invoked (with no arguments) and the (single) returned value is encoded in the place of the function.
 When encoding a Lua object, if a function is found, then it is invoked (with no arguments) and the (single) returned value is encoded in the place of the function.
 
 
+!!! note
+
+    All examples below use in-memory JSON or content read from the SPIFFS file system. However, where a streaming implementation really shines is in fetching large JSON structures from the remote resources and extracting values on-the-fly. An elaborate streaming example can be found in the [`/lua_examples`](../../../lua_examples/sjson-streaming.lua) folder.
+
 ## sjson.encoder()
 ## sjson.encoder()
 
 
 This creates an encoder object that can convert a Lua object into a JSON encoded string.
 This creates an encoder object that can convert a Lua object into a JSON encoded string.
@@ -53,7 +57,8 @@ A string of up to `size` bytes, or `nil` if the encoding is complete and all dat
 #### Example
 #### Example
 The following example prints out (in 64 byte chunks) a JSON encoded string containing the first 4k of every file in the file system. The total string
 The following example prints out (in 64 byte chunks) a JSON encoded string containing the first 4k of every file in the file system. The total string
 can be bigger than the total amount of memory on the NodeMCU.
 can be bigger than the total amount of memory on the NodeMCU.
-```
+
+```lua
 function files() 
 function files() 
    result = {}
    result = {}
    for k,v in pairs(file.list()) do
    for k,v in pairs(file.list()) do
@@ -230,5 +235,5 @@ for k,v in pairs(t) do print(k,v) end
 
 
 ##Constants
 ##Constants
 
 
-There is one constant -- `sjson.NULL` -- which is used in Lua structures to represent the presence of a JSON null.
+There is one constant, `sjson.NULL`, which is used in Lua structures to represent the presence of a JSON null.
 
 

+ 70 - 0
lua_examples/sjson-streaming.lua

@@ -0,0 +1,70 @@
+-- Test sjson and GitHub API
+
+local s = tls.createConnection()
+s:on("connection", function(sck, c)
+  sck:send("GET /repos/nodemcu/nodemcu-firmware/git/trees/master HTTP/1.0\r\nUser-agent: nodemcu/0.1\r\nHost: api.github.com\r\nConnection: close\r\nAccept: application/json\r\n\r\n")
+end)
+
+function startswith(String, Start)
+  return string.sub(String, 1, string.len(Start)) == Start
+end
+
+local seenBlank = false
+local partial
+local wantval = { tree = 1, path = 1, url = 1 }
+-- Make an sjson decoder that only keeps certain fields
+local decoder = sjson.decoder({
+  metatable =
+  {
+    __newindex = function(t, k, v)
+      if wantval[k] or type(k) == "number" then
+        rawset(t, k, v)
+      end
+    end
+  }
+})
+local function handledata(s)
+  decoder:write(s)
+end
+
+-- The receive callback is somewhat gnarly as it has to deal with find the end of the header
+-- and having the newline sequence split across packets
+s:on("receive", function(sck, c)
+  if partial then
+    c = partial .. c
+    partial = nil
+  end
+  if seenBlank then
+    handledata(c)
+    return
+  end
+  while c do
+    if startswith(c, "\r\n") then
+      seenBlank = true
+      c = c:sub(3)
+      handledata(c)
+      return
+    end
+    local s, e = c:find("\r\n")
+    if s then
+      -- Throw away line
+      c = c:sub(e + 1)
+    else
+      partial = c
+      c = nil
+    end
+  end
+end)
+
+local function getresult()
+  local result = decoder:result()
+  -- This gets the resulting decoded object with only the required fields
+  print(result['tree'][4]['path'], "is at",
+    result['tree'][4]['url'])
+end
+
+s:on("disconnection", getresult)
+s:on("reconnection", getresult)
+
+-- Make it all happen!
+s:connect(443, "api.github.com")