Docs

Server

This class offers a basic API for communicating with a server using POST and GET requests as well as a downloading resources.

Server callbacks

Every method in this class will use the asynchronous execution concept: it will return immediately and execute a function when the server has responded.

Server.anyFunction(parameters, function(status, response)
{
    if(status == Server.StatusOK)
    {
        Console.print(response);
    }
});

The execution of server calls is guaranteed to be serially and consecutively and will be executed on a separate thread that will never stall the audio or UI thread. Nevertheless it should be obvious that you will never call one of these methods in a MIDI callback, right?

The status will be an integer containing the HTTP status code . The Server API class has a few constants that contains the most important codes (OK, 404, etc).

The response argument contains an object with the response from the server.

This means whatever you do on the server-side, you have to return a valid JSON-formatted text.

GET vs POST

There are two different kind of HTTP requests, GET and POST. There is plenty of information available about this subject, but the gist of it is that you use GET for non-sensitive data and POST for sensitive data.

About URLs

In 99% of all cases, you will communicate with a single server. In order to save you some typing, the Server API class uses a Base URL that you need to setup once using Server.setBaseURL() .

Calling this method will also start the server thread, so unless you explicitely use it, it won't eat up resources.

From then on, every call to the server just needs a sub URL to work - you also don't need to take care about the slashes:

Server.setBaseURL("https:forum.hise.audio");
Server.callSomething("api/recent"); 
// => https://forum.hise.audio/api/recent/

Encryption

If you use SSL for the communication and the POST method for passing around parameters, the communication with the server should be safe enough. However if you want to store any kind of data to a file, please use the File.writeEncryptedObject() to make sure that there is no sensitive data lurking around on your hard drive.

Debugging server calls & downloads

The ServerController floating tile offers a few useful tools that will assist you during the development of Server related tasks, so you might want to consider adding this to the scripting workspace while you're working on your server code.

Class methods

callWithGET

Calls a sub URL and executes the callback when finished.

Server.callWithGET(String subURL, var parameters, var callback)


This calls the given URL with the parameters as GET arguments and will execute the callback function when the server responded.

The parameters have to be a non-nested JSON object and will automatically change the URL to embed these parameters

Server.setBaseURL("https://forum.hise.audio");

// The GET arguments as JSON object
const var p =
{
    "term": "HISE",
    "in": "titlespost"
};

// => https://forum.hise.audio/api/search?term=HISE&in=titlesposts
Server.callWithGET("api/search", p, function(status, response)
{
    if(status == Server.StatusOK)
    {
        // Just use the response like any other JSON object
        Console.print("There are " + response.matchCount + " results");
    }
});


callWithPOST

Calls a sub URL with POST arguments and executes the callback when finished.

Server.callWithPOST(String subURL, var parameters, var callback)


The arguments in a POST call are not embedded in the URL so they are more suitable for sensitive information.

Server.setBaseURL("http://hise.audio");

const var p = 
{
    "first_argument": 9000
};

// This dummy file just returns the `first_argument` as `post_argument`...
Server.callWithPOST("post_test.php", p, function(status, response)
{
    Console.print(response.post_argument);
});


cleanFinishedDownloads

Removes all finished downloads from the list.

Server.cleanFinishedDownloads()



downloadFile

Downloads a file to the given target and returns a Download object.

Server.downloadFile(String subURL, var parameters, var targetFile, var callback)


This method will start a download in the background and periodically executes the callback that can be used to track the progress.

The target parameter has to be a valid File object that points to a file (not a directory).

Be aware that this file will be deleted and overwritten!

Unlike the other methods, the function you pass in as callback must not have any parameters. Instead you can query the state of the download via the this.data object, which always points to the current download.
The object has these properties:

Property Type Description
finished bool false as long as the file is being downloaded. It will be executed exactly once with 'true' at the end of the download (or if you pause the download).
success bool at the end of the download (when finished is true), this can be used to check whether the download was successful, or if it was interrupted by something. If you pause the download, this will also be false .
numTotal int the total download size in bytes. This will not change during download.
numDownloaded int the number of bytes that have been downloaded until now.

In addition to these properties, you can use the this object in the function with all the API methods available in the Download class.

Server.setBaseURL("http://hise.audio");
const var target = FileSystem.getFolder(FileSystem.Documents).getChildFile("HISE_1_1_1.exe");

Server.downloadFile("download/HISE_1_1_1.exe", {}, target, function()
{
    var message = "";
    
    message += Engine.doubleToString(this.data.numDownloaded / 1024.0 / 1024.0, 1);
    message += "MB / " + Engine.doubleToString(this.data.numTotal / 1024.0 / 1024.0, 1) + "MB";
    
    Console.print(message);
     
    if(this.data.finished)
         Console.print(this.data.sucess ? "Done" : "Fail");
});


inline function onButton1Control(component, value)
{
	if(value)
        Server.stopDownload("download/HISE_1_1_1.exe", {});
};

Content.getComponent("Button1").setControlCallback(onButton1Control);

Also be aware that if you call this method again with the same URL and parameters, it will not add another download, but just replace the callback in the already pending download. If you call this method with a file that already exists, the method assumes that it's a previously stopped download and resumes the download at the position (delete the file before calling the method if you don't want this behaviour).


getPendingCalls

Returns a list of all pending Calls.

Server.getPendingCalls()



getPendingDownloads

Returns a list of all pending Downloads.

Server.getPendingDownloads()


The lifetime of a Download object will exceed the download time (so you can display a list of completed downloads). You can query the list of all available downloads with this method. If you want to remove all finished downloads, call Server.cleanFinishedDownloads()

isEmailAddress

Checks if given email address is valid - not fool proof.

Server.isEmailAddress(String email)



isOnline

Returns true if the system is connected to the internet.

Server.isOnline()



setBaseURL

Sets the base URL for all server queries.

Server.setBaseURL(String url)



setHttpHeader

Adds the given String to the HTTP POST header.

Server.setHttpHeader(String additionalHeader)



setNumAllowedDownloads

Sets the maximal number of parallel downloads.

Server.setNumAllowedDownloads(int maxNumberOfParallelDownloads)



setServerCallback

This function will be called whenever there is server activity.

Server.setServerCallback(var callback)


You can use this function to implement some kind of notification to the user that there is something waiting for a response of the server and there is some internet activity.

For a real world use case you might to show some element spinning and then hide it when ready, but in this example, we'll just log to the Console:

Server.setBaseURL("https://forum.hise.audio/api");
Server.setServerCallback(function(isWaiting)
{
    Console.print(isWaiting ? "SERVER IS BUSY" : "DONE");
});

function printName(status, obj)
{
    if(status == 200)
        Console.print(" " + obj.username);
};

// Now hammer the queue with the top 5 Posters
Server.callWithGET("user/d-healey", {}, printName);
Server.callWithGET("user/christoph-hart", {}, printName);
Server.callWithGET("user/ustk", {}, printName);
Server.callWithGET("user/Lindon", {}, printName);
Server.callWithGET("user/hisefilo", {}, printName);

The output:

Interface: SERVER IS BUSY
Interface:  d.healey
Interface:  Christoph Hart
Interface:  ustk
Interface:  Lindon
Interface:  hisefilo
Interface: DONE

As you can see the start / end callback is only called once. Be aware that this callback is not used when there is a download in progress as this has it's own notification tools.