Product Updater Server .lsl 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. // :CATEGORY:Update
  2. // :NAME:Open Updater
  3. // :AUTHOR:Ferd Frederix
  4. // :KEYWORDS:
  5. // :CREATED:2013-09-06
  6. // :EDITED:2014-02-24
  7. // :ID:586
  8. // :NUM:803
  9. // :REV:1.1
  10. // :WORLD:Second Life, OpenSim
  11. // :DESCRIPTION:
  12. // Grid-wide Updater for products. This is the Server
  13. // :CODE:
  14. // Script by Ferd Frederix
  15. // fred@mitsi.com
  16. // License: CC-BY-NC
  17. // This means you must leave the headers in this script intact, and it is not to be sold by itself, not even for a Linden
  18. // You are allowed to use and sell Products that use this script.
  19. //
  20. // Open Update server
  21. // Rev 1.0 5/24/2013
  22. // Rev 1.1 1/21/2014 missing llUrlUnesacape - Thxxx Linn!
  23. // Put Products in a box inside the prim that has this script. Put the Product Updater scipt in products that get rezzed, and not the box that holds them.
  24. // You must make the name of the box that you put in this server "Name-VN", where N is a version number such as 1, 1.0, 2 and so on.
  25. // The Name must not have a | in it.
  26. // The box MUST have a name followed by -V and a version number
  27. //
  28. // Examples: Horsie-V1.0 ( Same as V1 )
  29. // Horsie-V1 ( Same as V1.0, V1.000 etc. )
  30. // Horsie-V1.1 ( his will be sent if the product is named Horsie-V0.99999 or lower )
  31. // Horsie-V4.1.1 ( This is an illegal number as it has 2 decimals, and will not update as you expect)
  32. // Horsie|From Me-V4.1 ( This is an illegal name as it has a "|" in it)
  33. //////////////////////////////////////////////////////////
  34. // IMPORTANT CONFIGURATION //
  35. //////////////////////////////////////////////////////////
  36. // You MUST put in a UUID from this web site here and put the same UUID in the updater script in your products
  37. // Get one from Latif Khalifa at
  38. // http://gridurl.appspot.com/random
  39. //
  40. string UUID = "92e723e8-3653-451c-816d-23f920cd02c8"; // You MUST change this here and in the products upadter script that you put in your products.
  41. // Debugging and setup things that can be changed
  42. integer debug = FALSE; // Show what is happening in chat
  43. integer ENABLED = TRUE; // If TRUE, issue updates to clients, if FALSE, do everything but actually give inventory
  44. float HoverText = 1.0; // Set to 0.0 to turn hovertext status updates off
  45. //////////////////////////////////////////////////////////
  46. // CODE BEGINS, Move on, nothing here to change //
  47. //////////////////////////////////////////////////////////
  48. // global vars
  49. integer nServed; // how many updates sent, starts at zero
  50. // HTTP-IN and other web traffic stuff
  51. key URLReq = NULL_KEY;
  52. string url; // sop we can release HTTP-In keys
  53. key urlRequestId; // the key of the request for a HTTP-In URL
  54. key http_RequestID; // the key of th4e Post to outselves
  55. integer CHECKTIMER = 600; // run a self-test every 5 minutes. if this fails, request a new URL
  56. RequestHTTPInURL()
  57. {
  58. llSetTimerEvent(0); // Do not run diags unless we have a valid URL
  59. llReleaseURL(url); // there is a limit to the number of URLS, so we always release them.
  60. url = "";
  61. urlRequestId = llRequestURL(); // get a HTTP-In URL
  62. }
  63. DEBUG(string msg)
  64. {
  65. if (debug)
  66. llOwnerSay(llGetScriptName() + " : " + msg);
  67. }
  68. key Request(string URL)
  69. {
  70. llSetText("Registering",<0,0,1>,HoverText); // blue
  71. string url = "http://gridurl.appspot.com/reg?service=" + UUID + "&url=" + llEscapeURL(URL) + "/";
  72. return llHTTPRequest( url, [HTTP_METHOD, "GET"], "");
  73. }
  74. default
  75. {
  76. // When rezzed, lets start everything from scratch
  77. on_rez(integer param)
  78. {
  79. llResetScript();
  80. }
  81. // when reset, we get a HTTP-IN URL. Without this, we can do nothing
  82. state_entry()
  83. {
  84. llSetText("Initializing",<0,0,1>,HoverText); // blue
  85. RequestHTTPInURL();
  86. }
  87. // This event will occur whenever a URL is granted or the web server it created gets a POST or GET
  88. http_request(key id, string method, string body)
  89. {
  90. if (method == URL_REQUEST_GRANTED)
  91. {
  92. DEBUG(body);
  93. url = body; // save body response, which is our actual URL, so we can release it.
  94. llSetText("Update Server is Starting",<0,0,1>,HoverText);
  95. URLReq = Request(body); // send it to the server so the gadgets in the field know where to go to get updates.
  96. llSetTimerEvent(2); // check server just to be certain
  97. }
  98. else if (method == URL_REQUEST_DENIED)
  99. {
  100. llSetText("ERROR: URL request was denied, retrying in 1 minute",<1,0,0>,HoverText);
  101. llSleep(60);
  102. RequestHTTPInURL();
  103. }
  104. else if (id == URLReq)
  105. {
  106. if (body == "OK")
  107. {
  108. llSetText("Test passed ",<0,0,1>,HoverText);
  109. llSleep(1);
  110. }
  111. else
  112. {
  113. llSetText("Unable to register, please check your UUID",<1,0,0>,HoverText);
  114. }
  115. }
  116. else if(method == "GET")
  117. {
  118. DEBUG("GET ACK");
  119. llHTTPResponse(id, 200, "ACK");
  120. }
  121. else if(method == "POST")
  122. {
  123. DEBUG("POST received");
  124. string resp = llGetHTTPHeader(id, "x-query-string");
  125. // Product Name|Ver|UUID|Avatar Name is the message
  126. resp = llUnescapeURL(resp);
  127. DEBUG("Query String = " + resp);
  128. list info = llParseString2List(resp,["|"],[]);
  129. DEBUG(llDumpList2String(info,"|"));
  130. // get rid of the q= at the beginning of the name
  131. string name= llList2String(info,0);
  132. list names = llParseString2List(name,["="],[]);
  133. string shortName = llList2String(names,1);
  134. DEBUG("shortName:" + shortName);
  135. names = llParseString2List(shortName,["-V"],["-V"]);
  136. float VerWanted = (float) llList2String(names,1);
  137. DEBUG("Version of product:" + (string) VerWanted);
  138. string productName = llList2String(names,0);
  139. DEBUG("productName:" + productName);
  140. key Theirkey = (key) llList2String(info,1);
  141. DEBUG("Owner key:" + (string) Theirkey);
  142. string Avatar = llList2String(info,2);
  143. // should look like this for a version 1 Object
  144. // Object-1|1.0|10000000-0000-0000-0000-000000000000|SecondLife OwnerName
  145. integer count = llGetInventoryNumber(INVENTORY_OBJECT);
  146. while (count--)
  147. {
  148. string fullname = llGetInventoryName(INVENTORY_OBJECT,count); // obj 1 = 0
  149. list parts = llParseString2List(fullname,["-V"],["-V"]);
  150. string invName = llList2String(parts,0);
  151. float invVersion = (float) llList2String(parts,1);
  152. DEBUG("Inv Name :" + (string) invName);
  153. DEBUG("Inv Version:" + (string) invVersion);
  154. if (productName == invName && invVersion > VerWanted )
  155. {
  156. DEBUG("Giving:" + invName);
  157. nServed++; // counter for products dispensed
  158. if (ENABLED) llGiveInventory(Theirkey,fullname);
  159. llSetText(Avatar + " got " + fullname + "\nTotal Items Updated:" + (string) nServed, <1,1,1>,1.0 );
  160. }
  161. }
  162. llHTTPResponse(id, 200, "ACK");
  163. }
  164. else
  165. {
  166. llSetText("Unknown command received",<1,0,0>,HoverText);
  167. llHTTPResponse(id, 501, "Not Implemented "+method);
  168. }
  169. }
  170. // This even will run when a web page is fetched
  171. http_response(key request_id, integer status, list metadata, string body)
  172. {
  173. // This would be the response from Grispot that out URL was accepted.
  174. if(URLReq == request_id)
  175. {
  176. URLReq = NULL_KEY;
  177. if(status == 200)
  178. {
  179. llSetText("Server is OK",<0,1,0>,HoverText);
  180. }
  181. else
  182. {
  183. llSetText("The internet is broken - retrying",<1,0,0>,HoverText);
  184. llSleep(60); // be nice
  185. RequestHTTPInURL(); // try again
  186. }
  187. }
  188. // this occurs when we test ourselves. We should have gotten an ACK to keep us happy.
  189. // if no ACK, we need a new URL
  190. else if (request_id == http_RequestID)
  191. {
  192. if (body != "ACK")
  193. {
  194. llSetText("The internet is broken - retrying",<1,0,0>,HoverText);
  195. llSleep(60); // be nice to ourserver, the server has probably run out of URLS.
  196. RequestHTTPInURL();
  197. }
  198. else
  199. {
  200. llSetText("Server is ready",<0,1,0>,HoverText);
  201. }
  202. }
  203. }
  204. // run a self test every so often by GETing from ourselves
  205. // This also resets the timer to CHECKTIMER, as the very first one of these happens at startup in a few seconds.
  206. timer()
  207. {
  208. llSetText("Update Server is checking itself",<0,0,1>,HoverText);
  209. http_RequestID = llHTTPRequest(url,[HTTP_METHOD,"GET"],"");
  210. llSetTimerEvent(CHECKTIMER); // check server just to be certain
  211. }
  212. }