Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Node app #42

Draft
wants to merge 33 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
768d27e
node app, initial commit
PythonFZ Sep 25, 2024
8b6830d
test list get / append with znsocket client on JS side
PythonFZ Sep 25, 2024
2b68a44
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Sep 25, 2024
d0fb029
make prettier
PythonFZ Sep 26, 2024
1aaf0a1
try CI testing
PythonFZ Sep 26, 2024
fa8aed6
test against znsocket docker container
PythonFZ Sep 26, 2024
4ee758c
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Sep 26, 2024
a0cdc11
fix testing
PythonFZ Sep 26, 2024
e527f7c
Merge branch 'node-app' of https://github.com/zincware/znsocket into …
PythonFZ Sep 26, 2024
0631561
bit more testing for the client
PythonFZ Sep 26, 2024
ae5a516
show npm version
PythonFZ Sep 26, 2024
24d4188
cleanup tests
PythonFZ Sep 27, 2024
8d4e857
clean up project structure
PythonFZ Sep 27, 2024
77f1717
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Sep 27, 2024
67eaf40
clean up API a bit
PythonFZ Sep 27, 2024
96b47b3
add connect promise
PythonFZ Sep 27, 2024
a7c46f9
test dict
PythonFZ Sep 27, 2024
dcd0ec4
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Sep 27, 2024
c8695f4
use kwargs
PythonFZ Sep 27, 2024
320d672
Merge branch 'node-app' of https://github.com/zincware/znsocket into …
PythonFZ Sep 27, 2024
147b9e4
support callbacks
PythonFZ Sep 27, 2024
c8f0c62
bump npm version
PythonFZ Sep 27, 2024
06d592f
update test, more similar to redis
PythonFZ Sep 30, 2024
68de930
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Sep 30, 2024
42e32e5
add some callback stuff
PythonFZ Sep 30, 2024
ffbdc82
Merge branch 'node-app' of https://github.com/zincware/znsocket into …
PythonFZ Sep 30, 2024
3dd72b7
improve callbacks
PythonFZ Sep 30, 2024
a912829
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Sep 30, 2024
ff9a144
move abc / fix timimg
PythonFZ Sep 30, 2024
d17fb18
bump version
PythonFZ Sep 30, 2024
aa16fcd
only require passing znsocket once, not twice.
PythonFZ Oct 1, 2024
db576e4
lint and docstrings
PythonFZ Oct 3, 2024
e887028
remove code duplication
PythonFZ Oct 3, 2024
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
22 changes: 17 additions & 5 deletions .github/workflows/pytest.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ on:
branches:
- main
schedule:
- cron: '14 3 * * 1' # at 03:14 on Monday.
- cron: "14 3 * * 1" # at 03:14 on Monday.

jobs:
pytest:
Expand All @@ -22,26 +22,34 @@ jobs:
- ubuntu-latest

services:
# Label used to access the service container
redis:
# Docker Hub image
image: redis
# Set health checks to wait until redis has started
options: >-
--health-cmd "redis-cli ping"
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
# Maps port 6379 on service container to the host
- 6379:6379
znsocket:
image: pythonf/znsocket
options: >-
--health-cmd "python healthcheck.py"
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 4748:4748

steps:
- uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- uses: actions/setup-node@v4
with:
node-version: 22
- name: Install Poetry
uses: snok/install-poetry@v1
with:
Expand All @@ -50,11 +58,15 @@ jobs:
- name: Install package
run: |
poetry install --no-interaction
npm install
- name: Run pytest
run: |
poetry run python --version
poetry run coverage run -m pytest
poetry run coverage lcov
- name: Run jest
run: |
npm test -- . -t native_
- name: Coveralls
uses: coverallsapp/github-action@master
with:
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -162,3 +162,4 @@ cython_debug/
#.idea/
tmp/
TODO.md
node_modules/
3 changes: 3 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Ignore artifacts:
build
coverage
1 change: 1 addition & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
8 changes: 3 additions & 5 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
{
"python.testing.pytestArgs": [
"tests"
],
"python.testing.unittestEnabled": false,
"python.testing.pytestEnabled": true
"python.testing.pytestArgs": ["tests"],
"python.testing.unittestEnabled": false,
"python.testing.pytestEnabled": true
}
5 changes: 5 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
FROM python:3
WORKDIR /app
COPY . /app
RUN pip install -e .
CMD ["znsocket", "--port", "4748"]
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
[![PyPI version](https://badge.fury.io/py/znsocket.svg)](https://badge.fury.io/py/znsocket)
[![npm version](https://badge.fury.io/js/znsocket.svg)](https://badge.fury.io/js/znsocket)
[![Coverage Status](https://coveralls.io/repos/github/zincware/ZnSocket/badge.svg?branch=main)](https://coveralls.io/github/zincware/ZnSocket?branch=main)
![PyTest](https://github.com/zincware/ZnSocket/actions/workflows/pytest.yaml/badge.svg)
[![zincware](https://img.shields.io/badge/Powered%20by-zincware-darkcyan)](https://github.com/zincware)

# ZnSocket - Redis-like Key-Value Store in Python

ZnSocket provides a [Redis](https://redis.io/)-compatible API using [python-socketio](https://python-socketio.readthedocs.io/en/stable/) and Python objects for storage. It is designed for testing and applications requiring key-value storage while being easily installable via `pip`. For production, consider using [redis-py](https://redis-py.readthedocs.io/) and a Redis instance.
Expand All @@ -12,24 +14,29 @@ ZnSocket provides a [Redis](https://redis.io/)-compatible API using [python-sock
> Although this value can be adapted, you will notice slow data transfers for large files.

## Installation

To install ZnSocket, use:

```bash
pip install znsocket
```

## Example

Start the ZnSocket server using the CLI:

```bash
znsocket --port 5000
```

For additional options, run:

```bash
znsocket --help
```

Here's a simple example of how to use the ZnSocket client:

```python
from znsocket import Client

Expand All @@ -44,8 +51,8 @@ assert c.get("name") == "Fabian"
> [!NOTE]
> ZnSocket does not encode/decode strings. Using it is equivalent to using `Redis.from_url(storage, decode_responses=True)` in the Redis client.


## Lists

ZnSocket provides a synchronized version of the Python `list` implementation. Unlike a regular Python list, the data in `znsocket.List` is not stored locally; instead, it is dynamically pushed to and pulled from the server.

Below is a step-by-step example of how to use `znsocket.List` to interact with a ZnSocket server.
Expand All @@ -67,6 +74,7 @@ print(sync_list[::2])
```

## Dicts

ZnSocket provides a synchronized version of the Python `dict` implementation similar to the `list` implementation.

Below is a step-by-step example of how to use `znsocket.Dict` to interact with a ZnSocket server.
Expand Down
10 changes: 10 additions & 0 deletions docker-compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
services:
znsocket:
image: pythonf/znsocket:latest
ports:
- "4748:4748"
healthcheck:
test: python healthcheck.py
interval: 10s
timeout: 5s
retries: 5
22 changes: 22 additions & 0 deletions healthcheck.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import argparse
import socket
import sys


def check_socketio_server(port: int):
try:
s = socket.create_connection(("localhost", port), timeout=5)
s.close()
sys.exit(0) # success
except Exception as e:
print(f"Health check failed: {e}")
sys.exit(1) # failure


if __name__ == "__main__":
parser = argparse.ArgumentParser(
description="Check if a socket.io server is running."
)
parser.add_argument("--port", type=int, default=4748, help="The port to check.")
args = parser.parse_args()
check_socketio_server(args.port)
177 changes: 177 additions & 0 deletions js/client.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
import { io, Manager } from "socket.io-client"; // Removed the unnecessary 'constants' import

export const createClient = ({ url, namespace = "znsocket", socket }) => {
return new Client({ url, namespace, socket });
};

export class Client {
constructor({ url, namespace = "znsocket", socket }) {
// Correct concatenation of URL and namespace for socket connection
if (socket) {
this._socket = socket;
} else if (url) {
const path = `${url}/${namespace}`;
this._socket = io(path);
} else {
// connect to the default URL with namespace
const manager = new Manager();
this._socket = manager.socket("/znsocket");
}
}
connect() {
return new Promise((resolve, reject) => {
this._socket.on("connect", () => {
resolve("Connected");
});
});
}

on(event, callback) {
this._socket.on(event, callback);
}

emit(event, data) {
this._socket.emit(event, data);
}

disconnect() {
this._socket.close();
}

lLen(key) {
return new Promise((resolve, reject) => {
this._socket.emit("llen", { name: key }, (data) => {
// Check if there is an error or invalid response and reject if necessary
resolve(data);
});
});
}

lIndex(key, index) {
return new Promise((resolve, reject) => {
this._socket.emit("lindex", { name: key, index: index }, (data) => {
resolve(data || null);
});
});
}

lSet(key, index, value) {
return new Promise((resolve, reject) => {
this._socket.emit(
"lset",
{ name: key, index: index, value: value },
(data) => {
resolve("OK"); // TODO
},
);
});
}

lRem(key, count, value) {
return new Promise((resolve, reject) => {
this._socket.emit(
"lrem",
{ name: key, count: count, value: value },
(data) => {
resolve("OK"); // TODO
},
);
});
}

rPush(key, value) {
return new Promise((resolve, reject) => {
this._socket.emit("rpush", { name: key, value: value }, (data) => {
resolve("OK"); // TODO
});
});
}

lPush(key, value) {
return new Promise((resolve, reject) => {
this._socket.emit("lpush", { name: key, value: value }, (data) => {
resolve("OK"); // TODO
});
});
}

hGet(key, field) {
return new Promise((resolve, reject) => {
this._socket.emit("hget", { name: key, key: field }, (data) => {
resolve(data || null);
});
});
}

hSet(key, field, value) {
return new Promise((resolve, reject) => {
this._socket.emit(
"hset",
{ name: key, mapping: { [field]: value } },
(data) => {
resolve("OK"); // TODO
},
);
});
}

hDel(key, field) {
return new Promise((resolve, reject) => {
this._socket.emit("hdel", { name: key, key: field }, (data) => {
resolve("OK"); // TODO
});
});
}

hExists(key, field) {
return new Promise((resolve, reject) => {
this._socket.emit("hexists", { name: key, key: field }, (data) => {
if (data === 1) {
resolve(true);
} else {
resolve(false);
}
});
});
}

hLen(key) {
return new Promise((resolve, reject) => {
this._socket.emit("hlen", { name: key }, (data) => {
resolve(data);
});
});
}

hKeys(key) {
return new Promise((resolve, reject) => {
this._socket.emit("hkeys", { name: key }, (data) => {
resolve(data);
});
});
}

hVals(key) {
return new Promise((resolve, reject) => {
this._socket.emit("hvals", { name: key }, (data) => {
resolve(data);
});
});
}

hGetAll(key) {
return new Promise((resolve, reject) => {
this._socket.emit("hgetall", { name: key }, (data) => {
resolve(data);
});
});
}

flushAll() {
return new Promise((resolve, reject) => {
this._socket.emit("flushall", {}, (data) => {
resolve("OK"); // TODO
});
});
}
}
Loading
Loading