rsgi-wsrpc 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- rsgi_wsrpc-0.1.0/LICENSE +21 -0
- rsgi_wsrpc-0.1.0/PKG-INFO +560 -0
- rsgi_wsrpc-0.1.0/README.md +516 -0
- rsgi_wsrpc-0.1.0/pyproject.toml +65 -0
- rsgi_wsrpc-0.1.0/rsgi_wsrpc/__init__.py +57 -0
- rsgi_wsrpc-0.1.0/rsgi_wsrpc/compat.py +66 -0
- rsgi_wsrpc-0.1.0/rsgi_wsrpc/core/__init__.py +19 -0
- rsgi_wsrpc-0.1.0/rsgi_wsrpc/core/constants.py +32 -0
- rsgi_wsrpc-0.1.0/rsgi_wsrpc/core/lib/config.py +170 -0
- rsgi_wsrpc-0.1.0/rsgi_wsrpc/core/lifecycle.py +59 -0
- rsgi_wsrpc-0.1.0/rsgi_wsrpc/core/logger.py +123 -0
- rsgi_wsrpc-0.1.0/rsgi_wsrpc/core/router.py +18 -0
- rsgi_wsrpc-0.1.0/rsgi_wsrpc/core/security.py +156 -0
- rsgi_wsrpc-0.1.0/rsgi_wsrpc/core/session.py +372 -0
- rsgi_wsrpc-0.1.0/rsgi_wsrpc/core/tabular.py +115 -0
- rsgi_wsrpc-0.1.0/rsgi_wsrpc/plugins/__init__.py +18 -0
- rsgi_wsrpc-0.1.0/rsgi_wsrpc/plugins/auth/__init__.py +66 -0
- rsgi_wsrpc-0.1.0/rsgi_wsrpc/plugins/auth/config.py +54 -0
- rsgi_wsrpc-0.1.0/rsgi_wsrpc/plugins/auth/core.py +53 -0
- rsgi_wsrpc-0.1.0/rsgi_wsrpc/plugins/auth/handlers.py +1061 -0
- rsgi_wsrpc-0.1.0/rsgi_wsrpc/plugins/auth/models.py +337 -0
- rsgi_wsrpc-0.1.0/rsgi_wsrpc/plugins/auth/permissions.py +65 -0
- rsgi_wsrpc-0.1.0/rsgi_wsrpc/plugins/auth/security.py +193 -0
- rsgi_wsrpc-0.1.0/rsgi_wsrpc/plugins/broadcast/__init__.py +178 -0
- rsgi_wsrpc-0.1.0/rsgi_wsrpc/plugins/db/__init__.py +22 -0
- rsgi_wsrpc-0.1.0/rsgi_wsrpc/plugins/db/session.py +138 -0
- rsgi_wsrpc-0.1.0/rsgi_wsrpc/plugins/raw_ws/__init__.py +28 -0
- rsgi_wsrpc-0.1.0/rsgi_wsrpc/plugins/raw_ws/id_gen.py +26 -0
- rsgi_wsrpc-0.1.0/rsgi_wsrpc/plugins/raw_ws/manager.py +126 -0
- rsgi_wsrpc-0.1.0/rsgi_wsrpc/plugins/raw_ws/router.py +54 -0
- rsgi_wsrpc-0.1.0/rsgi_wsrpc/plugins/raw_ws/session.py +136 -0
- rsgi_wsrpc-0.1.0/rsgi_wsrpc/plugins/smart_cache/__init__.py +24 -0
- rsgi_wsrpc-0.1.0/rsgi_wsrpc/plugins/smart_cache/engine.py +345 -0
- rsgi_wsrpc-0.1.0/rsgi_wsrpc/plugins/smart_cache/handlers.py +54 -0
- rsgi_wsrpc-0.1.0/rsgi_wsrpc.egg-info/PKG-INFO +560 -0
- rsgi_wsrpc-0.1.0/rsgi_wsrpc.egg-info/SOURCES.txt +38 -0
- rsgi_wsrpc-0.1.0/rsgi_wsrpc.egg-info/dependency_links.txt +1 -0
- rsgi_wsrpc-0.1.0/rsgi_wsrpc.egg-info/requires.txt +25 -0
- rsgi_wsrpc-0.1.0/rsgi_wsrpc.egg-info/top_level.txt +1 -0
- rsgi_wsrpc-0.1.0/setup.cfg +4 -0
rsgi_wsrpc-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Alex Titoff and rsgi-wsrpc contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,560 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: rsgi-wsrpc
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: High-performance reactive fullstack Python framework on Rust RSGI (Granian) with symmetric WSRPC (JSON-RPC 2.0) and Tabular Data Compression.
|
|
5
|
+
Author-email: Alex Titoff <a.tit.off@gmail.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/atitoff-dotcom/rsgi-wsrpc
|
|
8
|
+
Project-URL: Documentation, https://github.com/atitoff-dotcom/rsgi-wsrpc/blob/main/docs/readme.md
|
|
9
|
+
Project-URL: Repository, https://github.com/atitoff-dotcom/rsgi-wsrpc.git
|
|
10
|
+
Keywords: rsgi,granian,wsrpc,json-rpc,websocket,reactive,fastapi-alternative,django-alternative
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Framework :: AsyncIO
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Topic :: Internet :: WWW/HTTP
|
|
19
|
+
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
|
|
20
|
+
Requires-Python: >=3.11
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
License-File: LICENSE
|
|
23
|
+
Requires-Dist: granian>=1.6.0
|
|
24
|
+
Requires-Dist: orjson>=3.9.0
|
|
25
|
+
Requires-Dist: pyjwt>=2.8.0
|
|
26
|
+
Requires-Dist: cryptography>=42.0.0
|
|
27
|
+
Provides-Extra: db
|
|
28
|
+
Requires-Dist: sqlalchemy>=2.0.0; extra == "db"
|
|
29
|
+
Provides-Extra: sqlite
|
|
30
|
+
Requires-Dist: sqlalchemy>=2.0.0; extra == "sqlite"
|
|
31
|
+
Requires-Dist: aiosqlite>=0.19.0; extra == "sqlite"
|
|
32
|
+
Provides-Extra: postgres
|
|
33
|
+
Requires-Dist: sqlalchemy>=2.0.0; extra == "postgres"
|
|
34
|
+
Requires-Dist: asyncpg>=0.29.0; extra == "postgres"
|
|
35
|
+
Provides-Extra: mysql
|
|
36
|
+
Requires-Dist: sqlalchemy>=2.0.0; extra == "mysql"
|
|
37
|
+
Requires-Dist: asyncmy>=0.2.9; extra == "mysql"
|
|
38
|
+
Provides-Extra: full
|
|
39
|
+
Requires-Dist: sqlalchemy>=2.0.0; extra == "full"
|
|
40
|
+
Requires-Dist: aiosqlite>=0.19.0; extra == "full"
|
|
41
|
+
Requires-Dist: asyncpg>=0.29.0; extra == "full"
|
|
42
|
+
Requires-Dist: asyncmy>=0.2.9; extra == "full"
|
|
43
|
+
Dynamic: license-file
|
|
44
|
+
|
|
45
|
+
# rsgi-wsrpc: Reactive Full-Featured Python Framework
|
|
46
|
+
|
|
47
|
+
> **"Everything Django should have been, and everything FastAPI forgot."**
|
|
48
|
+
> High-performance asynchronous web framework built on **Rust (Granian RSGI)** with bidirectional **WSRPC (JSON-RPC 2.0)**, built-in async database ORM, modern authentication, and transactional two-phase file uploading.
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## 🧭 Table of Contents
|
|
53
|
+
1. [Core Philosophy & Manifesto](#-core-philosophy--manifesto)
|
|
54
|
+
2. [Architecture: Core + Plugins + Application](#-architecture-core--plugins--application)
|
|
55
|
+
* [Architecture for Beginners with Diagrams (docs/architecture_for_beginners.md)](docs/architecture_for_beginners.md)
|
|
56
|
+
* [Recommended Project Structure (Directory Tree)](#-recommended-project-structure-directory-tree)
|
|
57
|
+
3. [Comparison: rsgi-wsrpc vs Django vs FastAPI](#-comparison-rsgi-wsrpc-vs-django-vs-fastapi)
|
|
58
|
+
4. [🤖 AI-Native: Token-Efficient & Purpose-Built for LLMs](#-ai-native-token-efficient--purpose-built-for-llms)
|
|
59
|
+
5. [Quickstart in 60 Seconds](#-quickstart-in-60-seconds)
|
|
60
|
+
6. [Core Network Engine](#-core-network-engine)
|
|
61
|
+
* [Complete Core Developer Guide (docs/core.md)](docs/core.md)
|
|
62
|
+
7. [Official System Plugins](#-official-system-plugins)
|
|
63
|
+
* [Database Plugin (db)](#1-database-plugin-pluginsdb)
|
|
64
|
+
* [Authentication & User Plugin (auth)](#2-authentication--user-plugin-pluginsauth)
|
|
65
|
+
* [Two-Phase File Upload Plugin (files)](#3-two-phase-file-upload-plugin-pluginsfiles)
|
|
66
|
+
* [Smart Event-Driven Cache Plugin (smart_cache)](#4-smart-event-driven-cache-plugin-pluginssmart_cache)
|
|
67
|
+
* [Modular Backend Test Framework (tests/)](#5-modular-backend-test-framework-tests)
|
|
68
|
+
8. [Creating Custom Plugins & Modules in the app Directory](#-creating-custom-plugins--modules-in-the-app-directory)
|
|
69
|
+
9. [Client Library (TypeScript/JavaScript)](#-client-library-typescriptjavascript)
|
|
70
|
+
10. [License](#-license)
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## 💡 Core Philosophy & Manifesto
|
|
75
|
+
|
|
76
|
+
The modern web has changed: users no longer tolerate static web pages reloading for hundreds of milliseconds. Users expect instant interactions (1–5 ms), reactive real-time state synchronization, and live progress streaming.
|
|
77
|
+
|
|
78
|
+
Yet Python developers were forced to choose between two extremes:
|
|
79
|
+
1. **Django** — a 20-year-old monolithic design from the Web 2.0 era. Adding websockets and reactivity requires bundling `Django + DRF + Channels + Redis + Celery + Daphne`, consuming hundreds of megabytes of RAM per worker.
|
|
80
|
+
2. **FastAPI** — performant, but trapped in the flat HTTP/1.1 REST paradigm (Request-Response). Every user action opens a new TCP connection, exchanges kilobytes of redundant HTTP headers, and lacks built-in batteries (auth, sessions, file transactions) — forcing developers to stitch together 50 disparate third-party libraries.
|
|
81
|
+
|
|
82
|
+
**`rsgi-wsrpc` combines the best of both worlds:**
|
|
83
|
+
* **From Rust and Granian** — blistering RSGI runtime performance without Python GIL overhead.
|
|
84
|
+
* **From WSRPC (JSON-RPC 2.0)** — a single persistent, multiplexed channel for all operations, symmetric RPC invocation (server can call client), and native multi-return streaming.
|
|
85
|
+
* **From Django** — production-grade batteries (Auth, DB, Two-Phase File uploads) delivered as decoupled, lightweight plugins.
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## 🏛 Architecture: Core + Plugins + Application
|
|
90
|
+
|
|
91
|
+
The architecture enforces a strict unidirectional dependency hierarchy (Clean Architecture):
|
|
92
|
+
|
|
93
|
+
```text
|
|
94
|
+
┌─────────────────────────────────────────────────────────────────────────┐
|
|
95
|
+
│ 1. YOUR APPLICATION (Application) │
|
|
96
|
+
│ │
|
|
97
|
+
│ Knows about all components: configures application in code (Code-First),
|
|
98
|
+
│ activates necessary system plugins, and executes domain business logic
|
|
99
|
+
│ Examples: Social Network, CRM, Forum, Customer Portal, IoT Server. │
|
|
100
|
+
└────────────────────────────────────┬────────────────────────────────────┘
|
|
101
|
+
│ consumes and aggregates
|
|
102
|
+
┌────────────────────────────────────▼────────────────────────────────────┐
|
|
103
|
+
│ 2. SYSTEM & APPLICATION PLUGINS │
|
|
104
|
+
│ │
|
|
105
|
+
│ [ Plugin: DB ] [ Plugin: Auth ] [ Plugin: Files ] │
|
|
106
|
+
│ Async SQLAlchemy 2.0 Users, JWT, 2PC file streaming, │
|
|
107
|
+
│ SQLite / PostgreSQL roles and permissions registry & Nginx offload │
|
|
108
|
+
│ │
|
|
109
|
+
│ [ Domain Plugins: Forum, Billing, Notifications, Analytics... ] │
|
|
110
|
+
└────────────────────────────────────┬────────────────────────────────────┘
|
|
111
|
+
│ registers into
|
|
112
|
+
┌────────────────────────────────────▼────────────────────────────────────┐
|
|
113
|
+
│ 3. NETWORK CORE (Core) │
|
|
114
|
+
│ │
|
|
115
|
+
│ Pure high-performance socket and RSGI runtime (Granian in Rust). │
|
|
116
|
+
│ ZERO knowledge of databases or application domain models. │
|
|
117
|
+
│ Responsible for: WSRPC (JSON-RPC 2.0), multi-return, sessions, 2PC. │
|
|
118
|
+
└─────────────────────────────────────────────────────────────────────────┘
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### Core Architectural Rules:
|
|
122
|
+
1. **The Core is Autonomous**: `core/` contains zero imports from application domains or database models.
|
|
123
|
+
2. **Plugins are Modular**: Each plugin tackles one concern and registers its handlers via core APIs (`@rpc_method`, `@on_startup`, `session.register_on_close`).
|
|
124
|
+
3. **Application Governs Composition**: Need a lightweight microservice without a database? Simply omit the `db` plugin. Need a full-stack portal? Import the complete battery bundle.
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
### 📁 Recommended Project Structure (Directory Tree)
|
|
129
|
+
|
|
130
|
+
Below is the production-tested repository layout, clearly demarcating the network engine (`core/`), official batteries (`app/system/`), and custom application modules (`app/<modules>/`):
|
|
131
|
+
|
|
132
|
+
```text
|
|
133
|
+
my_project/
|
|
134
|
+
├── core/ # ⚡ NETWORK CORE (RSGI + WSRPC)
|
|
135
|
+
│ ├── lib/
|
|
136
|
+
│ │ └── config.py # Code-First configuration & configure()
|
|
137
|
+
│ ├── constants.py # System constants and roles (UserRole)
|
|
138
|
+
│ ├── lifecycle.py # Async hooks @on_startup and @on_shutdown
|
|
139
|
+
│ ├── logger.py # High-performance structured logging
|
|
140
|
+
│ ├── router.py # HTTP routing on top of RSGI (@http_route)
|
|
141
|
+
│ ├── security.py # Argon2id, JWT tokens, RSA cryptography
|
|
142
|
+
│ ├── session.py # JsonRpcSession, @rpc_method, ContextVars, Rate-Limiter
|
|
143
|
+
│ └── tabular.py # Deterministic tabular payload compression (RFC 0002, pack_tabular)
|
|
144
|
+
│
|
|
145
|
+
├── app/ # 📦 APPLICATION & PLUGIN LAYER
|
|
146
|
+
│ ├── system/ # 🔌 System Plugins (Official Batteries)
|
|
147
|
+
│ │ ├── db.py # Async SQLAlchemy 2.0 engine (async_session, Base)
|
|
148
|
+
│ │ ├── broadcast.py # Event broadcaster across active sockets
|
|
149
|
+
│ │ ├── auth/ # Users, scopes, and Row-Level Security (RLS)
|
|
150
|
+
│ │ │ ├── models.py # Models: User, Role, Permit
|
|
151
|
+
│ │ │ ├── handlers.py # RPC methods: auth.*
|
|
152
|
+
│ │ │ ├── permissions.py # Scope and role verification logic
|
|
153
|
+
│ │ │ └── security.py # Hashing & authorization rules
|
|
154
|
+
│ │ ├── login/ # Authentication, RSA handshake, RefreshToken
|
|
155
|
+
│ │ │ ├── handlers.py # RPC methods: login.submit, login.refresh, login.whoami
|
|
156
|
+
│ │ │ └── db.py # Active sessions and token persistence
|
|
157
|
+
│ │ ├── files/ # File metadata registry & storage service
|
|
158
|
+
│ │ │ ├── models.py # FileMetadata ORM model
|
|
159
|
+
│ │ │ ├── service.py # FileStorageService (quota, schema migration, deletion)
|
|
160
|
+
│ │ │ └── handlers.py # HTTP route /upload and RPC methods: files.*
|
|
161
|
+
│ │ ├── admin/ # Administration control plane (sessions, cache, users)
|
|
162
|
+
│ │ │ └── handlers.py
|
|
163
|
+
│ │ └── internal_api/ # Interactive RPC documentation generator
|
|
164
|
+
│ │ ├── api.html # Built-in UI sandbox
|
|
165
|
+
│ │ ├── handlers.py # API inspection endpoints
|
|
166
|
+
│ │ └── generate_docs.py # Docstring and signature parser
|
|
167
|
+
│ │
|
|
168
|
+
│ └── <business_modules>/ # 🚀 Your application business domains
|
|
169
|
+
│ ├── forum/ # Example: Community discussion module
|
|
170
|
+
│ │ ├── models.py # Topic, Message, Tag models
|
|
171
|
+
│ │ └── handlers.py # RPC methods: forum.get_topics, forum.create_topic
|
|
172
|
+
│ ├── billing/ # Example: Billing and invoicing module
|
|
173
|
+
│ │ ├── models.py # Invoice, Transaction models
|
|
174
|
+
│ │ └── handlers.py # RPC methods: billing.create_invoice, billing.pay
|
|
175
|
+
│ └── notifications/ # Example: Real-time notification service
|
|
176
|
+
│ └── handlers.py # Push dispatching via broadcast
|
|
177
|
+
│
|
|
178
|
+
├── client/ # 💻 CLIENT LIBRARIES
|
|
179
|
+
│ └── wsrpc.ts # Official TypeScript/JavaScript WSRPC client
|
|
180
|
+
│
|
|
181
|
+
├── docs/ # 📚 Framework Documentation (EN)
|
|
182
|
+
│ ├── readme.md
|
|
183
|
+
│ ├── core.md # Comprehensive Core developer guide
|
|
184
|
+
│ └── files.md # Two-phase file upload guide (2PC)
|
|
185
|
+
│
|
|
186
|
+
├── docs_ru/ # 📚 Framework Documentation (RU Twin)
|
|
187
|
+
│ ├── readme.md
|
|
188
|
+
│ ├── core.md # Comprehensive Core developer guide
|
|
189
|
+
│ └── files.md # Two-phase file upload guide (2PC)
|
|
190
|
+
│
|
|
191
|
+
├── main.py # 🚀 Entrypoint: plugin composition, RSGI application
|
|
192
|
+
└── pyproject.toml # 📦 Dependencies and package manifest
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
## ⚡ Comparison: rsgi-wsrpc vs Django vs FastAPI
|
|
198
|
+
|
|
199
|
+
### 1. Client-Server Interaction Model
|
|
200
|
+
|
|
201
|
+
#### Traditional REST (FastAPI / Django):
|
|
202
|
+
Every operation re-initiates a TCP/TLS handshake, transfers cookies/headers, and terminates:
|
|
203
|
+
```text
|
|
204
|
+
[ Client ] ──── TCP + TLS Handshake (50-100 ms) ────► [ Server ]
|
|
205
|
+
[ Client ] ──── POST /api/items (Headers + Body) ───► [ Server ]
|
|
206
|
+
[ Client ] ◄─── 200 OK (Headers + Body) ──────────── [ Server ] (connection closed)
|
|
207
|
+
|
|
208
|
+
[ Client ] ──── TCP + TLS Handshake (50-100 ms) ────► [ Server ]
|
|
209
|
+
[ Client ] ──── GET /api/user/profile ──────────────► [ Server ]
|
|
210
|
+
[ Client ] ◄─── 200 OK ───────────────────────────── [ Server ]
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
#### Reactive WSRPC (`rsgi-wsrpc`):
|
|
214
|
+
A single persistent, multiplexed WebSocket channel. Zero handshake latency, instant 1–3 ms roundtrips:
|
|
215
|
+
```text
|
|
216
|
+
[ Client ] ═════════════════════════════════════════► [ Server ]
|
|
217
|
+
(Persistent secure WSRPC socket)
|
|
218
|
+
|
|
219
|
+
─── id: 1, method: "items.create" ───────► (1 ms)
|
|
220
|
+
◄── id: 1, result: { id: 42 } ──────────── (1 ms)
|
|
221
|
+
|
|
222
|
+
─── id: 2, method: "user.get_profile" ───► (1 ms)
|
|
223
|
+
◄── id: 2, result: { name: "Alex" } ────── (1 ms)
|
|
224
|
+
|
|
225
|
+
◄── SERVER PUSH: method: "notify" ──────── (Server initiates RPC on client!)
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
### 2. Feature Matrix
|
|
229
|
+
|
|
230
|
+
| Feature | Django | FastAPI | `rsgi-wsrpc` |
|
|
231
|
+
| :--- | :--- | :--- | :--- |
|
|
232
|
+
| **Network Engine** | Python WSGI / slow ASGI | Uvicorn (ASGI) | **Granian (Rust RSGI)** 🚀 |
|
|
233
|
+
| **Response Latency** | 80–250 ms | 30–120 ms | **1–5 ms** |
|
|
234
|
+
| **Symmetry** | ❌ Client ➔ Server only | ❌ Client ➔ Server only | ✅ **Client ⇄ Server (Bidirectional)** |
|
|
235
|
+
| **Progress Streaming** | ❌ Requires Redis + Channels | ❌ Heavy websocket boilerplate | ✅ **Native multi-return (`stream: true`)** |
|
|
236
|
+
| **RAM Footprint** | ~150–250 MB per worker | ~80–120 MB per worker | **~25–40 MB per worker** |
|
|
237
|
+
| **File Transfers** | Buffered in worker RAM | Buffered in RAM / SpooledFile | **Streaming O(1) RAM + 2PC + Nginx Offload** |
|
|
238
|
+
| **Built-in Auth** | ✅ Included (Synchronous) | ❌ None (Roll your own) | ✅ **Included (JWT + Refresh + Argon2)** |
|
|
239
|
+
| **Infrastructure** | Python + Postgres + Redis + Celery | Python + Postgres + ... | **Single Granian binary + SQLite/Postgres** |
|
|
240
|
+
| **AI-Native Engineering** | ❌ Highly Inefficient | ⚠️ Moderate (heavy boilerplate) | 🚀 **Maximum (AI-Native Architecture)** |
|
|
241
|
+
| **LLM Token Consumption** | ~3,000 – 5,000 tokens / feature | ~2,000 – 3,500 tokens / feature | **~300 – 600 tokens (5–10x savings!)** |
|
|
242
|
+
| **Files Touched per Feature** | 5–7 files | 4–6 files | **1–2 files (`handlers.py` + `rpc.call`)** |
|
|
243
|
+
| **Code Boilerplate** | Extreme (DTOs, URLs, views, redux) | High (Pydantic schemas, Depends) | **Minimal (clean `@rpc_method`)** |
|
|
244
|
+
|
|
245
|
+
---
|
|
246
|
+
|
|
247
|
+
## 🤖 AI-Native: Token-Efficient & Purpose-Built for LLMs
|
|
248
|
+
|
|
249
|
+
`rsgi-wsrpc` is engineered from the ground up for modern AI-assisted engineering: **code authored, reviewed, and refactored by LLMs and Autonomous AI Agents (Claude, Cursor, Gemini, GPT-4o, GitHub Copilot)**.
|
|
250
|
+
|
|
251
|
+
In conventional frameworks (FastAPI / Django), up to 80% of generated tokens are squandered on glue code, serialization boilerplate, and redundant plumbing. In `rsgi-wsrpc`, the unified contract yields **massive savings on LLM context windows and developer token budgets**.
|
|
252
|
+
|
|
253
|
+
```text
|
|
254
|
+
TOKEN CONSUMPTION FOR IMPLEMENTING A FEATURE (E.G. ADD COMMENT WITH REAL-TIME PUSH)
|
|
255
|
+
|
|
256
|
+
Django REST: ████████████████████████████████████████ (~4,200 tokens)
|
|
257
|
+
FastAPI: █████████████████████████ (~2,600 tokens)
|
|
258
|
+
rsgi-wsrpc: ███ (~350 tokens) ──► UP TO 85% TOKEN REDUCTION!
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
### Why AI Writes `rsgi-wsrpc` Code Faster, More Accurately, and Cheaper:
|
|
262
|
+
|
|
263
|
+
#### 1. Zero-Boilerplate Simplicity
|
|
264
|
+
You no longer need to burn context asking models to generate Pydantic request DTOs, response DTOs, HTTP error handlers, route registration boilerplate, and mirrored frontend `fetch()` wrappers.
|
|
265
|
+
* **Backend**: One decorator `@rpc_method("domain.action")`. User (`current_user_ctx`) and session context are accessible natively without intricate `Depends()` dependency graphs.
|
|
266
|
+
* **Frontend**: One line: `await rpc.call("domain.action", { ... })`.
|
|
267
|
+
|
|
268
|
+
#### 2. Unified Protocol vs Stack Sprawl
|
|
269
|
+
In traditional systems, developers must explain multiple disparate transport layers to the AI: REST for CRUD, WebSockets/SSE for notifications, Redis Pub/Sub for worker tasks, and Multipart for file uploads. Models exhaust their attention budgets and hallucinate.
|
|
270
|
+
With `rsgi-wsrpc`, **all communication adheres to one symmetrical protocol WSRPC (JSON-RPC 2.0)**: queries, mutations, progress streams (`stream: true`), server push notifications (`rpc.on`), and interactive server-to-client dialogs (`rpc.registerMethod`).
|
|
271
|
+
|
|
272
|
+
#### 3. High Context Locality
|
|
273
|
+
Modules in `app/<module>/` are strictly decoupled. When assigning an AI agent a feature or bug fix, you only need to provide **1 single file** (`handlers.py`), rather than sprawling architectural files.
|
|
274
|
+
* **Fewer Input Tokens**: Instant, near-zero latency generation from AI agents.
|
|
275
|
+
* **Higher Precision**: Eliminates hallucinations caused by oversized, noisy context windows.
|
|
276
|
+
* **Direct Cost Reduction**: Lowers operational API billing on commercial models.
|
|
277
|
+
|
|
278
|
+
---
|
|
279
|
+
|
|
280
|
+
## 🚀 Installation & Quickstart
|
|
281
|
+
|
|
282
|
+
### 📦 Installation via PIP
|
|
283
|
+
|
|
284
|
+
Install the minimal core (Granian RSGI, Orjson, WSRPC, Cryptography):
|
|
285
|
+
```bash
|
|
286
|
+
pip install rsgi-wsrpc
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
Or install with database support and drivers depending on your target stack:
|
|
290
|
+
```bash
|
|
291
|
+
pip install "rsgi-wsrpc[sqlite]" # Async SQLite (aiosqlite + SQLAlchemy 2.0)
|
|
292
|
+
pip install "rsgi-wsrpc[postgres]" # Async PostgreSQL (asyncpg + SQLAlchemy 2.0)
|
|
293
|
+
pip install "rsgi-wsrpc[mysql]" # Async MySQL (asyncmy + SQLAlchemy 2.0)
|
|
294
|
+
pip install "rsgi-wsrpc[full]" # All drivers and plugins included
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
---
|
|
298
|
+
|
|
299
|
+
### ⚡ Option A: Interactive Showcase Demo (1-Click)
|
|
300
|
+
|
|
301
|
+
The repository includes a ready-to-run interactive showcase (`examples/showcase/`):
|
|
302
|
+
|
|
303
|
+
```bash
|
|
304
|
+
# Linux / macOS:
|
|
305
|
+
./examples/showcase/run.sh
|
|
306
|
+
|
|
307
|
+
# macOS (without terminal):
|
|
308
|
+
# Double-click examples/showcase/run_mac.command directly in Finder!
|
|
309
|
+
|
|
310
|
+
# Windows (cmd):
|
|
311
|
+
examples\showcase\run.bat
|
|
312
|
+
|
|
313
|
+
# Windows (PowerShell):
|
|
314
|
+
.\examples\showcase\run.ps1
|
|
315
|
+
```
|
|
316
|
+
The launcher automatically provisions a `.venv`, installs dependencies, and boots the Granian server. Open `http://127.0.0.1:8080` in your browser to inspect real-time WSRPC operations, the reactive database, Tabular payload compression, and streaming progress.
|
|
317
|
+
|
|
318
|
+
---
|
|
319
|
+
|
|
320
|
+
### 🛠 Option B: Minimal Server (`main.py`)
|
|
321
|
+
```python
|
|
322
|
+
from core.session import rpc_method, JsonRpcSession
|
|
323
|
+
from core.lifecycle import on_startup
|
|
324
|
+
|
|
325
|
+
# Register RPC method
|
|
326
|
+
@rpc_method("math.add")
|
|
327
|
+
async def add_numbers(session: JsonRpcSession, params: dict):
|
|
328
|
+
a = params.get("a", 0)
|
|
329
|
+
b = params.get("b", 0)
|
|
330
|
+
return {"result": a + b}
|
|
331
|
+
|
|
332
|
+
# Multi-return streaming progress method
|
|
333
|
+
@rpc_method("task.run_long")
|
|
334
|
+
async def run_task(session: JsonRpcSession, params: dict):
|
|
335
|
+
rpc_id = params.get("rpc_id")
|
|
336
|
+
for step in range(1, 4):
|
|
337
|
+
# Transmit intermediate progress chunk to the socket
|
|
338
|
+
await session.send_stream_chunk(rpc_id, {"progress": step * 33})
|
|
339
|
+
return {"status": "completed"}
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
### 2. Launch Server via Granian
|
|
343
|
+
```bash
|
|
344
|
+
granian --interface rsgi --host 127.0.0.1 --port 8080 main:app
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
### 3. Invoke from Client (JavaScript / TypeScript)
|
|
348
|
+
```javascript
|
|
349
|
+
import { BinaryWSRPC } from './wsrpc.js';
|
|
350
|
+
|
|
351
|
+
const client = new BinaryWSRPC('ws://127.0.0.1:8080');
|
|
352
|
+
await client.connect();
|
|
353
|
+
|
|
354
|
+
// Regular RPC call
|
|
355
|
+
const sum = await client.call('math.add', { a: 10, b: 25 });
|
|
356
|
+
console.log(sum.result); // 35
|
|
357
|
+
|
|
358
|
+
// Multi-return streaming call
|
|
359
|
+
await client.callStream('task.run_long', {}, (chunk) => {
|
|
360
|
+
console.log(`Progress: ${chunk.progress}%`);
|
|
361
|
+
});
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
---
|
|
365
|
+
|
|
366
|
+
## ⚙️ Core Network Engine
|
|
367
|
+
|
|
368
|
+
> 📖 **For the complete technical manual with code examples, see: [docs/core.md](docs/core.md)**.
|
|
369
|
+
|
|
370
|
+
The network core resides in the `core/` directory and exposes the following building blocks:
|
|
371
|
+
|
|
372
|
+
* **[core/session.py](core/session.py)**:
|
|
373
|
+
* `JsonRpcSession`: Manages persistent client sockets.
|
|
374
|
+
* Multiplexes incoming and outgoing RPC requests by numeric `id`.
|
|
375
|
+
* Built-in **Rate-Limiter (Token Bucket)** for protection against flooding (30 req/s) with zero runtime overhead.
|
|
376
|
+
* Isolated Python `ContextVar` instances (`current_user_ctx`, `current_session_ctx`, `current_rpc_id_ctx`, `current_transport_ctx`), accessible anywhere in the async execution context.
|
|
377
|
+
* Session termination hooks: `session.register_on_close(callback)` for clean resource teardown.
|
|
378
|
+
* Symmetric client invocation from server: `await session.send_request("client_method", params)`.
|
|
379
|
+
|
|
380
|
+
* **[core/router.py](core/router.py)**:
|
|
381
|
+
* `@http_route(path, methods)` decorator to register raw RSGI HTTP handlers.
|
|
382
|
+
* High-throughput file streams, webhooks, and health checks.
|
|
383
|
+
|
|
384
|
+
* **[core/tabular.py](docs/tabular_compression.md)**:
|
|
385
|
+
* Deterministic tabular payload compression (RFC 0002, `pack_tabular`, `@tabular_response`).
|
|
386
|
+
* Cuts 50–70% of network traffic by transmitting property schemas once and packing records into a 2D matrix.
|
|
387
|
+
* Direct SQL tuple optimization bypasses dictionary allocations, minimizing Python GC overhead.
|
|
388
|
+
|
|
389
|
+
* **[core/security.py](core/security.py)**:
|
|
390
|
+
* Password hashing using **Argon2id**.
|
|
391
|
+
* JWT access token issuance and validation.
|
|
392
|
+
* Asymmetric RSA encryption for secure credential exchange.
|
|
393
|
+
|
|
394
|
+
* **[core/lifecycle.py](core/lifecycle.py)**:
|
|
395
|
+
* Application startup dispatcher `@on_startup` (runs migrations, cache warming, and background daemons before opening sockets).
|
|
396
|
+
|
|
397
|
+
* **[core/lib/config.py](core/lib/config.py)**:
|
|
398
|
+
* Settings parser for `settings.yaml` supporting environment variable overrides.
|
|
399
|
+
|
|
400
|
+
---
|
|
401
|
+
|
|
402
|
+
## 🔌 Official System Plugins
|
|
403
|
+
|
|
404
|
+
The framework includes pre-built and tested system batteries in `app/system/`:
|
|
405
|
+
|
|
406
|
+
### 1. Database Plugin (`plugins/db`)
|
|
407
|
+
* **Stack**: Async SQLAlchemy 2.0 + `orjson` for ultra-fast JSON serialization.
|
|
408
|
+
* **Engines**: SQLite out-of-the-box (zero configuration). Seamless switch to PostgreSQL via `settings.yaml`.
|
|
409
|
+
* **Usage**:
|
|
410
|
+
```python
|
|
411
|
+
from app.system.db import async_session, Base
|
|
412
|
+
from sqlalchemy import select
|
|
413
|
+
|
|
414
|
+
async with async_session() as db:
|
|
415
|
+
users = (await db.execute(select(User))).scalars().all()
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
---
|
|
419
|
+
|
|
420
|
+
### 2. Authentication & User Plugin (`plugins/auth`)
|
|
421
|
+
* **Features**:
|
|
422
|
+
* `User` model, flexible role architecture (dynamic roles in `auth_role` DB table, custom `UserRole` subclasses, superadmin bypass).
|
|
423
|
+
* **Row-Level Security (RLS)**: base classes `BasicSecureModel` and `RowSecureModel` for tenant/owner scoping.
|
|
424
|
+
* Reliable session extension via `RefreshToken` and multi-device tracking in `ActiveSession`.
|
|
425
|
+
* Context-based user retrieval anywhere without passing parameters:
|
|
426
|
+
```python
|
|
427
|
+
from core.session import current_user_ctx
|
|
428
|
+
user = current_user_ctx.get()
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
---
|
|
432
|
+
|
|
433
|
+
### 3. Two-Phase File Upload Plugin (`plugins/files`)
|
|
434
|
+
* Comprehensive architecture: see **[docs/files.md](docs/files.md)**.
|
|
435
|
+
* **Two-Phase Commit Workflow**:
|
|
436
|
+
1. Client initiates upload transaction: server provisions isolated `/tmp/app_uploads/<folder_hash>/`.
|
|
437
|
+
2. Client streams files via `POST /upload`. Bytes stream directly to disk without memory buffering.
|
|
438
|
+
3. If client disconnects — core triggers `session.on_close` and erases the temp folder immediately.
|
|
439
|
+
4. On completion — folder moves atomically to production storage `/files/<folder_hash>/` in 0 milliseconds.
|
|
440
|
+
5. Files are indexed in unified `file_metadata` database table (quotas, original names, MIME types).
|
|
441
|
+
6. Downloads are served directly by **Nginx** with zero Python overhead.
|
|
442
|
+
|
|
443
|
+
---
|
|
444
|
+
|
|
445
|
+
### 4. Smart Reactive Cache Plugin (`plugins/smart_cache`)
|
|
446
|
+
* Comprehensive architecture: see **[docs/smart_cache.md](docs/smart_cache.md)** and **[RFC 0001](rfc/0001-smart-cache.md)**.
|
|
447
|
+
* **0 ms Latency Principle & Push Invalidation**:
|
|
448
|
+
* Instant screen rendering from L1 RAM (or L2 IndexedDB/localStorage) with zero network wait.
|
|
449
|
+
* Server automatically tracks mutations and pushes `cache.invalidate` impulses or targeted `cache.patch` via `@invalidates(tags=...)`.
|
|
450
|
+
* Zero blind polling — the WebSocket stays completely silent until data actually changes.
|
|
451
|
+
* Version handshake (`cache.sync_check`) on reconnect syncs only tags that changed during offline state.
|
|
452
|
+
|
|
453
|
+
---
|
|
454
|
+
|
|
455
|
+
### 5. Modular Backend Test Framework (`tests/`)
|
|
456
|
+
* Comprehensive guide: see **[docs/testing.md](docs/testing.md)**.
|
|
457
|
+
* **Client-Perspective Black-Box Testing**:
|
|
458
|
+
* Validates the backend exactly as a real frontend client interacts with it (over WebSocket WSRPC and HTTP).
|
|
459
|
+
* `PersonaManager`: pre-authenticated sessions (`admin`, `user`, `guest`) with automatic local database seeding and RLS bypass.
|
|
460
|
+
* Native verification of streaming (`stream: true`), push notification interception (`cache.invalidate`, `cache.patch`), and two-phase uploads.
|
|
461
|
+
* Built-in stress & load testing (`tests/suites/test_load.py`): benchmarks RPS, latency percentiles (p50/p95/p99), and broadcast fan-out reliability.
|
|
462
|
+
|
|
463
|
+
---
|
|
464
|
+
|
|
465
|
+
## 🛠 Creating Custom Plugins & Modules in the app Directory
|
|
466
|
+
|
|
467
|
+
Creating a custom feature module (e.g. support ticket system `app/tickets/`) is straightforward:
|
|
468
|
+
|
|
469
|
+
```python
|
|
470
|
+
# app/tickets/handlers.py
|
|
471
|
+
from core.session import rpc_method, RPCError, current_user_ctx
|
|
472
|
+
from app.system.db import async_session
|
|
473
|
+
from app.system.files.service import FileStorageService
|
|
474
|
+
|
|
475
|
+
@rpc_method("tickets.create")
|
|
476
|
+
async def create_ticket(session, params):
|
|
477
|
+
user = current_user_ctx.get()
|
|
478
|
+
if not user:
|
|
479
|
+
raise RPCError("Authentication required")
|
|
480
|
+
|
|
481
|
+
title = params.get("title")
|
|
482
|
+
text = params.get("text")
|
|
483
|
+
folder_hash = params.get("folder_hash") # If files were attached
|
|
484
|
+
|
|
485
|
+
# Persist ticket in database
|
|
486
|
+
async with async_session() as db:
|
|
487
|
+
async with db.begin():
|
|
488
|
+
ticket = Ticket(title=title, text=text, author_id=user.id, folder=folder_hash)
|
|
489
|
+
db.add(ticket)
|
|
490
|
+
|
|
491
|
+
return {"status": "ok", "ticket_id": ticket.id}
|
|
492
|
+
|
|
493
|
+
@rpc_method("tickets.delete")
|
|
494
|
+
async def delete_ticket(session, params):
|
|
495
|
+
ticket_id = params.get("ticket_id")
|
|
496
|
+
|
|
497
|
+
async with async_session() as db:
|
|
498
|
+
ticket = await db.get(Ticket, ticket_id)
|
|
499
|
+
if ticket and ticket.folder:
|
|
500
|
+
# Atomically delete all bundled files from disk and registry
|
|
501
|
+
await FileStorageService.delete_bundle(ticket.folder)
|
|
502
|
+
await db.delete(ticket)
|
|
503
|
+
await db.commit()
|
|
504
|
+
|
|
505
|
+
return {"deleted": True}
|
|
506
|
+
```
|
|
507
|
+
|
|
508
|
+
To enable the module, import its handlers in `main.py`:
|
|
509
|
+
```python
|
|
510
|
+
# main.py
|
|
511
|
+
import app.tickets.handlers # noqa: F401
|
|
512
|
+
```
|
|
513
|
+
|
|
514
|
+
---
|
|
515
|
+
|
|
516
|
+
## 💻 Client Library (TypeScript/JavaScript)
|
|
517
|
+
|
|
518
|
+
The framework includes the official zero-dependency client `client/wsrpc.ts`:
|
|
519
|
+
|
|
520
|
+
```typescript
|
|
521
|
+
import { BinaryWSRPC, wsConnected, wsStatus } from './wsrpc';
|
|
522
|
+
|
|
523
|
+
const rpc = new BinaryWSRPC('wss://api.example.com/ws');
|
|
524
|
+
await rpc.connect();
|
|
525
|
+
|
|
526
|
+
// 1. Standard typed RPC call
|
|
527
|
+
const profile = await rpc.call<UserProfile>('user.get_profile', { user_id: 42 });
|
|
528
|
+
console.log('User profile:', profile.name);
|
|
529
|
+
|
|
530
|
+
// 2. Multi-return: Progress streaming for long-running workloads
|
|
531
|
+
const report = await rpc.callStream<ReportResult>(
|
|
532
|
+
'reports.generate',
|
|
533
|
+
{ period: '2026-Q3' },
|
|
534
|
+
(chunk) => {
|
|
535
|
+
console.log(`[${chunk.percent}%] Progress: ${chunk.message}`);
|
|
536
|
+
updateProgressBar(chunk.percent); // Real-time UI progress update!
|
|
537
|
+
}
|
|
538
|
+
);
|
|
539
|
+
console.log('Report ready:', report.download_url);
|
|
540
|
+
|
|
541
|
+
// 3. Receive unsolicited Server Push notifications
|
|
542
|
+
const unsubscribe = rpc.on('chat.new_message', (msg) => {
|
|
543
|
+
console.log(`[${msg.author}]: ${msg.text}`);
|
|
544
|
+
messagesList.update(items => [...items, msg]);
|
|
545
|
+
});
|
|
546
|
+
|
|
547
|
+
// 4. Symmetric RPC: Server initiates an interactive prompt on the client
|
|
548
|
+
rpc.registerMethod('ui.confirm', async (params) => {
|
|
549
|
+
const isApproved = await showConfirmationModal(params.title, params.message);
|
|
550
|
+
return { confirmed: isApproved }; // Transmitted back to the server!
|
|
551
|
+
});
|
|
552
|
+
```
|
|
553
|
+
|
|
554
|
+
> 📖 **For in-depth UI framework integrations (Svelte, React, Vue), error handling, and unsubscription patterns, see: [docs/core.md](docs/core.md#8-typescriptjavascript-client-clientwsrpcts)**.
|
|
555
|
+
|
|
556
|
+
---
|
|
557
|
+
|
|
558
|
+
## 📄 License
|
|
559
|
+
This project is licensed under the **MIT License**.
|
|
560
|
+
Free for commercial use, modification, and distribution.
|