aLiYun.lua 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535
  1. --- 模块功能:阿里云物联网套件客户端功能.
  2. -- 目前的产品节点类型仅支持“设备”,设备认证方式支持“一机一密和“一型一密”
  3. -- @module aLiYun
  4. -- @author openLuat
  5. -- @license MIT
  6. -- @copyright openLuat
  7. -- @release 2018.04.16
  8. require"log"
  9. require"http"
  10. require"mqtt"
  11. module(..., package.seeall)
  12. local rrpc_state = false
  13. local sProductKey,sProductSecret,sGetDeviceNameFnc,sGetDeviceSecretFnc,sSetDeviceSecretFnc
  14. local sRegion = "cn-shanghai"
  15. --实例ID,根据此ID来判断是否需要一型一密免预注册认证
  16. local sInstanceId
  17. --连接方式
  18. local sConnectMode,sConnectHost,sConnectPort,sGetClientIdFnc,sGetUserNameFnc,sGetPasswordFnc
  19. local sKeepAlive,sCleanSession,sWill
  20. local isSleep = false--休眠,不去重连服务器
  21. local isAuthSleep =false --休眠,不去重连鉴权
  22. local sErrHandleCo,sErrHandleCb,sErrHandleTmout
  23. local outQueue =
  24. {
  25. SUBSCRIBE = {},
  26. PUBLISH = {},
  27. }
  28. local evtCb = {}
  29. local function insert(type,topic,qos,payload,cbFnc,cbPara)
  30. table.insert(outQueue[type],{t=topic,q=qos,p=payload,cb=cbFnc,para=cbPara})
  31. end
  32. local function remove(type)
  33. if #outQueue[type]>0 then return table.remove(outQueue[type],1) end
  34. end
  35. local function procSubscribe(client)
  36. local i
  37. for i=1,#outQueue["SUBSCRIBE"] do
  38. if not client:subscribe(outQueue["SUBSCRIBE"][i].t,outQueue["SUBSCRIBE"][i].q) then
  39. outQueue["SUBSCRIBE"] = {}
  40. return false,"procSubscribe"
  41. end
  42. end
  43. outQueue["SUBSCRIBE"] = {}
  44. return true
  45. end
  46. local function procReceive(client)
  47. local r,data,s
  48. while true do
  49. r,data,s = client:receive(60000,"aliyun_publish_ind")
  50. --接收到数据
  51. if r and data~="timeout" then
  52. log.info("aLiYun.procReceive",data.topic,string.toHex(data.payload))
  53. --OTA消息
  54. if data.topic=="/ota/device/upgrade/"..sProductKey.."/"..sGetDeviceNameFnc() then
  55. if aLiYunOta and aLiYunOta.upgrade then
  56. aLiYunOta.upgrade(data.payload)
  57. end
  58. --其他消息
  59. else
  60. if evtCb["receive"] then evtCb["receive"](data.topic,data.qos,data.payload) end
  61. end
  62. --如果有等待发送的数据,则立即退出本循环
  63. if #outQueue["PUBLISH"]>0 then
  64. return true,"procReceive"
  65. else
  66. if sErrHandleCo then coroutine.resume(sErrHandleCo,"feed") end
  67. end
  68. elseif data == "aliyun_publish_ind" and s:find("disconnect") then--主动断开
  69. client:disconnect()
  70. return false,"procReceive"
  71. elseif data == "aliyun_publish_ind" and s:find("send") then--来数据要发了
  72. log.info("aliyun aliyun_publish_ind")
  73. return true,"procReceive"
  74. else
  75. break
  76. end
  77. end
  78. return data=="timeout" or r,"procReceive"
  79. end
  80. local function procSend(client)
  81. if not procSubscribe(client) then
  82. return false,"procSubscribe"
  83. end
  84. while #outQueue["PUBLISH"]>0 do
  85. local item = table.remove(outQueue["PUBLISH"],1)
  86. local result = client:publish(item.t,item.p,item.q)
  87. if item.cb then item.cb(result,item.para) end
  88. if not result then
  89. return false,"procSend"
  90. else
  91. if sErrHandleCo then coroutine.resume(sErrHandleCo,"feed") end
  92. end
  93. end
  94. return true,"procSend"
  95. end
  96. --- 断开阿里云物联网套件的连接,并且不再重连
  97. -- @return nil
  98. -- @usage
  99. -- aLiYun.sleep()
  100. function sleep()
  101. isSleep = true
  102. log.info("aLiYun.sleep","open sleep, stop try reconnect")
  103. sys.publish("aliyun_publish_ind","disconnect")
  104. end
  105. --- 重新打开阿里云物联网套件的连接
  106. -- @return nil
  107. -- @usage
  108. -- aLiYun.wakeup()
  109. function wakeup()
  110. isSleep = false
  111. sys.publish("ALITUN_WAKEUP")
  112. log.info("aLiYun.wakeup","exit sleep")
  113. end
  114. --- 查看打开阿里云物联网套件的是否允许连接状态
  115. -- @return bool 是否允许连接阿里云
  116. -- @usage
  117. -- local ar = aLiYun.sleepStatus()
  118. function sleepStatus()
  119. return isSleep
  120. end
  121. --- 断开阿里云物联网套件的鉴权连接,并且不再重连
  122. -- @return nil
  123. -- @usage
  124. -- aLiYun.Authsleep()
  125. function Authsleep()
  126. isAuthSleep = true
  127. log.info("aLiYun.Authsleep","open sleep, stop try reconnect")
  128. sys.publish("aliyun_publish_ind","disconnect")
  129. end
  130. --- 重新打开阿里云物联网套件的鉴权连接
  131. -- @return nil
  132. -- @usage
  133. -- aLiYun.Authwakeup()
  134. function Authwakeup()
  135. isAuthSleep = false
  136. sys.publish("ALITUN_Auth_WAKEUP")
  137. log.info("aLiYun.auth_wakeup","exit sleep")
  138. end
  139. --- 查看打开阿里云物联网套件的是否允许鉴权状态
  140. -- @return bool 是否允许连接阿里云
  141. -- @usage
  142. -- local ar = aLiYun.AuthSleepStatus()
  143. function AuthSleepStatus()
  144. return isAuthSleep
  145. end
  146. function clientDataTask(host,tPorts,clientId,user,password)
  147. local retryConnectCnt = 0
  148. local portIdx = 0
  149. while true do
  150. if isSleep then sys.waitUntil("ALITUN_WAKEUP") end
  151. if not socket.isReady() then
  152. retryConnectCnt = 0
  153. --等待网络环境准备就绪,超时时间是5分钟
  154. sys.waitUntil("IP_READY_IND",300000)
  155. end
  156. if socket.isReady() then
  157. local mqttClient = mqtt.client(clientId,sKeepAlive or 240,user,password,sCleanSession,sWill)
  158. portIdx = portIdx%(#tPorts)+1
  159. if mqttClient:connect(host,tonumber(tPorts[portIdx]),sConnectMode=="direct" and "tcp" or "tcp_ssl") then
  160. retryConnectCnt = 0
  161. if aLiYunOta and aLiYunOta.connectCb then aLiYunOta.connectCb(true,sProductKey,sGetDeviceNameFnc()) end
  162. if evtCb["connect"] then evtCb["connect"](true) end
  163. local result,prompt = procSubscribe(mqttClient)
  164. if result then
  165. local procs,k,v = {procSend,procReceive}
  166. while true do
  167. for k,v in pairs(procs) do
  168. result,prompt = v(mqttClient)
  169. if not result then log.warn("aLiYun.clientDataTask."..prompt.." error") break end
  170. end
  171. if not result then break end
  172. if sErrHandleCo then coroutine.resume(sErrHandleCo,"feed") end
  173. end
  174. else
  175. log.warn("aLiYun.clientDataTask."..prompt.." error")
  176. end
  177. while #outQueue["PUBLISH"]>0 do
  178. local item = table.remove(outQueue["PUBLISH"],1)
  179. if item.cb then item.cb(false,item.para) end
  180. end
  181. if aLiYunOta and aLiYunOta.connectCb then aLiYunOta.connectCb(false,sProductKey,sGetDeviceNameFnc()) end
  182. if evtCb["connect"] then evtCb["connect"](false) end
  183. else
  184. retryConnectCnt = retryConnectCnt+1
  185. if evtCb["reconnect"] then evtCb["reconnect"]() end
  186. end
  187. mqttClient:disconnect()
  188. if retryConnectCnt>=5 then link.shut() retryConnectCnt=0 end
  189. sys.wait(2000)
  190. else
  191. --进入飞行模式,20秒之后,退出飞行模式
  192. net.switchFly(true)
  193. sys.wait(20000)
  194. net.switchFly(false)
  195. end
  196. end
  197. end
  198. local function getDeviceSecretCb(result,prompt,head,body)
  199. log.info("aLiYun.getDeviceSecretCb",result,prompt)
  200. if result and body then
  201. local tJsonDecode = json.decode(body)
  202. if tJsonDecode and tJsonDecode["data"] and tJsonDecode["data"]["deviceSecret"] and tJsonDecode["data"]["deviceSecret"]~="" then
  203. sSetDeviceSecretFnc(tJsonDecode["data"]["deviceSecret"])
  204. end
  205. end
  206. sys.publish("GetDeviceSecretEnd")
  207. end
  208. local function authCbFnc(result,statusCode,head,body)
  209. log.info("aLiYun.authCbFnc",result,statusCode,body)
  210. sys.publish("ALIYUN_AUTH_IND",result,statusCode,body)
  211. end
  212. local function getBody(tag)
  213. if tag=="auth" then
  214. local data = "clientId"..sGetDeviceNameFnc().."deviceName"..sGetDeviceNameFnc().."productKey"..sProductKey
  215. local signKey= sGetDeviceSecretFnc()
  216. local sign = crypto.hmac_md5(data,data:len(),signKey,signKey:len())
  217. return "productKey="..sProductKey.."&sign="..sign.."&clientId="..sGetDeviceNameFnc().."&deviceName="..sGetDeviceNameFnc()
  218. elseif tag=="register" then
  219. local random=rtos.tick()
  220. local data = "deviceName"..sGetDeviceNameFnc().."productKey"..sProductKey.."random"..random
  221. local sign = crypto.hmac_md5(data,data:len(),sProductSecret,sProductSecret:len())
  222. return "productKey="..sProductKey.."&deviceName="..sGetDeviceNameFnc().."&random="..random.."&sign="..sign.."&signMethod=HmacMD5"
  223. end
  224. end
  225. function clientAuthTask()
  226. while not socket.isReady() do sys.waitUntil("IP_READY_IND") end
  227. while true do
  228. if isAuthSleep then sys.waitUntil("ALITUN_Auth_WAKEUP") end
  229. local retryCnt,authBody = 0,getBody("auth")
  230. while true do
  231. http.request("POST",
  232. "https://iot-auth."..sRegion..".aliyuncs.com/auth/devicename",
  233. nil,{["Content-Type"]="application/x-www-form-urlencoded"},authBody,20000,authCbFnc)
  234. local _,result,statusCode,body = sys.waitUntil("ALIYUN_AUTH_IND")
  235. --log.info("aLiYun.clientAuthTask1",result and statusCode=="200",body)
  236. local invalidSign
  237. if result and statusCode=="200" then
  238. local tJsonDecode,result = json.decode(body)
  239. --log.info("aLiYun.clientAuthTask2",result,tJsonDecode["message"],tJsonDecode["data"])
  240. if result and tJsonDecode["message"]=="success" and tJsonDecode["data"] and type(tJsonDecode["data"])=="table" then
  241. --log.info("aLiYun.clientAuthTask3",tJsonDecode["data"]["iotId"],tJsonDecode["data"]["iotToken"])
  242. if tJsonDecode["data"]["iotId"] and tJsonDecode["data"]["iotId"]~="" and tJsonDecode["data"]["iotToken"] and tJsonDecode["data"]["iotToken"]~="" then
  243. if evtCb["auth"] then evtCb["auth"](true) end
  244. local ports,host,returnMqtt = {}
  245. if tJsonDecode["data"]["resources"] and type(tJsonDecode["data"]["resources"])=="table" then
  246. if tJsonDecode["data"]["resources"]["mqtt"] then
  247. returnMqtt,host = true,tJsonDecode["data"]["resources"]["mqtt"]["host"]
  248. table.insert(ports,tJsonDecode["data"]["resources"]["mqtt"]["port"])
  249. end
  250. end
  251. sys.taskInit(clientDataTask,returnMqtt and host or sProductKey..".iot-as-mqtt."..sRegion..".aliyuncs.com",#ports~=0 and ports or {1883},sGetDeviceNameFnc(),tJsonDecode["data"]["iotId"],tJsonDecode["data"]["iotToken"])
  252. return
  253. end
  254. end
  255. if body and body:match("invalid sign") then
  256. invalidSign = true
  257. end
  258. end
  259. if sProductSecret and invalidSign then
  260. http.request("POST","https://iot-auth."..sRegion..".aliyuncs.com/auth/register/device",nil,
  261. {['Content-Type']="application/x-www-form-urlencoded"},
  262. getBody("register"),30000,getDeviceSecretCb)
  263. sys.waitUntil("GetDeviceSecretEnd")
  264. sys.wait(1000)
  265. authBody = getBody("auth")
  266. end
  267. retryCnt = retryCnt+1
  268. if retryCnt==3 then
  269. break
  270. end
  271. end
  272. if evtCb["auth"] then evtCb["auth"](false) end
  273. sys.wait(5000)
  274. end
  275. end
  276. local function directProc()
  277. log.info("rrpc",rrpc_state)
  278. local clientId
  279. clientId = (sGetClientIdFnc and sGetClientIdFnc() or sGetDeviceNameFnc()).."|securemode=3,timestamp=2524608000000,signmethod=hmacsha1"..(rrpc_state and ",ext=1" or "").."|"
  280. log.info("clientId",clientId)
  281. local userName = sGetUserNameFnc and sGetUserNameFnc() or (sGetDeviceNameFnc().."&"..sProductKey)
  282. local password
  283. if sGetPasswordFnc then
  284. password = sGetPasswordFnc()
  285. else
  286. local content = "clientId"..(sGetClientIdFnc and sGetClientIdFnc() or sGetDeviceNameFnc()).."deviceName"..sGetDeviceNameFnc().."productKey"..sProductKey.."timestamp2524608000000"
  287. local signKey= sGetDeviceSecretFnc()
  288. password = crypto.hmac_sha1(content,content:len(),signKey,signKey:len())
  289. end
  290. log.info("aLiYun.directProc",clientId,userName,password)
  291. sys.taskInit(clientDataTask,sConnectHost or (sProductKey..".iot-as-mqtt."..sRegion..".aliyuncs.com"),{sConnectPort},clientId,userName,password)
  292. end
  293. local function clientDirectTask()
  294. while not socket.isReady() do sys.waitUntil("IP_READY_IND") end
  295. local tm=os.time()
  296. --一机一密
  297. if sProductSecret==nil then
  298. directProc()
  299. --一型一密
  300. else
  301. local clientId
  302. --预注册
  303. if sInstanceId==nil then
  304. clientId = (sGetClientIdFnc and sGetClientIdFnc() or sGetDeviceNameFnc()).."|securemode=2,authType=register,random="..tm..",signmethod=hmacsha1"..(rrpc_state and ",ext=1" or "").."|"
  305. --免预注册
  306. else
  307. clientId = (sGetClientIdFnc and sGetClientIdFnc() or sGetDeviceNameFnc()).."|securemode=-2,authType=regnwl,random="..tm..",signmethod=hmacsha1,instanceId="..sInstanceId.."|"
  308. end
  309. local userName = sGetUserNameFnc and sGetUserNameFnc() or (sGetDeviceNameFnc().."&"..sProductKey)
  310. local content = "deviceName"..sGetDeviceNameFnc().."productKey"..sProductKey.."random"..tm
  311. local signKey= sProductSecret
  312. local password = crypto.hmac_sha1(content,content:len(),signKey,signKey:len())
  313. while true do
  314. if isAuthSleep then sys.waitUntil("ALITUN_Auth_WAKEUP") end
  315. local mqttClient = mqtt.client(clientId,sKeepAlive or 240,userName,password)
  316. local r,ack = mqttClient:connect(sConnectHost,sConnectPort,"tcp_ssl")
  317. if r then
  318. local result,data = mqttClient:receive(60000)
  319. --接收到数据
  320. if result then
  321. log.info("aLiYun.clientDirectTask register rsp",data.topic,data.payload)
  322. local tJsonDecode,res = json.decode(data.payload)
  323. if res and tJsonDecode["deviceName"] and tJsonDecode["deviceSecret"] then
  324. sSetDeviceSecretFnc(tJsonDecode["deviceSecret"])
  325. sys.wait(1000)
  326. mqttClient:disconnect()
  327. directProc()
  328. break
  329. end
  330. end
  331. end
  332. mqttClient:disconnect()
  333. if ack==4 then
  334. directProc()
  335. break
  336. else
  337. sys.wait(5000)
  338. end
  339. end
  340. end
  341. end
  342. --- 配置阿里云物联网套件的产品信息和设备信息
  343. -- @string productKey 产品标识
  344. -- @string[opt=nil] productSecret 产品密钥
  345. -- 一机一密认证方案时,此参数传入nil
  346. -- 一型一密认证方案时,此参数传入真实的产品密钥
  347. -- @function getDeviceNameFnc 获取设备名称的函数
  348. -- @function getDeviceSecretFnc 获取设备密钥的函数
  349. -- @function[opt=nil] setDeviceSecretFnc 设置设备密钥的函数,一型一密认证方案才需要此参数
  350. -- @return nil
  351. -- @usage
  352. -- aLiYun.setup("b0FMK1Ga5cp",nil,getDeviceNameFnc,getDeviceSecretFnc)
  353. -- aLiYun.setup("a1AoVqkCIbG","7eCdPyR6fYPntFcM",getDeviceNameFnc,getDeviceSecretFnc,setDeviceSecretFnc)
  354. function setup(productKey,productSecret,getDeviceNameFnc,getDeviceSecretFnc,setDeviceSecretFnc)
  355. sProductKey,sProductSecret,sGetDeviceNameFnc,sGetDeviceSecretFnc,sSetDeviceSecretFnc = productKey,productSecret,getDeviceNameFnc,getDeviceSecretFnc,setDeviceSecretFnc
  356. if sConnectMode=="direct" then
  357. sys.taskInit(clientDirectTask)
  358. else
  359. sys.taskInit(clientAuthTask)
  360. end
  361. end
  362. --- 设置MQTT数据通道的参数
  363. -- @number[opt=1] cleanSession 1/0
  364. -- @table[opt=nil] will 遗嘱参数,格式为{qos=,retain=,topic=,payload=}
  365. -- @number[opt=240] keepAlive 单位秒
  366. -- @return nil
  367. -- @usage
  368. -- aLiYun.setMqtt(0)
  369. -- aLiYun.setMqtt(1,{qos=0,retain=1,topic="/willTopic",payload="will payload"})
  370. -- aLiYun.setMqtt(1,{qos=0,retain=1,topic="/willTopic",payload="will payload"},120)
  371. function setMqtt(cleanSession,will,keepAlive)
  372. sCleanSession,sWill,sKeepAlive = cleanSession,will,keepAlive
  373. end
  374. --- 设置地域region id
  375. -- @string region 地域id字符串,参考:https://help.aliyun.com/document_detail/40654.html?spm=a2c4g.11186623.2.16.c0a63f82Z7qCtA#concept-h4v-j5k-xdb
  376. -- @return nil
  377. -- @usage
  378. -- 设置华北1:aLiYun.setRegion("cn-qingdao")
  379. -- 设置华东1:aLiYun.setRegion("cn-hangzhou")
  380. -- 设置华南1:aLiYun.setRegion("cn-shenzhen")
  381. function setRegion(region)
  382. sRegion = region
  383. end
  384. -- 设置企业版实例id
  385. -- @string id,企业版实例id
  386. -- @return nil
  387. -- @usage
  388. -- aLiYun.setInstanceId(iot-060a1234")
  389. function setInstanceId(id)
  390. sInstanceId = id
  391. end
  392. --- 设置连接方式
  393. -- @string mode 连接方式,支持如下几种方式:
  394. -- "direct"表示MQTT-TCP直连
  395. -- @string host 服务器地址
  396. -- @number port 服务器端口
  397. -- @function getClientIdFnc 获取mqtt,client,id的函数
  398. -- @function getUserNameFnc 获取mqtt,client,userName的函数
  399. -- @function getPasswordFnc 获取mqtt,client,password的函数
  400. -- @return nil
  401. -- @usage
  402. -- 设置为MQTT-TCP直连:aLiYun.setConnectMode("direct")
  403. function setConnectMode(mode,host,port,getClientIdFnc,getUserNameFnc,getPasswordFnc)
  404. sConnectMode = mode
  405. sConnectHost = host
  406. sConnectPort = port or 1883
  407. sGetClientIdFnc = getClientIdFnc
  408. sGetUserNameFnc = getUserNameFnc
  409. sGetPasswordFnc = getPasswordFnc
  410. end
  411. --- 订阅主题
  412. -- @param topic string或者table类型,一个主题时为string类型,多个主题时为table类型,主题内容为UTF8编码
  413. -- @param qos number或者nil,topic为一个主题时,qos为number类型(0/1,默认0);topic为多个主题时,qos为nil
  414. -- @return nil
  415. -- @usage
  416. -- aLiYun.subscribe("/b0FMK1Ga5cp/862991234567890/get", 0)
  417. -- aLiYun.subscribe({["/b0FMK1Ga5cp/862991234567890/get"] = 0, ["/b0FMK1Ga5cp/862991234567890/get"] = 1})
  418. function subscribe(topic,qos)
  419. insert("SUBSCRIBE",topic,qos)
  420. sys.publish("aliyun_publish_ind","send")
  421. end
  422. --- 发布一条消息
  423. -- @string topic UTF8编码的主题
  424. -- @string payload 负载
  425. -- @number[opt=0] qos 质量等级,0/1,默认0
  426. -- @function[opt=nil] cbFnc 消息发布结果的回调函数
  427. -- 回调函数的调用形式为:cbFnc(result,cbPara)。result为true表示发布成功,false或者nil表示订阅失败;cbPara为本接口中的第5个参数
  428. -- @param[opt=nil] cbPara 消息发布结果回调函数的回调参数
  429. -- @return nil
  430. -- @usage
  431. -- aLiYun.publish("/b0FMK1Ga5cp/862991234567890/update","test",0)
  432. -- aLiYun.publish("/b0FMK1Ga5cp/862991234567890/update","test",1,cbFnc,"cbFncPara")
  433. function publish(topic,payload,qos,cbFnc,cbPara)
  434. insert("PUBLISH",topic,qos,payload,cbFnc,cbPara)
  435. sys.publish("aliyun_publish_ind","send")
  436. log.info("aliyun aliyun_publish_ind","publish")
  437. end
  438. --- 注册事件的处理函数
  439. -- @string evt 事件
  440. -- "auth"表示鉴权服务器认证结果事件
  441. -- "connect"表示接入服务器连接结果事件
  442. -- "reconnect"表示重连事件
  443. -- "receive"表示接收到接入服务器的消息事件
  444. -- @function cbFnc 事件的处理函数
  445. -- 当evt为"auth"时,cbFnc的调用形式为:cbFnc(result),result为true表示认证成功,false或者nil表示认证失败
  446. -- 当evt为"connect"时,cbFnc的调用形式为:cbFnc(result),result为true表示连接成功,false或者nil表示连接失败
  447. -- 当evt为"receive"时,cbFnc的调用形式为:cbFnc(topic,qos,payload),topic为UTF8编码的主题(string类型),qos为质量等级(number类型),payload为原始编码的负载(string类型)
  448. -- 当evt为"reconnect"时,cbFnc的调用形式为:cbFnc(),表示lib中在自动重连阿里云服务器
  449. -- @return nil
  450. -- @usage
  451. -- aLiYun.on("connect",cbFnc)
  452. function on(evt,cbFnc)
  453. evtCb[evt] = cbFnc
  454. end
  455. --- 设置阿里云task连续一段时间工作异常的处理程序
  456. -- @function cbFnc 异常处理函数,cbFnc的调用形式为:cbFnc()
  457. -- @number[opt=150] tmout 连续工作异常的时间,当连续异常到达这个时间之后,会调用cbFnc()
  458. -- @return nil
  459. -- @usage
  460. -- aLiYun.setErrHandle(function() sys.restart("ALIYUN_TASK_INACTIVE") end, 300)
  461. function setErrHandle(cbFnc,tmout)
  462. sErrHandleCb = cbFnc
  463. sErrHandleTmout = tmout or 150
  464. if not sErrHandleCo then
  465. sErrHandleCo = sys.taskInit(function()
  466. while true do
  467. if sys.wait(sErrHandleTmout*1000) == nil then
  468. if not isSleep then
  469. sErrHandleCb()
  470. end
  471. end
  472. end
  473. end)
  474. end
  475. end
  476. function rrpcUseCustomTopic(state)
  477. rrpc_state = state
  478. end