-
Notifications
You must be signed in to change notification settings - Fork 65
feat: add support for VNC using x11vnc and novnc #15
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
Changes from 38 commits
c8f0fd7
c17d815
e7c84c2
0e08053
33f8d5f
ff920e7
07b8945
93ed2f2
4efffa6
47505a8
5c299f9
3524787
30a75a5
c53fdec
4dcae11
dfba7f8
0fb4544
280609c
5bdf00a
d9db262
483b807
eea1159
070c494
7acd091
869399a
21c63dd
d533660
e4ac029
89c5795
64f77bf
95d9072
37e97c3
0de885a
b5bb082
34c9ccb
c5691f3
4103ecc
0288e85
6f45deb
a2b6e06
4ce4632
787a4ab
3e48c2f
71a06d8
684cde8
db172e5
7a84ba9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,78 +7,115 @@ Each sandbox is isolated from the others and can be customized with any dependen | |
 | ||
|
||
### Example app using Computer Use with Anthropic's Claude | ||
Check out the [example open-source app](https://github.com/e2b-dev/secure-computer-use) in a separate repository. | ||
|
||
Check out the [example open-source app](https://github.com/e2b-dev/secure-computer-use) in a separate repository. | ||
|
||
## 🚀 Getting started | ||
|
||
The E2B Desktop Sandbox is built on top of [E2B Sandbox](https://e2b.dev/docs). | ||
|
||
### 1. Get E2B API key | ||
|
||
Sign up at [E2B](https://e2b.dev) and get your API key. | ||
Set environment variable `E2B_API_KEY` with your API key. | ||
|
||
### 2. Install SDK | ||
|
||
**Python** | ||
|
||
```bash | ||
pip install e2b-desktop | ||
``` | ||
|
||
**JavaScript** | ||
|
||
```bash | ||
npm install @e2b/desktop | ||
``` | ||
|
||
### 3. Create Desktop Sandbox | ||
|
||
**Python** | ||
|
||
```python | ||
from e2b_desktop import Sandbox | ||
|
||
# Basic initialization | ||
desktop = Sandbox() | ||
|
||
# With custom configuration | ||
desktop = Sandbox( | ||
display=":0", # Custom display (defaults to :0) | ||
resolution=(1920, 1080), # Custom resolution | ||
dpi=96, # Custom DPI | ||
) | ||
``` | ||
|
||
**JavaScript** | ||
|
||
```javascript | ||
import { Sandbox } from '@e2b/desktop' | ||
import { Sandbox } from "@e2b/desktop"; | ||
|
||
const desktop = await Sandbox.create() | ||
``` | ||
// Basic initialization | ||
const desktop = await Sandbox.create(); | ||
|
||
## Stream virtual desktop screen | ||
You can enable streaming the desktop screen by passing `videoStream: true` to the `Sandbox.create` function in JavaScript and `video_stream=True` to the `Sandbox` constructor in Python. | ||
// With custom configuration | ||
const desktop = await Sandbox.create({ | ||
display: ":0", // Custom display (defaults to :0) | ||
resolution: [1920, 1080], // Custom resolution | ||
dpi: 96, // Custom DPI | ||
}); | ||
``` | ||
|
||
Then call `getVideoStreamUrl` in JS and `get_video_stream_url` method in Python to get the stream URL that will look like this: `https://e2b.dev/stream/sandbox/<sandbox-id>?token=<secret-token>` and open it in your browser. | ||
## Features | ||
|
||
You'll need to wait a couple of seconds for the stream to buffer the first frames. | ||
### Streaming Integration | ||
|
||
**Python** | ||
|
||
```python | ||
from e2b_desktop import Sandbox | ||
desktop = Sandbox() | ||
|
||
# Start the stream | ||
desktop.stream.start( | ||
port=6080, # Custom HTTPS port for streaming | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When is setting this useful? The comments should explain when a user would want this There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I removed an example of how to change the port from the readmes. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it's okay to leave out |
||
enable_auth=True # Enable authentication with an auto-generated password | ||
mlejva marked this conversation as resolved.
Show resolved
Hide resolved
|
||
) | ||
|
||
desktop = Sandbox(video_stream=True) | ||
stream_url = desktop.get_video_stream_url() | ||
print(stream_url) | ||
# Open stream_url in your browser | ||
# You'll need to wait a couple of seconds for the stream to buffer the first frames | ||
# Get stream URL | ||
url = desktop.stream.get_url() | ||
print(url) | ||
|
||
# Stop the stream | ||
desktop.stream.stop() | ||
``` | ||
|
||
**JavaScript** | ||
|
||
```javascript | ||
import { Sandbox } from '@e2b/desktop' | ||
import { Sandbox } from "@e2b/desktop"; | ||
|
||
const desktop = await Sandbox.create({ videoStream: true, onVideoStreamStart: (streamUrl) => { | ||
console.log(streamUrl) | ||
}}) | ||
// Open streamUrl in your browser | ||
// You'll need to wait a couple of seconds for the stream to buffer the first frames | ||
``` | ||
const desktop = await Sandbox.create(); | ||
|
||
 | ||
// Start the stream | ||
await desktop.stream.start({ | ||
port: 6080, // Custom HTTPS port for streaming | ||
enableAuth: true, // Enable authentication with an auto-generated password | ||
mlejva marked this conversation as resolved.
Show resolved
Hide resolved
|
||
}); | ||
|
||
## Features | ||
// Get stream URL | ||
const url = desktop.stream.getUrl(); | ||
console.log(url); | ||
|
||
// Stop the stream | ||
await desktop.stream.stop(); | ||
``` | ||
|
||
### Mouse control | ||
|
||
**Python** | ||
|
||
```python | ||
from e2b_desktop import Sandbox | ||
desktop = Sandbox() | ||
|
@@ -92,55 +129,85 @@ desktop.mouse_move(100, 200) # Move to x, y coordinates | |
``` | ||
|
||
**JavaScript** | ||
|
||
```javascript | ||
import { Sandbox } from '@e2b/desktop' | ||
import { Sandbox } from "@e2b/desktop"; | ||
|
||
const desktop = await Sandbox.create() | ||
const desktop = await Sandbox.create(); | ||
|
||
await desktop.doubleClick() | ||
await desktop.leftClick() | ||
await desktop.rightClick() | ||
await desktop.middleClick() | ||
await desktop.scroll(10) // Scroll by the amount. Positive for up, negative for down. | ||
await desktop.moveMouse(100, 200) // Move to x, y coordinates | ||
await desktop.doubleClick(); | ||
await desktop.leftClick(); | ||
await desktop.rightClick(); | ||
await desktop.middleClick(); | ||
await desktop.scroll(10); // Scroll by the amount. Positive for up, negative for down. | ||
await desktop.moveMouse(100, 200); // Move to x, y coordinates | ||
``` | ||
|
||
### Keyboard control | ||
|
||
**Python** | ||
|
||
```python | ||
from e2b_desktop import Sandbox | ||
desktop = Sandbox() | ||
|
||
desktop.write("Hello, world!") # Write text at the current cursor position | ||
desktop.hotkey("ctrl", "c") # Press ctrl+c | ||
# Write text at the current cursor position with customizable typing speed | ||
desktop.write("Hello, world!") # Default: chunk_size=25, delay_in_ms=75 | ||
desktop.write("Fast typing!", chunk_size=50, delay_in_ms=25) # Faster typing | ||
|
||
# Press keys | ||
desktop.press("enter") | ||
desktop.press("space") | ||
desktop.press("backspace") | ||
desktop.press("ctrl+c") | ||
``` | ||
|
||
**JavaScript** | ||
|
||
```javascript | ||
import { Sandbox } from "@e2b/desktop"; | ||
|
||
const desktop = await Sandbox.create(); | ||
|
||
// Write text at the current cursor position with customizable typing speed | ||
await desktop.write("Hello, world!"); // Default: chunkSize=25, delayInMs=75 | ||
await desktop.write("Fast typing!", 50, 25); // Faster typing | ||
|
||
// Press keys | ||
await desktop.press("enter"); | ||
await desktop.press("space"); | ||
await desktop.press("backspace"); | ||
await desktop.press("ctrl+c"); // Copy | ||
``` | ||
|
||
### Screenshot | ||
|
||
```python | ||
from e2b_desktop import Sandbox | ||
desktop = Sandbox() | ||
|
||
# Take a screenshot and save it as "screenshot.png" locally | ||
image = desktop.take_screenshot() | ||
image = desktop.screenshot() | ||
# Save the image to a file | ||
with open("screenshot.png", "wb") as f: | ||
f.write(image) | ||
``` | ||
|
||
**JavaScript** | ||
|
||
```javascript | ||
import { Sandbox } from '@e2b/desktop' | ||
import { Sandbox } from "@e2b/desktop"; | ||
|
||
const desktop = await Sandbox.create() | ||
const image = await desktop.takeScreenshot() | ||
const desktop = await Sandbox.create(); | ||
const image = await desktop.screenshot(); | ||
// Save the image to a file | ||
fs.writeFileSync("screenshot.png", image) | ||
fs.writeFileSync("screenshot.png", image); | ||
``` | ||
|
||
### Open file | ||
|
||
**Python** | ||
|
||
```python | ||
from e2b_desktop import Sandbox | ||
desktop = Sandbox() | ||
|
@@ -151,18 +218,21 @@ desktop.open("/home/user/index.js") # Then open it | |
``` | ||
|
||
**JavaScript** | ||
|
||
```javascript | ||
import { Sandbox } from '@e2b/desktop' | ||
import { Sandbox } from "@e2b/desktop"; | ||
|
||
const desktop = await Sandbox.create() | ||
const desktop = await Sandbox.create(); | ||
|
||
// Open file with default application | ||
await desktop.files.write("/home/user/index.js", "console.log('hello')") // First create the file | ||
await desktop.open("/home/user/index.js") // Then open it | ||
await desktop.files.write("/home/user/index.js", "console.log('hello')"); // First create the file | ||
await desktop.open("/home/user/index.js"); // Then open it | ||
``` | ||
|
||
### Run any bash commands | ||
|
||
**Python** | ||
|
||
```python | ||
from e2b_desktop import Sandbox | ||
desktop = Sandbox() | ||
|
@@ -173,45 +243,18 @@ print(out) | |
``` | ||
|
||
**JavaScript** | ||
```javascript | ||
import { Sandbox } from '@e2b/desktop' | ||
|
||
const desktop = await Sandbox.create() | ||
|
||
// Run any bash command | ||
const out = await desktop.commands.run("ls -la /home/user") | ||
console.log(out) | ||
``` | ||
|
||
### Run PyAutoGUI commands | ||
**Python** | ||
```python | ||
from e2b_desktop import Sandbox | ||
desktop = Sandbox() | ||
|
||
# Run any PyAutoGUI command | ||
desktop.pyautogui("pyautogui.click()") | ||
``` | ||
|
||
**JavaScript** | ||
```javascript | ||
import { Sandbox } from '@e2b/desktop' | ||
import { Sandbox } from "@e2b/desktop"; | ||
|
||
const desktop = await Sandbox.create() | ||
const desktop = await Sandbox.create(); | ||
|
||
// Run any PyAutoGUI command | ||
await desktop.runPyautoguiCode("pyautogui.click()") | ||
// Run any bash command | ||
const out = await desktop.commands.run("ls -la /home/user"); | ||
console.log(out); | ||
``` | ||
|
||
<!-- ### Customization | ||
```python | ||
from e2b_desktop import Sandbox | ||
desktop = Sandbox() | ||
``` --> | ||
|
||
## Under the hood | ||
You can use [PyAutoGUI](https://pyautogui.readthedocs.io/en/latest/) to control the whole environment programmatically. | ||
|
||
The desktop-like environment is based on Linux and [Xfce](https://www.xfce.org/) at the moment. We chose Xfce because it's a fast and lightweight environment that's also popular and actively supported. However, this Sandbox template is fully customizable and you can create your own desktop environment. | ||
Check out the sandbox template's code [here](./template/). | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
are the examples up-to-date?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. Usage: #15 (comment)