From 615365588885dbf1740129435734be95c35e3bb5 Mon Sep 17 00:00:00 2001 From: TomDo1234 Date: Wed, 3 Apr 2024 15:42:25 +1100 Subject: [PATCH] Done with the basics --- docz/docs/03-demos/30-cloud/14-cloudflare.md | 212 +++++-------------- 1 file changed, 56 insertions(+), 156 deletions(-) diff --git a/docz/docs/03-demos/30-cloud/14-cloudflare.md b/docz/docs/03-demos/30-cloud/14-cloudflare.md index 77df9b1..e15003a 100644 --- a/docz/docs/03-demos/30-cloud/14-cloudflare.md +++ b/docz/docs/03-demos/30-cloud/14-cloudflare.md @@ -45,175 +45,75 @@ Workers ::: -### Reading Data +### Overview -In the Lambda handler, the `event.body` attribute is a Base64-encoded string -representing the HTTP request form data. This body must be parsed. +Cloudflare Workers exposes a handler in src/index.(js|ts) when you create a worker project using C3 as per above, +this handler exposes a Request object which can be used to expose the formdata or json of the request to the worker -#### Processing Form Bodies - -The `busboy` body parser[^2] is battle-tested in NodeJS deployments. - -`busboy` fires a `'file'` event for every file in the form body. The callback -receives a NodeJS stream that should be collected into a Buffer: - -```js -/* accumulate the files manually */ -var files = {}; -bb.on('file', function(fieldname, file, filename) { - /* concatenate the individual data buffers */ - var buffers = []; - file.on('data', function(data) { buffers.push(data); }); - file.on('end', function() { files[fieldname] = Buffer.concat(buffers); }); -}); -``` - -`busboy` fires a `'finish'` event when the body parsing is finished. Callbacks -can assume every file in the form body has been stored in NodeJS Buffer objects. - -#### Processing NodeJS Buffers - -The SheetJS `read` method[^3] can read the Buffer objects and generate SheetJS -workbook objects[^4] which can be processed with other API functions. - -For example, a handler can use `sheet_to_csv`[^5] to generate CSV text: - -```js -/* on the finish event, all of the fields and files are ready */ -bb.on('finish', function() { - /* grab the first file */ - var f = files["upload"]; - if(!f) callback(new Error("Must submit a file for processing!")); - - /* f[0] is a buffer */ - // highlight-next-line - var wb = XLSX.read(f[0]); - - /* grab first worksheet and convert to CSV */ - var ws = wb.Sheets[wb.SheetNames[0]]; - callback(null, { statusCode: 200, body: XLSX.utils.sheet_to_csv(ws) }); -}); -``` - -
Complete Code Sample (click to show) - -This example takes the first uploaded file submitted with the key `upload`, -parses the file and returns the CSV content of the first worksheet. - -```js -const XLSX = require('xlsx'); -var Busboy = require('busboy'); - -exports.handler = function(event, context, callback) { - /* set up busboy */ - var ctype = event.headers['Content-Type']||event.headers['content-type']; - var bb = Busboy({headers:{'content-type':ctype}}); - - /* busboy is evented; accumulate the fields and files manually */ - var fields = {}, files = {}; - bb.on('error', function(err) { callback(null, { body: err.message }); }); - bb.on('field', function(fieldname, val) {fields[fieldname] = val }); - // highlight-start - bb.on('file', function(fieldname, file, filename) { - /* concatenate the individual data buffers */ - var buffers = []; - file.on('data', function(data) { buffers.push(data); }); - file.on('end', function() { files[fieldname] = [Buffer.concat(buffers), filename]; }); - }); - // highlight-end - - /* on the finish event, all of the fields and files are ready */ - bb.on('finish', function() { - /* grab the first file */ - var f = files["upload"]; - if(!f) callback(new Error("Must submit a file for processing!")); - - /* f[0] is a buffer */ - // highlight-next-line - var wb = XLSX.read(f[0]); - - /* grab first worksheet and convert to CSV */ - var ws = wb.Sheets[wb.SheetNames[0]]; - callback(null, { statusCode: 200, body: XLSX.utils.sheet_to_csv(ws) }); - }); - - /* start the processing */ - // highlight-next-line - bb.end(Buffer.from(event.body, "base64")); +```ts +export default { + async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise { + const data = await request.formData() + // const data = await request.json() if you are receiving a json request + //... + }, }; ``` -
+### Reading Data + +The SheetJS `read` method[^4] can read ArrayBuffer objects and generate SheetJS +workbook objects[^5] which can be processed with other API functions. + +For example, a handler can use `sheet_to_csv`[^6] to generate CSV text: + +```ts +import XLSX from "xlsx"; +export default { + async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise { + if (request.method === 'POST') { + const data = await request.formData() + // const data = await request.json() if you are doing a json request + const file = data.get('file') as File; + const buffer = await file.arrayBuffer(); + const wb = XLSX.read(buffer); + const ws = wb.Sheets[wb.SheetNames[0]]; + var b64 = XLSX.write(wb, { type: "base64", bookType: "xlsx" }); + return new Response(XLSX.utils.sheet_to_csv(ws)) + } + return new Response('Hello World!'); + }, +}; +``` ### Writing Data -For safely transmitting binary data, Base64 strings should be used. - -The SheetJS `write` method[^6] with the option `type: "base64"` will generate -Base64-encoded strings. - -```js -/* sample SheetJS workbook object */ -var wb = XLSX.read("S,h,e,e,t,J,S\n5,4,3,3,7,9,5", {type: "binary"}); -/* write to XLSX file in Base64 encoding */ -var b64 = XLSX.write(wb, { type: "base64", bookType: "xlsx" }); -``` - -The Lambda callback response function accepts options. Setting `isBase64Encoded` -to `true` will ensure the callback handler decodes the data. To ensure browsers -will try to download the response, the `Content-Disposition` header must be set: - -```js -callback(null, { - statusCode: 200, - /* Base64-encoded file */ - isBase64Encoded: true, - body: b64, - headers: { - /* Browsers will treat the response as the file SheetJSLambda.xlsx */ - "Content-Disposition": 'attachment; filename="SheetJSLambda.xlsx"' - } -}); -``` - -
Complete Code Sample (click to show) - -This example creates a sample workbook object and sends the file in the response: - -```js -var XLSX = require('xlsx'); - -exports.handler = function(event, context, callback) { - /* make workbook */ - var wb = XLSX.read("S,h,e,e,t,J,S\n5,4,3,3,7,9,5", {type: "binary"}); - /* write to XLSX file in Base64 encoding */ - // highlight-next-line - var body = XLSX.write(wb, { type: "base64", bookType: "xlsx" }); - /* mark as attached file */ - var headers = { "Content-Disposition": 'attachment; filename="SheetJSLambda.xlsx"'}; - /* Send back data */ - callback(null, { - statusCode: 200, - // highlight-next-line - isBase64Encoded: true, - body: body, - headers: headers - }); +```ts +import XLSX from "xlsx"; +export default { + async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise { + var wb = XLSX.read("S,h,e,e,t,J,S\n5,4,3,3,7,9,5", {type: "binary"}); + var data = XLSX.write(wb, { type: "buffer", bookType: "xlsx" }); + return new Response(data,{ + status: 200, + headers: { + "Content-Disposition": 'attachment; filename="SheetJSCFWorker.xlsx"' //Content disposition will make the browser download the file + } + }) + }, }; ``` -
- -### Lambda Demo +### Cloudflare Workers Demo :::note pass -At the time of writing, the Cloudflare Free Tier included an allowance of 1 million -free requests per month and 400 thousand GB-seconds of compute resources. +At the time of writing, the Cloudflare Workers Free Tier included an allowance of 100,000 +free requests per day and 10 milliseconds of CPU time per invocation. ::: -0) If you do not have an account, create a new Cloudflare free tier account[^7]. +1) If you do not have an account, create a new account[^7]. #### Create Project ZIP @@ -665,10 +565,10 @@ S,h,e,e,t,J,S [^1]: See ["Node.js compatibility"](https://developers.cloudflare.com/workers/runtime-apis/nodejs/) in the Cloudflare documentation [^2]: See ["Get started guide"](https://developers.cloudflare.com/workers/get-started/guide/#1-create-a-new-worker-project) [^3]: [Wrangler documentation](https://developers.cloudflare.com/workers/wrangler/) -[^4]: See ["Workbook Object" in "SheetJS Data Model"](/docs/csf/book) for more details. -[^5]: See [`sheet_to_csv` in "CSV and Text"](/docs/api/utilities/csv#delimiter-separated-output) -[^6]: See [`write` in "Writing Files"](/docs/api/write-options) -[^7]: Registering for a free account [on the Cloudflare Free Tier](https://Cloudflare.amazon.com/free/) requires a valid phone number and a valid credit card. +[^4]: See [`read` in "Reading Files"](/docs/api/parse-options) +[^5]: See ["Workbook Object" in "SheetJS Data Model"](/docs/csf/book) for more details. +[^6]: See [`sheet_to_csv` in "CSV and Text"](/docs/api/utilities/csv#delimiter-separated-output) +[^7]: Registering for a free account [on the Cloudflare Free Tier](https://dash.cloudflare.com/sign-up). [^8]: The `Cloudflare-sdk` module is distributed [on the public NPM registry](https://npm.im/Cloudflare-sdk) [^9]: See ["Managing access keys for IAM users"](https://docs.Cloudflare.amazon.com/IAM/latest/UserGuide/id_credentials_access-keys.html) in the Cloudflare documentation [^10]: See [`read` in "Reading Files"](/docs/api/parse-options)