Skip to content

Commit c2d60e6

Browse files
Merge pull request #485 from everly-gif/feat-refactor-node-templates
2 parents 3aa6d1d + eac5463 commit c2d60e6

File tree

4 files changed

+166
-162
lines changed

4 files changed

+166
-162
lines changed

templates/node/base/params.twig

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
let payload = {};
2+
{% if method.parameters.all | length %}
3+
{% for parameter in method.parameters.all | filter((param) => not param.isGlobal) %}
4+
{% if parameter.required %}
5+
if (typeof {{ parameter.name | caseCamel | escapeKeyword }} === 'undefined') {
6+
throw new {{spec.title | caseUcfirst}}Exception('Missing required parameter: "{{ parameter.name | caseCamel | escapeKeyword }}"');
7+
}
8+
9+
{% endif %}
10+
{% endfor %}
11+
{% for parameter in method.parameters.query %}
12+
13+
if (typeof {% if parameter.isGlobal %}this.{% endif %}{{ parameter.name | caseCamel | escapeKeyword }} !== 'undefined') {
14+
payload['{{ parameter.name }}'] = {% if parameter.isGlobal %}this.{% endif %}{{ parameter.name | caseCamel | escapeKeyword }}{% if method.consumes[0] == "multipart/form-data" and ( parameter.type != "string" and parameter.type != "array" and parameter.type != "file" ) %}.toString(){% endif %};
15+
}
16+
{% endfor %}
17+
{% for parameter in method.parameters.body %}
18+
19+
if (typeof {% if parameter.isGlobal %}this.{% endif %}{{ parameter.name | caseCamel | escapeKeyword }} !== 'undefined') {
20+
payload['{{ parameter.name }}'] = {% if parameter.isGlobal %}this.{% endif %}{{ parameter.name | caseCamel | escapeKeyword}}{% if method.consumes[0] == "multipart/form-data" and ( parameter.type != "string" and parameter.type != "array" and parameter.type != "file" ) %}.toString(){% endif %};
21+
}
22+
{% endfor %}
23+
{% endif %}

templates/node/base/requests/api.twig

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
return await this.client.call('{{ method.method | caseLower }}', path, {
2+
{% for parameter in method.parameters.header %}
3+
'{{ parameter.name }}': ${{ parameter.name | caseCamel | escapeKeyword }},
4+
{% endfor %}
5+
{% for key, header in method.headers %}
6+
'{{ key }}': '{{ header }}',
7+
{% endfor %}
8+
}, payload{% if method.type == 'location' %}, 'arraybuffer'{% endif %});
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
{% for parameter in method.parameters.all %}
2+
{% if parameter.type == 'file' %}
3+
const size = {{ parameter.name | caseCamel | escapeKeyword }}.size;
4+
5+
const headers = {
6+
{% for parameter in method.parameters.header %}
7+
'{{ parameter.name }}': ${{ parameter.name | caseCamel | escapeKeyword }},
8+
{% endfor %}
9+
{% for key, header in method.headers %}
10+
'{{ key }}': '{{ header }}',
11+
{% endfor %}
12+
};
13+
14+
let id = undefined;
15+
let response = undefined;
16+
17+
let chunksUploaded = 0;
18+
19+
{% for parameter in method.parameters.all %}
20+
{% if parameter.isUploadID %}
21+
if({{ parameter.name | caseCamel | escapeKeyword }} != 'unique()') {
22+
try {
23+
response = await this.client.call('get', path + '/' + {{ parameter.name }}, headers);
24+
chunksUploaded = response.chunksUploaded;
25+
} catch(e) {
26+
}
27+
}
28+
{% endif %}
29+
{% endfor %}
30+
31+
let currentChunk = Buffer.from('');
32+
let currentChunkSize = 0;
33+
let currentChunkStart = 0;
34+
35+
const selfClient = this.client;
36+
37+
async function uploadChunk(lastUpload = false) {
38+
if(chunksUploaded - 1 >= currentChunkStart / client.CHUNK_SIZE) {
39+
return;
40+
}
41+
42+
const start = currentChunkStart;
43+
const end = Math.min(((start + client.CHUNK_SIZE) - 1), size);
44+
45+
if(!lastUpload || currentChunkStart !== 0) {
46+
headers['content-range'] = 'bytes ' + start + '-' + end + '/' + size;
47+
}
48+
49+
if (id) {
50+
headers['x-{{spec.title | caseLower }}-id'] = id;
51+
}
52+
53+
const stream = Stream.Readable.from(currentChunk);
54+
payload['{{ parameter.name }}'] = { type: 'file', file: stream, filename: {{ parameter.name }}.filename };
55+
56+
response = await selfClient.call('{{ method.method | caseLower }}', path, headers, payload{% if method.type == 'location' %}, 'arraybuffer'{% endif %});
57+
58+
if (!id) {
59+
id = response['$id'];
60+
}
61+
62+
if (onProgress !== null) {
63+
onProgress({
64+
$id: response['$id'],
65+
progress: Math.min((start+client.CHUNK_SIZE) * client.CHUNK_SIZE, size) / size * 100,
66+
sizeUploaded: end+1,
67+
chunksTotal: response['chunksTotal'],
68+
chunksUploaded: response['chunksUploaded']
69+
});
70+
}
71+
72+
currentChunkStart += client.CHUNK_SIZE;
73+
}
74+
75+
return await new Promise((resolve, reject) => {
76+
const writeStream = new Stream.Writable();
77+
writeStream._write = async (mainChunk, encoding, next) => {
78+
// Segment incoming chunk into up to 5MB chunks
79+
const mainChunkSize = Buffer.byteLength(mainChunk);
80+
const chunksCount = Math.ceil(mainChunkSize / client.CHUNK_SIZE);
81+
const chunks = [];
82+
83+
for(let i = 0; i < chunksCount; i++) {
84+
const chunk = mainChunk.slice(i * client.CHUNK_SIZE, client.CHUNK_SIZE);
85+
chunks.push(chunk);
86+
}
87+
88+
for (const chunk of chunks) {
89+
const chunkSize = Buffer.byteLength(chunk);
90+
91+
if(chunkSize + currentChunkSize == client.CHUNK_SIZE) {
92+
// Upload chunk
93+
currentChunk = Buffer.concat([currentChunk, chunk]);
94+
await uploadChunk();
95+
currentChunk = Buffer.from('');
96+
currentChunkSize = 0;
97+
} else if(chunkSize + currentChunkSize > client.CHUNK_SIZE) {
98+
// Upload chunk, put rest into next chunk
99+
const bytesToUpload = client.CHUNK_SIZE - currentChunkSize;
100+
const newChunkSection = chunk.slice(0, bytesToUpload);
101+
currentChunk = Buffer.concat([currentChunk, newChunkSection]);
102+
currentChunkSize = Buffer.byteLength(currentChunk);
103+
await uploadChunk();
104+
currentChunk = chunk.slice(bytesToUpload, undefined);
105+
currentChunkSize = chunkSize - bytesToUpload;
106+
} else {
107+
// Append into current chunk
108+
currentChunk = Buffer.concat([currentChunk, chunk]);
109+
currentChunkSize = chunkSize + currentChunkSize;
110+
}
111+
}
112+
113+
next();
114+
}
115+
116+
writeStream.on("finish", async () => {
117+
if(currentChunkSize > 0) {
118+
await uploadChunk(true);
119+
}
120+
121+
resolve(response);
122+
});
123+
124+
writeStream.on("error", (err) => {
125+
reject(err);
126+
});
127+
128+
{{ parameter.name | caseCamel | escapeKeyword }}.stream.pipe(writeStream);
129+
});
130+
{% endif %}
131+
{% endfor %}

templates/node/lib/services/service.js.twig

Lines changed: 4 additions & 162 deletions
Original file line numberDiff line numberDiff line change
@@ -56,173 +56,15 @@ class {{ service.name | caseUcfirst }} extends Service {
5656
* @returns {Promise}
5757
*/
5858
async {{ method.name | caseCamel }}({% for parameter in method.parameters.all | filter((param) => not param.isGlobal) %}{{ parameter.name | caseCamel | escapeKeyword }}{% if not loop.last %}, {% endif %}{% endfor %}{% if 'multipart/form-data' in method.consumes %}, onProgress = () => {}{% endif %}) {
59-
{% for parameter in method.parameters.all | filter((param) => not param.isGlobal) %}
60-
{% if parameter.required %}
61-
if (typeof {{ parameter.name | caseCamel | escapeKeyword }} === 'undefined') {
62-
throw new {{spec.title | caseUcfirst}}Exception('Missing required parameter: "{{ parameter.name | caseCamel | escapeKeyword }}"');
63-
}
64-
65-
{% endif %}
66-
{% endfor %}
6759
let path = '{{ method.path }}'{% for parameter in method.parameters.path %}.replace('{{ '{' }}{{ parameter.name | caseCamel }}{{ '}' }}', {% if parameter.isGlobal %}this.{% endif %}{{ parameter.name | caseCamel | escapeKeyword }}){% endfor %};
68-
let payload = {};
69-
{% for parameter in method.parameters.query %}
70-
71-
if (typeof {% if parameter.isGlobal %}this.{% endif %}{{ parameter.name | caseCamel | escapeKeyword }} !== 'undefined') {
72-
payload['{{ parameter.name }}'] = {% if parameter.isGlobal %}this.{% endif %}{{ parameter.name | caseCamel | escapeKeyword }}{% if method.consumes[0] == "multipart/form-data" and ( parameter.type != "string" and parameter.type != "array" and parameter.type != "file" ) %}.toString(){% endif %};
73-
}
74-
{% endfor %}
75-
{% for parameter in method.parameters.body %}
76-
77-
if (typeof {% if parameter.isGlobal %}this.{% endif %}{{ parameter.name | caseCamel | escapeKeyword }} !== 'undefined') {
78-
payload['{{ parameter.name }}'] = {% if parameter.isGlobal %}this.{% endif %}{{ parameter.name | caseCamel | escapeKeyword}}{% if method.consumes[0] == "multipart/form-data" and ( parameter.type != "string" and parameter.type != "array" and parameter.type != "file" ) %}.toString(){% endif %};
79-
}
80-
{% endfor %}
81-
60+
{{ include ('node/base/params.twig')}}
8261
{% if 'multipart/form-data' in method.consumes %}
83-
{% for parameter in method.parameters.all %}
84-
{% if parameter.type == 'file' %}
85-
const size = {{ parameter.name | caseCamel | escapeKeyword }}.size;
86-
87-
const headers = {
88-
{% for parameter in method.parameters.header %}
89-
'{{ parameter.name }}': ${{ parameter.name | caseCamel | escapeKeyword }},
90-
{% endfor %}
91-
{% for key, header in method.headers %}
92-
'{{ key }}': '{{ header }}',
93-
{% endfor %}
94-
};
95-
96-
let id = undefined;
97-
let response = undefined;
98-
99-
let chunksUploaded = 0;
100-
101-
{% for parameter in method.parameters.all %}
102-
{% if parameter.isUploadID %}
103-
if({{ parameter.name | caseCamel | escapeKeyword }} != 'unique()') {
104-
try {
105-
response = await this.client.call('get', path + '/' + {{ parameter.name }}, headers);
106-
chunksUploaded = response.chunksUploaded;
107-
} catch(e) {
108-
}
109-
}
110-
{% endif %}
111-
{% endfor %}
112-
113-
let currentChunk = Buffer.from('');
114-
let currentChunkSize = 0;
115-
let currentChunkStart = 0;
116-
117-
const selfClient = this.client;
118-
119-
async function uploadChunk(lastUpload = false) {
120-
if(chunksUploaded - 1 >= currentChunkStart / client.CHUNK_SIZE) {
121-
return;
122-
}
123-
124-
const start = currentChunkStart;
125-
const end = Math.min(((start + client.CHUNK_SIZE) - 1), size);
126-
127-
if(!lastUpload || currentChunkStart !== 0) {
128-
headers['content-range'] = 'bytes ' + start + '-' + end + '/' + size;
129-
}
130-
131-
if (id) {
132-
headers['x-{{spec.title | caseLower }}-id'] = id;
133-
}
134-
135-
const stream = Stream.Readable.from(currentChunk);
136-
payload['{{ parameter.name }}'] = { type: 'file', file: stream, filename: {{ parameter.name }}.filename };
137-
138-
response = await selfClient.call('{{ method.method | caseLower }}', path, headers, payload{% if method.type == 'location' %}, 'arraybuffer'{% endif %});
139-
140-
if (!id) {
141-
id = response['$id'];
142-
}
143-
144-
if (onProgress !== null) {
145-
onProgress({
146-
$id: response['$id'],
147-
progress: Math.min((start+client.CHUNK_SIZE) * client.CHUNK_SIZE, size) / size * 100,
148-
sizeUploaded: end+1,
149-
chunksTotal: response['chunksTotal'],
150-
chunksUploaded: response['chunksUploaded']
151-
});
152-
}
153-
154-
currentChunkStart += client.CHUNK_SIZE;
155-
}
156-
157-
return await new Promise((resolve, reject) => {
158-
const writeStream = new Stream.Writable();
159-
writeStream._write = async (mainChunk, encoding, next) => {
160-
// Segment incoming chunk into up to 5MB chunks
161-
const mainChunkSize = Buffer.byteLength(mainChunk);
162-
const chunksCount = Math.ceil(mainChunkSize / client.CHUNK_SIZE);
163-
const chunks = [];
164-
165-
for(let i = 0; i < chunksCount; i++) {
166-
const chunk = mainChunk.slice(i * client.CHUNK_SIZE, client.CHUNK_SIZE);
167-
chunks.push(chunk);
168-
}
169-
170-
for (const chunk of chunks) {
171-
const chunkSize = Buffer.byteLength(chunk);
172-
173-
if(chunkSize + currentChunkSize == client.CHUNK_SIZE) {
174-
// Upload chunk
175-
currentChunk = Buffer.concat([currentChunk, chunk]);
176-
await uploadChunk();
177-
currentChunk = Buffer.from('');
178-
currentChunkSize = 0;
179-
} else if(chunkSize + currentChunkSize > client.CHUNK_SIZE) {
180-
// Upload chunk, put rest into next chunk
181-
const bytesToUpload = client.CHUNK_SIZE - currentChunkSize;
182-
const newChunkSection = chunk.slice(0, bytesToUpload);
183-
currentChunk = Buffer.concat([currentChunk, newChunkSection]);
184-
currentChunkSize = Buffer.byteLength(currentChunk);
185-
await uploadChunk();
186-
currentChunk = chunk.slice(bytesToUpload, undefined);
187-
currentChunkSize = chunkSize - bytesToUpload;
188-
} else {
189-
// Append into current chunk
190-
currentChunk = Buffer.concat([currentChunk, chunk]);
191-
currentChunkSize = chunkSize + currentChunkSize;
192-
}
193-
}
194-
195-
next();
196-
}
197-
198-
writeStream.on("finish", async () => {
199-
if(currentChunkSize > 0) {
200-
await uploadChunk(true);
201-
}
202-
203-
resolve(response);
204-
});
205-
206-
writeStream.on("error", (err) => {
207-
reject(err);
208-
});
209-
210-
{{ parameter.name | caseCamel | escapeKeyword }}.stream.pipe(writeStream);
211-
});
212-
{% endif %}
213-
{% endfor %}
62+
{{ include ('node/base/requests/file.twig')}}
21463
{% else %}
215-
return await this.client.call('{{ method.method | caseLower }}', path, {
216-
{% for parameter in method.parameters.header %}
217-
'{{ parameter.name }}': ${{ parameter.name | caseCamel | escapeKeyword }},
218-
{% endfor %}
219-
{% for key, header in method.headers %}
220-
'{{ key }}': '{{ header }}',
221-
{% endfor %}
222-
}, payload{% if method.type == 'location' %}, 'arraybuffer'{% endif %});
64+
{{ include('node/base/requests/api.twig') }}
22365
{% endif %}
22466
}
22567
{% endfor %}
22668
}
22769

228-
module.exports = {{ service.name | caseUcfirst }};
70+
module.exports = {{ service.name | caseUcfirst }};

0 commit comments

Comments
 (0)