Resource Web Access
The Multi Theft Auto Server provides a web interface that resources can use in a variety of ways. This document’s purpose is to explain what these ways are and how to go about using them.
There are three key parts that make up this system.
- Pages - The ability to serve any http items (specified the meta.xml) as a page or file.
- Calls - The ability to call any exported http functions (specified in the meta.xml).
Added in 1.6.0 r22639
- Router - Use a designated http function to route requests within a resource manually (overriding the two parts above).
Pages
Section PagesSpecifying a file in the meta
Section Specifying a file in the metaYou can define files in a resource that will be accessible via the web server. To do this, you need to add them to meta.xml using the html tag.
<html src="index.html" />The html tag in addition to src has two more attributes:
- default - Specifies the file that will be the main page of the resource.
- raw - Indicates that the file will not be parsed by the Lua interpreter and is treated as a binary file (used, for example, for images).
You can access the resource through a web browser at: http://server-ip:http-port/resource-name/optional-page/ For example, for a local server and the performancebrowser: http://192.168.33.107:22005/performancebrowser/
The HTTP port is usually the server port + 2; by default it is 22005.
The performancebrowser resource has a file defined in its meta that will be displayed as the main page - that is, when no specific page is provided in the URL.
<html src="pad.gif" raw="true" /> <html src="loading.gif" raw="true" /> <html src="main.htm" default="true"/> <html src="main.css" raw="true" /> <html src="main.js" raw="true" />You can specify a page like this: http://192.168.33.107:22005/webadmin/groups and it will display the groups.htm file.
If no file is marked as default in meta.xml, then the first file listed in the html tag will be used as the default page.
For example, in this case:
<html src="acls.htm" /> <html src="groups.htm" /> <html src="players.htm" /> <html src="admin.js" raw="true"/> <html src="icon_minus_8_on_F.png" raw="true"/> <html src="icon_plus_8_on_F.png" raw="true"/> <html src="icon_x_8_on_F.png" raw="true"/>
<html src="ie-70.css" raw="true"/> <html src="css.css" raw="true"/> <html src="groups.css" raw="true"/>The default file will be acls.htm because it is listed first.
Binary files
Section Binary filesDespite the misleading name, the html tag node can contain any type of file. If the files do not require processing by the Lua interpreter (for example, binary files like images or .zip archives, or files that do not use Lua at all like .js or plain .html) you should set the raw attribute to true.
Files marked as raw are not pre-processed before being sent to the browser.
<html src="icon_minus_8_on_F.png" raw="true"/>Parsed files
Section Parsed filesIf a file is not specified in the metafile as raw, then it is passed through a pre-processor before it is returned to the client. This pre-processor works much like PHP or ASP but uses Lua. You can embed standard MTA scripts within HTML pages, controlling the output. Almost all standard MTA functions work, plus a number of special HTTP Functions.
Aside from HTTP functions, embedded Lua has access to the following environment variables that contain information about how the page was requested.
Calls
Section CallsIt is important that processed files are executed in a separate virtual machine (Lua VM) from the .lua code in the resource. Therefore, if you want to call a function from the resource code, that function must be exported so it can be invoked using the call function from within the processed HTML files.
You can specify that certain exported functions in your resource are able to be called from the HTTP interface. All the SDKs (listed below) allow you to call these functions from a remote location.
To export a function and make it callable via the web server, you need to add an entry in meta.xml using the export tag and set the http attribute to true.
<export function='functionName' http='true' />It can be a normal Lua function like any other, returning as many values as you want, but it must not return non-element userdata such as xmlnode etc., functions, or threads, nor may it return tables containing any of the aforementioned types.
Protocol
Section ProtocolCalls are made via an HTTP POST request to the URL: http://server-ip:http-port/resource/call/exported-function-name/ The request body should be a JSON array of arguments passed to the function. The request will return a JSON array of values that were returned by the function as the HTTP response. The server supports HTTP Basic authentication and you can configure access via the ACL and the built-in accounts system.
Calls from the HTTP web interface
Section Calls from the HTTP web interfaceUsing calls is probably easiest from the web interface and can be done almost seamlessly.
First, add this to your meta.xml file:
<include resource="ajax" />Secondly, add the following to the <head> section of the page you want to call from
<* = exports.ajax:start(getResourceName(getThisResource())) *>Finally, you can create a javascript block on your page and call your functions almost as if they were local. The only difference is that the calls are asynchronous - you should specify a callback function as the last argument for your call. This is called when the function returns.
Here’s a simple example.
meta.xml
<meta> <include resource="ajax" /> <script src='code.lua' /> <html src='page.htm' default='true' /> <export function='showChatMessage' http='true' /></meta>code.lua
function showChatMessage ( message ) outputChatBox ( message ) return 5;endpage.htm
<html> <head> <* = exports.ajax:start(getResourceName(getThisResource())) *> <script type='text/javascript'> function say() { var message = document.getElementById('message') showChatMessage ( message.value, function ( number ) { // the function has been called and returned something message.value = "The function returned " + number; } ); } </script> </head> <body> <input type='text' id='message' /><input type='button' value='say' onclick='say();' /> </body></html>You can see (fairly complex) examples of how this can be done in the resources resourcebrowser, resourcemanager and webadmin.
Router
Section RouterAdded in 1.6.0 r22639
A router is a function that overrides both the function call mechanism and basic web server functionality, to allow a scripter to personalize the routing and client-response for each resource separately. For example, this allows a scripter to write an api named resource with a router function, that can serve any sort of information in a RESTy fashion. You may also take this further, and name the resource v1 (or v2…) for easy API versioning. You can spin up and down the different resources as you wish, and users of your API can continue using an older version this way.
How to setup a router function
Section How to setup a router functionA router function has to be specified in the meta.xml (see example below). You can name the function however you like, there are no restrictions, as long as the function can be found in the global Lua scope in your scripts.
<export function="httpRouter" http="true" router="true" />Then you have to specify the function in any Lua script:
function httpRouter(request) return 200 -- see below for a more complex return valueendRequest
Section RequestThis section describes all the fields, that can be found in the request table passed to the router function for every call. The descriptions below use the following example URL: http://127.0.0.1:22005/api/vehicles/123?meow=true (api is the resource name).
| Field | Type | Description |
|---|---|---|
| account | account | An account that was used for this request (can be a guest account). |
| method | string | One of the following: OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, CONNECT, PATCH. |
| path | string | The requested path within your resource: /vehicles/123. |
| absolute_path | string | The absolute path from the URL: /api/vehicles/123?meow=true". |
| hostname | string | The hostname of the web server: 127.0.0.1. |
| port | integer | The client port used by the web server: 56758 (can be anything, but never 22005). |
| body | string | The body portion of the request sent by the client. |
| query | table | A key-value table (with string keys and values) with the path’s query fields (only query). |
| formData | table | A key-value table (with string keys and values) with the request form data (both query and body fields). |
| cookies | table | A key-value table (with string keys and values) with the request cookies. |
| headers | table | A key-value table (with string keys and values) with the request headers (like User-Agent). |
Response
Section ResponseThis section describes all the possible variants, that can be returned by the router function. There are three variants in total:
- Return literally nothing: response will use http status code 200 and an empty body.
- Return an integer: response will convert the number to an http status code and use an empty body.
- Return a table: response will be filled with the fields from the table (defaults to http status code 200 and empty body, if not overriden by a table field).
Response table fields
Section Response table fields| Field | Type | Description |
|---|---|---|
| status | integer | A number that will be converted to an http status code. |
| body | string | A string that will be used for the response body. |
| headers | table | A key-value table (with string keys and values) that will be written to the header section of the response. |
| cookies | table | A table with simple string key and value entries, or any-type key with table values (key is not used), entries. Check the examples below, if it’s unclear. |
Examples
Section Examplesfunction httpRouter(request) -- HTTP status code 200 & empty bodyendfunction httpRouter(request) return 404 --< HTTP status code & empty bodyendfunction httpRouter(request) return { status = 404, body = "not found", }endfunction httpRouter(request) return { status = 505, body = "foo", cookies = { foo = "1234", { name = "bar", -- Cookie name must always be a lowercase "name" key value = "6666", -- Cookie value must always be a lowercase "value" key Version = "2", -- Any other cookie field can use any case } }, headers = { ["content-type"] = "text/html", ["etag"] = "c561c68d0ba92bbeb8b0f612a9199f722e3a621a", ["access-control-allow-origin"] = "*", ["x-custom-header"] = "MTA server", } }endSecuring the web interface
Section Securing the web interfaceThe ACL has a number of rights that can affect what files can be accessed.
- resource.ResourceName.http - If enabled, the resource will be accessible from http://server-ip:http-port/resource-name/
This works as with other ACL rights - You can enable it just for Admin users, or any other group of users you wish.
SDKs
Section SDKsAll SDKs except the PHP SDK and JavaScript SDK are unofficial and community-made - meaning they may be outdated and may contain bugs, security vulnerabilities, or even dead links. The MTA Team is not responsible for any community-created SDKs and does not provide support for them.
There are a number of so-called ‘SDKs’ available that allow you to interface with the server from other programming languages. With these, you could (in theory) write whole gamemodes. In practice, this is probably a bad idea, but it is useful for statistics and administration. The PHP SDK is the most developed version. Feel free to modify or create your own SDKs - if you do please send us a copy.
- PHP SDK (Simple article on how to use it here)
- JavaScript SDK
- Java SDK (forum post) - Author: Skyline (laserlaser)
- Node.js SDK (npm) - Author: 4O4
- Python SDK - Author: Ceevyl
- Rust SDK - Author: João Silva
- C# SDK - Author: 50p
Perl SDK
Currently there is not a Perl SDK as such, but you can use the following code to call a function on an MTA server, assuming you have access:
using JSON;
sub callFunction { my ($server, $resourcename, $functionname) = @_; my $content = objToJson([@_[3..$#_]]); $ua = LWP::UserAgent->new; $ua->parse_head(0); $ua->agent(""); my $url = "http://" . $server . "/" . $resourcename . "/call/" . $functionname; $req = HTTP::Request->new(POST => $url); $req->content_type('application/x-www-form-urlencoded'); $req->content($content); $req->header('Accept' => 'text/html'); $res = $ua->request($req); my $ret = ""; eval { $ret = jsonToObj($res->content); }; return $ret;}This requires that you install the JSON package. You can do this easily by navigating to your perl ‘bin’ directory and executing “cpan”, then typing “install JSON”.
Syntax:
my $ret = callFunction("hostname:httpPort", "resourceName", "functionName" [, args ...]);The function returns an array of the values returned by the function.