Skip to content
This repository was archived by the owner on Jul 16, 2022. It is now read-only.

Dart Functions upgrade for Appwrite Functions v2 #313

Draft
wants to merge 13 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions dart/file_backup_v2/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# 🗂 File Backup using the Dropbox API
A sample Dart Cloud Function that leverages Dropbox to create backups of important files uploaded to Appwrite.

## 📝 Environment Variables
Add the following environment variables in your Cloud Function settings.

* **APPWRITE_API_KEY** - Create a key from the Appwrite console with the following scope (`files.read`)
* **APPWRITE_ENDPOINT** - Your Appwrite Endpoint
* **DROPBOX_KEY** - OAuth token from [Dropbox](https://blogs.dropbox.com/developers/2014/05/generate-an-access-token-for-your-own-account)

## 🚀 Building and Packaging

To package this example as a cloud function, follow these steps.

```bash
$ cd demos-for-functions/dart/file_backup
Copy link
Contributor

Choose a reason for hiding this comment

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

Let's check this command in all readmes, should be V2

Copy link
Contributor

Choose a reason for hiding this comment

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

Let's check with Eldad. Do we call it V2? I think we use naming convention Gen2 (generation 2)


$ PUB_CACHE=.appwrite/ dart pub get
```

* Ensure that your folder structure looks like this
```
.
├── .appwrite/
├── main.dart
├── pubspec.lock
└── pubspec.yaml
```

* Create a tarfile

```bash
$ cd ..
$ tar -zcvf code.tar.gz file_backup
Comment on lines +33 to +34
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we please test this once? I remember reports from Discord that people didn't get function working when tarring from outside of the folder. They had to tar it from inside and use . to get it working.
Could be fake alert, but lets please check.

```

* Upload the tarfile to your Appwrite Console and use the following entrypoint command

```bash
dart main.dart
Copy link
Contributor

Choose a reason for hiding this comment

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

In opr-examples we always put code in a source folder. Do we want to do it here for consistency? So the file would be lib/main.dart: https://github.com/open-runtimes/examples/blob/main/dart/convert-phone-number-to-country-name/lib/main.dart

```
Comment on lines +37 to +41
Copy link
Contributor

Choose a reason for hiding this comment

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

Entrypoint, not Entrypoint command
main.dart, not dart main.dart.

Same goes for all readmes.


## 🎯 Trigger

Head over to your function in the Appwrite console and under the Settings Tab, enable the `storage.files.create` event.
Copy link
Contributor

Choose a reason for hiding this comment

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

Event were refactored. Can we update these notes?


If your function errors out with code 124, increase the timeout under the Settings Tab.
62 changes: 62 additions & 0 deletions dart/file_backup_v2/main.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import 'dart:convert';
import 'dart:typed_data';
import 'package:dart_appwrite/dart_appwrite.dart';
import 'package:http/http.dart' as http;

Future<void> backup(
Uint8List buffer,
String originalFileName,
String dropboxAuthToken,
) async {
final dropboxEndpoint =
Uri.parse('https://content.dropboxapi.com/2/files/upload');

final headers = {
'Authorization': 'Bearer $dropboxAuthToken',
'Content-Type': 'application/octet-stream',
'Dropbox-API-Arg': '{"path": "/$originalFileName", "mode": "add" }'
};

final dropboxResponse =
await http.post(dropboxEndpoint, body: buffer, headers: headers);

if (dropboxResponse.statusCode != 200) {
throw Exception(
'Could not backup file $originalFileName! Dropbox response was: ${dropboxResponse.body}');
}
}

Future<void> start(final request, final response) async {
final env = request.env;
final endpoint = env['APPWRITE_ENDPOINT'];
if (endpoint == null) {
throw ('Appwrite endpoint not specified. Please set an environment variable "APPWRITE_ENDPOINT" with your endpoint to the function');
}

final client = Client()
..setEndpoint(endpoint)
..setProject(env['APPWRITE_FUNCTION_PROJECT_ID'])
..setKey(env['APPWRITE_API_KEY']);

Comment on lines +37 to +40
Copy link
Contributor

Choose a reason for hiding this comment

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

Not experienced with flutter, but are there supposed to be 2 dots?

final payload = jsonDecode(env['APPWRITE_FUNCTION_EVENT_DATA']!);
final bucketId = payload['bucketId'];
final fileId = payload['\$id']!;
final originalName = payload[r'name']!;

final storage = Storage(client);

final dropboxKey = env['DROPBOX_KEY'];
if (dropboxKey == null) {
throw(
'Dropbox key not specified. Please set an environment variable "DROPBOX_KEY" containing your dropbox key');
}

final response = await storage.getFileDownload(bucketId: bucketId, fileId: fileId);

try {
await backup(response.data!, originalName, dropboxKey!);
response.send('Successfully backed up $originalName');
} catch (e) {
response.send('Failed backing up the file: $e');
}
}
10 changes: 10 additions & 0 deletions dart/file_backup_v2/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
name: file_backup
description: Demo for backing up files to Dropbox in an Appwrite function.

environment:
sdk: '>=2.12.0 <3.0.0'

dependencies:
dart_appwrite: ^4.0.1
http: ^0.13.4

9 changes: 9 additions & 0 deletions dart/generate-giphy-gif_v2/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Files and directories created by pub.
.dart_tool/
.packages

# Conventional directory for build output.
build/

# Some Constants.
constants.dart
61 changes: 61 additions & 0 deletions dart/generate-giphy-gif_v2/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# GIPHYGif Generator

A sample Dart Cloud Function which takes a keyword and returns the first result with giphy gif url

## Getting Started

Head over to the [Giphy Developers](https://developers.giphy.com/docs/api) to read their quick start guide and get your API key. Make sure to use the **GIPHY API** and not the **GIPHY SDK**.
<img src = 'https://github.com/2002Bishwajeet/demos-for-functions/blob/feat-implement-generate-giphy-gif-dart/dart/generate-giphy-gif/screenshots/SDKvsAPI.png' width = '100%' height = '50%' />

Since we are retrieving an url from the API, the GIPHY API is more than enough for our needs.

## ☁️ Create a new Function
Copy link
Contributor

Choose a reason for hiding this comment

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

Lets add this title to all readmes, or remove it from here


**NOTE:** If your project is not created yet, you will be prompted to create a new project.

1. Go to your `appwrite console`
2. Select your project and go to `Functions`
<img src = 'https://github.com/2002Bishwajeet/demos-for-functions/blob/feat-implement-generate-giphy-gif-dart/dart/generate-giphy-gif/screenshots/functions.png' width = '100%' />
3. Under `Functions` click on `Add Function`
<img src ='https://github.com/2002Bishwajeet/demos-for-functions/blob/feat-implement-generate-giphy-gif-dart/dart/generate-giphy-gif/screenshots/function2.png' width = '100%' />

**NOTE:** If you don't see the Dart option in the runtimes. Follow [`troubleshooting.md`](troubleshoot.md) guide to learn how to add the Dart runtime.

## 📝 Environment Variables

Go to Settings tab of your Cloud Function. Add the following environment variable.

* **GIPHY_API_KEY** - API Key of your GIPHY account

## 🚀 Building and Packaging

To package this example as a cloud function, follow these steps.

* Ensure that your folder structure looks like this

```
.
├── main.dart
└── pubspec.yaml
```

* Create a tarfile

```bash
cd ..
tar -zcvf code.tar.gz generate-giphy-gif
```

* Navigate to the Overview Tab of your Cloud Function > Deploy Tag
* Input the command that will run your function (in this case "main.dart") as your entrypoint
* Upload your tarfile
* Click 'Activate'

## 🎯 Trigger

Head over to your function in the Appwrite console and just press **Execute**. You will notice the output in your logs


## 👨‍💻 Live Working

<img src = "screenshots\ans.gif"/>
29 changes: 29 additions & 0 deletions dart/generate-giphy-gif_v2/main.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import 'dart:convert';
import 'package:http/http.dart' as http;

Future<void> start(final request, final response) async {
Uri url = Uri();
if(request.env['GIPHY_API_KEY'] == null) {
throw Exception("GIPHY_API_KEY is required");
}

url = url.replace(
scheme: 'https',
host: 'api.giphy.com',
path: 'v1/gifs/search',
queryParameters: {
'api_key': request.env['GIPHY_API_KEY'], // The Api key which we will store in Appwrite Console.
// Note you can change the var name to something else too.

'q': env['APPWRITE_FUNCTION_DATA'], // The search query which we will pass during execution
'limit': '1', // Since we want the first top result we set the limit to 1.
// This parameter is optional. To read about what parameters you can pass .
// https://developers.giphy.com/docs/api/endpoint#search -> Refer to this
},
);

http.Response response = await http.get(url);

var data = json.decode(response.body);
response.send(data['data'][0]['url']);
}
10 changes: 10 additions & 0 deletions dart/generate-giphy-gif_v2/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
name: giphy
description: A simple command-line application.
version: 1.0.0

environment:
sdk: ">=2.12.0 <3.0.0"


dependencies:
http: ^0.13.4
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added dart/generate-giphy-gif_v2/screenshots/ans.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added dart/generate-giphy-gif_v2/screenshots/ss4.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
27 changes: 27 additions & 0 deletions dart/generate-giphy-gif_v2/troubleshoot.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<center>

# TroubleShoot Guide ⚒️

</center>

## Add Dart Runtime to your Appwrite Console

* Go to your appwrite directory

If you are using WSL it should be located in `\home\username\appwrite\`

* Open up the `.env` file

* Keep the `_APP_FUNCTIONS_ENVS` empty and add the `dart-2.17` alongside the existing ones in the `_APP_FUNCTIONS_RUNTIMES`

<img src = "screenshots/ss4.png" width = "100%">

* Save the file

* Then run the following command in the WSL terminal

```bash
docker compose up -d
```

This command will restart all the existing appwrite containers along with the latest changes. Now hopover to appwrite console and you can see the `Dart` Runtime option in the functions.
47 changes: 47 additions & 0 deletions dart/generate_open_street_map_v2/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# 🗂 Generate Open Street Maps
A sample Dart Cloud Function that saves an open street maps tile for given latitude and longitude to Appwrite storage.

## 📝 Environment Variables
Add the following environment variables in your Cloud Function settings.

* **APPWRITE_API_KEY** - Create a key from the Appwrite console with the following scope (`files.write`)
* **APPWRITE_ENDPOINT** - Your Appwrite Endpoint
* **APPWRITE_BUCKET_ID** - ID of the bucket that you want to upload the map image to

## 🚀 Building and Packaging

To package this example as a cloud function, follow these steps.

* Ensure that your folder structure looks like this
```
.
├── main.dart
├── pubspec.lock
└── pubspec.yaml
```

* Create a tarfile

```bash
$ cd ..
$ tar -zcvf code.tar.gz generate_open_street_map
```

* Upload the tarfile to your Appwrite Console and use the following entrypoint

```bash
main.dart
```

## 🎯 Trigger

Head over to your function in the Appwrite console and after clicking the `Execute Now` button, enter a JSON object in the form of
```json
{
"latitude": 37.7822403,
"longitude": -122.3910414
}
```
with your respective coordinates.

If your function errors out with code 124, increase the timeout under the Settings Tab.
72 changes: 72 additions & 0 deletions dart/generate_open_street_map_v2/main.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import 'dart:convert';
import 'dart:math';
import 'dart:io';

import 'package:http/http.dart' as http;
import 'package:dart_appwrite/dart_appwrite.dart';
import 'package:vector_math/vector_math.dart';

const zoomLevel = 15;

String ensureEnvVariable(String key, final request) {
final value = request.env[key];
if (value == null) {
print(
'Could not find environment variable $key. Please set it following the instructions in the readme file.');
exit(1);
}

return value;
}

// Adapted from https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames#Mathematics
Point<int> coordinatesToTilePoint(double latitude, double longitude) {
final x = (pow(2, zoomLevel) * ((longitude + 180) / 360)).floor();

final radLat = radians(latitude);
final y = (pow(2, zoomLevel - 1) *
(1 - (log(tan(radLat) + (1 / cos(radLat))) / pi)))
.floor();

return Point(x, y);
}

Future<List<int>> fetchTile(double latitude, double longitude) async {
final point = coordinatesToTilePoint(latitude, longitude);
final tileUrl =
'https://tile.openstreetmap.org/${zoomLevel}/${point.x}/${point.y}.png';

print(tileUrl);

final response = await http.get(Uri.parse(tileUrl));
if (response.statusCode != 200) {
print('There was an error loading the tile for $point: ${response.body}');
exit(1);
}

return response.bodyBytes;
}

Future<void> start(final request, final response) async {
final client = Client();
client
.setKey(ensureEnvVariable('APPWRITE_API_KEY', request))
.setProject(ensureEnvVariable('APPWRITE_FUNCTION_PROJECT_ID', request))
.setEndpoint(ensureEnvVariable('APPWRITE_ENDPOINT', request));

final data = jsonDecode(ensureEnvVariable('APPWRITE_FUNCTION_DATA', request));
final bucketId = ensureEnvVariable('APPWRITE_BUCKET_ID');

final storage = Storage(client);
final latitude = data['latitude'];
final longitude = data['longitude'];

final imageBytes = await fetchTile(latitude, longitude);
final filename = 'osm_tile_${latitude}_${longitude}_z$zoomLevel.png';

final file = await storage.createFile(
bucketId: bucketId,
file: InputFile.fromBytes('file', imageBytes, filename: filename, contentType: 'image/png'),
);
response.json({"message": "Map created", "fileId": file.$id, "bucketId": bucketId });
}
Loading