Join us in Outworldz at www.outworldz.com:9000 or follow us:

Search dozens of selected web sites for OpenSim and LSL script

New! Script Meta-Search will search thousands of scripts here and at other sites for LSL or Opensim scripts.
Loading

Want to add a script or a project? Upload it and a half million people will see it and your name here this year.

Home   Show All
Category: Contributor: Creator
Viewer 2 Reverse_Ajax__Longpolling_the_HTTPi  

Reverse_Ajax__Longpolling_the_HTTPi

# This "server-push" technique using lon...

Category: Viewer 2
By : Becky Pippen
Created: 2010-09-02 Edited: 2010-09-02
Worlds: Second Life

the Zip file

Download all files for Reverse_Ajax__Longpolling_the_HTTPi
Contents are in zip format, with .LSL (text) source code and LSLEdit (text + Solution) formats.
Get file # 1. Reverse_Ajax__Longpolling_the_HTTPi_1.lsl
Get file # 2. Reverse_Ajax__Longpolling_the_HTTPi_2.lsl
1 // Reverse Ajax: Long-polling HTTP-in.
2 // Becky Pippen, 2010, contributed to the public domain.
3
4 integer face = 4; // Prim face for Shared Media
5
6 string myURL; // HTTP-in URL
7 key inId = NULL_KEY; // GET request id
8 list msgQueue = []; // strings of Javascript
9
10 // url is our own HTTP-in url.
11 // This sets up a bootloader web page like this:
12 // <html><body>
13 // <div><script id='sc'></script></div>
14 // <script> callbacks and poll.beg() defined here </script>
15 // <button onclick=poll.beg()>Start</button>
16 // <div id='dv'></div>
17 // </body></html>
18 // When the button is pressed, the JS code sets src= on script#sc
19 // and reattaches the script element to the parent <div> element which
20 // initiates a GET to the prim's HTTP-in port
21 //
22 setDataURI(string url)
23 {
24 string dataURI = "data:text/html,
25 <!DOCTYPE HTML><html><body><div><script id='sc'></script></div><script>
26 var poll=function(){var sc=document.getElementById('sc'),t2,seq=0,s0;return{
27 beg:function(){s0=document.createElement('script');s0.onload=poll.end;t2=setTimeout('poll.end()',20000);
28 s0.src='" + url + "/?r='+(seq++);sc.parentNode.replaceChild(s0,sc);sc=s0;},
29 end:function(){clearTimeout(t2);t2=null;sc.onload=null;setTimeout('poll.beg()',500);},};}();</script>
30 <button id='btn'onclick=poll.beg()>Start</button><div id='dv'></div></body></html>";
31
32 llSetPrimMediaParams(face, [PRIM_MEDIA_CURRENT_URL, dataURI]);
33 }
34
35 // Returns zero or more queued messages. Assumes no single message is
36 // longer than MAX_SIZE_CHARS (will hang if there is)
37 //
38 string popQueuedMessages()
39 {
40 string totalMsg = "";
41 integer totalMsgSize = 0;
42 string nextMsg = "";
43 integer nextMsgSize = 0;
44
45 // HTTP response bodies are limited to 2048 bytes after encoding
46 // in UTF-8. LSL string sizes are measured in characters, which,
47 // in UTF-8, use one byte (for ASCII chars), two bytes (most Latin-1),
48 // or three bytes (a few international characters). So, unless
49 // you re-write this section so that it measures UTF-8 size, keep
50 // MAX_SIZE_CHARS small enough so the text will fit in a response body.
51 //
52 integer MAX_SIZE_CHARS = 1000; // Max HTTP body size
53
54 integer numMessagesQueued = llGetListLength(msgQueue);
55 integer count = 0;
56 integer done = FALSE;
57 while(!done && count < numMessagesQueued) {
58 nextMsg = llList2String(msgQueue, count);
59 nextMsgSize = llStringLength(nextMsg);
60
61 if(totalMsgSize + nextMsgSize < MAX_SIZE_CHARS) {
62 totalMsg += nextMsg;
63 totalMsgSize += nextMsgSize;
64 ++count;
65 } else {
66 done = TRUE;
67 }
68 }
69
70 // Delete the messages from the queue that we're going to send:
71 if(count > 0) {
72 msgQueue = llDeleteSubList(msgQueue, 0, count - 1);
73 }
74
75 return totalMsg;
76 }
77
78 // Called when there are previous messages still queued, or if there
79 // is no GET request currently open to respond to.
80 //
81 pushMessageToSend(string msg)
82 {
83 msgQueue = msgQueue + [msg]; // last element is the last one stacked
84
85 // See if we can send some messages now:
86 if(inId != NULL_KEY) {
87 llHTTPResponse(inId, 200, popQueuedMessages());
88 inId = NULL_KEY;
89 } // else wait for the next incoming GET request
90 }
91
92 // Replaces all occurrences of 'from' with 'to' in 'src'
93 // From http://snipplr.com/view/13279/lslstrreplace/
94 //
95 string str_replace(string subject, string search, string replace)
96 {
97 return llDumpList2String(llParseStringKeepNulls(subject, [search], []), replace);
98 }
99
100 // Optionally filter out characters in text that would mess up the
101 // web page display. This demo just escapes ' and " and adds a space after '<'.
102 //
103 string addSlashes(string s)
104 {
105 return str_replace(str_replace(str_replace(s, "<", "< "), "\"", "\\\""), "'", "\\\'");
106 }
107
108 // This is the main interface for LSL to control the Shared Media web page.
109 // The messages we send consist of Javascript function statements that the
110 // browser will evaluate and execute in the context of the web page.
111 // See sendMessageF() for a similar function with macro replacement.
112 //
113 sendMessage(string msg)
114 {
115 // Test for the easy case: if there are no other messages waiting
116 // in the queue, and if there is an open GET connection, then just
117 // respond immediately:
118
119 if(llGetListLength(msgQueue) == 0 && inId != NULL_KEY) {
120 // Nothing in the queue and an open GET, so respond immediately:
121 llHTTPResponse(inId, 200, msg);
122 inId = NULL_KEY;
123 } else {
124 pushMessageToSend(msg);
125 }
126 }
127
128 // Same as sendMessage() but with macro replacements. For each nth string
129 // element in replacements, replace all occurrences of {@n}. For example,
130 // sendMessageF( "alert('{@0} {@1}!')", ["Hello", "World"] );
131 // will send "alert('Hello World!')" to the web browser.
132 //
133 sendMessageF(string msg, list replacements)
134 {
135 integer numrepl = llGetListLength(replacements);
136 integer i;
137 for (i = 0; i < numrepl; ++i) {
138 msg = str_replace(msg, "{@" + (string)i + "}", llList2String(replacements, i));
139 }
140
141 sendMessage(msg);
142 }
143
144 // Chat logger demo: writes a new <tr> table row to the web page
145 // for every line of open chat it hears.
146 //
147 webAppInit()
148 {
149 string msg;
150 string m0;
151
152 // First, send over a few handy function definitions:
153
154 msg = "function $$(t) { return document.getElementsByTagName(t)[0]; };";
155 msg += "function h() { return $$('head'); };";
156 msg += "function b() { return $$('body'); };";
157 msg += "function e(id) { return document.getElementById(id); };";
158 sendMessage(msg);
159
160 // Send some CSS. WebKit is sensitive about appending <style> elements
161 // to <head>, so we'll append it to an existing <div> tag in <body> instead.
162
163 msg = "e('dv').innerHTML += \"{@0}\";";
164 m0 = "<style>td:nth-child(2) { text-align:right } tr:nth-child(odd) { background-color:#f8e8f8 }</style>";
165 sendMessageF(msg, [m0]);
166
167 // Write a <table> element into element div#dv. The lines of chat will
168 // become rows in this table appended to tbody#tbd
169
170 msg = "e('dv').innerHTML += \"{@0}\";";
171 m0 = "<table><tbody id='tbd'></tbody></table>";
172 sendMessageF(msg, [m0]);
173
174 llListen(0, "", NULL_KEY, "");
175 }
176
177 default
178 {
180 {
181 llClearPrimMedia(face);
183
184 webAppInit();
185 }
186
187 http_request(key id, string method, string body)
188 {
189 if(method == URL_REQUEST_GRANTED) {
190 myURL = body;
191 llOwnerSay("myURL=" + myURL);
192 setDataURI(myURL);
193 } else if(method == "GET") {
194 // Either send some queued messages now with llHTTPResponse(),
195 // or if there's nothing to do now, save the GET id and
196 // wait for somebody to call sendMessage().
197 if(llGetListLength(msgQueue) > 0) {
198 llHTTPResponse(id, 200, popQueuedMessages());
199 inId = NULL_KEY;
200 } else {
201 inId = id;
202 }
203 }
204 }
205
206 // When we hear chat from name, send a Javascript statement that
207 // appends HTML to element #tbd. I.e., we'll make a string of HTML
208 // formatted like this:
209 // <tr style="color:hsl(200,100%,30%)">
210 // <td>[01:23]</td>
211 // <td>Avatar Name</td>
212 // <td>the chat text</td>
213 // </tr>
214 // and send it wrapped it in a Javascript statement like this:
215 // e('tbd').innerHTML += htmlstring;
216 //
217 listen(integer chan, string name, key id, string chat)
218 {
219 integer s = (integer)("0x" + llGetSubString((string)id, 0, 6));
220 string hue = (string)(s % 360);
221 string color = "hsl(" + hue + ",100%, 30%)";
222
223 string msg = "e('tbd').innerHTML += '{@0}';";
224 string m0 = "<tr style=\"color: {@4}\">";
225 m0 += "<td>{@1}</td>";
226 m0 += "<td>{@2}:</td>";
227 m0 += "<td>{@3}</td>";
228 m0 += "</tr>";
229
231 sendMessageF(msg, [m0, "[" + t + "]", name, addSlashes(chat), color]);
232 }
233 }

Reverse_Ajax__Longpolling_the_HTTPi

Here's an expanded listing for reference with more descriptive names:

Category: Viewer 2
By : Becky Pippen
Created: 2010-09-02 Edited: 2010-09-02
Worlds: Second Life

1 <!DOCTYPE HTML>
2 <html>
3 <body>
4 <div>
5 <script id='script'> </script>
6 </div>
7 <script>
8 var poll=function(){
9 var script=document.getElementById('script'),
10 timeoutId,
11 seq=0,
12 newScript;
13 return {
14 beg:function() { // Initiate a long-poll GET
15 newScript=document.createElement('script'); // The response will go here
16 newScript.onload=poll.end; // Call poll.end() when we get a response
17 timeoutId=setTimeout('poll.end()',20000); // ... or if we time out
18 newScript.src=' HTTP-in URL goes here /?r='+(seq++);
19 script.parentNode.replaceChild(newScript,script); // this triggers the GET
20 script=newScript;},
21
22 end:function() {
23 clearTimeout(timeoutId);
24 timeoutId=null;
25 script.onload=null;
26 setTimeout('poll.beg()',500); // Wait a bit before re-polling
27 },
28 };
29 }();
30 </script>
31 <button id='btn'onclick=poll.beg()>Start<button>
32 <div id='dv'> </div>
33 </body>
34 </html>

Back to the Best Free Tools in Second Life and OpenSim.