# Быстрый старт

На предыдущих страницах было много информации о бесконечных кодах ответа и кодах выхода.
Вам действительно нужны все эти сложности прямо сейчас? Ну, возможно. А может и нет. Можем сказать с уверенность, что некоторые из них вам нужны, все зависит от вашего варианта использования и от того, насколько вы хотите что бы ваша система была самодостаточной и насколько подвержена ошибкам.

# Начните с малого, стремитесь к высокому

Мы рекомендуем начинать с наименьшего количества кода и сложности и добавлять его по мере необходимости. Вы абсолютно сможете использовать автоматизацию, не перехватывая ни одного кода выхода. Если вы единственный пользователь кластера (то есть вы используете свой кластер исключительно для автоматизации и ничего больше) - тогда вы не увидите добрую половину возможных кодов ошибок.

Вы можете начать создавать свое приложение, не обрабатывая никаких ошибок, а только выводя их на консоль на случай появления ошибок, а затем добавьте код, чтобы отловить их позже, если они у вас случаются часто.

Тот же подход можно применить и к шагам сеанса браузера. Например. вы можете пропустить операции с папками и остановку профиля и добавить их только тогда, когда облачное хранилище станет для вас актуальным. Посмотрите, насколько коротким может выглядеть ваш старт:

val apiUrl = "https://api.surfinite.com"
val apiKey = "MY_API_KEY"
val profileId = "my_profile_id"
val url = "$apiUrl/profiles/$profileId/start?use_lock=false&api_key=$apiKey"

val browserKey = runCatching {
    HttpClient(CIO) { expectSuccess = true }.use { client ->
        val responseBodyString = client.post(url).bodyAsText()
        Json.parseToJsonElement(responseBodyString)
            .jsonObject["browserKey"]!!
            .jsonPrimitive.content
    }
}.getOrElse {
    it.printStackTrace()
    return
}

val profileDir = File("profiledirs").combineSafe(profileId)

val options = ChromeOptions()
options.addArguments(
    "--user-data-dir=\"${profileDir.absolutePath}\"",
    "--profile-id=$profileId",
    "--browser-key=$browserKey"
)

options.setBinary("/home/myuser/.surfinite/browser/chrome")
System.setProperty("webdriver.chrome.driver", "/home/myuser/.surfinite/browser/chromedriver")

val driver = runCatching { ChromeDriver(options) }
    .getOrElse {
        it.printStackTrace()
        return
    }

driver["https://example.com"]

Этот код длиной 36 строк способен запустить браузер. Вы сможете протестировать свою логику Selenium.

# Добавляйте сложность по мере продвижения

После добавления шагов загрузки и выгрузки папки (и даже обработки кода выхода «4») код остается длинной в 84 строки.

val apiUrl = "https://api.surfinite.com"
val apiKey = "MY_API_KEY"
val profileId = "my_profile_id"
val url = "$apiUrl/profiles/$profileId/start?use_lock=false&api_key=$apiKey"

val browserKey = runCatching {
    HttpClient(CIO) { expectSuccess = true }.use { client ->
        val responseBodyString = client.post(url).bodyAsText()
        Json.parseToJsonElement(responseBodyString)
            .jsonObject["browserKey"]!!
            .jsonPrimitive.content
    }
}.getOrElse {
    it.printStackTrace()
    return
}

val profileDir = File("profiledirs").combineSafe(profileId)

var process = ProcessBuilder(
    listOf(
        "/home/myuser/.surfinite/aemulari/aemulari",
        "create-folder",
        "--profile-id", profileId,
        "--path", profileDir.absolutePath,
        "--api-key", apiKey
    )
)
    .redirectOutput(ProcessBuilder.Redirect.INHERIT)
    .redirectError(ProcessBuilder.Redirect.INHERIT)
    .start()

process.waitFor()

var code = process.exitValue()
if (code != 0) {
    println("Download folder exited with code $code")
    return
}

val options = ChromeOptions()
options.addArguments(
    "--user-data-dir=\"${profileDir.absolutePath}\"",
    "--profile-id=$profileId",
    "--browser-key=$browserKey"
)

options.setBinary("/home/myuser/.surfinite/browser/chrome")
System.setProperty("webdriver.chrome.driver", "/home/myuser/.surfinite/browser/chromedriver")

val driver = runCatching { ChromeDriver(options) }
    .getOrElse {
        it.printStackTrace()
        return
    }

driver["https://example.com"]
// ...
driver.quit()

process = ProcessBuilder(
    listOf(
        "/home/myuser/.surfinite/aemulari/aemulari",
        "upload-folder",
        "--profile-id", profileId,
        "--path", profileDir.absolutePath,
        "--api-key", apiKey,
        "--delete"
    )
)
    .redirectOutput(ProcessBuilder.Redirect.INHERIT)
    .redirectError(ProcessBuilder.Redirect.INHERIT)
    .start()

process.waitFor()

code = process.exitValue()
if (code != 0) {
    if (code == 4) profileDir.deleteRecursively()
    else {
        println("Upload folder exited with code $code")
        return
    }
}

Мы пытаемся сказать: не бойтесь всех этих возможных неудач. Это функции для вашей будщей разработки, а не требования. Вам придется потратить еще немного времени на то, чтобы все заработало, хотя когда дело доходит до оптимизации - у вас будет полный контроль над каждым шагом и большая гибкость, что означает более быстрое развитие для вас!