Skip to content

Commit

Permalink
feat(server): add FastAPI example and custom paths
Browse files Browse the repository at this point in the history
- FastAPI example in docs and in examples/ directory
- Add support for custom socket.io paths
  • Loading branch information
floryst committed Aug 30, 2023
1 parent fdc6034 commit f82a381
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 23 deletions.
53 changes: 31 additions & 22 deletions documentation/content/doc/server.md
Original file line number Diff line number Diff line change
Expand Up @@ -286,43 +286,52 @@ These are exposed as keyword arguments to `VolViewApi(app, server_kwargs={}, asg

##### FastAPI middleware example

Install `FastAPI` and `uvicorn`, and then create a `server.py` file with the following contents:
FastAPI is an ASGI-compatible web framework. This guide will go through the
FastAPI example found in `examples/example_fastapi.py`.

```python
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
First install `FastAPI` and `uvicorn[standard]`.

from volview_server import VolViewMiddleware
from custom.user_api import Api
```
python -m pip install FastAPI 'uvicorn[standard]'
```

app = FastAPI()
To start the FastAPI server, use `uvicorn` as follows.

app.add_middleware(VolViewMiddleware, ApiClass=Api)
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
)
```
uvicorn examples.example_fastapi:app
```

Edit the VolView `.env` file to point to the FastAPI server:

@app.get("/")
def index():
return {"hello": "world"}
```
VITE_REMOTE_SERVER_URL=http://localhost:8000/
```

To start the FastAPI server:
Rebuild the VolView viewer app and navigate to the "Remote Functions" tab to
verify that the server works.

```
uvicorn server:app
###### Changing the socket.io path

If the default `https://your-host/socket.io/` path conflicts with an existing
route, VolView can be configured to use a different path. In this guide, we will
rename the default `/socket.io/` path to `/my-custom-path/`.

On the server-side, the VolView middleware must be configured with the new path,
as shown.

```python
app.add_middlware(volview, asgi_kwargs={"socketio_path": "/my-custom-path"})
```

Edit the VolView `.env` file to point to the FastAPI server:
Then, the VolView client server URL must be updated to match. The following sets
the server URL in the `.env` file.

```
VITE_REMOTE_SERVER_URL=http://localhost:8000/
VITE_REMOTE_SERVER_URL=http://localhost:8000/my-custom-path
```

Rebuild the VolView viewer app and navigate to the "Remote Functions" tab to see
that the server works.
Restart both the server and the client to verify that a successful connection is
achieved.

#### Python-socketio supported deployment strategies

Expand Down
28 changes: 28 additions & 0 deletions server/examples/example_fastapi.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import sys
import os

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

from volview_server import VolViewApi

# Import the VolView example API
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
from example_api import volview


app = FastAPI()

# Adds volview middlware
app.add_middleware(volview)

# Set CORS configuration
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
)


@app.get("/")
def index():
return {"hello": "world"}
18 changes: 17 additions & 1 deletion src/core/remote/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { nanoid } from 'nanoid';
import { Socket, io } from 'socket.io-client';
import { z } from 'zod';
import * as ChunkedParser from '@/src/core/remote/chunkedParser';
import { URL } from 'whatwg-url';

const CLIENT_ID_SIZE = 24;
const RPC_ID_SIZE = 24;
Expand Down Expand Up @@ -104,6 +105,20 @@ export interface RpcApi {
export interface RpcClientOptions {
serializers?: Array<(input: any) => any>;
deserializers?: Array<(input: any) => any>;
path?: string;
}

function justHostUrl(url: string) {
const parts = new URL(url);
parts.pathname = '';
return String(parts);
}

function getSocketIoPath(url: string) {
const parts = new URL(url);
return parts.pathname.replace(/^\/+$/, '').length === 0
? '/socket.io/'
: parts.pathname;
}

/**
Expand Down Expand Up @@ -156,7 +171,8 @@ export default class RpcClient {
async connect(uri: string) {
await this.disconnect();
// @ts-ignore reset socket.io URI
this.socket.io.uri = uri;
this.socket.io.uri = justHostUrl(uri);
this.socket.io.opts.path = getSocketIoPath(uri);

let promise = this.waiting.get('connect');
if (!promise) {
Expand Down

0 comments on commit f82a381

Please sign in to comment.