Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improvements to asynchronous HTTP function pages, game_restart() now clears existing call_later() time sources #179

Merged
merged 4 commits into from
Oct 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,70 @@
<body>
<!--<div class="body-scroll" style="top: 150px;">-->
<h1><span data-field="title" data-format="default">HTTP</span></h1>
<p>This section lists the different Asynchronous HTTP functions available in <span data-keyref="GameMaker Name">GameMaker</span>. These functions will generate an <a href="../../../../The_Asset_Editors/Object_Properties/Async_Events/HTTP.htm">Asynchronous HTTP Event</a> in all instances that have it:</p>
<p>This section lists the different Asynchronous HTTP functions available in <span data-keyref="GameMaker Name">GameMaker</span>.</p>
<p>HTTP stands for <a href="https://en.wikipedia.org/wiki/HTTP">Hypertext Transfer Protocol</a>, which is a protocol for communication on the World Wide Web. It is used when you browse the internet using a web browser, download files, log in to a website, interact with RESTful APIs, ... It has a variant named HTTPS (S indicating &quot;Secure&quot;).</p>
<p>HTTP <em>requests</em> are sent to a web server, which replies by sending back a <em>response</em>. A request uses one of several <em>methods</em>, of which GET and POST are the most common ones. Both the request and response may contain headers (a collection of key-value pairs) and a request body (the actual data to send). The response contains a status code indicating the status and can contain data (e.g. file contents).</p>
<p><span data-keyref="GameMaker Name">GameMaker</span> lets you create and send HTTP requests using the functions on this page. The response is returned in an <a href="../../../../The_Asset_Editors/Object_Properties/Async_Events/HTTP.htm">Asynchronous HTTP Event</a> in all instances that have it.</p>
<h2 id="request_functions">Request Functions</h2>
<p>The most general function is <span class="inline3_func"><a data-xref="{title}" href="http_request.htm">http_request</a></span>, which allows you to specify any request method as well as headers and data.</p>
<p>The other functions can be used for more specific requests:</p>
<ul class="colour">
<li><a data-xref="{title}" href="http_request.htm">http_request</a></li>
<li><a data-xref="{title}" href="http_get.htm">http_get</a></li>
<li><a data-xref="{title}" href="http_get_file.htm">http_get_file</a></li>
<li><a data-xref="{title}" href="http_post_string.htm">http_post_string</a></li>
<li><span class="inline3_func"><a data-xref="{title}" href="http_get.htm">http_get</a></span> for a GET request</li>
<li><span class="inline3_func"><a data-xref="{title}" href="http_get_file.htm">http_get_file</a></span> to download a file using GET</li>
<li><span class="inline3_func"><a data-xref="{title}" href="http_post_string.htm">http_post_string</a></span> to make a HTTP request using POST</li>
</ul>
<h3 id="urls">URLs</h3>
<p>All request functions take a URL. The URL string: </p>
<ul class="colour">
<li>must include the protocol, e.g. <span class="inline2">&quot;http://www.google.com&quot;</span> or <span class="inline2">&quot;https://www.google.com&quot;</span>.</li>
<li>can contain an IP address, e.g. <span class="inline2">&quot;http://1.1.1.1&quot;</span>.</li>
<li>can contain <a href="https://en.wikipedia.org/wiki/Query_string">query parameters</a>, e.g. <span class="inline2">&quot;http://www.example.com/examples?example_id={id}&quot;</span>.</li>
</ul>
<p>Note that: </p>
<h2 id="making_requests">Making Requests</h2>
<p>Let&#39;s look at how a general HTTP request is handled from start to end:</p>
<p class="code_heading">Mouse Left Pressed Event</p>
<p class="code">var _map_headers = ds_map_create();<br />
request_id = http_request(&quot;http://www.google.com&quot;, &quot;GET&quot;, _map_headers, &quot;&quot;);<br />
ds_map_destroy(_map_headers);</p>
<p class="code_heading">Async - HTTP Event</p>
<p class="code">if (async_load[? &quot;id&quot;] != request_id) exit;<br />
<br />
var _status = async_load[? &quot;status&quot;];<br />
if (_status &lt; 0)<br />
{<br />
    // Error occurred<br />
    <br />
    exit;<br />
}<br />
<br />
if (_status == 1)<br />
{<br />
    // Downloading<br />
    <br />
    exit;<br />
}<br />
<br />
if (_status == 0)<br />
{<br />
    // Request completed!<br />
    <br />
    if (async_load[? &quot;http_status&quot;] == 200)<br />
    {<br />
        // Request was succesful<br />
        <br />
    }<br />
}
</p>
<p>In this example, a <strong>Mouse Left Pressed</strong> event calls the function <span class="inline3_func"><a data-xref="{title}" href="http_request.htm">http_request</a></span>. The request uses the <span class="inline2">&quot;GET&quot;</span> method to retrieve a webpage. No headers are passed and the request body is set to an empty string <span class="inline2">&quot;&quot;</span>.</p>
<p>The <a href="../../../../The_Asset_Editors/Object_Properties/Async_Events/HTTP.htm">Async HTTP event</a> is then triggered one or more times. In this event, the <span class="inline2"><a data-xref="{title}" href="../../../GML_Overview/Variables/Builtin_Global_Variables/async_load.htm">async_load</a></span>&#39;s <span class="inline2">&quot;id&quot;</span> key is first checked to see if it matches the <span class="inline2">request_id</span> stored earlier. If not, this means the event was not triggered for the request made earlier and the code is exited. Next, the <span class="inline2">&quot;status&quot;</span> key is checked. This can hold one of three values: </p>
<ul class="colour">
<li>You can use an IP address in the <span class="inline2">url</span> parameter of all these functions, e.g. <span class="inline2">&quot;http://1.1.1.1&quot;</span>.</li>
<li>The URL string must include the protocol, e.g. <span class="inline2">&quot;http://www.google.com&quot;</span> or <span class="inline2">&quot;https://www.google.com&quot;</span>.</li>
<li>&lt; 0 : error</li>
<li>0 : request completed</li>
<li>1 : content is being downloaded</li>
</ul>
<h2>Connection Timeout</h2>
<p>While downloading content, the event will trigger multiple times, during which the <span class="inline2">&quot;status&quot;</span> key will hold the value 1. Finally, it runs a last time and <span class="inline2">async_load[? &quot;status&quot;]</span> will hold 0 or &lt; 0.</p>
<p>The last time the event triggers for this request, the <span class="inline2">&quot;status&quot;</span> key will hold 0. This value indicates the request has completed. The HTTP status is then checked. If it is 200 (indicating &quot;success&quot;), the data can be found in <span class="inline2">async_load[? &quot;result&quot;]</span>.</p>
<h2 id="connection_timeout">Connection Timeout</h2>
<p>The asynchronous HTTP functions send a request to a server, which might take some time to respond. If the server takes too long to respond, the connection may time out. In <span data-keyref="GameMaker Name">GameMaker</span> this happens after <span data-keyref="HTTP_Timeout_Default">60000</span> ms by default.</p>
<p>The following two functions can be used to get and change this value: </p>
<ul class="colour">
Expand All @@ -43,6 +94,24 @@ <h2 id="cross_domain_issues">Cross-Domain Issues</h2>
<li><a data-xref="{title}" href="http_set_request_crossorigin.htm">http_set_request_crossorigin</a></li>
</ul>
<p>In most cases these functions should not need to be used, but if the game is stored on a secured server - where certain assets may require basic authentication to be accessed and are generating security errors when loading - setting the cross-origin type for image requests to <span class="inline2">&quot;use-credentials&quot;</span> may be necessary (as opposed to the default <span class="inline2">&quot;anonymous&quot;</span> setting).</p>
<h2 id="func_ref">Function Reference</h2>
<h3>Requests</h3>
<ul class="colour">
<li><a data-xref="{title}" href="http_request.htm">http_request</a></li>
<li><a data-xref="{title}" href="http_get.htm">http_get</a></li>
<li><a data-xref="{title}" href="http_get_file.htm">http_get_file</a></li>
<li><a data-xref="{title}" href="http_post_string.htm">http_post_string</a></li>
</ul>
<h3>Timeouts</h3>
<ul class="colour">
<li><a data-xref="{title}" href="http_get_connect_timeout.htm">http_get_connect_timeout</a></li>
<li><a data-xref="{title}" href="http_set_connect_timeout.htm">http_set_connect_timeout</a></li>
</ul>
<h3>Cross-Domain</h3>
<ul class="colour">
<li><a data-xref="{title}" href="http_get_request_crossorigin.htm">http_get_request_crossorigin</a></li>
<li><a data-xref="{title}" href="http_set_request_crossorigin.htm">http_set_request_crossorigin</a></li>
</ul>
<p> </p>
<p> </p>
<div class="footer">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,10 @@
<body>
<!--<div class="body-scroll" style="top: 150px;">-->
<h1><span data-field="title" data-format="default">http_get</span></h1>
<p>This function connects to the specified URL in order to retrieve information.</p>
<p>As this is an asynchronous function, <span data-keyref="GameMaker Name">GameMaker</span> will not block while waiting for a reply, but will keep on running unless it gets callback information. This information will be in the form of a string and will trigger an <b>Async HTTP Event</b> in any instance that has one defined in its object events. You should also note that HTTP request parameters (the bits sometimes &quot;tacked on&quot; to the end of a URL when you submit a form on a web page) are perfectly acceptable when using this function, for example:</p>
<p class="code"><span data-field="title" data-format="default">http_get</span>(&quot;http://www.example.com/logon?username={name}&quot;);</p>
<p>will pass the string held in the variable <span class="inline2">name</span> to the server as well as retrieve the data from that URL. So, essentially, any time a simple, short piece of data needs to be passed from the client to the server, this would be a reasonable choice as the function to use.</p>
<p>This function sends a GET request to the specified URL in order to retrieve information.</p>
<p>This is an asynchronous function, so <span data-keyref="GameMaker Name">GameMaker</span> will not block while waiting for a reply, but will keep on running unless it gets callback information. This information will be in the form of a string and will trigger an <b>Async HTTP Event</b> in any instance that has one defined in its object events.</p>
<div data-conref="../../../../assets/snippets/Note_HTTP_Requests_CrossOrigin.hts"> </div>
<h2>Async Callback</h2>
<p>This function will generate multiple &quot;callbacks&quot; which are picked up by any <a href="../../../../The_Asset_Editors/Object_Properties/Async_Events/HTTP.htm">HTTP Events</a>. These will generate a <span data-keyref="Type_ID_DS_Map"><a href="../../Data_Structures/DS_Maps/ds_map_create.htm" target="_blank">DS Map</a></span> (more commonly known as a &quot;dictionary&quot;) that is exclusive to this event and is stored in the special variable <span class="inline2"><a data-xref="{title}" href="../../../GML_Overview/Variables/Builtin_Global_Variables/async_load.htm">async_load</a></span>. This DS map will contain different values depending on whether there is data being returned or not. For example, if you have requested a file, the event will trigger multiple times as each packet of data is received so that you can show a progress bar, for example.</p>
<div data-conref="../../../../assets/snippets/Note_HTTP_async_load_Contents.hts"> </div>
<p> </p>
Expand All @@ -35,25 +34,25 @@ <h4>Syntax:</h4>
<tr>
<td>url</td>
<td><span data-keyref="Type_String"><a href="../../../GML_Overview/Data_Types.htm" target="_blank">String</a></span></td>
<td>The web address of the server that you wish to get information from</td>
<td>The web address of the server that you wish to get information from. See <a data-xref="{text}" href="HTTP.htm#urls">URLs</a></td>
</tr>
</tbody>
</table>
<p> </p>
<h4>Returns:</h4>
<p class="code"><span data-keyref="Type_ID_Async_Event"><a href="../Asynchronous_Functions.htm" target="_blank">Async Request ID</a></span> (or -1 if something went wrong)</p>
<p> </p>
<h4>Extended Example:</h4>
<p>The <span class="inline3_func"><span data-field="title" data-format="default">http_get</span></span> function can be called from any event, and since it&#39;s asynchronous the callback can be almost instantaneous or could take several seconds. Calling the function is simple and would look something like this:</p>
<p class="code">request_id = http_get(&quot;http://www.MacSweeneyGames.com/logon?username={name}&quot;);</p>
<h4>Example:</h4>
<p>The <span class="inline3_func"><span data-field="title" data-format="default">http_get</span></span> function can be called from any event, and since it&#39;s asynchronous the callback can be almost instantaneous or could take several seconds. Calling the function is simple and looks something like this:</p>
<p class="code">request_id = http_get($&quot;http://www.MacSweeneyGames.com/logon?username={name}&quot;);</p>
<p>The above code will pass the string held in the variable <span class="inline2">name</span> to the given server as well as retrieve the data from that URL, triggering an Async Event which will contain the <span class="inline2"><a data-xref="{title}" href="../../../GML_Overview/Variables/Builtin_Global_Variables/async_load.htm">async_load</a></span> DS map (the <span class="inline2">async_load</span> map index will be stored in the variable <span class="inline2">request_id</span> so you can check for the correct callback). The Async Event triggered would be the <a data-xref="{title}" href="../../../../The_Asset_Editors/Object_Properties/Async_Events/HTTP.htm">HTTP</a> sub-event, and in that event you would have the following:</p>
<p class="code_heading">Async HTTP Event</p>
<p class="code">if (ds_map_find_value(async_load, &quot;id&quot;) == request_id)<br />
<p class="code">if (async_load[? &quot;id&quot;] == request_id)<br />
{<br />
    var _status = async_load[? &quot;status&quot;];<br />
    var _r_str = (_status == 0) ? async_load[? &quot;result&quot;] : &quot;null&quot;;<br />
}</p>
<p>The above code first checks the ID of the async request, then assigns a value to <span class="inline2">_r_str</span> depending on the <span class="inline2">&quot;status&quot;</span> of the callback. If the value is equal to 0 (signalling success), the result from the callback is stored in a variable for future use, otherwise the variable is set to a default value (in this case <span class="inline2">&quot;null&quot;</span>).</p>
<p>The above code first checks the ID of the async request, then assigns a value to <span class="inline2">_r_str</span> depending on the <span class="inline2">&quot;status&quot;</span> of the callback. If the value is equal to 0 (signalling the request completed), the result from the callback is stored in a variable for future use, otherwise the variable is set to a default value (in this case <span class="inline2">&quot;null&quot;</span>).</p>
<p> </p>
<p> </p>
<div class="footer">
Expand Down
Loading
Loading