Skip to content

Commit

Permalink
Add get remote service function (#657)
Browse files Browse the repository at this point in the history
* Add get remote service function

* Fix auto create workspace

* Fix conftest
  • Loading branch information
oeway authored Aug 18, 2024
1 parent 5dfb639 commit 40a76f7
Show file tree
Hide file tree
Showing 11 changed files with 60 additions and 36 deletions.
53 changes: 40 additions & 13 deletions docs/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ async def start_server(server_url):
print("Hello " + name)
return "Hello " + name

await server.register_service({
svc = await server.register_service({
"name": "Hello World",
"id": "hello-world",
"config": {
Expand All @@ -94,8 +94,11 @@ async def start_server(server_url):
"hello": hello
})

print(f"Hello world service registered at workspace: {server.config.workspace}")
print(f"Test it with the HTTP proxy: {server_url}/{server.config.workspace}/services/hello-world/hello?name=John")
print(f"Hello world service registered at workspace: {server.config.workspace}, id: {svc.id}")

print(f'You can use this service using the service id: {svc.id}')

print(f"You can also test the service via the HTTP proxy: {server_url}/{server.config.workspace}/services/{svc.id}/hello?name=John")

# Keep the server running
await server.serve()
Expand All @@ -117,7 +120,7 @@ def start_server(server_url):
print("Hello " + name)
return "Hello " + name

server.register_service({
svc = server.register_service({
"name": "Hello World",
"id": "hello-world",
"config": {
Expand All @@ -126,8 +129,11 @@ def start_server(server_url):
"hello": hello
})

print(f"Hello world service registered at workspace: {server.config.workspace}")
print(f"Test it with the HTTP proxy: {server_url}/{server.config.workspace}/services/hello-world/hello?name=John")
print(f"Hello world service registered at workspace: {server.config.workspace}, id: {svc.id}")

print(f'You can use this service using the service id: {svc.id}')

print(f"You can also test the service via the HTTP proxy: {server_url}/{server.config.workspace}/services/{svc.id}/hello?name=John")

if __name__ == "__main__":
server_url = "http://localhost:9527"
Expand Down Expand Up @@ -166,8 +172,8 @@ async def main():
server = await connect_to_server({"server_url": "http://localhost:9527"})

# Get an existing service
# Since "hello-world" is registered as a public service, we can access it using only the name "hello-world"
svc = await server.get_service("hello-world")
# NOTE: You need to replace the service id with the actual id you obtained when registering the service
svc = await server.get_service("ws-user-scintillating-lawyer-94336986/YLNzuQvQHVqMAyDzmEpFgF:hello-world")
ret = await svc.hello("John")
print(ret)
if __name__ == "__main__":
Expand All @@ -184,8 +190,8 @@ def main():
server = connect_to_server({"server_url": "http://localhost:9527"})

# Get an existing service
# Since "hello-world" is registered as a public service, we can access it using only the name "hello-world"
svc = server.get_service("hello-world")
# NOTE: You need to replace the service id with the actual id you obtained when registering the service
svc = server.get_service("ws-user-scintillating-lawyer-94336986/YLNzuQvQHVqMAyDzmEpFgF:hello-world")
ret = svc.hello("John")
print(ret)

Expand All @@ -196,25 +202,46 @@ if __name__ == "__main__":

**NOTE: In Python, the recommended way to interact with the server to use asynchronous functions with `asyncio`. However, if you need to use synchronous functions, you can use `from hypha_rpc.sync import login, connect_to_server` instead. The have the exact same arguments as the asynchronous versions. For more information, see [Synchronous Wrapper](/hypha-rpc?id=synchronous-wrapper)**


As a shortcut you can also use `get_remote_service`:
```python

from hypha_rpc import get_remote_service

# NOTE: You need to replace the service id with the actual id you obtained when registering the service
# The url format should be in the format: http://<server_url>/<workspace>/services/<client_id>:<service_id> (client_id is optional)
svc = await get_remote_service("http://localhost:9527/ws-user-scintillating-lawyer-94336986/services/YLNzuQvQHVqMAyDzmEpFgF:hello-world")
```

#### JavaScript Client

Include the following script in your HTML file to load the `hypha-rpc` client:

```html
<script src="https://cdn.jsdelivr.net/npm/[email protected].24/dist/hypha-rpc-websocket.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected].26/dist/hypha-rpc-websocket.min.js"></script>
```

Use the following code in JavaScript to connect to the server and access an existing service:

```javascript
async function main(){
const server = await hyphaWebsocketClient.connectToServer({"server_url": "http://localhost:9527"})
const svc = await server.get_service("hello-world")
// NOTE: You need to replace the service id with the actual id you obtained when registering the service
const svc = await server.get_service("ws-user-scintillating-lawyer-94336986/YLNzuQvQHVqMAyDzmEpFgF:hello-world")
const ret = await svc.hello("John")
console.log(ret)
}
```

As a shortcut you can also use `hyphaWebsocketClient.getRemoteService`:

```javascript
// NOTE: You need to replace the service id with the actual id you obtained when registering the service
const svc = await hyphaWebsocketClient.getRemoteService("http://localhost:9527/ws-user-scintillating-lawyer-94336986/services/YLNzuQvQHVqMAyDzmEpFgF:hello-world")
const ret = await svc.hello("John")
console.log(ret)
```

### Peer-to-Peer Connection via WebRTC

By default all the clients connected to Hypha server communicate via the websocket connection or the HTTP proxy. This is suitable for most use cases which involves lightweight data exchange. However, if you need to transfer large data or perform real-time communication, you can use the WebRTC connection between clients. With hypha-rpc, you can easily create a WebRTC connection between two clients easily. See the [WebRTC support](/hypha-rpc?id=peer-to-peer-connection-via-webrtc) for more details.
Expand Down Expand Up @@ -375,7 +402,7 @@ For more details, see the service request api endpoint [here](https://ai.imjoy.i

Probes are useful for monitoring the status of services. They can be used to check whether a service is running correctly or to retrieve information about the service. Probes are executed by the server and can be used to monitor the health of services.

We create a convinient shortcut to register probes for monitoring services. Here is an example of how to register a probe for a service:
We create a convenient shortcut to register probes for monitoring services. Here is an example of how to register a probe for a service:

```python
from hypha_rpc import connect_to_server
Expand Down
10 changes: 5 additions & 5 deletions docs/migration-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ To connect to the server, instead of installing the `imjoy-rpc` module, you will
pip install -U hypha-rpc # new install
```

We also changed our versioning strategy, we use the same version number for the server and client, so it's easier to match the client and server versions. For example, `hypha-rpc` version `0.20.24` is compatible with Hypha server version `0.20.24`.
We also changed our versioning strategy, we use the same version number for the server and client, so it's easier to match the client and server versions. For example, `hypha-rpc` version `0.20.26` is compatible with Hypha server version `0.20.26`.

#### 2. Change the imports to use `hypha-rpc`

Expand Down Expand Up @@ -128,10 +128,10 @@ loop.run_forever()
To connect to the server, instead of using the `imjoy-rpc` module, you will need to use the `hypha-rpc` module. The `hypha-rpc` module is a standalone module that provides the RPC connection to the Hypha server. You can include it in your HTML using a script tag:

```html
<script src="https://cdn.jsdelivr.net/npm/[email protected].24/dist/hypha-rpc-websocket.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected].26/dist/hypha-rpc-websocket.min.js"></script>
```

We also changed our versioning strategy, we use the same version number for the server and client, so it's easier to match the client and server versions. For example, `hypha-rpc` version `0.20.24` is compatible with Hypha server version `0.20.24`.
We also changed our versioning strategy, we use the same version number for the server and client, so it's easier to match the client and server versions. For example, `hypha-rpc` version `0.20.26` is compatible with Hypha server version `0.20.26`.

#### 2. Change the connection method and use camelCase for service function names

Expand All @@ -149,7 +149,7 @@ Here is a suggested list of search and replace operations to update your code:
Here is an example of how the updated code might look:

```html
<script src="https://cdn.jsdelivr.net/npm/[email protected].24/dist/hypha-rpc-websocket.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected].26/dist/hypha-rpc-websocket.min.js"></script>
<script>
async function main(){
const server = await hyphaWebsocketClient.connectToServer({"server_url": "https://hypha.amun.ai"});
Expand Down Expand Up @@ -197,7 +197,7 @@ We created a tutorial to introduce this new feature: [service type annotation](.
Here is a quick example in JavaScript:

```html
<script src="https://cdn.jsdelivr.net/npm/[email protected].24/dist/hypha-rpc-websocket.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected].26/dist/hypha-rpc-websocket.min.js"></script>

<script>
async function main(){
Expand Down
2 changes: 1 addition & 1 deletion docs/service-type-annotation.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ if __name__ == "__main__":
**JavaScript Client: Service Usage**

```html
<script src="https://cdn.jsdelivr.net/npm/[email protected].24/dist/hypha-rpc-websocket.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected].26/dist/hypha-rpc-websocket.min.js"></script>
<script>
async function main() {
const server = await hyphaWebsocketClient.connectToServer({"server_url": "https://hypha.amun.ai"});
Expand Down
2 changes: 1 addition & 1 deletion helm-chart/hypha-server/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ image:
repository: ghcr.io/amun-ai/hypha
pullPolicy: IfNotPresent
# Overrides the image tag whose default is the chart appVersion.
tag: "0.20.24"
tag: "0.20.26"

imagePullSecrets: []
nameOverride: ""
Expand Down
2 changes: 1 addition & 1 deletion hypha/VERSION
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
"version": "0.20.24"
"version": "0.20.26"
}
2 changes: 1 addition & 1 deletion hypha/core/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ def model_validate(cls, data):

class TokenConfig(BaseModel):
expires_in: Optional[int] = Field(None, description="Expiration time in seconds")
workspace: Optional[str] = Field(None, description="Workspace ID")
workspace: Optional[str] = Field(None, description="Workspace name")
permission: Optional[str] = Field(
"read_write",
description="Permission level",
Expand Down
17 changes: 7 additions & 10 deletions hypha/core/store.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,24 +164,21 @@ async def load_or_create_workspace(self, user_info: UserInfo, workspace: str):
workspace = user_info.get_workspace()

assert workspace != "*", "Dynamic workspace is not allowed for this endpoint"
# Anonymous and Temporary users are not allowed to create persistant workspaces
persistent = (
not user_info.is_anonymous and "temporary-test-user" not in user_info.roles
)

# Ensure calls to store for workspace existence and permissions check
workspace_info = await self.get_workspace_info(workspace, load=True)

# If workspace does not exist, automatically create it
if not workspace_info:
if workspace != user_info.get_workspace():
raise KeyError(
f"User can only connect to a pre-existing workspace or their own workspace: {workspace}"
if not user_info.check_permission(workspace, UserPermission.read):
raise PermissionError(
f"User {user_info.id} does not have permission to access workspace {workspace}"
)
# Simplified logic for workspace creation, ensure this matches the actual store method signatures
workspace_info = await self.register_workspace(
{
"name": workspace,
"description": f"Default user workspace for {user_info.id}",
"persistent": persistent,
"description": f"Auto-created workspace by {user_info.id}",
"persistent": False,
"owners": [user_info.id],
"read_only": user_info.is_anonymous,
}
Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ aioboto3==11.2.0
aiofiles==23.2.1
base58==2.1.1
fastapi==0.106.0
hypha-rpc==0.20.24
hypha-rpc==0.20.26
jinja2==3.1.2
lxml==4.9.3
msgpack==1.0.5
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
REQUIREMENTS = [
"aiofiles",
"fastapi>=0.70.0,<=0.106.0",
"hypha-rpc>=0.20.24",
"hypha-rpc>=0.20.26",
"msgpack>=1.0.2",
"numpy",
"pydantic[email]>=2.6.1",
Expand Down
2 changes: 1 addition & 1 deletion tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ def _generate_token(id, roles):
email=id + "@test.com",
parent=None,
roles=roles,
scope=create_scope(workspaces={id: UserPermission.admin}),
scope=create_scope(workspaces={f"ws-user-{id}": UserPermission.admin}),
expires_at=None,
)
token = generate_presigned_token(root_user_info)
Expand Down
2 changes: 1 addition & 1 deletion tests/test_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ async def run(self, ctx):
# )
with pytest.raises(
Exception,
match=r".*User can only connect to a pre-existing workspace or their own workspace.*",
match=r".*does not have permission to access workspace .*",
):
rpc = await connect_to_server(
{"name": "my app", "workspace": "test", "server_url": WS_SERVER_URL}
Expand Down

0 comments on commit 40a76f7

Please sign in to comment.