Skip to content

Commit 79b8fb1

Browse files
authored
Merge pull request #1298 from Geun-Oh/main
Add Cloudflare KV Storage
2 parents 1bc6b49 + 71bbf1e commit 79b8fb1

16 files changed

+1086
-0
lines changed

.github/dependabot.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,12 @@ updates:
2626
- "🤖 Dependencies"
2727
schedule:
2828
interval: "daily"
29+
- package-ecosystem: "gomod"
30+
directory: "/cloudflarekv/" # Location of package manifests
31+
labels:
32+
- "🤖 Dependencies"
33+
schedule:
34+
interval: "daily"
2935
- package-ecosystem: "gomod"
3036
directory: "/couchbase/" # Location of package manifests
3137
labels:
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
name-template: "CloudflareKV - v$RESOLVED_VERSION"
2+
tag-template: "cloudflarekv/v$RESOLVED_VERSION"
3+
tag-prefix: cloudflarekv/v
4+
include-paths:
5+
- cloudflarekv
6+
categories:
7+
- title: "🚀 New"
8+
labels:
9+
- "✏️ Feature"
10+
- title: "🧹 Updates"
11+
labels:
12+
- "🧹 Updates"
13+
- "🤖 Dependencies"
14+
- title: "🐛 Fixes"
15+
labels:
16+
- "☢️ Bug"
17+
- title: "📚 Documentation"
18+
labels:
19+
- "📒 Documentation"
20+
change-template: "- $TITLE (#$NUMBER)"
21+
change-title-escapes: '\<*_&' # You can add # and @ to disable mentions, and add ` to disable code blocks.
22+
exclude-contributors:
23+
- dependabot
24+
- dependabot[bot]
25+
version-resolver:
26+
major:
27+
labels:
28+
- "major"
29+
minor:
30+
labels:
31+
- "minor"
32+
- "✏️ Feature"
33+
patch:
34+
labels:
35+
- "patch"
36+
- "📒 Documentation"
37+
- "☢️ Bug"
38+
- "🤖 Dependencies"
39+
- "🧹 Updates"
40+
default: patch
41+
template: |
42+
$CHANGES
43+
**Full Changelog**: https://github.com/$OWNER/$REPOSITORY/compare/$PREVIOUS_TAG...cloudflarekv/v$RESOLVED_VERSION
44+
Thank you $CONTRIBUTORS for making this update possible.
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
#!/bin/bash
2+
3+
# generate cloudflarekv/index.ts
4+
cat <<EOF > cloudflarekv/index.ts
5+
export default { async fetch(Request, env) {
6+
7+
const namespace = env.TEST_NAMESPACE1;
8+
9+
if (Request.url === "http://localhost:8787/health") {
10+
return new Response("Success");
11+
}
12+
13+
if (Request.url === "http://localhost:8787/writeworkerskvkeyvaluepair") {
14+
const res = await Request.json();
15+
const { key, val } = res;
16+
WriteWorkersKVKeyValuePair(namespace, key, val);
17+
return new Response("Success");
18+
}
19+
20+
else if (Request.url === "http://localhost:8787/listworkerskvkeys") {
21+
const resp = await Request.json();
22+
const { limit, prefix, cursor } = resp;
23+
const list = await ListWorkersKVKeys(namespace, limit, prefix, cursor);
24+
return new Response(list);
25+
}
26+
27+
else if (Request.url === "http://localhost:8787/deleteworkerskvpairbykey") {
28+
const res = await Request.json();
29+
const { key } = res;
30+
await DeleteWorkersKVPairByKey(namespace, key);
31+
32+
return new Response(key)
33+
}
34+
35+
else if (Request.url === "http://localhost:8787/getworkerskvvaluebykey") {
36+
const key = (await Request.json()).key;
37+
const res = await GetWorkersKVValueByKey(namespace, key);
38+
39+
return new Response(res);
40+
}
41+
42+
else if (Request.url === "http://localhost:8787/deleteworkerskventries") {
43+
const res = await Request.json();
44+
const { keys } = res;
45+
const newKeys = keys.filter(x => x.length > 0);
46+
await DeleteWorkersKVEntries(namespace, newKeys);
47+
48+
return new Response("Success")
49+
}
50+
}
51+
}
52+
53+
const GetWorkersKVValueByKey = async (NAMESPACE, key) => {
54+
const val = await NAMESPACE.get(key);
55+
56+
return val;
57+
}
58+
59+
const WriteWorkersKVKeyValuePair = async (NAMESPACE, key, val) => {
60+
await NAMESPACE.put(key, val);
61+
62+
return "Wrote Successfully"
63+
}
64+
65+
const DeleteWorkersKVPairByKey = async (NAMESPACE, key) => {
66+
await NAMESPACE.delete(key);
67+
68+
return "Delete Successfully"
69+
}
70+
71+
const ListWorkersKVKeys = async (NAMESPACE, limit, prefix, cursor) => {
72+
const resp = await NAMESPACE.list({ limit, prefix, cursor });
73+
74+
return JSON.stringify(resp.keys);
75+
}
76+
77+
const DeleteWorkersKVEntries = async (NAMESPACE, keys) => {
78+
for (let key of keys) {
79+
await NAMESPACE.delete(key);
80+
}
81+
82+
return "Delete Successfully"
83+
}
84+
85+
86+
EOF
87+
88+
echo "index.ts generated"
89+
90+
# generate cloudflarekv/wrangler.toml
91+
cat <<EOF > cloudflarekv/wrangler.toml
92+
main = "index.ts"
93+
94+
kv_namespaces = [
95+
{ binding = "TEST_NAMESPACE1", id = "hello", preview_id = "world" },
96+
]
97+
98+
workers_dev = true
99+
100+
compatibility_date = "2024-03-20"
101+
102+
[dev]
103+
port = 8787
104+
local_protocol = "http"
105+
EOF
106+
107+
echo "wrangler.toml generated"

.github/workflows/benchmark.yml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,10 +88,21 @@ jobs:
8888
# NOTE: Keep this in sync with the version from go.mod
8989
go-version: "1.20.x"
9090

91+
- name: Setup Node.js
92+
uses: actions/setup-node@v3
93+
with:
94+
node-version: '18'
95+
9196
- name: Install Azurite
9297
run: |
9398
docker run -d -p 10000:10000 mcr.microsoft.com/azure-storage/azurite azurite-blob --blobHost 0.0.0.0 --blobPort 10000
9499
100+
- name: Install Cloudflare Worker
101+
run : |
102+
.github/scripts/initialize-wrangler.sh
103+
cd cloudflarekv && npx wrangler dev &
104+
npx wait-on tcp:8787
105+
95106
- name: Install Coherence
96107
run: |
97108
docker run -d -p 1408:1408 -p 30000:30000 ghcr.io/oracle/coherence-ce:22.06.5
@@ -144,8 +155,10 @@ jobs:
144155
set -o pipefail
145156
for d in */ ; do
146157
[[ $d == "tls/" ]] && continue
158+
[[ $d == "node_modules/" ]] && continue
147159
148160
cd "$d"
161+
echo "Bench dir: $d"
149162
go test ./... -benchmem -run=^$ -bench . | tee -a ../output.txt
150163
cd ..
151164
done
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
name: Release Drafter Cloudflare KV
2+
on:
3+
push:
4+
# branches to consider in the event; optional, defaults to all
5+
branches:
6+
- master
7+
- main
8+
paths:
9+
- "cloudflarekv/**"
10+
jobs:
11+
draft_release_cloudflarekv:
12+
runs-on: ubuntu-latest
13+
timeout-minutes: 30
14+
steps:
15+
- uses: release-drafter/release-drafter@v6
16+
with:
17+
config-name: release-drafter-cloudflarekv.yml
18+
env:
19+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
name: Tests CloudflareKV
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
pull_request:
8+
branches:
9+
- main
10+
11+
jobs:
12+
Tests:
13+
runs-on: ubuntu-latest
14+
strategy:
15+
matrix:
16+
go-version:
17+
- 1.21.x
18+
- 1.22.x
19+
20+
steps:
21+
- name: Checkout Repository
22+
uses: actions/checkout@v2
23+
24+
- name: Setup Go
25+
uses: actions/setup-go@v5
26+
with:
27+
go-version: ${{ matrix.go-version }}
28+
29+
- name: Setup Node.js
30+
uses: actions/setup-node@v4
31+
with:
32+
node-version: '18'
33+
34+
- name: Start Wrangler Dev
35+
run: |
36+
.github/scripts/initialize-wrangler.sh
37+
cd cloudflarekv && npx wrangler dev &
38+
npx wait-on tcp:8787
39+
40+
- name: Run Go Tests
41+
run: cd cloudflarekv && go test ./... -v -race

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
vendor/
2929
vendor
3030
/Godeps/
31+
node_modules/
3132

3233
# Go specific
3334
go.work*

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ type Storage interface {
5454
- [AzureBlob](./azureblob/README.md) <a href="https://github.com/gofiber/storage/actions?query=workflow%3A%22Tests+Azure+Blob%22"> <img src="https://img.shields.io/github/actions/workflow/status/gofiber/storage/test-azureblob.yml?branch=main&label=%F0%9F%A7%AA%20&style=flat&color=75C46B" /> </a>
5555
- [Badger](./badger/README.md) <a href="https://github.com/gofiber/storage/actions?query=workflow%3A%22Tests+Badger%22"> <img src="https://img.shields.io/github/actions/workflow/status/gofiber/storage/test-badger.yml?branch=main&label=%F0%9F%A7%AA%20&style=flat&color=75C46B" /> </a>
5656
- [Bbolt](./bbolt) <a href="https://github.com/gofiber/storage/actions?query=workflow%3A%22Tests+Bbolt%22"> <img src="https://img.shields.io/github/actions/workflow/status/gofiber/storage/test-bbolt.yml?branch=main&label=%F0%9F%A7%AA%20&style=flat&color=75C46B" /> </a>
57+
- [CloudflareKV](./cloudflarekv/README.md) <a href="https://github.com/gofiber/storage/actions?query=workflow%3A%22Tests+CloudflareKV%22"> <img src="https://img.shields.io/github/actions/workflow/status/gofiber/storage/test-cloudflarekv.yml?branch=main&label=%F0%9F%A7%AA%20&style=flat&color=75C46B" /> </a>
5758
- [Coherence](./coherence/README.md) <a href="https://github.com/gofiber/storage/actions?query=workflow%3A%22Tests+Coherence%22"> <img src="https://img.shields.io/github/actions/workflow/status/gofiber/storage/test-coherence.yml?branch=main&label=%F0%9F%A7%AA%20&style=flat&color=75C46B" /> </a>
5859
- [Couchbase](./couchbase/README.md) <a href="https://github.com/gofiber/storage/actions?query=workflow%3A%22Tests+Couchbase%22"> <img src="https://img.shields.io/github/actions/workflow/status/gofiber/storage/test-couchbase.yml?branch=main&label=%F0%9F%A7%AA%20&style=flat&color=75C46B" /> </a>
5960
- [DynamoDB](./dynamodb/README.md) <a href="https://github.com/gofiber/storage/actions?query=workflow%3A%22Tests+DynamoDB%22"> <img src="https://img.shields.io/github/actions/workflow/status/gofiber/storage/test-dynamodb.yml?branch=main&label=%F0%9F%A7%AA%20&style=flat&color=75C46B" /> </a>

cloudflarekv/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
index.ts
2+
wrangler.toml

cloudflarekv/README.md

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
---
2+
id: cloudflarekv
3+
title: Cloudflare KV
4+
---
5+
6+
![Release](https://img.shields.io/github/v/tag/gofiber/storage?filter=cloudflarekv*)
7+
[![Discord](https://img.shields.io/discord/704680098577514527?style=flat&label=%F0%9F%92%AC%20discord&color=00ACD7)](https://gofiber.io/discord)
8+
![Test](https://img.shields.io/github/actions/workflow/status/gofiber/storage/test-cloudflarekv.yml?label=Tests)
9+
![Security](https://img.shields.io/github/actions/workflow/status/gofiber/storage/gosec.yml?label=Security)
10+
![Linter](https://img.shields.io/github/actions/workflow/status/gofiber/storage/linter.yml?label=Linter)
11+
12+
A Cloudflare KV storage driver using [cloudflare/cloudflare-go](https://github.com/cloudflare/cloudflare-go).
13+
14+
**Note: Requires Go 1.21 and above**
15+
16+
### Table of Contents
17+
18+
- [Signatures](#signatures)
19+
- [Installation](#installation)
20+
- [Examples](#examples)
21+
- [Config](#config)
22+
- [Default Config](#default-config)
23+
24+
### Signatures
25+
26+
```go
27+
func New(config ...Config) Storage
28+
func (s *Storage) Get(key string) ([]byte, error)
29+
func (s *Storage) Set(key string, val []byte, exp time.Duration) error
30+
func (s *Storage) Delete(key string) error
31+
func (s *Storage) Reset() error
32+
func (s *Storage) Close() error
33+
func (s *Storage) Conn() *cloudflare.API
34+
```
35+
36+
### Installation
37+
38+
```bash
39+
go mod init github.com/<user>/<repo>
40+
```
41+
42+
And then install the Cloudflare KV implementation:
43+
44+
```bash
45+
go get github.com/gofiber/storage/cloudflarekv
46+
```
47+
48+
### Examples
49+
50+
Import the storage package.
51+
52+
```go
53+
import "github.com/gofiber/storage/cloudflarekv"
54+
```
55+
56+
You can use the following methods to create storage. The Key must be an API Token generated with at least `Account.Workers KV Storage` permission. Check the [Create API Token](https://developers.cloudflare.com/fundamentals/api/get-started/create-token/) documentation to generate one.
57+
58+
```go
59+
// Initialize default config
60+
store := cloudflarekv.New()
61+
62+
store := cloudflarekv.New(cloudflarekv.Config{
63+
Key: "",
64+
Email: "",
65+
AccountID: "fiber",
66+
NamespaceID: "fiber",
67+
Reset: false,
68+
})
69+
70+
```
71+
72+
### Config
73+
74+
```go
75+
type Config struct {
76+
77+
// Cloudflare Auth Token
78+
//
79+
// Optional. Default is ""
80+
Key string
81+
82+
// Cloudflare Email
83+
//
84+
// Optional. Default is ""
85+
Email string
86+
87+
// Account id
88+
//
89+
// Optional. Default is "fiber"
90+
AccountID string
91+
92+
// Namespace id
93+
//
94+
// Optional. Default is "fiber"
95+
NamespaceID string
96+
97+
// Reset clears any existing keys in existing Table
98+
//
99+
// Optional. Default is false
100+
Reset bool
101+
}
102+
```
103+
104+
### Default Config
105+
106+
```go
107+
var ConfigDefault = Config{
108+
Key: "",
109+
Email: "",
110+
AccountID: "fiber",
111+
NamespaceID: "fiber",
112+
Reset: false,
113+
}
114+
```

0 commit comments

Comments
 (0)