Flussonic Media Server documentation

Lua Scripts

Erlivideo has a built-in experimental possibility to write scripts in the lua scripting language. luerl is used as the interpreter, so error messages may be different from the standard ones.

Important. All functionalities described in this section are experimental and may be changed without notice.

In addition to the standard lua library, erlivideo adds some features to scripts:

HTTP client

http.get(url) http.get(url, headers) http.get(url, headers, body) http.get(url, headers, timeout) http.get(url, headers, body, timeout) An HTTP GET request is sent. A table with keys: code, headers, body is sent as the reply.

http.post(url) An HTTP POSt request is sent. The arguments and answer are like those in http.get.

http.qs_encode(table) The table is encoded into a query string.

JSON module

json.encode(table) The table is translated into JSON

json.decode(text) JSON is translated into the table

Flussonic API

flussonic.config() partial erlivideo config is returned

flussonic.streams() current list of streams

flussonic.files() current list of open files

flussonic.caches() current list of disk caches

flussonic.clients() flussonic.clients(stream) current list either of all sessions or of specific sessions of the stream

flussonic.log(text) output into the log by means of erlivideo

flussonic.debug(text) debugging output into the log by means of erlivideo

flussonic.now() current time UTC

flussonic.uuid() uuid is generated

table.to_string(table) returns the table as text

Comet server

comet.create_channel("channel") comet.create_channel("channel", 100) a channel in the inner comet server is created. Channel is optionally specified

comet.send("channel", "message") a message is sent via the comet server internal channel

SWIFT client

auth_info = swift.auth("http://proxy-server/", "account", "password") authorization data for further access is returned

swift.list_containers(auth_info) the list of containers of the authorized account

swift.create_container(auth_info, 'videos') swift.create_container(auth_info, 'videos', {}) a container, possibly with a meta-date, is created

swift.delete_container(auth_info, 'videos') deleting the container

swift.list_objects(auth_info, 'videos') list of objects in the container

swift.create_object(auth_info, 'videos', 'file.txt', 'contents') creating an object

swift.upload_file(auth_info, 'videos', 'remote_path.mp4', 'local_path.mp4') swift.upload_file(auth_info, 'videos', 'remote_path.mp4', 'local_path.mp4', 'local_callback_name') downloading a file. The name of the local function can also be specified as a line that will be invoked upon booting for indicating load on the server

FTP client

ftp.list("ftp://user:password@host/path") The list of files in the directory

ftp.upload("local.mp4", "ftp://user:password@host/path/remote.mp4") function progress(p) end ftp.upload("local.mp4", "ftp://user:password@host/path/remote.mp4", "progress") the local file is uploaded to ftp. Optionally, a callback is invoked for the download status

Crypto API

crypto.md5("Hi") md5 in hex format

crypto.sha1("Hi") sha1 in hex format

crypto.sha256("Hi") sha256 in hex format

Login using Lua Anchor Anchor x2

The login backend in Lua should be a normal script, the result of which should be returned in the end by the return operator. This script receives an additional global table req with the following fields, some of which are optional:

  • token - a token from the query string or automatically generated
  • ip - IP address of the user
  • name - stream/file name
  • referer - the optional referrer of the player (the address of the page it was inserted into)

The answer should be return true, {user_id = 15, unique = true}, return "redirect", "http://someotherserver/path" or return false, {code = 403}

Event handlers Anchor Anchor x2

An example of using Lua for filtering and sending internal Flussonic events is given in section Events API.

Web scripts Anchor Anchor x2

Lua may be used to generate web pages with the use of the Flussonic infrastructure.

To do so, specify in the config: web_script mytest priv/myscripts;

After that, when referring to address http://192.168.2.3:8080/mytest/counter, a lua scriptpriv/myscripts/web.lua will be called, the http_handler.counter(req) function will be called in it:

http_handler = {}

http_handler.counter = function(req)
  if not req.cookies.flusession then
    session_id = flussonic.uuid()
    headers = {}
    headers["Set-Cookie"] = "flusession="..session_id
    headers["Location"] = "/mytest/counter"
    return "http", 302, headers, "auth\n"
  else
    session_id = req.cookies.flusession
    value = flussonic.session.get(session_id, "key1")
    if not value or value == "undefined" then
      flussonic.session.set(session_id, "key1", 1)
    end
    value = flussonic.session.get(session_id, "key1")
    flussonic.session.set(session_id, "key1", value + 1)
    return "http", 200, {}, tostring(value).."\n"
  end
end

Now this script should be invoked:

$ curl -v http://localhost:8080/mytest/counter
...
< HTTP/1.1 302 Found
< Connection: keep-alive
< Server: Cowboy
< Date: Fri, 06 Mar 2015 10:20:13 GMT
< Content-Length: 5
< Location: /mytest/counter
< Set-Cookie: flusession=4a41cc61-b089-4cd5-9c4a-28402c6db525
$ curl -s http://localhost:8080/mytest/counter -H 'Cookie: flusession=4a41cc61-b089-4cd5-9c4a-28402c6db525'
1
$ curl -s http://localhost:8080/mytest/counter -H 'Cookie: flusession=4a41cc61-b089-4cd5-9c4a-28402c6db525'
2
$ curl -s http://localhost:8080/mytest/counter -H 'Cookie: flusession=4a41cc61-b089-4cd5-9c4a-28402c6db525'
3
$ curl -s http://localhost:8080/mytest/counter -H 'Cookie: flusession=4a41cc61-b089-4cd5-9c4a-28402c6db525'
4

This script, all the functions described above will be available. Also, table req is available:

  • req.query is the parsed query string
  • req.headers are HTTP headers
  • req.method is the HTTP method in uppercase letters
  • req.body is- the body of the HTTP header. If the body is in the www-form-encoded format, it should be parsed in lua on its own with the use of http.qs_decode:
if req.method == "POST" then
  post = http.qs_decode(req.body)
end

The lua script may return the following responses:

  • return 'http', 200, {["Content-Type"] = "text/plain"}, "Hello, world!\n" - the http response can be sent directly
  • return "json", {key = "value"} - the table will be packed into JSON
  • return "template", {var1 = "value1", var2 = "value2"} - in this case, erlivideo will take the file called priv/cameras/list.html that should be a valid DTL template, where the values from the script
  • return "template" will be substituted, {headers = {}}, {var1 = "value1"} the same but with the possibility to set headers

Examples Anchor Anchor x2

Sometimes, the task is disabling authorization for secondary servers, i.e., for multiple IP addresses. In order to avoid adding this logic to the back-end, one can write his own authorization script:

if req.ip == "94.95.96.97" then
  return true, {}
end

reply = http.get("http://backend/script.php")

if not reply.code == 200 then
  return false, {code = reply.code}
end

opts = {}
if reply.headers["x-userid"] then
  opts.user_id = reply.headers["x-userid"]
end

if reply.headers["x-unique"] then
  opts.unique = true
end

return true, opts