# Downloading folder

This step is useful if you store profile folders on our servers (this is the behavior when using Surfinite App). Though, you can absolutely skip it if you store your folders locally, e.g. you use your own dedicated server and want to avoid the additional overhead of downloading and uploading folder everytime the profile is used.

# Folder contents

Browser folder usually contains a lot of files, which might be necessary for your automation:

  • Cookies
  • Preferences
  • Passwords
  • Bookmarks & Extensions
  • History
  • Session, LocalStorage, IndexedDB and other data

Some of it is stored on our servers in archived format, some of it must be fetched using the API (like bookmarks and cookies), and some is downloaded and cached locally (like extensions, so that you do not download them on every launch).

As downloading a folder is such a complicated task, requiring multiple requests, a lot of unzipping and moving files from multiple sources, we implemented all of these operations in our helper tool - aemulari , so you can call it once with the necessary parameters and not care about the details.

# aemulari

We distribute aemulari in a binary executable form. If you have installed Surfinite App, you would find it in:

  • for Windows: C:\Users\<Username>\.surfinite\aemulari\aemulari.exe
  • for macOS: /Users/<Username>/.surfinite/aemulari/aemulari
  • for Linux: /home/<Username>/.surfinite/aemulari/aemulari

This tool is capable of downloading and uploading profile folders, as well as checking proxies. You can run it with a --help argument to get description on how to use it. But, as we are focusing on downloading a profile folder, the corresponding aemulari command is create-folder, and here's its help message:

$ ./aemulari create-folder --help

Create folder usage:
  --profile-id TEXT     Profile ID to use
  --path TEXT           Path to the folder. E.g. "path=C:\Profiles\MyProfile". 
                        If the folder does not exist, it will be created. If 
                        omitted, system's default temp dir would be used with 
                        profile id: <temp-dir>\<profile-id>
  --api-key TEXT        Your API key

Common options:
  --verbose             Be verbose (enable logging)


You can provide arguments in both forms key=value and key value, for example:

./aemulari create-folder --profile-id="my_profile_id" --path=C:\Users\Me\profiles\my_profile_id --api-key MY_API_KEY

If the operation succeeds, the executable will print the profile folder path to stdout and finish with an exit code of 0.

# Exit codes

Code Meaning
0 Success. Path to the profile folder is printed to stdout. However, it is only useful if you did not set it in command line arguments
1 Unknown error, can indicate anything from invalid arguments to some network errors. There should be an error message printed to stdout
2 Network error (bad curl code somewhere). There must be an error message printed to stdout
101 Unauthorized. The api key is invalid
104 Not Found. The profile does not exist or your API Key does not belong to the profile's cluster
109 Conflict. The profile is currently synchronizing with the server (somebody is uploading profile folder)
110 Gone. The profile is deleted and is currently in Recycle Bin. You must restore it to use it
200 Internel Server Error. There will be no message printed to stdout

You will get the server's error message printed to stdout in case you get error codes 101-110. Usually you should contact support if you get exit codes 1, 2 or 200 and have no way of fixing it yourself.

# Use from code

Every programming language has an API for instantiating processes. Usually you provide it with a path to aemulari and your arguments. However, there's one tricky part. Every process is initialized with three standard pipes:

  1. stdin for standard input
  2. stdout for standard output
  3. stderr for standard error

You can ignore stdin completely. Though, we recommend putting stdout to an INHERIT IO mode, so that aemulari inherits standard output stream from the calling process, i.e. your program. That way you will see that aemulari outputs to the same place where you print other information in your code. This might be especially useful if using --verbose flag.

Enough theory, here's an example of how to download profile folder from code:

val pathToAemulari = "/home/myuser/.surfinite/aemulari/aemulari"

val profileId = "my_profile_id"
val apiKey = "MY_API_KEY"

val pathToProfile = "/home/myuser/surfiprofiles/$profileId"

// Start aemulari with our arguments
val process = ProcessBuilder(
    listOf(
        pathToAemulari,
        "create-folder",
        "--profile-id", profileId,
        "--path", pathToProfile,
        "--api-key", apiKey
    )
)
    .redirectOutput(ProcessBuilder.Redirect.INHERIT)
    .redirectError(ProcessBuilder.Redirect.INHERIT)
    .start()

// Wait for the process to exit
process.waitFor()

val exitCode = process.exitValue()
if (exitCode == 0) {
    println("Success")
} else {
    // The error message was already printed, as we called
    // redirectOutput(INHERIT), so just print the exit code
    println("Got error from aemulari. Code: $exitCode")
}