Skip to content

Commit 96e2c9b

Browse files
Merge pull request #405 from appwrite/0.14.x
2 parents 9381507 + 166c157 commit 96e2c9b

File tree

22 files changed

+430
-249
lines changed

22 files changed

+430
-249
lines changed

.travis.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ env:
2828
- SDK=FlutterBeta
2929
- SDK=KotlinJava8
3030
- SDK=KotlinJava11
31+
- SDK=KotlinJava17
3132
- SDK=Node12
3233
- SDK=Node14
3334
- SDK=Node16

example.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ function getSSLPage($url) {
183183
->setTwitter('appwrite_io')
184184
->setDiscord('564160730845151244', 'https://appwrite.io/discord')
185185
->setDefaultHeaders([
186-
'X-Appwrite-Response-Format' => '0.12.0',
186+
'X-Appwrite-Response-Format' => '0.13.0',
187187
])
188188
;
189189

templates/android/library/src/main/java/io/appwrite/Client.kt.twig

Lines changed: 42 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import okhttp3.RequestBody.Companion.toRequestBody
2323
import java.io.BufferedInputStream
2424
import java.io.BufferedReader
2525
import java.io.File
26+
import java.io.RandomAccessFile
2627
import java.io.IOException
2728
import java.net.CookieManager
2829
import java.net.CookiePolicy
@@ -225,7 +226,7 @@ class Client @JvmOverloads constructor(
225226
headers: Map<String, String> = mapOf(),
226227
params: Map<String, Any?> = mapOf(),
227228
responseType: Class<T>,
228-
convert: ((Map<String, Any,>) -> T)? = null
229+
converter: ((Map<String, Any,>) -> T)? = null
229230
): T {
230231
val filteredParams = params.filterValues { it != null }
231232

@@ -261,7 +262,7 @@ class Client @JvmOverloads constructor(
261262
.get()
262263
.build()
263264

264-
return awaitResponse(request, responseType, convert)
265+
return awaitResponse(request, responseType, converter)
265266
}
266267

267268
val body = if (MultipartBody.FORM.toString() == headers["content-type"]) {
@@ -298,7 +299,7 @@ class Client @JvmOverloads constructor(
298299
.method(method, body)
299300
.build()
300301

301-
return awaitResponse(request, responseType, convert)
302+
return awaitResponse(request, responseType, converter)
302303
}
303304

304305
/**
@@ -316,8 +317,9 @@ class Client @JvmOverloads constructor(
316317
headers: MutableMap<String, String>,
317318
params: MutableMap<String, Any?>,
318319
responseType: Class<T>,
319-
convert: ((Map<String, Any,>) -> T),
320+
converter: ((Map<String, Any,>) -> T),
320321
paramName: String,
322+
idParamName: String? = null,
321323
onProgress: ((UploadProgress) -> Unit)? = null,
322324
): T {
323325
val file = params[paramName] as File
@@ -330,74 +332,84 @@ class Client @JvmOverloads constructor(
330332
file.asRequestBody()
331333
)
332334
return call(
333-
"POST",
335+
method = "POST",
334336
path,
335337
headers,
336338
params,
337339
responseType,
338-
convert
340+
converter
339341
)
340342
}
341343

342-
val input = file.inputStream().buffered()
344+
val input = RandomAccessFile(file, "r")
343345
val buffer = ByteArray(CHUNK_SIZE)
344346
var offset = 0L
345347
var result: Map<*, *>? = null
346348

347-
generateSequence {
348-
val readBytes = input.read(buffer)
349-
if (readBytes >= 0) {
350-
buffer.copyOf(readBytes)
351-
} else {
352-
input.close()
353-
null
354-
}
355-
}.forEach {
349+
if (idParamName?.isNotEmpty() == true && params[idParamName] != "unique()") {
350+
// Make a request to check if a file already exists
351+
val current = call(
352+
method = "GET",
353+
path = "$path/${params[idParamName]}",
354+
headers = headers,
355+
params = emptyMap(),
356+
responseType = Map::class.java,
357+
)
358+
val chunksUploaded = current["chunksUploaded"] as Long
359+
offset = (chunksUploaded * CHUNK_SIZE).coerceAtMost(size)
360+
}
361+
362+
while (offset < size) {
363+
input.seek(offset)
364+
input.read(buffer)
365+
356366
params[paramName] = MultipartBody.Part.createFormData(
357367
paramName,
358368
file.name,
359-
it.toRequestBody()
369+
buffer.toRequestBody()
360370
)
361371

362372
headers["Content-Range"] =
363373
"bytes $offset-${((offset + CHUNK_SIZE) - 1).coerceAtMost(size)}/$size"
364374

365375
result = call(
366-
"POST",
376+
method = "POST",
367377
path,
368378
headers,
369379
params,
370-
Map::class.java
380+
responseType = Map::class.java
371381
)
372382

373383
offset += CHUNK_SIZE
374384
headers["x-{{ spec.title | caseLower }}-id"] = result!!["\$id"].toString()
375-
onProgress?.invoke(UploadProgress(
376-
id = result!!["\$id"].toString(),
377-
progress = offset.coerceAtMost(size).toDouble()/size * 100,
378-
sizeUploaded = offset.coerceAtMost(size),
379-
chunksTotal = result!!["chunksTotal"].toString().toInt(),
380-
chunksUploaded = result!!["chunksUploaded"].toString().toInt(),
381-
))
385+
onProgress?.invoke(
386+
UploadProgress(
387+
id = result!!["\$id"].toString(),
388+
progress = offset.coerceAtMost(size).toDouble() / size * 100,
389+
sizeUploaded = offset.coerceAtMost(size),
390+
chunksTotal = result!!["chunksTotal"].toString().toInt(),
391+
chunksUploaded = result!!["chunksUploaded"].toString().toInt(),
392+
)
393+
)
382394
}
383395

384-
return convert(result as Map<String, Any>)
396+
return converter(result as Map<String, Any>)
385397
}
386398

387399
/**
388400
* Await Response
389401
*
390402
* @param request
391403
* @param responseType
392-
* @param convert
404+
* @param converter
393405
*
394406
* @return [T]
395407
*/
396408
@Throws({{ spec.title | caseUcfirst }}Exception::class)
397409
private suspend fun <T> awaitResponse(
398410
request: Request,
399411
responseType: Class<T>,
400-
convert: ((Map<String, Any,>) -> T)? = null
412+
converter: ((Map<String, Any,>) -> T)? = null
401413
) = suspendCancellableCoroutine<T> {
402414
http.newCall(request).enqueue(object : Callback {
403415
override fun onFailure(call: Call, e: IOException) {
@@ -463,7 +475,7 @@ class Client @JvmOverloads constructor(
463475
object : TypeToken<Map<String, Any>>(){}.type
464476
)
465477
it.resume(
466-
convert?.invoke(map) ?: map as T
478+
converter?.invoke(map) ?: map as T
467479
)
468480
}
469481
})

templates/android/library/src/main/java/io/appwrite/services/ServiceTemplate.kt.twig

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ class {{ service.name | caseUcfirst }}(client: Client) : Service(client) {
114114
{{ method.headers|map((header, key) => " \"#{key}\" to \"#{header}\"")|join(',\n')|raw }}
115115
)
116116
{% if method.responseModel %}
117-
val convert: (Map<String, Any>) -> {{ _self.resultType(sdk.namespace, method) }} = {
117+
val converter: (Map<String, Any>) -> {{ _self.resultType(sdk.namespace, method) }} = {
118118
{% if method.responseModel == 'any' %}
119119
it
120120
{% else %}
@@ -123,20 +123,26 @@ class {{ service.name | caseUcfirst }}(client: Client) : Service(client) {
123123
}
124124
{% endif %}
125125
{% if 'multipart/form-data' in method.consumes %}
126+
val idParamName: String? = {% if method.parameters.all | filter(p => p.isUploadID) | length > 0 %}{% for parameter in method.parameters.all | filter(parameter => parameter.isUploadID) %}"{{ parameter.name }}"{% endfor %}{% else %}null{% endif %}
127+
126128
{% for parameter in method.parameters.all %}
127129
{% if parameter.type == 'file' %}
128130
val paramName = "{{ parameter.name }}"
129131
{% endif %}
132+
{% if parameter.isUploadID %}
133+
idParamName = "{{ parameter.name }}"
134+
{% endif %}
130135
{% endfor %}
131136
return client.chunkedUpload(
132137
path,
133138
headers,
134139
params,
135140
responseType = {{ _self.resultType(sdk.namespace, method) }}::class.java,
136141
{% if method.responseModel %}
137-
convert = convert,
142+
converter,
138143
{% endif %}
139144
paramName,
145+
idParamName,
140146
onProgress,
141147
)
142148
{% else %}
@@ -147,7 +153,7 @@ class {{ service.name | caseUcfirst }}(client: Client) : Service(client) {
147153
params,
148154
responseType = {{ _self.resultType(sdk.namespace, method) }}::class.java,
149155
{% if method.responseModel %}
150-
convert = convert,
156+
converter,
151157
{% endif %}
152158
)
153159
{% endif %}

templates/cli/lib/commands/command.js.twig

Lines changed: 48 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ const {{ service.name | caseLower }}{{ method.name | caseUcfirst }} = async ({ {
4747
let archivePath = fs.realpathSync('code.tar.gz')
4848
if (typeof archivePath !== 'undefined') {
4949
payload['{{ parameter.name }}'] = archivePath;
50+
{{ parameter.name }} = archivePath;
5051
}
5152

5253
{% elseif parameter.type == 'file' %}
@@ -114,50 +115,61 @@ const {{ service.name | caseLower }}{{ method.name | caseUcfirst }} = async ({ {
114115
const streamFilePath = payload['{{ parameter.name }}'];
115116
let id = undefined;
116117

118+
let counter = 0;
117119
const totalCounters = Math.ceil(size / libClient.CHUNK_SIZE);
118120

119-
for (let counter = 0; counter < totalCounters; counter++) {
120-
const start = (counter * libClient.CHUNK_SIZE);
121-
const end = Math.min((((counter * libClient.CHUNK_SIZE) + libClient.CHUNK_SIZE) - 1), size);
122-
const headers = {
121+
const headers = {
123122
{% for parameter in method.parameters.header %}
124-
'{{ parameter.name }}': ${{ parameter.name | caseCamel | escapeKeyword }},
123+
'{{ parameter.name }}': ${{ parameter.name | caseCamel | escapeKeyword }},
125124
{% endfor %}
126125
{% for key, header in method.headers %}
127-
'{{ key }}': '{{ header }}',
126+
'{{ key }}': '{{ header }}',
127+
{% endfor %}
128+
};
129+
130+
{% for parameter in method.parameters.all %}
131+
{% if parameter.isUploadID %}
132+
if({{ parameter.name | caseCamel | escapeKeyword }} != 'unique()') {
133+
try {
134+
response = await client.call('get', path + '/' + {{ parameter.name }}, headers);
135+
counter = response.chunksUploaded;
136+
} catch(e) {
137+
}
138+
}
139+
{% endif %}
128140
{% endfor %}
129-
'content-range': 'bytes ' + start + '-' + end + '/' + size
130-
};
131141

132-
if (id) {
133-
headers['x-appwrite-id'] = id;
134-
}
142+
for (counter; counter < totalCounters; counter++) {
143+
const start = (counter * libClient.CHUNK_SIZE);
144+
const end = Math.min((((counter * libClient.CHUNK_SIZE) + libClient.CHUNK_SIZE) - 1), size);
145+
146+
headers['content-range'] = 'bytes ' + start + '-' + end + '/' + size;
147+
148+
if (id) {
149+
headers['x-appwrite-id'] = id;
150+
}
151+
152+
const stream = fs.createReadStream(streamFilePath, {
153+
start,
154+
end
155+
});
156+
payload['{{ parameter.name }}'] = stream;
157+
158+
response = await client.call('{{ method.method | caseLower }}', path, headers, payload{% if method.type == 'location' %}, 'arraybuffer'{% endif %});
159+
160+
if (!id) {
161+
id = response['$id'];
162+
}
135163

136-
const stream = fs.createReadStream(streamFilePath, {
137-
start,
138-
end
164+
if (onProgress !== null) {
165+
onProgress({
166+
$id: response['$id'],
167+
progress: Math.min((counter+1) * libClient.CHUNK_SIZE, size) / size * 100,
168+
sizeUploaded: end+1,
169+
chunksTotal: response['chunksTotal'],
170+
chunksUploaded: response['chunksUploaded']
139171
});
140-
payload['{{ parameter.name }}'] = stream;
141-
142-
response = await client.call('{{ method.method | caseLower }}', path, headers, payload{% if method.type == 'location' %}, 'arraybuffer'{% endif %}){% if method.packaging %}.catch(err => {
143-
fs.unlinkSync(archivePath);
144-
throw err
145-
});{% endif %}
146-
147-
148-
if (!id) {
149-
id = response['$id'];
150-
}
151-
152-
if (onProgress !== null) {
153-
onProgress({
154-
$id: response['$id'],
155-
progress: Math.min((counter+1) * libClient.CHUNK_SIZE, size) / size * 100,
156-
sizeUploaded: end+1,
157-
chunksTotal: response['chunksTotal'],
158-
chunksUploaded: response['chunksUploaded']
159-
});
160-
}
172+
}
161173
}
162174
}
163175
{% endif %}
@@ -209,4 +221,4 @@ module.exports = {
209221
{{ service.name | caseLower }}{{ method.name | caseUcfirst }}{% if not loop.last %},{% endif %}
210222

211223
{% endfor %}
212-
};
224+
};

templates/dart/lib/src/chunked_upload_io.dart.twig

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,8 @@ Future<Response> chunkedUpload({
6666
}
6767
final progress = UploadProgress(
6868
$id: res.data['\$id'] ?? '',
69-
progress: min(offset,size)/size * 100,
70-
sizeUploaded: min(offset,size),
69+
progress: min(offset-1,size)/size * 100,
70+
sizeUploaded: min(offset-1,size),
7171
chunksTotal: res.data['chunksTotal'] ?? 0,
7272
chunksUploaded: res.data['chunksUploaded'] ?? 0,
7373
);

0 commit comments

Comments
 (0)