ruleset temp_acct_mgr { meta { shares __testing, oldECI } global { __testing = { "queries": [ { "name": "__testing" }, { "name": "oldECI", "args": [ "p" ] } ], "events": [ { "domain": "owner", "type": "eci_requested", "attrs": [ "owner_id" ] }, { "domain": "owner", "type": "need_sync" } ] } skyPre = meta:host + "/sky/cloud/"; skyPost = "/io.picolabs.visual_params/dname"; validMethod = function(raw) { raw == "password" => raw | raw == "code" => raw | "password" } ownerIdForPico = function(p) { ent:owners.filter(function(v){v{"pico_id"} == p}).keys()[0] } oldECI = function(p) { owner_id = ownerIdForPico(p); ent:owners{[owner_id,"eci"]}; } } rule owner_initialize { select when owner need_sync or owner creation or owner eci_requested or pico ruleset_added if not ent:owners then noop(); fired { ent:owners := {}; } } rule pico_ruleset_added { select when pico ruleset_added rid re#temp_acct_mgr# every { engine:installRuleset(url="temp_acct.krl", base=meta:rulesetURI); engine:newChannel(name=time:now(),type="to owner") setting(new_channel); } fired { raise owner event "admin" attributes { "txnId": meta:txnId }; ent:owners{"Root"} := { "pico_id": meta:picoId, "eci": new_channel{"id"}, "dname": "Root Pico", "method": "password" }; } } rule owner_need_sync { select when owner need_sync foreach engine:listChildren() setting (pico_id) pre { old_eci = oldECI(pico_id); use_eci = old_eci || engine:listChannels(pico_id)[0]{"id"} dname = http:get(skyPre+use_eci+skyPost){"content"}.decode(); owner_id = ownerIdForPico(pico_id) || dname; raw = http:get(skyPre+use_eci+"/temp_acct/method"){"content"}.decode(); method = validMethod(raw.klog("RAW_METHOD")); } engine:newChannel(pico_id,time:now(),"to owner") setting(new_channel); always { ent:owners{owner_id} := { "pico_id": pico_id, "eci": new_channel{"id"}, "dname": dname, "method": method }; raise owner event "channel_expiration" attributes {"eci":old_eci} if old_eci } } rule owner_channel_expiration { select when owner channel_expiration engine:removeChannel(event:attr("eci")); } rule owner_creation_owner_id_uniqueness_guard { select when owner creation pre { owner_id = event:attr("owner_id"); } if ent:owners >< owner_id then send_directive("owner_id already in use",{"owner_id": owner_id}); fired { last; } } rule owner_creation { select when owner creation fired { raise pico event "new_child_request" attributes event:attrs(); } } rule pico_new_child_created { select when pico new_child_created pre { child_id = event:attr("id"); child_eci = event:attr("eci"); rs_attrs = event:attr("rs_attrs"); owner_id = rs_attrs{"owner_id"}; method = rs_attrs{"method"}; code = method == "code"; dname = rs_attrs{"dname"} || owner_id; } every { engine:installRuleset(child_id, url="temp_acct.krl", base=meta:rulesetURI); event:send({"eci":child_eci, "domain":"owner", "type":"creation", "attrs":rs_attrs}); engine:newChannel(child_id,time:now(),"to owner") setting(new_channel); // CHANGE? send_directive( "new owner pico", { "owner_id": owner_id, "pico_id": child_id, "eci": new_channel{"id"}, "method": method}); } always { raise owner event "new_owner_pico_with_code" attributes rs_attrs.put({"owner_pico_id":child_id}) if code; ent:owners{owner_id} := { "pico_id": child_id, "eci": new_channel{"id"}, "dname": dname, "method": method }; } } rule owner_new_owner_pico_with_code { select when owner new_owner_pico_with_code pre { owner_pico_id = event:attr("owner_pico_id"); } every { // CHANGE? engine:newChannel(owner_pico_id,"code query","secret") setting(code_query_channel); send_directive("new owner pico code query channel", event:attrs().put("eci",code_query_channel{"id"})); } } rule find_owner_pico_by_pico_id { select when owner eci_requested pre { pico_id = event:attr("owner_id"); looks_right = pico_id.length() == 25 && pico_id.ord() == "c".ord(); owner_id = ownerIdForPico(pico_id); entry = ent:owners{owner_id}; eci = entry{"eci"}; options = {"owner_id":owner_id,"pico_id":pico_id,"eci":eci,"method":"did"}; } if looks_right && eci then send_directive("here it is",options); fired { last; } } rule find_owner_pico_by_pico_id_only { select when owner eci_requested pre { pico_id = event:attr("owner_id"); looks_right = pico_id.length() == 25 && pico_id.ord() == "c".ord(); is_my_child = engine:listChildren() >< pico_id; options = {"pico_id":pico_id,"method":"did"}; } if looks_right && is_my_child then every { engine:newChannel(pico_id,time:now(),"to owner") setting(new_channel); send_directive("here it is",options.put({"eci":new_channel{"id"}})); } fired { last; } } rule find_owner_pico_by_name { select when owner eci_requested pre { owner_id = event:attr("owner_id"); entry = ent:owners{owner_id}; pico_id = entry{"pico_id"}; eci = entry{"eci"}; method = entry{"method"}; nonce = random:word(); options = {"owner_id":owner_id,"pico_id":pico_id,"eci":eci,"method":method,"nonce":nonce}; } if eci then every { send_directive("here it is",options); event:send({"eci":eci, "domain":"owner", "type":"eci_provided", "attrs":options}); } fired { last; ent:lastOne := options; } } rule owner_pico_not_found { select when owner eci_requested if event:attr("owner_id") then send_directive("here it is",{"owner_id":event:attr("owner_id"),"method":"password"}); fired { last; } } rule owner_pico_not_found_options { select when owner eci_requested send_directive("options",{"immediateLogin":true,"rid":meta:rid}); } rule pico_child_deleted { select when information child_deleted pre { child_id = event:attr("id"); owner_id = ent:owners.filter(function(v){v{"pico_id"}==child_id}).keys()[0]; } if owner_id then noop(); fired { ent:owners{owner_id} := null; } } }