Skip to content
Merged
Show file tree
Hide file tree
Changes from 13 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
111 changes: 107 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ const response = await fetch('http://localhost:3000/send-to-all-clients?encoding
});

const result = await response.json();
console.log(result.success ? 'Injected' : 'Failed');
console.log(result.results.length > 0 ? 'Injected' : 'Failed');
```

**Go Example:**
Expand All @@ -69,7 +69,7 @@ func main() {
defer resp.Body.Close()

body, _ := io.ReadAll(resp.Body)
if strings.Contains(string(body), `"success":true`) {
if strings.Contains(string(body), `"results"`) {
println("Injected")
}
}
Expand All @@ -91,7 +91,7 @@ public class RespProxyClient {

var response = client.send(request, HttpResponse.BodyHandlers.ofString());

if (response.body().contains("\"success\":true")) {
if (response.body().contains("\"results\"")) {
System.out.println("Injected");
}
}
Expand All @@ -108,7 +108,7 @@ req = urllib.request.Request("http://localhost:3000/send-to-all-clients?encoding

with urllib.request.urlopen(req) as response:
result = json.loads(response.read())
print("Injected" if result["success"] else "Failed")
print("Injected" if len(result["results"]) > 0 else "Failed")
```

Key Endpoints: `POST /send-to-client/{id}`, `POST /send-to-all-clients`, `GET /connections`, `GET /stats`
Expand Down Expand Up @@ -318,6 +318,109 @@ Forcefully close a specific client connection.
}
```

#### Add Interceptor
```http
POST /interceptors
```
Add a custom interceptor to match commands and return custom responses.

**Example:**
```bash
curl -X POST "http://localhost:3000/interceptors" \
-H "Content-Type: application/json" \
-d '{"name":"ping-interceptor","match":"*1\r\n$4\r\nPING\r\n","response":"+CUSTOM PONG\r\n","encoding":"raw"}'
```

**Response:**
```json
{
"success": true,
"name": "ping-interceptor"
}
```

#### Create Scenario
```http
POST /scenarios
```
Set up automated response sequence for testing.

**Example:**
```bash
curl -X POST "http://localhost:3000/scenarios" \
-H "Content-Type: application/json" \
-d '{"responses":["+OK\r\n",":42\r\n"],"encoding":"raw"}'
```

**Response:**
```json
{
"success": true,
"totalResponses": 2
}
```

#### Get Nodes
```http
GET /nodes
```
List all proxy node IDs.

**Example:**
```bash
curl http://localhost:3000/nodes
```

**Response:**
```json
{
"ids": ["localhost:6379:6379", "localhost:6379:6380"]
}
```

#### Add Node
```http
POST /nodes
```
Add a new proxy node dynamically.

**Example:**
```bash
curl -X POST "http://localhost:3000/nodes" \
-H "Content-Type: application/json" \
-d '{"listenPort":6380,"targetHost":"localhost","targetPort":6379}'
```

**Response:**
```json
{
"success": true,
"cfg": {
"listenPort": 6380,
"targetHost": "localhost",
"targetPort": 6379
}
}
```

#### Delete Node
```http
DELETE /nodes/{nodeId}
```
Remove a proxy node.

**Example:**
```bash
curl -X DELETE "http://localhost:3000/nodes/localhost:6379:6380"
```

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

## Use Cases

### Testing Redis Applications
Expand Down
4 changes: 2 additions & 2 deletions bun.lock
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"dependencies": {
"@hono/zod-validator": "^0.7.2",
"hono": "^4.8.5",
"redis-monorepo": "github:redis/node-redis#master",
"redis-monorepo": "github:nkaradzhov/node-redis#proxy-improvements",
"zod": "^4.0.8",
},
"devDependencies": {
Expand Down Expand Up @@ -66,7 +66,7 @@

"redis": ["[email protected]", "", { "dependencies": { "@redis/bloom": "5.8.3", "@redis/client": "5.8.3", "@redis/json": "5.8.3", "@redis/search": "5.8.3", "@redis/time-series": "5.8.3" } }, "sha512-MfSrfV6+tEfTw8c4W0yFp6XWX8Il4laGU7Bx4kvW4uiYM1AuZ3KGqEGt1LdQHeD1nEyLpIWetZ/SpY3kkbgrYw=="],

"redis-monorepo": ["redis-monorepo@github:redis/node-redis#e6025b1", {}, "redis-node-redis-e6025b1"],
"redis-monorepo": ["redis-monorepo@github:nkaradzhov/node-redis#b5c9b07", {}, "nkaradzhov-node-redis-b5c9b07"],

"undici-types": ["[email protected]", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],

Expand Down
54 changes: 54 additions & 0 deletions examples/cluster/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
networks:
redis-net:
driver: bridge

services:
redis:
image: redislabs/client-libs-test:8.2
container_name: redis
ports:
- "3000:3000"
networks:
- redis-net
healthcheck:
test: ["CMD", "redis-cli", "-p", "3000", "PING"]
interval: 10s
timeout: 3s
retries: 5

resp-proxy:
image: redislabs/client-resp-proxy
container_name: resp-proxy
environment:
LISTEN_HOST: "0.0.0.0"
LISTEN_PORT: "6379,6380,6381"
TARGET_HOST: "redis"
TARGET_PORT: "3000"
API_PORT: "4000"
ENABLE_LOGGING: true
SIMULATE_CLUSTER: true
ports:
- "6379:6379"
- "6380:6380"
- "6381:6381"
- "4000:4000"
depends_on:
- redis
networks:
- redis-net
healthcheck:
test: ["CMD", "sh", "-c", "wget -qO- http://localhost:4000/stats || exit 1"]
interval: 10s
timeout: 3s
retries: 5

# debug:
# image: nicolaka/netshoot:latest
# container_name: debug
# depends_on:
# - resp-proxy
# networks:
# - redis-net
# command: sleep infinity
# stdin_open: true
# tty: true
88 changes: 88 additions & 0 deletions examples/cluster/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# Cluster Example

Short example demonstrating how to use the Proxy in cluster simulating mode in front of a standalone Redis.

## Step 1: Setup redis + proxy

- Option 1: Using Docker Compose

Running the provided `docker-compose.yml` file:

```bash
docker-compose up
```

- Option 2: Using external Redis server

1. Start a standalone Redis server on port 3000

2. Run the proxy in cluster mode:
```bash
docker run \
-p 6379:6379 -p 6380:6380 -p 6381:6381 -p 4000:4000 \
-e TARGET_HOST=<redis-host> \
-e TARGET_PORT=<redis-port> \
-e TIMEOUT=0 \
-e API_PORT=4000 \
-e SIMULATE_CLUSTER=yes \
redislabs/client-resp-proxy

```
This will start a Proxy instance (ports 6379, 6380 and 6381 for proxying and 4000 for the REST API).
The proxy will simulate a cluster with 3 nodes running on ports 6379, 6479 and 6579 by intercepting the `cluster slots` command and returning a fake response.

## Step 2: Check if `cluster slots` reports correctly

Open a separate terminal

```bash
redis-cli cluster slots
```

Response should be similar to the following, where the ports are the proxy listen ports ( 6379, 6479 and 6579 ):
```
1) 1) (integer) 0
2) (integer) 5460
3) 1) "0.0.0.0"
2) (integer) 6379
3) "proxy-id-6379"
2) 1) (integer) 5461
2) (integer) 10922
3) 1) "0.0.0.0"
2) (integer) 6380
3) "proxy-id-6380"
3) 1) (integer) 10923
2) (integer) 16383
3) 1) "0.0.0.0"
2) (integer) 6381
3) "proxy-id-6381"
```

### Step 3: Test push

```bash
redis-cli subscribe foo
```

Open another terminal

Push a message to all connected clients
```bash
echo '>3\r\n$7\r\nmessage\r\n$3\r\nfoo\r\n$4\r\neeee\r' | base64
# PjMNCiQ3DQptZXNzYWdlDQokMw0KZm9vDQokNA0KZWVlZQ0K
curl -X POST "http://localhost:4000/send-to-all-clients?encoding=base64" -d "PjMNCiQ3DQptZXNzYWdlDQokMw0KZm9vDQokNA0KZWVlZQ0K"
```

You should see the following message in the `redis-cli subscribe` terminal:
```
1) "message"
2) "foo"
3) "eeee"
```

### Step 4: Test topology change

Changing cluster topology is done by adding an interceptor that will catch the `cluster slots` command and return a different response. In this case we swapped the ports of node 2 and node 3.
```
curl -X POST "http://localhost:4000/interceptors" -H 'Content-Type: application/json' -d '{"name":"test", "match":"*2\r\n$7\r\ncluster\r\n$5\r\nslots\r\n", "response":"*3\r\n*3\r\n:0\r\n:5460\r\n*3\r\n$9\r\n127.0.0.1\r\n:6381\r\n$13\r\nproxy-id-6379\r\n*3\r\n:5461\r\n:10921\r\n*3\r\n$9\r\n127.0.0.1\r\n:6380\r\n$13\r\nproxy-id-6380\r\n*3\r\n:10922\r\n:16383\r\n*3\r\n$9\r\n127.0.0.1\r\n:6379\r\n$13\r\nproxy-id-6381\r\n", "encoding":"raw"}'
```
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
"dependencies": {
"@hono/zod-validator": "^0.7.2",
"hono": "^4.8.5",
"redis-monorepo": "github:redis/node-redis#master",
"redis-monorepo": "github:nkaradzhov/node-redis#proxy-improvements",
"zod": "^4.0.8"
},
"devDependencies": {
Expand Down
Loading
Loading