Skip to content

Commit

Permalink
fix: payload use
Browse files Browse the repository at this point in the history
  • Loading branch information
loks0n committed Sep 17, 2024
1 parent f786b69 commit 0129058
Show file tree
Hide file tree
Showing 2 changed files with 151 additions and 149 deletions.
133 changes: 74 additions & 59 deletions templates/react-native/src/payload.ts.twig
Original file line number Diff line number Diff line change
@@ -1,63 +1,78 @@
interface ReactNativeFileObject {
uri: string;
type?: string;
name?: string;
uri: string;
type?: string;
name?: string;
}

export class Payload {
private data: Buffer;
public filename?: string;
public size: number;

constructor(data: Buffer, filename?: string) {
this.data = data;
this.filename = filename;
this.size = data.byteLength;
}

public toBinary(offset: number = 0, length?: number): Buffer {
if (offset === 0 && length === undefined) {
return this.data;
} else if (length === undefined) {
return this.data.subarray(offset);
} else {
return this.data.subarray(offset, offset + length);
}
}

public toFileObject(type: string): ReactNativeFileObject {
return {
uri: `data:${type};base64,${this.data.toString("base64")}`,
type: type,
name: this.filename,
};
}

public toJson<T = unknown>(): Promise<T> {
return JSON.parse(this.toString());
}

public toString(): string {
return this.data.toString("utf-8");
}

public static fromBinary(bytes: Buffer, name?: string): Payload {
return new Payload(bytes, name);
}

public static fromJson(object: any, name?: string): Payload {
const data = Buffer.from(JSON.stringify(object), "utf-8");
return new Payload(data, name);
}

public static fromString(text: string, name?: string): Payload {
const data = Buffer.from(text, "utf-8");
return new Payload(data, name);
}

public static async fromFileObject(file: ReactNativeFileObject): Promise<Payload> {
const response = await fetch(file.uri);
const data = Buffer.from(await response.arrayBuffer());
return new Payload(data, file.name);
}
}
private data: Buffer;
public filename?: string;
public size: number;
public type?: string;

constructor(data: Buffer, filename?: string, type?: string) {
this.data = data;
this.filename = filename;
this.size = data.byteLength;
this.type = type;
}

public toBinary(offset: number = 0, length?: number): Buffer {
if (offset === 0 && length === undefined) {
return this.data;
} else if (length === undefined) {
return this.data.subarray(offset);
} else {
return this.data.subarray(offset, offset + length);
}
}

public toFileObject(): ReactNativeFileObject {
const base64Data = this.data.toString("base64");
const uri = `data:${this.type};base64,${base64Data}`;
return {
uri: uri,
type: this.type,
name: this.filename,
};
}

public toJson<T = unknown>(): T {
return JSON.parse(this.toString());
}

public toString(): string {
return this.data.toString("utf-8");
}

public static fromBinary(
bytes: Buffer,
name?: string,
type?: string
): Payload {
return new Payload(bytes, name, type);
}

public static fromJson(object: any, name?: string): Payload {
const data = Buffer.from(JSON.stringify(object), "utf-8");
return new Payload(data, name, "application/json");
}

public static fromString(
text: string,
name?: string,
type?: string
): Payload {
const data = Buffer.from(text, "utf-8");
return new Payload(data, name, type || "text/plain");
}

public static async fromFileObject(
file: ReactNativeFileObject
): Promise<Payload> {
const response = await fetch(file.uri);
const arrayBuffer = await response.arrayBuffer();
const data = Buffer.from(arrayBuffer);
return new Payload(data, file.name, file.type);
}
}
167 changes: 77 additions & 90 deletions templates/react-native/src/services/template.ts.twig
Original file line number Diff line number Diff line change
@@ -1,133 +1,125 @@
import { Service } from '../service';
import { {{ spec.title | caseUcfirst}}Exception, Client } from '../client';
import { {{ spec.title | caseUcfirst }}Exception, Client } from '../client';
import { Payload } from '../payload';
import type { Models } from '../models';
import type { UploadProgress, Params } from '../client';
import * as FileSystem from 'expo-file-system';
import { Platform } from 'react-native';

{% set added = [] %}
{% for method in service.methods %}
{% for parameter in method.parameters.all %}
{% if parameter.enumValues is not empty %}
{% if parameter.enumName is not empty %}
{% set name = parameter.enumName %}
{% else %}
{% set name = parameter.name %}
{% endif %}
{% if name not in added %}
{%~ for method in service.methods %}
{%~ for parameter in method.parameters.all %}
{%~ if parameter.enumValues is not empty %}
{%~ if parameter.enumName is not empty %}
{% set name = parameter.enumName %}
{% else %}
{% set name = parameter.name %}
{%- endif %}
{%~ if name not in added -%}
import { {{ name | caseUcfirst }} } from '../enums/{{ name | caseDash }}';
{% set added = added|merge([name]) %}
{% endif %}
{% endif %}
{% endfor %}
{% endfor %}
{%~ set added = added|merge([name]) -%}
{%- endif %}
{%- endif %}
{%- endfor %}
{%- endfor %}

export class {{ service.name | caseUcfirst }} extends Service {

constructor(client: Client)
{
super(client);
}
{% for method in service.methods %}
{%~ for method in service.methods %}

/**
* {{ method.title }}
*
{% if method.description %}
{{ method.description|comment2 }}
{% endif %}
{%~ if method.description %}
* {{ method.description }}
{%~ endif %}
*
{% for parameter in method.parameters.all %}
{%~ for parameter in method.parameters.all %}
* @param {{ '{' }}{{ parameter | getPropertyType(method) | raw }}{{ '}' }} {{ parameter.name | caseCamel | escapeKeyword }}
{% endfor %}
* @throws {{ '{' }}{{ spec.title | caseUcfirst}}Exception}
{%~ endfor %}
* @throws {{ '{' }}{{ spec.title | caseUcfirst }}Exception}
* @returns {% if method.type == 'webAuth' %}{void|string}{% elseif method.type == 'location' %}{URL}{% else %}{Promise}{% endif %}

*/
{% if method.type != 'location' and method.type != 'webAuth'%}async {% endif %}{{ method.name | caseCamel }}{{ method.responseModel | getGenerics(spec) | raw }}({% for parameter in method.parameters.all %}{{ parameter.name | caseCamel | escapeKeyword }}{% if not parameter.required or parameter.nullable %}?{% endif %}: {{ parameter | getPropertyType(method) | raw }}{% if not loop.last %}, {% endif %}{% endfor %}{% if 'multipart/form-data' in method.consumes %}, onProgress = (progress: UploadProgress) => {}{% endif %}): {{ method | getReturn(spec) | raw }} {
{% for parameter in method.parameters.all %}
{% if parameter.required %}
{% if method.type != 'location' and method.type != 'webAuth'%}async {% endif %}{{ method.name | caseCamel }}{{ method.responseModel | getGenerics(spec) | raw }}({%~ for parameter in method.parameters.all %}{{ parameter.name | caseCamel | escapeKeyword }}{%~ if not parameter.required or parameter.nullable %}?{%- endif %}: {{ parameter | getPropertyType(method) | raw }}{%~ if not loop.last %}, {%- endif %}{%- endfor %}{%~ if 'multipart/form-data' in method.consumes %}, onProgress = (progress: UploadProgress) => {}{%- endif %}): {{ method | getReturn(spec) | raw }} {
{%~ for parameter in method.parameters.all %}
{%~ if parameter.required %}
if (typeof {{ parameter.name | caseCamel | escapeKeyword }} === 'undefined') {
throw new {{spec.title | caseUcfirst}}Exception('Missing required parameter: "{{ parameter.name | caseCamel | escapeKeyword }}"');
}

{% endif %}
{% endfor %}
const apiPath = '{{ method.path }}'{% for parameter in method.parameters.path %}.replace('{{ '{' }}{{ parameter.name | caseCamel | escapeKeyword }}{{ '}' }}', {{ parameter.name | caseCamel | escapeKeyword }}){% endfor %};
{%~ endif %}
{%~ endfor %}
const apiPath = '{{ method.path }}'{%~ for parameter in method.parameters.path %}.replace('{{ '{' }}{{ parameter.name | caseCamel | escapeKeyword }}{{ '}' }}', {{ parameter.name | caseCamel | escapeKeyword }}){%- endfor %};
const params: Params = {};

{% for parameter in method.parameters.query %}
{%~ for parameter in method.parameters.query %}
if (typeof {{ parameter.name | caseCamel | escapeKeyword }} !== 'undefined') {
params['{{ parameter.name }}'] = {{ parameter.name | caseCamel | escapeKeyword }};
}

{% endfor %}
{% for parameter in method.parameters.body %}
{%~ endfor %}
{%~ for parameter in method.parameters.body %}
if (typeof {{ parameter.name | caseCamel | escapeKeyword }} !== 'undefined') {
params['{{ parameter.name }}'] = {{ parameter.name | caseCamel | escapeKeyword }};
}

{% endfor %}
{%~ endfor %}
const uri = new URL(this.client.config.endpoint + apiPath);
{% if method.type == 'location' or method.type == 'webAuth' %}
{% if method.auth|length > 0 %}
{% for node in method.auth %}
{% for key,header in node|keys %}
params['{{header|caseLower}}'] = this.client.config.{{header|caseLower}};

{% endfor %}
{% endfor %}
{% endif %}
{%~ if method.type == 'location' or method.type == 'webAuth' %}
{%~ if method.auth|length > 0 %}
{%~ for node in method.auth %}
{%~ for key,header in node|keys %}
params['{{header|caseLower}}'] = this.client.config.{{header|caseLower}};
{%~ endfor %}
{%~ endfor %}
{%~ endif %}

for (const [key, value] of Object.entries(Service.flatten(params))) {
uri.searchParams.append(key, value);
}
{% endif %}
{% if method.type == 'webAuth' %}
{%~ endif %}
{%~ if method.type == 'webAuth' or method.type == 'location' %}
return uri;
{% elseif method.type == 'location' %}
return uri;
{% else %}
{% if 'multipart/form-data' in method.consumes %}
{% for parameter in method.parameters.all %}
{% if parameter.type == 'file' %}
{%~ else %}
const apiHeaders: { [header: string]: string } = {
{%~ for parameter in method.parameters.header %}
'{{ parameter.name | caseCamel | escapeKeyword }}': this.client.${{ parameter.name | caseCamel | escapeKeyword }},
{%- endfor %}
{%~ for key, header in method.headers %}
'{{ key }}': '{{ header }}',
{%~ endfor %}
}

{%~ if 'multipart/form-data' in method.consumes and method.type == 'upload' %}
{%~ for parameter in method.parameters.all %}
{%~ if parameter.type == 'file' %}

const size = {{ parameter.name | caseCamel | escapeKeyword }}.size;

if (size <= Service.CHUNK_SIZE) {
return await this.client.call('{{ method.method | caseLower }}', uri, {
{% for parameter in method.parameters.header %}
'{{ parameter.name | caseCamel | escapeKeyword }}': this.client.${{ parameter.name | caseCamel | escapeKeyword }},
{% endfor %}
{% for key, header in method.headers %}
'{{ key }}': '{{ header }}',
{% endfor %}
}, params);
}

const apiHeaders: { [header: string]: string } = {
{% for parameter in method.parameters.header %}
'{{ parameter.name | caseCamel | escapeKeyword }}': this.client.${{ parameter.name | caseCamel | escapeKeyword }},
{% endfor %}
{% for key, header in method.headers %}
'{{ key }}': '{{ header }}',
{% endfor %}
params['{{ parameter.name }}'] = {{ parameter.name | caseCamel | escapeKeyword }}.toFileObject();
return await this.client.call('{{ method.method | caseLower }}', uri, apiHeaders, params);
}

let offset = 0;
let response = undefined;
{% for parameter in method.parameters.all %}
{% if parameter.isUploadID %}
{%~ for parameter in method.parameters.all %}
{%~ if parameter.isUploadID %}
if({{ parameter.name | caseCamel | escapeKeyword }} != 'unique()') {
try {
response = await this.client.call('GET', new URL(this.client.config.endpoint + apiPath + '/' + {{ parameter.name }}), apiHeaders);
offset = response.chunksUploaded * Service.CHUNK_SIZE;
} catch(e) {
}
}
{% endif %}
{% endfor %}
{%~ endif %}
{%~ endfor %}

let timestamp = new Date().getTime();
while (offset < size) {
Expand All @@ -138,18 +130,20 @@ export class {{ service.name | caseUcfirst }} extends Service {
apiHeaders['x-{{spec.title | caseLower }}-id'] = response.$id;
}

let chunk = await FileSystem.readAsStringAsync({{ parameter.name | caseCamel | escapeKeyword }}.uri, {
encoding: FileSystem.EncodingType.Base64,
position: offset,
length: Service.CHUNK_SIZE
});
var path = `data:${{'{'}}{{ parameter.name | caseCamel | escapeKeyword }}.type{{'}'}};base64,${{'{'}}chunk{{'}'}}`;
let chunkBuffer = {{ parameter.name | caseCamel | escapeKeyword }}.toBinary(offset, end - offset + 1);
let chunk = chunkBuffer.toString('base64');

var path = `data:${{ parameter.name | caseCamel | escapeKeyword }}.type};base64,${chunk}`;
if (Platform.OS.toLowerCase() === 'android') {
path = FileSystem.cacheDirectory + '/tmp_chunk_' + timestamp;
await FileSystem.writeAsStringAsync(path, chunk, {encoding: FileSystem.EncodingType.Base64});
}

params['{{ parameter.name }}'] = {{ '{' }} uri: path, name: {{ parameter.name | caseCamel | escapeKeyword }}.name, type: {{ parameter.name | caseCamel | escapeKeyword }}.type {{ '}' }};
params['{{ parameter.name }}'] = {
uri: path,
name: {{ parameter.name | caseCamel | escapeKeyword }}.filename,
type: {{ parameter.name | caseCamel | escapeKeyword }}.type
};

response = await this.client.call('{{ method.method | caseLower }}', uri, apiHeaders, params);

Expand All @@ -165,19 +159,12 @@ export class {{ service.name | caseUcfirst }} extends Service {
offset += Service.CHUNK_SIZE;
}
return response;
{% endif %}
{% endfor %}
{% else %}
return await this.client.call('{{ method.method | caseLower }}', uri, {
{% for parameter in method.parameters.header %}
'{{ parameter.name | caseCamel | escapeKeyword }}': this.client.${{ parameter.name | caseCamel | escapeKeyword }},
{% endfor %}
{% for key, header in method.headers %}
'{{ key }}': '{{ header }}',
{% endfor %}
}, params);
{% endif %}
{% endif %}
{%~ endif %}
{%~ endfor %}
{%~ else %}
return await this.client.call('{{ method.method | caseLower }}', uri, apiHeaders, params);
{%~ endif %}
{%~ endif %}
}
{% endfor %}
{%~ endfor %}
};

0 comments on commit 0129058

Please sign in to comment.