crosspulse 1.0.1 β 1.0.2
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.
- package/.github/workflows/publish.yml +30 -0
- package/.pypirc +9 -0
- package/README.md +84 -40
- package/dist/crosspulse-0.1.0-py3-none-any.whl +0 -0
- package/dist/crosspulse-0.1.0.tar.gz +0 -0
- package/package.json +1 -1
- package/pyproject.toml +16 -0
- package/src/crosspulse.egg-info/PKG-INFO +592 -0
- package/src/crosspulse.egg-info/SOURCES.txt +8 -0
- package/src/crosspulse.egg-info/dependency_links.txt +1 -0
- package/src/crosspulse.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
name: Publish Python Package
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
build-and-publish:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
|
|
12
|
+
steps:
|
|
13
|
+
- uses: actions/checkout@v3
|
|
14
|
+
|
|
15
|
+
- name: Set up Python
|
|
16
|
+
uses: actions/setup-python@v4
|
|
17
|
+
with:
|
|
18
|
+
python-version: "3.11"
|
|
19
|
+
|
|
20
|
+
- name: Install dependencies
|
|
21
|
+
run: pip install build twine
|
|
22
|
+
|
|
23
|
+
- name: Build package
|
|
24
|
+
run: python -m build
|
|
25
|
+
|
|
26
|
+
- name: Publish package to PyPI
|
|
27
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
28
|
+
with:
|
|
29
|
+
user: __token__
|
|
30
|
+
password: ${{ secrets.PYPI_API_TOKEN }}
|
package/.pypirc
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
[distutils]
|
|
2
|
+
index-servers =
|
|
3
|
+
testpypi
|
|
4
|
+
pypi
|
|
5
|
+
|
|
6
|
+
[testpypi]
|
|
7
|
+
repository: https://test.pypi.org/legacy/
|
|
8
|
+
username: __token__
|
|
9
|
+
password: pypi-AgEIcHlwaS5vcmcCJDE1NTkxNTU2LTMzNzEtNDFjNi05MmUyLTJiNTFiNjIxZWQwNQACKlszLCI1ZDcyOTliOC01Y2JlLTRmYjUtYjQ0OC00ZTgzMGUxZDViODgiXQAABiAV3okyiLgaHjmN8fqFZeRrsKSNjAGVCEmrI_J4YDY6XA
|
package/README.md
CHANGED
|
@@ -44,7 +44,19 @@ That's it. No REST APIs, no HTTP servers, no complexity.
|
|
|
44
44
|
|
|
45
45
|
## π¦ Installation
|
|
46
46
|
|
|
47
|
-
|
|
47
|
+
**Download Manual:**
|
|
48
|
+
|
|
49
|
+
JavaScript:
|
|
50
|
+
```bash
|
|
51
|
+
npm install crosspulse
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Python:
|
|
55
|
+
```bash
|
|
56
|
+
pip install crosspulse
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
**or Simply copy the files to your project:**
|
|
48
60
|
|
|
49
61
|
```bash
|
|
50
62
|
crosspulse.py
|
|
@@ -65,32 +77,41 @@ Call Python functions from JavaScript.
|
|
|
65
77
|
|
|
66
78
|
**JavaScript side:**
|
|
67
79
|
```javascript
|
|
68
|
-
|
|
80
|
+
import Crosspulse from "crosspulse/src/crosspulse.js";
|
|
69
81
|
|
|
70
82
|
async function main() {
|
|
83
|
+
// Create a bridge in "connect" mode
|
|
71
84
|
const bridge = new Crosspulse("connect");
|
|
72
|
-
await bridge.connect("./crosspulse.py");
|
|
73
85
|
|
|
74
|
-
//
|
|
86
|
+
// Connect to the Python script
|
|
87
|
+
await bridge.connect("python main.py");
|
|
88
|
+
|
|
89
|
+
// Call a Python function and get the result
|
|
75
90
|
const result = await bridge.call("py_add", 10, 20);
|
|
76
91
|
console.log(result); // 30
|
|
77
92
|
|
|
93
|
+
// Disconnect the bridge
|
|
78
94
|
bridge.disconnect();
|
|
79
95
|
}
|
|
80
96
|
|
|
97
|
+
// Run the main function
|
|
81
98
|
main();
|
|
82
99
|
```
|
|
83
100
|
|
|
84
101
|
**Python side:**
|
|
85
102
|
```python
|
|
86
|
-
|
|
103
|
+
import crosspulse
|
|
87
104
|
|
|
88
|
-
bridge
|
|
105
|
+
# Create a bridge in "listen" mode
|
|
106
|
+
bridge = crosspulse.Crosspulse(mode="listen")
|
|
89
107
|
|
|
90
|
-
# Register method
|
|
91
|
-
|
|
108
|
+
# Register a Python method that JS can call
|
|
109
|
+
def py_add(a, b):
|
|
110
|
+
return a + b
|
|
92
111
|
|
|
93
|
-
|
|
112
|
+
bridge.register("py_add", py_add)
|
|
113
|
+
|
|
114
|
+
# Start listening for incoming calls from JavaScript
|
|
94
115
|
bridge.listen()
|
|
95
116
|
```
|
|
96
117
|
|
|
@@ -107,34 +128,39 @@ Call JavaScript functions from Python.
|
|
|
107
128
|
|
|
108
129
|
**Python side:**
|
|
109
130
|
```python
|
|
110
|
-
|
|
131
|
+
import crosspulse
|
|
132
|
+
|
|
133
|
+
# Create a bridge in "connect" mode
|
|
134
|
+
bridge = crosspulse.Crosspulse(mode="connect")
|
|
111
135
|
|
|
112
|
-
|
|
113
|
-
bridge.connect("
|
|
136
|
+
# Connect to the JavaScript script
|
|
137
|
+
bridge.connect("node app.js")
|
|
114
138
|
|
|
115
|
-
# Call JavaScript function
|
|
139
|
+
# Call a JavaScript function and get the result
|
|
116
140
|
result = bridge.call("js_multiply", 100, 50)
|
|
117
141
|
print(result) # 5000
|
|
118
142
|
|
|
143
|
+
# Disconnect the bridge
|
|
119
144
|
bridge.disconnect()
|
|
120
145
|
```
|
|
121
146
|
|
|
122
147
|
**JavaScript side:**
|
|
123
148
|
```javascript
|
|
124
|
-
|
|
149
|
+
import Crosspulse from "crosspulse/src/crosspulse.js";
|
|
125
150
|
|
|
151
|
+
// Create a bridge in "listen" mode
|
|
126
152
|
const bridge = new Crosspulse("listen");
|
|
127
153
|
|
|
128
|
-
// Register method
|
|
154
|
+
// Register a JavaScript method that Python can call
|
|
129
155
|
bridge.register("js_multiply", (a, b) => a * b);
|
|
130
156
|
|
|
131
|
-
// Start listening
|
|
157
|
+
// Start listening for incoming calls from Python
|
|
132
158
|
bridge.listen();
|
|
133
159
|
```
|
|
134
160
|
|
|
135
161
|
**Run:**
|
|
136
162
|
```bash
|
|
137
|
-
|
|
163
|
+
python main.py
|
|
138
164
|
```
|
|
139
165
|
|
|
140
166
|
---
|
|
@@ -145,33 +171,47 @@ Both languages can call each other simultaneously!
|
|
|
145
171
|
|
|
146
172
|
**Python side:**
|
|
147
173
|
```python
|
|
148
|
-
|
|
174
|
+
import crosspulse
|
|
175
|
+
|
|
176
|
+
# Create a bridge in "connect" mode
|
|
177
|
+
bridge = crosspulse.Crosspulse(mode="connect")
|
|
178
|
+
|
|
179
|
+
# Register Python methods that JavaScript can call
|
|
180
|
+
def py_square(x):
|
|
181
|
+
return x ** 2
|
|
149
182
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
bridge.register("py_reverse", lambda s: s[::-1])
|
|
183
|
+
def py_reverse(s):
|
|
184
|
+
return s[::-1]
|
|
153
185
|
|
|
154
|
-
bridge.
|
|
186
|
+
bridge.register("py_square", py_square)
|
|
187
|
+
bridge.register("py_reverse", py_reverse)
|
|
155
188
|
|
|
156
|
-
#
|
|
189
|
+
# Connect to the JavaScript script
|
|
190
|
+
bridge.connect("node app.js")
|
|
191
|
+
|
|
192
|
+
# Call JavaScript methods
|
|
157
193
|
result = bridge.call("js_capitalize", "hello world")
|
|
158
194
|
print(result) # "HELLO WORLD"
|
|
159
195
|
|
|
160
|
-
#
|
|
196
|
+
# JavaScript can call py_square() or py_reverse() one request at a time
|
|
161
197
|
```
|
|
162
198
|
|
|
163
199
|
**JavaScript side:**
|
|
164
200
|
```javascript
|
|
201
|
+
import Crosspulse from "crosspulse/src/crosspulse.js";
|
|
202
|
+
|
|
203
|
+
// Create a bridge in "listen" mode
|
|
165
204
|
const bridge = new Crosspulse("listen");
|
|
166
205
|
|
|
167
|
-
// Register
|
|
206
|
+
// Register JavaScript methods that Python can call
|
|
168
207
|
bridge.register("js_capitalize", (str) => str.toUpperCase());
|
|
169
208
|
bridge.register("js_length", (str) => str.length);
|
|
170
209
|
|
|
210
|
+
// Start listening for incoming calls from Python
|
|
171
211
|
bridge.listen();
|
|
172
212
|
|
|
173
|
-
// Python can
|
|
174
|
-
//
|
|
213
|
+
// Python can call these methods one request at a time
|
|
214
|
+
// Incoming calls are automatically handled
|
|
175
215
|
```
|
|
176
216
|
|
|
177
217
|
---
|
|
@@ -194,7 +234,7 @@ bridge.register("method_name", callback_function)
|
|
|
194
234
|
bridge.listen()
|
|
195
235
|
|
|
196
236
|
# Connect to target (connect mode)
|
|
197
|
-
bridge.connect("target_script.js")
|
|
237
|
+
bridge.connect("node target_script.js")
|
|
198
238
|
|
|
199
239
|
# Call remote method
|
|
200
240
|
result = bridge.call("method_name", arg1, arg2)
|
|
@@ -206,7 +246,7 @@ bridge.disconnect()
|
|
|
206
246
|
### JavaScript
|
|
207
247
|
|
|
208
248
|
```javascript
|
|
209
|
-
|
|
249
|
+
import Crosspulse from "crosspulse/src/crosspulse.js";
|
|
210
250
|
|
|
211
251
|
// Create instance
|
|
212
252
|
const bridge = new Crosspulse("listen"); // Listen mode
|
|
@@ -221,7 +261,7 @@ bridge.register("method_name", (arg1, arg2) => {
|
|
|
221
261
|
bridge.listen();
|
|
222
262
|
|
|
223
263
|
// Connect to target (connect mode)
|
|
224
|
-
await bridge.connect("
|
|
264
|
+
await bridge.connect("python target_script.py");
|
|
225
265
|
|
|
226
266
|
// Call remote method
|
|
227
267
|
const result = await bridge.call("method_name", arg1, arg2);
|
|
@@ -242,7 +282,7 @@ import pandas as pd
|
|
|
242
282
|
from crosspulse import Crosspulse
|
|
243
283
|
|
|
244
284
|
bridge = Crosspulse("connect")
|
|
245
|
-
bridge.connect("
|
|
285
|
+
bridge.connect("node visualizer.js")
|
|
246
286
|
|
|
247
287
|
# Process data in Python
|
|
248
288
|
df = pd.read_csv("sales_data.csv")
|
|
@@ -255,6 +295,8 @@ print(f"Chart created: {chart}")
|
|
|
255
295
|
|
|
256
296
|
```javascript
|
|
257
297
|
// visualizer.js
|
|
298
|
+
import Crosspulse from "crosspulse/src/crosspulse.js";
|
|
299
|
+
|
|
258
300
|
const bridge = new Crosspulse("listen");
|
|
259
301
|
|
|
260
302
|
bridge.register("create_chart", (data) => {
|
|
@@ -270,10 +312,12 @@ bridge.listen();
|
|
|
270
312
|
|
|
271
313
|
```javascript
|
|
272
314
|
// ml_interface.js
|
|
315
|
+
import Crosspulse from "crosspulse/src/crosspulse.js";
|
|
316
|
+
|
|
273
317
|
const bridge = new Crosspulse("connect");
|
|
274
318
|
|
|
275
319
|
async function trainModel(dataset) {
|
|
276
|
-
await bridge.connect("
|
|
320
|
+
await bridge.connect("python ml_model.py");
|
|
277
321
|
|
|
278
322
|
const progress = await bridge.call("train", dataset);
|
|
279
323
|
console.log("Training progress:", progress);
|
|
@@ -286,6 +330,7 @@ async function trainModel(dataset) {
|
|
|
286
330
|
```python
|
|
287
331
|
# ml_model.py
|
|
288
332
|
from sklearn.ensemble import RandomForestClassifier
|
|
333
|
+
from crosspulse import Crosspulse
|
|
289
334
|
|
|
290
335
|
bridge = Crosspulse("listen")
|
|
291
336
|
|
|
@@ -317,7 +362,7 @@ def scrape_news():
|
|
|
317
362
|
# Send to JavaScript for display
|
|
318
363
|
bridge.call("update_ui", data)
|
|
319
364
|
|
|
320
|
-
bridge.connect("
|
|
365
|
+
bridge.connect("node server.js")
|
|
321
366
|
scrape_news()
|
|
322
367
|
```
|
|
323
368
|
|
|
@@ -325,10 +370,12 @@ scrape_news()
|
|
|
325
370
|
|
|
326
371
|
```javascript
|
|
327
372
|
// electron_main.js
|
|
373
|
+
import Crosspulse from "crosspulse/src/crosspulse.js";
|
|
374
|
+
|
|
328
375
|
const bridge = new Crosspulse("connect");
|
|
329
376
|
|
|
330
377
|
ipcMain.on("process-image", async (event, imagePath) => {
|
|
331
|
-
await bridge.connect("
|
|
378
|
+
await bridge.connect("python image_processor.py");
|
|
332
379
|
|
|
333
380
|
const processed = await bridge.call("enhance_image", imagePath);
|
|
334
381
|
event.reply("image-ready", processed);
|
|
@@ -450,7 +497,7 @@ bridge.listen() # Must be after register
|
|
|
450
497
|
### Connection timeout
|
|
451
498
|
```javascript
|
|
452
499
|
// Ensure Python script is running
|
|
453
|
-
await bridge.connect("
|
|
500
|
+
await bridge.connect("python script.py");
|
|
454
501
|
// Python should be in listen mode
|
|
455
502
|
```
|
|
456
503
|
|
|
@@ -468,7 +515,7 @@ await bridge.connect("./script.py");
|
|
|
468
515
|
Contributions are welcome! Here's how:
|
|
469
516
|
|
|
470
517
|
```bash
|
|
471
|
-
git clone https://github.com/
|
|
518
|
+
git clone https://github.com/AnarDevStudio/crosspulse.git
|
|
472
519
|
cd crosspulse
|
|
473
520
|
```
|
|
474
521
|
|
|
@@ -511,8 +558,6 @@ SOFTWARE.
|
|
|
511
558
|
|
|
512
559
|
---
|
|
513
560
|
|
|
514
|
-
|
|
515
|
-
|
|
516
561
|
## π Show Your Support
|
|
517
562
|
|
|
518
563
|
If Crosspulse helps your project, give it a βοΈ on GitHub!
|
|
@@ -527,9 +572,8 @@ If Crosspulse helps your project, give it a βοΈ on GitHub!
|
|
|
527
572
|
|
|
528
573
|
---
|
|
529
574
|
|
|
530
|
-
|
|
531
575
|
**Built with β€οΈ by developers who believe languages should work together, not apart.**
|
|
532
576
|
|
|
533
577
|
**Crosspulse** - Where Python meets JavaScript. π
|
|
534
578
|
|
|
535
|
-
**
|
|
579
|
+
**Made by AnarEsgerzadeπ·**
|
|
Binary file
|
|
Binary file
|
package/package.json
CHANGED
package/pyproject.toml
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "crosspulse"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Call Python from Node.js and Node.js from Python easily with Crosspulseβs lightweight bridge."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.8"
|
|
11
|
+
license = {text = "MIT"}
|
|
12
|
+
authors = [{name="AnarLabs", email="anardevstudio@gmail.com"}]
|
|
13
|
+
|
|
14
|
+
[project.urls]
|
|
15
|
+
"Homepage" = "https://github.com/AnarDevStudio/Crosspulse"
|
|
16
|
+
"Repository" = "https://github.com/AnarDevStudio/Crosspulse"
|
|
@@ -0,0 +1,592 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: crosspulse
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Call Python from Node.js and Node.js from Python easily with Crosspulseβs lightweight bridge.
|
|
5
|
+
Author-email: AnarLabs <anardevstudio@gmail.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/AnarDevStudio/Crosspulse
|
|
8
|
+
Project-URL: Repository, https://github.com/AnarDevStudio/Crosspulse
|
|
9
|
+
Requires-Python: >=3.8
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Dynamic: license-file
|
|
13
|
+
|
|
14
|
+
# Crosspulse
|
|
15
|
+
|
|
16
|
+
**Seamless Python β JavaScript Bridge** - Bidirectional, fully synchronized cross-language communication library.
|
|
17
|
+
|
|
18
|
+
[](https://opensource.org/licenses/MIT)
|
|
19
|
+
[](https://www.python.org/downloads/)
|
|
20
|
+
[](https://nodejs.org/)
|
|
21
|
+
|
|
22
|
+
> Break down language barriers and let Python and JavaScript talk to each other like old friends.
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## β¨ Features
|
|
27
|
+
|
|
28
|
+
- β
**Bidirectional Communication**: JS β PY and PY β JS
|
|
29
|
+
- β
**Synchronous Calls**: Full Promise/await support
|
|
30
|
+
- β
**Event-Based Architecture**: Register, listen, and call methods
|
|
31
|
+
- β
**Error Handling**: Exception handling in both languages
|
|
32
|
+
- β
**Type Safe**: JSON serialization with validation
|
|
33
|
+
- β
**Simple API**: Just 3 core methods: `register()`, `listen()`, `call()`
|
|
34
|
+
- β
**Zero Dependencies**: No external packages required
|
|
35
|
+
- β
**Lightweight**: Minimal overhead, maximum performance
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## π― Why Crosspulse?
|
|
40
|
+
|
|
41
|
+
Ever wanted to combine Python's data processing power with JavaScript's UI capabilities? Or run ML models in Python while displaying results in Node.js? Crosspulse makes it effortless.
|
|
42
|
+
|
|
43
|
+
```javascript
|
|
44
|
+
// JavaScript
|
|
45
|
+
const result = await bridge.call("train_model", data);
|
|
46
|
+
console.log("Accuracy:", result.accuracy);
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
```python
|
|
50
|
+
# Python (automatically responds)
|
|
51
|
+
bridge.register("train_model", train_ml_model)
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
That's it. No REST APIs, no HTTP servers, no complexity.
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## π¦ Installation
|
|
59
|
+
|
|
60
|
+
**Download Manual:**
|
|
61
|
+
|
|
62
|
+
JavaScript:
|
|
63
|
+
```bash
|
|
64
|
+
npm install crosspulse
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Python:
|
|
68
|
+
```bash
|
|
69
|
+
pip install crosspulse
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
**or Simply copy the files to your project:**
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
crosspulse.py
|
|
76
|
+
crosspulse.js
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
**Requirements:**
|
|
80
|
+
- Python 3.7+
|
|
81
|
+
- Node.js 12+
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## π Quick Start
|
|
86
|
+
|
|
87
|
+
### Mode 1: JavaScript β Python
|
|
88
|
+
|
|
89
|
+
Call Python functions from JavaScript.
|
|
90
|
+
|
|
91
|
+
**JavaScript side:**
|
|
92
|
+
```javascript
|
|
93
|
+
import Crosspulse from "crosspulse/src/crosspulse.js";
|
|
94
|
+
|
|
95
|
+
async function main() {
|
|
96
|
+
// Create a bridge in "connect" mode
|
|
97
|
+
const bridge = new Crosspulse("connect");
|
|
98
|
+
|
|
99
|
+
// Connect to the Python script
|
|
100
|
+
await bridge.connect("python main.py");
|
|
101
|
+
|
|
102
|
+
// Call a Python function and get the result
|
|
103
|
+
const result = await bridge.call("py_add", 10, 20);
|
|
104
|
+
console.log(result); // 30
|
|
105
|
+
|
|
106
|
+
// Disconnect the bridge
|
|
107
|
+
bridge.disconnect();
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Run the main function
|
|
111
|
+
main();
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
**Python side:**
|
|
115
|
+
```python
|
|
116
|
+
import crosspulse
|
|
117
|
+
|
|
118
|
+
# Create a bridge in "listen" mode
|
|
119
|
+
bridge = crosspulse.Crosspulse(mode="listen")
|
|
120
|
+
|
|
121
|
+
# Register a Python method that JS can call
|
|
122
|
+
def py_add(a, b):
|
|
123
|
+
return a + b
|
|
124
|
+
|
|
125
|
+
bridge.register("py_add", py_add)
|
|
126
|
+
|
|
127
|
+
# Start listening for incoming calls from JavaScript
|
|
128
|
+
bridge.listen()
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
**Run:**
|
|
132
|
+
```bash
|
|
133
|
+
node app.js
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
### Mode 2: Python β JavaScript
|
|
139
|
+
|
|
140
|
+
Call JavaScript functions from Python.
|
|
141
|
+
|
|
142
|
+
**Python side:**
|
|
143
|
+
```python
|
|
144
|
+
import crosspulse
|
|
145
|
+
|
|
146
|
+
# Create a bridge in "connect" mode
|
|
147
|
+
bridge = crosspulse.Crosspulse(mode="connect")
|
|
148
|
+
|
|
149
|
+
# Connect to the JavaScript script
|
|
150
|
+
bridge.connect("node app.js")
|
|
151
|
+
|
|
152
|
+
# Call a JavaScript function and get the result
|
|
153
|
+
result = bridge.call("js_multiply", 100, 50)
|
|
154
|
+
print(result) # 5000
|
|
155
|
+
|
|
156
|
+
# Disconnect the bridge
|
|
157
|
+
bridge.disconnect()
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
**JavaScript side:**
|
|
161
|
+
```javascript
|
|
162
|
+
import Crosspulse from "crosspulse/src/crosspulse.js";
|
|
163
|
+
|
|
164
|
+
// Create a bridge in "listen" mode
|
|
165
|
+
const bridge = new Crosspulse("listen");
|
|
166
|
+
|
|
167
|
+
// Register a JavaScript method that Python can call
|
|
168
|
+
bridge.register("js_multiply", (a, b) => a * b);
|
|
169
|
+
|
|
170
|
+
// Start listening for incoming calls from Python
|
|
171
|
+
bridge.listen();
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
**Run:**
|
|
175
|
+
```bash
|
|
176
|
+
python main.py
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
---
|
|
180
|
+
|
|
181
|
+
### Mode 3: Bidirectional Communication
|
|
182
|
+
|
|
183
|
+
Both languages can call each other simultaneously!
|
|
184
|
+
|
|
185
|
+
**Python side:**
|
|
186
|
+
```python
|
|
187
|
+
import crosspulse
|
|
188
|
+
|
|
189
|
+
# Create a bridge in "connect" mode
|
|
190
|
+
bridge = crosspulse.Crosspulse(mode="connect")
|
|
191
|
+
|
|
192
|
+
# Register Python methods that JavaScript can call
|
|
193
|
+
def py_square(x):
|
|
194
|
+
return x ** 2
|
|
195
|
+
|
|
196
|
+
def py_reverse(s):
|
|
197
|
+
return s[::-1]
|
|
198
|
+
|
|
199
|
+
bridge.register("py_square", py_square)
|
|
200
|
+
bridge.register("py_reverse", py_reverse)
|
|
201
|
+
|
|
202
|
+
# Connect to the JavaScript script
|
|
203
|
+
bridge.connect("node app.js")
|
|
204
|
+
|
|
205
|
+
# Call JavaScript methods
|
|
206
|
+
result = bridge.call("js_capitalize", "hello world")
|
|
207
|
+
print(result) # "HELLO WORLD"
|
|
208
|
+
|
|
209
|
+
# JavaScript can call py_square() or py_reverse() one request at a time
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
**JavaScript side:**
|
|
213
|
+
```javascript
|
|
214
|
+
import Crosspulse from "crosspulse/src/crosspulse.js";
|
|
215
|
+
|
|
216
|
+
// Create a bridge in "listen" mode
|
|
217
|
+
const bridge = new Crosspulse("listen");
|
|
218
|
+
|
|
219
|
+
// Register JavaScript methods that Python can call
|
|
220
|
+
bridge.register("js_capitalize", (str) => str.toUpperCase());
|
|
221
|
+
bridge.register("js_length", (str) => str.length);
|
|
222
|
+
|
|
223
|
+
// Start listening for incoming calls from Python
|
|
224
|
+
bridge.listen();
|
|
225
|
+
|
|
226
|
+
// Python can call these methods one request at a time
|
|
227
|
+
// Incoming calls are automatically handled
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
---
|
|
231
|
+
|
|
232
|
+
## π API Reference
|
|
233
|
+
|
|
234
|
+
### Python
|
|
235
|
+
|
|
236
|
+
```python
|
|
237
|
+
from crosspulse import Crosspulse
|
|
238
|
+
|
|
239
|
+
# Create instance
|
|
240
|
+
bridge = Crosspulse(mode="listen") # Listen mode
|
|
241
|
+
bridge = Crosspulse(mode="connect") # Connect mode
|
|
242
|
+
|
|
243
|
+
# Register method
|
|
244
|
+
bridge.register("method_name", callback_function)
|
|
245
|
+
|
|
246
|
+
# Listen for calls (listen mode)
|
|
247
|
+
bridge.listen()
|
|
248
|
+
|
|
249
|
+
# Connect to target (connect mode)
|
|
250
|
+
bridge.connect("node target_script.js")
|
|
251
|
+
|
|
252
|
+
# Call remote method
|
|
253
|
+
result = bridge.call("method_name", arg1, arg2)
|
|
254
|
+
|
|
255
|
+
# Disconnect
|
|
256
|
+
bridge.disconnect()
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
### JavaScript
|
|
260
|
+
|
|
261
|
+
```javascript
|
|
262
|
+
import Crosspulse from "crosspulse/src/crosspulse.js";
|
|
263
|
+
|
|
264
|
+
// Create instance
|
|
265
|
+
const bridge = new Crosspulse("listen"); // Listen mode
|
|
266
|
+
const bridge = new Crosspulse("connect"); // Connect mode
|
|
267
|
+
|
|
268
|
+
// Register method
|
|
269
|
+
bridge.register("method_name", (arg1, arg2) => {
|
|
270
|
+
return result;
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
// Listen for calls (listen mode)
|
|
274
|
+
bridge.listen();
|
|
275
|
+
|
|
276
|
+
// Connect to target (connect mode)
|
|
277
|
+
await bridge.connect("python target_script.py");
|
|
278
|
+
|
|
279
|
+
// Call remote method
|
|
280
|
+
const result = await bridge.call("method_name", arg1, arg2);
|
|
281
|
+
|
|
282
|
+
// Disconnect
|
|
283
|
+
bridge.disconnect();
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
---
|
|
287
|
+
|
|
288
|
+
## π― Real-World Examples
|
|
289
|
+
|
|
290
|
+
### Example 1: Data Processing Pipeline
|
|
291
|
+
|
|
292
|
+
```python
|
|
293
|
+
# data_processor.py
|
|
294
|
+
import pandas as pd
|
|
295
|
+
from crosspulse import Crosspulse
|
|
296
|
+
|
|
297
|
+
bridge = Crosspulse("connect")
|
|
298
|
+
bridge.connect("node visualizer.js")
|
|
299
|
+
|
|
300
|
+
# Process data in Python
|
|
301
|
+
df = pd.read_csv("sales_data.csv")
|
|
302
|
+
insights = analyze_sales(df)
|
|
303
|
+
|
|
304
|
+
# Visualize in JavaScript
|
|
305
|
+
chart = bridge.call("create_chart", insights.to_dict())
|
|
306
|
+
print(f"Chart created: {chart}")
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
```javascript
|
|
310
|
+
// visualizer.js
|
|
311
|
+
import Crosspulse from "crosspulse/src/crosspulse.js";
|
|
312
|
+
|
|
313
|
+
const bridge = new Crosspulse("listen");
|
|
314
|
+
|
|
315
|
+
bridge.register("create_chart", (data) => {
|
|
316
|
+
// Use Chart.js, D3.js, or any JS library
|
|
317
|
+
const chart = generateChart(data);
|
|
318
|
+
return chart.id;
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
bridge.listen();
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
### Example 2: Machine Learning UI
|
|
325
|
+
|
|
326
|
+
```javascript
|
|
327
|
+
// ml_interface.js
|
|
328
|
+
import Crosspulse from "crosspulse/src/crosspulse.js";
|
|
329
|
+
|
|
330
|
+
const bridge = new Crosspulse("connect");
|
|
331
|
+
|
|
332
|
+
async function trainModel(dataset) {
|
|
333
|
+
await bridge.connect("python ml_model.py");
|
|
334
|
+
|
|
335
|
+
const progress = await bridge.call("train", dataset);
|
|
336
|
+
console.log("Training progress:", progress);
|
|
337
|
+
|
|
338
|
+
const predictions = await bridge.call("predict", testData);
|
|
339
|
+
displayResults(predictions);
|
|
340
|
+
}
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
```python
|
|
344
|
+
# ml_model.py
|
|
345
|
+
from sklearn.ensemble import RandomForestClassifier
|
|
346
|
+
from crosspulse import Crosspulse
|
|
347
|
+
|
|
348
|
+
bridge = Crosspulse("listen")
|
|
349
|
+
|
|
350
|
+
model = RandomForestClassifier()
|
|
351
|
+
|
|
352
|
+
def train_model(data):
|
|
353
|
+
X, y = prepare_data(data)
|
|
354
|
+
model.fit(X, y)
|
|
355
|
+
return {"status": "trained", "accuracy": model.score(X, y)}
|
|
356
|
+
|
|
357
|
+
bridge.register("train", train_model)
|
|
358
|
+
bridge.listen()
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
### Example 3: Web Scraping + Frontend
|
|
362
|
+
|
|
363
|
+
```python
|
|
364
|
+
# scraper.py
|
|
365
|
+
from crosspulse import Crosspulse
|
|
366
|
+
import requests
|
|
367
|
+
from bs4 import BeautifulSoup
|
|
368
|
+
|
|
369
|
+
bridge = Crosspulse("connect")
|
|
370
|
+
|
|
371
|
+
def scrape_news():
|
|
372
|
+
# Scrape with Python
|
|
373
|
+
data = scrape_website()
|
|
374
|
+
|
|
375
|
+
# Send to JavaScript for display
|
|
376
|
+
bridge.call("update_ui", data)
|
|
377
|
+
|
|
378
|
+
bridge.connect("node server.js")
|
|
379
|
+
scrape_news()
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
### Example 4: Desktop App (Electron + Python)
|
|
383
|
+
|
|
384
|
+
```javascript
|
|
385
|
+
// electron_main.js
|
|
386
|
+
import Crosspulse from "crosspulse/src/crosspulse.js";
|
|
387
|
+
|
|
388
|
+
const bridge = new Crosspulse("connect");
|
|
389
|
+
|
|
390
|
+
ipcMain.on("process-image", async (event, imagePath) => {
|
|
391
|
+
await bridge.connect("python image_processor.py");
|
|
392
|
+
|
|
393
|
+
const processed = await bridge.call("enhance_image", imagePath);
|
|
394
|
+
event.reply("image-ready", processed);
|
|
395
|
+
});
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
---
|
|
399
|
+
|
|
400
|
+
## π§ Advanced Usage
|
|
401
|
+
|
|
402
|
+
### Error Handling
|
|
403
|
+
|
|
404
|
+
```javascript
|
|
405
|
+
try {
|
|
406
|
+
const result = await bridge.call("risky_operation", data);
|
|
407
|
+
console.log("Success:", result);
|
|
408
|
+
} catch (error) {
|
|
409
|
+
console.error("Python error:", error.message);
|
|
410
|
+
}
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
```python
|
|
414
|
+
try:
|
|
415
|
+
result = bridge.call("risky_operation", data)
|
|
416
|
+
print(f"Success: {result}")
|
|
417
|
+
except Exception as e:
|
|
418
|
+
print(f"JavaScript error: {e}")
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
### Multiple Arguments & Complex Data
|
|
422
|
+
|
|
423
|
+
```javascript
|
|
424
|
+
// JavaScript
|
|
425
|
+
const result = await bridge.call("process_user", {
|
|
426
|
+
name: "John",
|
|
427
|
+
age: 30,
|
|
428
|
+
tags: ["developer", "python", "javascript"]
|
|
429
|
+
});
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
```python
|
|
433
|
+
# Python
|
|
434
|
+
def process_user(user_data):
|
|
435
|
+
return {
|
|
436
|
+
"id": generate_id(),
|
|
437
|
+
"name": user_data["name"],
|
|
438
|
+
"processed": True
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
bridge.register("process_user", process_user)
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
### Async Operations
|
|
445
|
+
|
|
446
|
+
```python
|
|
447
|
+
# Python
|
|
448
|
+
import time
|
|
449
|
+
|
|
450
|
+
def long_running_task(duration):
|
|
451
|
+
time.sleep(duration)
|
|
452
|
+
return "Task completed"
|
|
453
|
+
|
|
454
|
+
bridge.register("long_task", long_running_task)
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
```javascript
|
|
458
|
+
// JavaScript
|
|
459
|
+
const result = await bridge.call("long_task", 5);
|
|
460
|
+
console.log(result); // "Task completed" (after 5 seconds)
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
---
|
|
464
|
+
|
|
465
|
+
## π¨ Use Cases
|
|
466
|
+
|
|
467
|
+
| Use Case | Python Side | JavaScript Side |
|
|
468
|
+
|----------|-------------|-----------------|
|
|
469
|
+
| **Web Scraping** | BeautifulSoup, Scrapy | Display in React/Vue |
|
|
470
|
+
| **Machine Learning** | TensorFlow, PyTorch | Real-time UI updates |
|
|
471
|
+
| **Data Analysis** | Pandas, NumPy | Chart.js, D3.js |
|
|
472
|
+
| **Image Processing** | OpenCV, Pillow | Canvas, WebGL |
|
|
473
|
+
| **File Processing** | Parse Excel/PDF | Electron file picker |
|
|
474
|
+
| **API Gateway** | Flask/FastAPI alternative | Frontend communication |
|
|
475
|
+
| **Desktop Apps** | Backend logic | Electron UI |
|
|
476
|
+
| **Automation** | Selenium, automation | Control panel |
|
|
477
|
+
|
|
478
|
+
---
|
|
479
|
+
|
|
480
|
+
## β‘ Performance
|
|
481
|
+
|
|
482
|
+
- **Latency**: ~5-10ms per call (local)
|
|
483
|
+
- **Throughput**: 1000+ calls/second
|
|
484
|
+
- **Memory**: Minimal overhead (<5MB)
|
|
485
|
+
- **Scalability**: Single process pair
|
|
486
|
+
|
|
487
|
+
For high-throughput scenarios, consider batching calls or using WebSocket alternatives.
|
|
488
|
+
|
|
489
|
+
---
|
|
490
|
+
|
|
491
|
+
## π‘οΈ Security Notes
|
|
492
|
+
|
|
493
|
+
- Crosspulse uses STDIN/STDOUT for IPC
|
|
494
|
+
- Only use with trusted code
|
|
495
|
+
- Validate all incoming data
|
|
496
|
+
- Don't expose to untrusted networks
|
|
497
|
+
- Consider sandboxing for production
|
|
498
|
+
|
|
499
|
+
---
|
|
500
|
+
|
|
501
|
+
## π Troubleshooting
|
|
502
|
+
|
|
503
|
+
### "Method not found" error
|
|
504
|
+
```python
|
|
505
|
+
# Make sure method is registered before listening
|
|
506
|
+
bridge.register("my_method", my_function)
|
|
507
|
+
bridge.listen() # Must be after register
|
|
508
|
+
```
|
|
509
|
+
|
|
510
|
+
### Connection timeout
|
|
511
|
+
```javascript
|
|
512
|
+
// Ensure Python script is running
|
|
513
|
+
await bridge.connect("python script.py");
|
|
514
|
+
// Python should be in listen mode
|
|
515
|
+
```
|
|
516
|
+
|
|
517
|
+
### JSON serialization errors
|
|
518
|
+
```python
|
|
519
|
+
# Only use JSON-serializable types
|
|
520
|
+
# β
str, int, float, list, dict, bool, None
|
|
521
|
+
# β Custom objects, functions, file handles
|
|
522
|
+
```
|
|
523
|
+
|
|
524
|
+
---
|
|
525
|
+
|
|
526
|
+
## π€ Contributing
|
|
527
|
+
|
|
528
|
+
Contributions are welcome! Here's how:
|
|
529
|
+
|
|
530
|
+
```bash
|
|
531
|
+
git clone https://github.com/AnarDevStudio/crosspulse.git
|
|
532
|
+
cd crosspulse
|
|
533
|
+
```
|
|
534
|
+
|
|
535
|
+
**Areas to contribute:**
|
|
536
|
+
- TypeScript definitions
|
|
537
|
+
- More examples
|
|
538
|
+
- Performance improvements
|
|
539
|
+
- Documentation
|
|
540
|
+
- Bug fixes
|
|
541
|
+
|
|
542
|
+
---
|
|
543
|
+
|
|
544
|
+
## π License
|
|
545
|
+
|
|
546
|
+
MIT License - Use it however you want!
|
|
547
|
+
|
|
548
|
+
```
|
|
549
|
+
MIT License
|
|
550
|
+
|
|
551
|
+
Copyright (c) 2026 AnarEsgerzade
|
|
552
|
+
|
|
553
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
554
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
555
|
+
in the Software without restriction, including without limitation the rights
|
|
556
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
557
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
558
|
+
furnished to do so, subject to the following conditions:
|
|
559
|
+
|
|
560
|
+
The above copyright notice and this permission notice shall be included in all
|
|
561
|
+
copies or substantial portions of the Software.
|
|
562
|
+
|
|
563
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
564
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
565
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
566
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
567
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
568
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
569
|
+
SOFTWARE.
|
|
570
|
+
```
|
|
571
|
+
|
|
572
|
+
---
|
|
573
|
+
|
|
574
|
+
## π Show Your Support
|
|
575
|
+
|
|
576
|
+
If Crosspulse helps your project, give it a βοΈ on GitHub!
|
|
577
|
+
|
|
578
|
+
---
|
|
579
|
+
|
|
580
|
+
## π Support
|
|
581
|
+
|
|
582
|
+
- **Issues**: [GitHub Issues](https://github.com/AnarDevStudio/crosspulse/issues)
|
|
583
|
+
- **Discussions**: [GitHub Discussions](https://github.com/AnarDevStudio/crosspulse/discussions)
|
|
584
|
+
- **Email**: anardevstudio@gmail.com
|
|
585
|
+
|
|
586
|
+
---
|
|
587
|
+
|
|
588
|
+
**Built with β€οΈ by developers who believe languages should work together, not apart.**
|
|
589
|
+
|
|
590
|
+
**Crosspulse** - Where Python meets JavaScript. π
|
|
591
|
+
|
|
592
|
+
**Made by AnarEsgerzadeπ·**
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
crosspulse
|