Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

⚡ Add a Deno example to wipe an Appwrite bucket #40

Merged
merged 10 commits into from
Dec 20, 2022
41 changes: 41 additions & 0 deletions deno/wipe_appwrite_bucket/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# 🗑 Wipe Appwrite Bucket

A Deno cloud function to wipe a complete bucket in Appwrite by passing the bucket id as a payload.

_Example input:_

```json
{
"bucketId":"profilePictures"
}
```

_Example output:_

```json
{
"success":true
}
```

## 📝 Environment Variables

List of environment variables used by this cloud function:

- **APPWRITE_FUNCTION_ENDPOINT** - Endpoint of Appwrite project
- **APPWRITE_FUNCTION_API_KEY** - Appwrite API Key
- **APPWRITE_FUNCTION_PROJECT_ID** - Appwrite project ID. If running on Appwrite, this variable is provided automatically.
stnguyen90 marked this conversation as resolved.
Show resolved Hide resolved

## 🚀 Deployment

There are two ways of deploying the Appwrite function, both having the same results, but each using a different process. We highly recommend using CLI deployment to achieve the best experience.

### Using CLI

Make sure you have [Appwrite CLI](https://appwrite.io/docs/command-line#installation) installed, and you have successfully logged into your Appwrite server. To make sure Appwrite CLI is ready, you can use the command `appwrite client --debug` and it should respond with green text `✓ Success`.

Make sure you are in the same folder as your `appwrite.json` file and run `appwrite deploy function` to deploy your function. You will be prompted to select which functions you want to deploy.

### Manual using tar.gz

Manual deployment has no requirements and uses Appwrite Console to deploy the tag. First, enter the folder of your function. Then, create a tarball of the whole folder and gzip it. After creating `.tar.gz` file, visit Appwrite Console, click on the `Deploy Tag` button and switch to the `Manual` tab. There, set the `entrypoint` to `src/mod.ts`, and upload the file we just generated.
1 change: 1 addition & 0 deletions deno/wipe_appwrite_bucket/src/deps.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * as sdk from "https://deno.land/x/appwrite@6.0.0/mod.ts";
51 changes: 51 additions & 0 deletions deno/wipe_appwrite_bucket/src/mod.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { sdk } from "./deps.ts";

export default async function (req: any, res: any) {
if (
!req.variables["APPWRITE_FUNCTION_ENDPOINT"] ||
!req.variables["APPWRITE_FUNCTION_PROJECT_ID"] ||
!req.variables["APPWRITE_FUNCTION_API_KEY"] ||
!req.payload
) {
return res.json({
success: false,
message: "Missing required environment variables or payload.",
});
}
let bucketId = "";
try {
const payload = JSON.parse(req.payload);
bucketId = payload.bucketId;
} catch (_err) {
return res.json({
success: false,
message: "Payload is invalid.",
});
}
const client = new sdk.Client();
const storage = new sdk.Storage(client);

client
.setEndpoint(req.variables["APPWRITE_FUNCTION_ENDPOINT"])
.setProject(req.variables["APPWRITE_FUNCTION_PROJECT_ID"])
.setKey(req.variables["APPWRITE_FUNCTION_API_KEY"]);

try {
const limit = 25;
const totalFiles = (await storage.listFiles(bucketId, [sdk.Query.limit(limit)])).total;
Aragur marked this conversation as resolved.
Show resolved Hide resolved
for (let i = 0; i < totalFiles; i += limit) {
const files = (await storage.listFiles(bucketId, [sdk.Query.limit(limit)])).files;
for (const file of files) {
await storage.deleteFile(bucketId, file.$id);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There isn't a need to await every file delete. It would be a good tradeoff between performance and inundating the server if each "page" of files were all deleted concurrently before fetching the next "page".

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice catch, I removed it. Thanks :)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should be able to delete every page concurrently rather than awaiting each delete. You can do something like:

while (true) {
  result = storage.listFiles();
  if (no results) break;
  
  promises = []
  result.files.forEach(file) {
    promise.push(storage.deleteFile(file);
  })
  
  try {
    await Promise.all(promises);
  } catch (e) {
    // handle accordingly
  }
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a lot. I optimized the loop now :)

}
}
return res.json({
success: true,
});
} catch (_err) {
return res.json({
success: false,
message: "Bucket not found.",
});
}
}