-
Notifications
You must be signed in to change notification settings - Fork 138
/
publish.sh
executable file
·149 lines (129 loc) · 5.48 KB
/
publish.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
#! /bin/bash
#
# This script uploads the edge chat demo to your Cloudflare Workers account.
#
# This is a temporary hack needed until we add Durable Objects support to Wrangler. Once Wrangler
# support exists, this script can probably go away.
#
# On first run, this script will ask for configuration, create the Durable Object namespace bindings,
# and generate metadata.json. On subsequent runs it will just update the script from source code.
set -euo pipefail
if ! which curl >/dev/null; then
echo "$0: please install curl" >&2
exit 1
fi
if ! which jq >/dev/null; then
echo "$0: please install jq" >&2
exit 1
fi
# If credentials.conf doesn't exist, prompt for the values and generate it.
if [ -e credentials.conf ]; then
source credentials.conf
else
echo "Please create a Cloudflare API Token with Workers Scripts Edit permission on your account (can be created using the Edit Cloudflare Workers API Token template)."
echo -n "API Token: "
read AUTH_TOKEN
echo -n "Cloudflare account ID (32 hex digits, found on the right sidebar of the Workers dashboard): "
read ACCOUNT_ID
SCRIPT_NAME=edge-chat-demo
cat > credentials.conf << __EOF__
ACCOUNT_ID=$ACCOUNT_ID
AUTH_TOKEN=$AUTH_TOKEN
SCRIPT_NAME=$SCRIPT_NAME
__EOF__
chmod 600 credentials.conf
echo "Wrote credentials.conf with these values."
fi
# curl_api performs a curl command passing the appropriate authorization headers, and parses the
# JSON response for errors. In case of errors, exit. Otherwise, write just the result part to
# stdout.
curl_api() {
RESULT=$(curl -s -H "Authorization: Bearer $AUTH_TOKEN" "$@")
if [ $(echo "$RESULT" | jq .success) = true ]; then
echo "$RESULT" | jq .result
return 0
else
echo "API ERROR:" >&2
echo "$RESULT" >&2
return 1
fi
}
# Let's verify the credentials work by listing Workers scripts and Durable Object namespaces. If
# either of these requests error then we're certainly not going to be able to continue.
echo "Checking if credentials can access Workers..."
curl_api https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/workers/scripts >/dev/null
echo "Checking if credentials can access Durable Objects..."
curl_api https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/workers/durable_objects/namespaces >/dev/null
echo "Credentials OK! Publishing..."
# upload_script uploads our Worker code with the appropriate metadata.
upload_script() {
curl_api https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/workers/scripts/$SCRIPT_NAME \
-X PUT \
-F "metadata=@metadata.json;type=application/json" \
-F "script=@chat.mjs;type=application/javascript+module" \
-F "html=@chat.html;type=application/octet-stream" > /dev/null
}
# upload_bootstrap_script is a temporary hack to work around a chicken-and-egg problem: in order
# to define a Durable Object namespace, we must tell it a script and class name. But when we upload
# our script, we need to configure the environment to bind to our durable object namespaces. This
# function uploads a version of our script with an empty environment (no bindings). The script won't
# be able to run correctly, but this gets us far enough to define the namespaces, and then we can
# upload the script with full environment later.
#
# This is obviously dumb and we (Cloudflare) will come up with something better soon.
upload_bootstrap_script() {
echo '{"main_module": "chat.mjs"}' > bootstrap-metadata.json
curl_api https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/workers/scripts/$SCRIPT_NAME \
-X PUT \
-F "metadata=@bootstrap-metadata.json;type=application/json" \
-F "script=@chat.mjs;type=application/javascript+module" \
-F "html=@chat.html;type=application/octet-stream" > /dev/null
rm bootstrap-metadata.json
}
# upsert_namespace configures a Durable Object namespace so that instances of it can be created
# and called from other scripts (or from the same script). This function checks if the namespace
# already exists, creates it if it doesn't, and either way writes the namespace ID to stdout.
#
# The namespace ID can be used to configure environment bindings in other scripts (or even the same
# script) such that they can send messages to instances of this namespace.
upsert_namespace() {
# Check if the namespace exists already.
EXISTING_ID=$(\
curl_api https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/workers/durable_objects/namespaces | \
jq -r ".[] | select(.script == \"$SCRIPT_NAME\" and .class == \"$1\") | .id")
if [ "$EXISTING_ID" != "" ]; then
echo $EXISTING_ID
return
fi
# No. Create it.
curl_api https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/workers/durable_objects/namespaces \
-X POST --data "{\"name\": \"$SCRIPT_NAME-$1\", \"script\": \"$SCRIPT_NAME\", \"class\": \"$1\"}" | \
jq -r .id
}
if [ ! -e metadata.json ]; then
# If metadata.json doesn't exist we assume this is first-time setup and we need to create the
# namespaces.
upload_bootstrap_script
ROOMS_ID=$(upsert_namespace ChatRoom)
LIMITERS_ID=$(upsert_namespace RateLimiter)
cat > metadata.json << __EOF__
{
"main_module": "chat.mjs",
"bindings": [
{
"type": "durable_object_namespace",
"name": "rooms",
"namespace_id": "$ROOMS_ID"
},
{
"type": "durable_object_namespace",
"name": "limiters",
"namespace_id": "$LIMITERS_ID"
}
]
}
__EOF__
fi
upload_script
echo "App uploaded to your account under the name: $SCRIPT_NAME"
echo "You may deploy it to a specific host in the Cloudflare Dashboard."