refactor the api

This commit is contained in:
Minecon724 2024-08-07 12:55:17 +02:00
parent ebddf95465
commit 5cf1466c54
Signed by: Minecon724
GPG key ID: 3CCC4D267742C8E8
14 changed files with 184 additions and 70 deletions

View file

@ -1,6 +0,0 @@
package eu.m724.vastapp.vastai
data class ApiFailure(
/** user friendly error message */
val errorMessage: String?,
)

View file

@ -1,8 +0,0 @@
package eu.m724.vastapp.vastai
enum class ApiRoute(val path: String, val method: String) {
SHOW_USER("/users/current", "GET"),
GET_INSTANCES("/instances", "GET"),
INSTANCES_COUNT("/instances/count", "GET"),
MACHINES_MAINTENANCES("/machines/maintenances", "GET")
}

View file

@ -0,0 +1,51 @@
package eu.m724.vastapp.vastai
import eu.m724.vastapp.BuildConfig
import org.chromium.net.CronetEngine
import org.chromium.net.UploadDataProvider
import org.chromium.net.UrlRequest
import java.util.concurrent.Executor
class RequestMaker(
private val apiKey: String,
private val cronetEngine: CronetEngine,
private val executor: Executor
) {
/**
* build an api request
* don't forget to call .start() on the returned [UrlRequest]
*
* @param endpoint the endpoint path starting with a slash like /users/current
* @param callback any callback for example [UserUrlRequestCallback]
* @param method request method, default GET
* @param headers additional request headers
* @param uploadDataProvider [UploadDataProvider] if request sends data
* @return an [UrlRequest] you must .start() yourself
*/
fun buildRequest(
endpoint: String,
callback: UrlRequest.Callback,
method: String = "GET",
headers: Map<String, String>? = null,
uploadDataProvider: UploadDataProvider? = null
): UrlRequest {
var requestBuilder = cronetEngine.newUrlRequestBuilder(
BuildConfig.VASIAI_API_ENDPOINT + endpoint,
callback,
executor
).addHeader("Authorization", "Bearer $apiKey")
requestBuilder = requestBuilder.setHttpMethod(method)
headers?.forEach { e ->
requestBuilder = requestBuilder.addHeader(e.key, e.value)
}
if (uploadDataProvider != null) {
requestBuilder = requestBuilder.setUploadDataProvider(uploadDataProvider, executor)
}
return requestBuilder.build()
}
}

View file

@ -1,57 +1,111 @@
package eu.m724.vastapp.vastai
import eu.m724.vastapp.BuildConfig
import eu.m724.vastapp.vastai.cronet.InstancesUrlRequestCallback
import eu.m724.vastapp.vastai.cronet.JsonUrlRequestCallback
import eu.m724.vastapp.vastai.cronet.UserUrlRequestCallback
import eu.m724.vastapp.vastai.cronet.upload.StringUploadDataProvider
import eu.m724.vastapp.vastai.data.RentedInstance
import eu.m724.vastapp.vastai.data.User
import eu.m724.vastapp.vastai.exceptions.ApiException
import kotlinx.coroutines.CompletableDeferred
import org.chromium.net.CronetEngine
import org.chromium.net.UploadDataProvider
import org.chromium.net.UrlRequest
import java.util.concurrent.Executor
class VastApi(
var apiKey: String, // TODO make private?
private val cronetEngine: CronetEngine,
private val executor: Executor
apiKey: String, // TODO make private?
cronetEngine: CronetEngine,
executor: Executor
) {
/**
* build an api request
* don't forget to call .start() on the returned [UrlRequest]
*
* @param endpoint the endpoint path starting with a slash like /users/current
* @param callback any callback for example [UserUrlRequestCallback]
* @param method request method, default GET
* @param uploadDataProvider [UploadDataProvider] if request sends data
* @return an [UrlRequest] you must .start() yourself
*/
fun buildRequest(
endpoint: String,
callback: UrlRequest.Callback,
method: String = "GET",
uploadDataProvider: UploadDataProvider?
): UrlRequest {
var requestBuilder = cronetEngine.newUrlRequestBuilder(
BuildConfig.VASIAI_API_ENDPOINT + endpoint,
callback,
executor
).addHeader("Authorization", "Bearer $apiKey")
private val requestMaker = RequestMaker(apiKey, cronetEngine, executor)
requestBuilder = requestBuilder.setHttpMethod(method)
fun getUser(): CompletableDeferred<User> {
val deferred = CompletableDeferred<User>()
if (uploadDataProvider != null) {
requestBuilder = requestBuilder.setUploadDataProvider(uploadDataProvider, executor)
}
val request = requestMaker.buildRequest(
"/users/current",
UserUrlRequestCallback(
onSuccess = { deferred.complete(it) },
onFailure = { deferred.completeExceptionally(it) }
)
)
return requestBuilder.build()
request.start()
return deferred
}
/**
* build an api request
* don't forget to call .start() on the returned [UrlRequest]
*
* @param apiRoute the api route
* @param callback any callback for example [UserUrlRequestCallback]
* @param uploadDataProvider [UploadDataProvider] if request sends data
* @return an [UrlRequest] you must .start() yourself
*/
fun buildRequest(apiRoute: ApiRoute, callback: UrlRequest.Callback, uploadDataProvider: UploadDataProvider? = null): UrlRequest {
return buildRequest(apiRoute.path, callback, apiRoute.method, uploadDataProvider)
fun getRentedInstances(): CompletableDeferred<List<RentedInstance>> {
val deferred = CompletableDeferred<List<RentedInstance>>()
val request = requestMaker.buildRequest(
"/instances",
InstancesUrlRequestCallback(
onSuccess = { deferred.complete(it) },
onFailure = { deferred.completeExceptionally(it) }
)
)
request.start()
return deferred
} // TODO maybe we could make a function that handles all that build stuff and just takes a type and path
fun deleteInstance(rentalId: Int): CompletableDeferred<Unit> {
val deferred = CompletableDeferred<Unit>()
val request = requestMaker.buildRequest(
"/instances/$rentalId",
JsonUrlRequestCallback(
onSuccess = {
if (it.getBoolean("success"))
deferred.complete(Unit)
else
deferred.completeExceptionally(ApiException("Failed to delete: $it"))
},
onFailure = { deferred.completeExceptionally(it) }
),
"DELETE"
)
request.start()
return deferred
}
fun startInstance(rentalId: Int): CompletableDeferred<Unit> {
val deferred = CompletableDeferred<Unit>()
val request = requestMaker.buildRequest(
"/instances/$rentalId",
JsonUrlRequestCallback(
onSuccess = {
deferred.complete(Unit)
},
onFailure = { deferred.completeExceptionally(it) }
),
"PUT",
mapOf(Pair("Content-Type", "application/json")),
StringUploadDataProvider("{\"state\": \"running\"}")
)
request.start()
return deferred
}
fun stopInstance(rentalId: Int): CompletableDeferred<Unit> { // TODO this too make one function that does all things
val deferred = CompletableDeferred<Unit>()
val request = requestMaker.buildRequest(
"/instances/$rentalId",
JsonUrlRequestCallback(
onSuccess = {
deferred.complete(Unit)
},
onFailure = { deferred.completeExceptionally(it) }
),
"PUT",
mapOf(Pair("Content-Type", "application/json")),
StringUploadDataProvider("{\"state\": \"stopped\"}")
)
request.start()
return deferred
}
}

View file

@ -1,6 +1,6 @@
package eu.m724.vastapp.vastai.api
package eu.m724.vastapp.vastai.cronet
import eu.m724.vastapp.vastai.api.exceptions.ApiException
import eu.m724.vastapp.vastai.exceptions.ApiException
import eu.m724.vastapp.vastai.data.RentedInstance
class InstancesUrlRequestCallback(

View file

@ -1,6 +1,6 @@
package eu.m724.vastapp.vastai.api
package eu.m724.vastapp.vastai.cronet
import eu.m724.vastapp.vastai.api.exceptions.ApiException
import eu.m724.vastapp.vastai.exceptions.ApiException
import org.json.JSONObject
open class JsonUrlRequestCallback(

View file

@ -1,9 +1,9 @@
package eu.m724.vastapp.vastai.api
package eu.m724.vastapp.vastai.cronet
import eu.m724.vastapp.vastai.api.exceptions.ApiException
import eu.m724.vastapp.vastai.api.exceptions.ClientException
import eu.m724.vastapp.vastai.api.exceptions.ServerError
import eu.m724.vastapp.vastai.api.exceptions.UnauthorizedException
import eu.m724.vastapp.vastai.exceptions.ApiException
import eu.m724.vastapp.vastai.exceptions.ClientException
import eu.m724.vastapp.vastai.exceptions.ServerError
import eu.m724.vastapp.vastai.exceptions.UnauthorizedException
import org.chromium.net.CronetException
import org.chromium.net.UrlRequest
import org.chromium.net.UrlResponseInfo

View file

@ -1,6 +1,6 @@
package eu.m724.vastapp.vastai.api
package eu.m724.vastapp.vastai.cronet
import eu.m724.vastapp.vastai.api.exceptions.ApiException
import eu.m724.vastapp.vastai.exceptions.ApiException
import eu.m724.vastapp.vastai.data.User
class UserUrlRequestCallback(

View file

@ -1,4 +1,4 @@
package eu.m724.vastapp.vastai.api.upload
package eu.m724.vastapp.vastai.cronet.upload
import org.json.JSONObject

View file

@ -1,4 +1,4 @@
package eu.m724.vastapp.vastai.api.upload
package eu.m724.vastapp.vastai.cronet.upload
import org.chromium.net.UploadDataProvider
import org.chromium.net.UploadDataSink

View file

@ -0,0 +1,6 @@
package eu.m724.vastapp.vastai.exceptions
open class ApiException(
override val message: String? = null,
override val cause: Throwable? = null
): Exception()

View file

@ -0,0 +1,6 @@
package eu.m724.vastapp.vastai.exceptions
open class ClientException(
message: String? = null,
cause: Throwable? = null
) : ApiException(message, cause)

View file

@ -0,0 +1,6 @@
package eu.m724.vastapp.vastai.exceptions
open class ServerError(
val statusCode: Int,
message: String?,
): ApiException(message, null)

View file

@ -0,0 +1,5 @@
package eu.m724.vastapp.vastai.exceptions
class UnauthorizedException(
message: String? = null
) : ClientException(message, null)