Skip to content

Commit df60f41

Browse files
committed
done
1 parent c0540c5 commit df60f41

File tree

10 files changed

+282
-59
lines changed

10 files changed

+282
-59
lines changed

.env.example

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
APPWRITE_ENDPOINT=https://cloud.appwrite.io/v1
22
APPWRITE_PROJECT_ID=64b53d0c41fcf5093b12
33
APPWRITE_API_KEY=****
4+
APPWRITE_SELF_SIGNED=1

README.md

+26-2
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,23 @@
22

33
> Minimalistic Appwrite schema dumper with data backup and restore features
44
5+
This backup tool will generate query for each document in AppWrite database and save them as a json files on a hard drive. That means It can handle as much documents as you need. Also there is a script to run AppWrite in Docker on localhost so you can test your backup.
6+
57
<a href="https://cloud.appwrite.io/card/64b53d046c81edba0b1a">
68
<img width="350" src="https://cloud.appwrite.io/v1/cards/cloud?userId=64b53d046c81edba0b1a" alt="Appwrite Cloud Card" />
79
</a>
810

11+
Got a question? Feel free to [ask It in issues](https://github.com/react-declarative/appwrite-backup-tool/issues), I need traffic
12+
913
## Setup
1014

1115
1. Install [Appwrite CLI](https://appwrite.io/docs/command-line) and login
1216

1317
> Windows
1418
15-
```cmd
19+
```powershell
1620
npm install -g appwrite-cli
17-
Set-ExecutionPolicy RemoteSigned
21+
Set-ExecutionPolicy RemoteSigned # In PowerShell as Administrator
1822
appwrite client --endpoint https://cloud.appwrite.io/v1
1923
appwrite login
2024
```
@@ -33,6 +37,7 @@ appwrite login
3337
APPWRITE_ENDPOINT=https://cloud.appwrite.io/v1
3438
APPWRITE_PROJECT_ID=64b53d0c41fcf5093b12
3539
APPWRITE_API_KEY=****
40+
APPWRITE_SELF_SIGNED=1
3641
```
3742

3843
## Usage
@@ -44,6 +49,7 @@ APPWRITE_API_KEY=****
4449
> Crossplatform
4550
4651
```bash
52+
npx -y rimraf backup
4753
npm run appwrite:backup
4854
```
4955

@@ -98,5 +104,23 @@ npm run appwrite:start:windows
98104
> Linux
99105
100106
```bash
107+
npx -y open-cli http://localhost:8080/
101108
npm run appwrite:start
102109
```
110+
111+
- Authorize CLI in Docker AppWrite instance
112+
113+
```bash
114+
npx -y open-cli http://localhost:8080/
115+
appwrite client --selfSigned true --endpoint http://localhost:8080/v1
116+
appwrite login
117+
```
118+
119+
## File upload speed
120+
121+
Looks like AppWrite file endpoint is limited `to 60 requests in every 1 minutes per IP address`. So [I added a delay](./scripts/restore.mjs), you can change it If you need to
122+
123+
```javascript
124+
const DOCUMENT_WRITE_DELAY = 1_000;
125+
const FILE_WRITE_DELAY = 1_000;
126+
```

docker/.env

+94
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
_APP_ENV=production
2+
_APP_LOCALE=en
3+
_APP_OPTIONS_ABUSE=enabled
4+
_APP_OPTIONS_FORCE_HTTPS=disabled
5+
_APP_OPENSSL_KEY_V1=learning-key
6+
_APP_DOMAIN=localhost
7+
_APP_DOMAIN_TARGET=localhost
8+
_APP_CONSOLE_WHITELIST_ROOT=enabled
9+
_APP_CONSOLE_WHITELIST_EMAILS=
10+
_APP_CONSOLE_WHITELIST_IPS=
11+
_APP_SETUP=1-click-gitpod
12+
_APP_SYSTEM_EMAIL_NAME=Appwrite
13+
_APP_SYSTEM_EMAIL_ADDRESS=[email protected]
14+
_APP_SYSTEM_RESPONSE_FORMAT=
15+
_APP_SYSTEM_SECURITY_EMAIL_ADDRESS=[email protected]
16+
_APP_USAGE_STATS=enabled
17+
_APP_LOGGING_PROVIDER=
18+
_APP_LOGGING_CONFIG=
19+
_APP_USAGE_AGGREGATION_INTERVAL=30
20+
_APP_USAGE_TIMESERIES_INTERVAL=30
21+
_APP_USAGE_DATABASE_INTERVAL=900
22+
_APP_WORKER_PER_CORE=6
23+
_APP_REDIS_HOST=redis
24+
_APP_REDIS_PORT=6379
25+
_APP_REDIS_USER=
26+
_APP_REDIS_PASS=
27+
_APP_DB_HOST=mariadb
28+
_APP_DB_PORT=3306
29+
_APP_DB_SCHEMA=appwrite
30+
_APP_DB_USER=user
31+
_APP_DB_PASS=password
32+
_APP_DB_ROOT_PASS=rootsecretpassword
33+
_APP_INFLUXDB_HOST=influxdb
34+
_APP_INFLUXDB_PORT=8086
35+
_APP_STATSD_HOST=telegraf
36+
_APP_STATSD_PORT=8125
37+
_APP_SMTP_HOST=
38+
_APP_SMTP_PORT=
39+
_APP_SMTP_SECURE=
40+
_APP_SMTP_USERNAME=
41+
_APP_SMTP_PASSWORD=
42+
_APP_SMS_PROVIDER=
43+
_APP_SMS_FROM=
44+
_APP_STORAGE_LIMIT=10000000
45+
_APP_STORAGE_PREVIEW_LIMIT=20000000
46+
_APP_STORAGE_ANTIVIRUS=disabled
47+
_APP_STORAGE_ANTIVIRUS_HOST=clamav
48+
_APP_STORAGE_ANTIVIRUS_PORT=3310
49+
_APP_STORAGE_DEVICE=Local
50+
_APP_STORAGE_S3_ACCESS_KEY=
51+
_APP_STORAGE_S3_SECRET=
52+
_APP_STORAGE_S3_REGION=us-east-1
53+
_APP_STORAGE_S3_BUCKET=
54+
_APP_STORAGE_DO_SPACES_ACCESS_KEY=
55+
_APP_STORAGE_DO_SPACES_SECRET=
56+
_APP_STORAGE_DO_SPACES_REGION=us-east-1
57+
_APP_STORAGE_DO_SPACES_BUCKET=
58+
_APP_STORAGE_BACKBLAZE_ACCESS_KEY=
59+
_APP_STORAGE_BACKBLAZE_SECRET=
60+
_APP_STORAGE_BACKBLAZE_REGION=us-west-004
61+
_APP_STORAGE_BACKBLAZE_BUCKET=
62+
_APP_STORAGE_LINODE_ACCESS_KEY=
63+
_APP_STORAGE_LINODE_SECRET=
64+
_APP_STORAGE_LINODE_REGION=eu-central-1
65+
_APP_STORAGE_LINODE_BUCKET=
66+
_APP_STORAGE_WASABI_ACCESS_KEY=
67+
_APP_STORAGE_WASABI_SECRET=
68+
_APP_STORAGE_WASABI_REGION=eu-central-1
69+
_APP_STORAGE_WASABI_BUCKET=
70+
_APP_FUNCTIONS_SIZE_LIMIT=30000000
71+
_APP_FUNCTIONS_TIMEOUT=900
72+
_APP_FUNCTIONS_BUILD_TIMEOUT=900
73+
_APP_FUNCTIONS_CONTAINERS=10
74+
_APP_FUNCTIONS_CPUS=
75+
_APP_FUNCTIONS_MEMORY=256
76+
_APP_FUNCTIONS_MEMORY_SWAP=256
77+
_APP_FUNCTIONS_RUNTIMES=node-16.0,php-8.0,python-3.9,ruby-3.0,java-16.0
78+
_APP_EXECUTOR_SECRET=your-secret-key
79+
_APP_EXECUTOR_HOST=http://appwrite-executor/v1
80+
_APP_EXECUTOR_RUNTIME_NETWORK=integration-for-gitpod_runtimes
81+
_APP_FUNCTIONS_INACTIVE_THRESHOLD=60
82+
DOCKERHUB_PULL_USERNAME=
83+
DOCKERHUB_PULL_PASSWORD=
84+
DOCKERHUB_PULL_EMAIL=
85+
OPEN_RUNTIMES_NETWORK=integration-for-gitpod_runtimes
86+
_APP_MAINTENANCE_INTERVAL=86400
87+
_APP_MAINTENANCE_RETENTION_CACHE=2592000
88+
_APP_MAINTENANCE_RETENTION_EXECUTION=1209600
89+
_APP_MAINTENANCE_RETENTION_AUDIT=1209600
90+
_APP_MAINTENANCE_RETENTION_ABUSE=86400
91+
_APP_MAINTENANCE_RETENTION_USAGE_HOURLY=8640000
92+
_APP_GRAPHQL_MAX_BATCH_SIZE=10
93+
_APP_GRAPHQL_MAX_COMPLEXITY=250
94+
_APP_GRAPHQL_MAX_DEPTH=3

docker/.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
!.env

package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99
"appwrite:push": "sh ./tools/appwrite_push.sh",
1010
"appwrite:fetch:windows": ".\\tools\\appwrite_fetch.bat",
1111
"appwrite:push:windows": ".\\tools\\appwrite_push.bat",
12-
"appwrite:start": "sh ./docker/run.sh",
13-
"appwrite:start:windows": ".\\docker\\run.bat"
12+
"appwrite:start": "cd docker && sh ./run.sh",
13+
"appwrite:start:windows": "cd docker & run.bat"
1414
},
1515
"keywords": [],
1616
"author": "",

scripts/backup.mjs

+39-28
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,17 @@ const FILES_PAGE_SIZE = 100;
1919
const TOTAL_DOCUMENTS_LIMIT = 100_000;
2020
const DOCUMENTS_PAGE_SIZE = 100;
2121

22+
const FILE_DOWNLOAD_DELAY = 1_000;
23+
2224
const client = new sdk.Client();
2325

24-
client
25-
.setEndpoint(process.env.APPWRITE_ENDPOINT)
26-
.setProject(process.env.APPWRITE_PROJECT_ID)
27-
.setKey(process.env.APPWRITE_API_KEY)
28-
.setSelfSigned();
26+
client.setEndpoint(process.env.APPWRITE_ENDPOINT)
27+
client.setProject(process.env.APPWRITE_PROJECT_ID)
28+
client.setKey(process.env.APPWRITE_API_KEY)
29+
30+
if (process.env.APPWRITE_SELF_SIGNED) {
31+
client.setSelfSigned();
32+
}
2933

3034
const databases = new sdk.Databases(client);
3135
const storage = new sdk.Storage(client);
@@ -74,32 +78,16 @@ const listDocuments = async (databaseId, collectionId) => {
7478
return result;
7579
};
7680

81+
const sleep = (timeout = 1_000) => new Promise((res) => {
82+
setTimeout(() => {
83+
res();
84+
}, timeout);
85+
});
86+
7787
await fs.mkdir("backup/buckets", { recursive: true });
7888
await fs.mkdir("backup/databases", { recursive: true });
7989

80-
{
81-
const { buckets, total } = await storage.listBuckets();
82-
83-
console.log(`Found ${total} buckets!`);
84-
85-
for (const bucket of buckets) {
86-
console.log(`Getting list of files in ${bucket.$id}`);
87-
const files = await listFiles(bucket.$id);
88-
console.log(`Making backup of ${bucket.$id}`);
89-
await fs.mkdir(`backup/buckets/${bucket.$id}`, { recursive: true });
90-
for (const file of files) {
91-
const metadata = await storage.getFile(bucket.$id, file.$id);
92-
const extension = path.extname(metadata.name);
93-
console.log(`Writing ${file.$id}${extension} from ${bucket.$id}`);
94-
const buffer = await storage.getFileView(bucket.$id, file.$id);
95-
await fs.writeFile(
96-
`backup/buckets/${bucket.$id}/${file.$id}${extension}`,
97-
buffer
98-
);
99-
}
100-
}
101-
}
102-
90+
// Backup documents
10391
{
10492
const { databases: databasesList, total } = await databases.list();
10593
console.log(`Found ${total} databases!`);
@@ -133,6 +121,29 @@ await fs.mkdir("backup/databases", { recursive: true });
133121
}
134122
}
135123

124+
// Backup files
125+
{
126+
const { buckets, total } = await storage.listBuckets();
127+
console.log(`Found ${total} buckets!`);
128+
for (const bucket of buckets) {
129+
console.log(`Getting list of files in ${bucket.$id}`);
130+
const files = await listFiles(bucket.$id);
131+
console.log(`Making backup of ${bucket.$id}`);
132+
await fs.mkdir(`backup/buckets/${bucket.$id}`, { recursive: true });
133+
for (const file of files) {
134+
const metadata = await storage.getFile(bucket.$id, file.$id);
135+
const extension = path.extname(metadata.name);
136+
console.log(`Writing ${file.$id}${extension} from ${bucket.$id}`);
137+
const buffer = await storage.getFileView(bucket.$id, file.$id);
138+
await fs.writeFile(
139+
`backup/buckets/${bucket.$id}/${file.$id}${extension}`,
140+
buffer
141+
);
142+
await sleep(FILE_DOWNLOAD_DELAY);
143+
}
144+
}
145+
}
146+
136147
{
137148
console.log("Checking backup consistence...");
138149
const databaseFiles = await glob(`backup/databases/*/*/*.json`);

scripts/restore.js

-27
This file was deleted.

0 commit comments

Comments
 (0)