Skip to content

Commit

Permalink
Client node fix (#8252)
Browse files Browse the repository at this point in the history
* fix client in node

* run all client tests in ci

* add changeset

* fix types

* add changeset

* format

* types

* add changeset

* format

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>
  • Loading branch information
pngwn and gradio-pr-bot authored May 9, 2024
1 parent 05fe491 commit 22df61a
Show file tree
Hide file tree
Showing 30 changed files with 95 additions and 62 deletions.
18 changes: 18 additions & 0 deletions .changeset/upset-lands-add.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
"@gradio/app": patch
"@gradio/audio": patch
"@gradio/client": patch
"@gradio/dataframe": patch
"@gradio/file": patch
"@gradio/gallery": patch
"@gradio/image": patch
"@gradio/imageeditor": patch
"@gradio/model3d": patch
"@gradio/multimodaltextbox": patch
"@gradio/simpleimage": patch
"@gradio/upload": patch
"@gradio/video": patch
"gradio": patch
---

fix:Client node fix
2 changes: 2 additions & 0 deletions .github/workflows/tests-js.yml
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ jobs:
run: pnpm ts:check
- name: unit tests
run: pnpm test:run
- name: client tests
run: pnpm --filter @gradio/client test
- name: do check
if: always()
uses: "gradio-app/github/actions/commit-status@main"
Expand Down
21 changes: 10 additions & 11 deletions client/js/src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,19 +59,18 @@ export class Client {
return fetch(input, init);
}

stream_factory(url: URL): EventSource | null {
async stream(url: URL): Promise<EventSource> {
if (typeof window === "undefined" || typeof EventSource === "undefined") {
import("eventsource")
.then((EventSourceModule) => {
return new EventSourceModule.default(url.toString());
})
.catch((error) =>
console.error("Failed to load EventSource module:", error)
);
try {
const EventSourceModule = await import("eventsource");
return new EventSourceModule.default(url.toString()) as EventSource;
} catch (error) {
console.error("Failed to load EventSource module:", error);
throw error;
}
} else {
return new EventSource(url.toString());
}
return null;
}

view_api: () => Promise<ApiInfo<JsApiData>>;
Expand Down Expand Up @@ -107,7 +106,7 @@ export class Client {
data?: unknown[],
event_data?: unknown
) => Promise<unknown>;
open_stream: () => void;
open_stream: () => Promise<void>;
private resolve_config: (endpoint: string) => Promise<Config | undefined>;
constructor(app_reference: string, options: ClientOptions = {}) {
this.app_reference = app_reference;
Expand Down Expand Up @@ -144,7 +143,7 @@ export class Client {
const heartbeat_url = new URL(
`${this.config.root}/heartbeat/${this.session_hash}`
);
this.heartbeat_event = this.stream_factory(heartbeat_url); // Just connect to the endpoint without parsing the response. Ref: https://github.com/gradio-app/gradio/pull/7974#discussion_r1557717540
this.heartbeat_event = await this.stream(heartbeat_url); // Just connect to the endpoint without parsing the response. Ref: https://github.com/gradio-app/gradio/pull/7974#discussion_r1557717540

if (this.config.space_id && this.options.hf_token) {
this.jwt = await get_jwt(
Expand Down
20 changes: 11 additions & 9 deletions client/js/src/test/mock_eventsource.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { vi } from "vitest";

Object.defineProperty(window, "EventSource", {
writable: true,
value: vi.fn().mockImplementation(() => ({
close: vi.fn(() => {}),
addEventListener: vi.fn(),
onmessage: vi.fn((_event: MessageEvent) => {}),
onerror: vi.fn((_event: Event) => {})
}))
});
if (process.env.TEST_MODE !== "node") {
Object.defineProperty(window, "EventSource", {
writable: true,
value: vi.fn().mockImplementation(() => ({
close: vi.fn(() => {}),
addEventListener: vi.fn(),
onmessage: vi.fn((_event: MessageEvent) => {}),
onerror: vi.fn((_event: Event) => {})
}))
});
}
34 changes: 23 additions & 11 deletions client/js/src/test/stream.test.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,36 @@
import { vi } from "vitest";
import { vi, type Mock } from "vitest";
import { Client } from "../client";
import { initialise_server } from "./server";

import { describe, it, expect, afterEach } from "vitest";
import {
describe,
it,
expect,
afterEach,
beforeAll,
afterAll,
beforeEach
} from "vitest";
import "./mock_eventsource.ts";
import NodeEventSource from "eventsource";

const server = initialise_server();
const IS_NODE = process.env.TEST_MODE === "node";

beforeAll(() => server.listen());
afterEach(() => server.resetHandlers());
afterAll(() => server.close());

describe("open_stream", () => {
let mock_eventsource: any;
let app: any;
let app: Client;

beforeEach(async () => {
app = await Client.connect("hmb/hello_world");
app.stream_factory = vi.fn().mockImplementation(() => {
mock_eventsource = new EventSource("");
app.stream = vi.fn().mockImplementation(() => {
mock_eventsource = IS_NODE
? new NodeEventSource("")
: new EventSource("");
return mock_eventsource;
});
});
Expand All @@ -30,21 +42,21 @@ describe("open_stream", () => {
it("should throw an error if config is not defined", () => {
app.config = undefined;

expect(() => {
app.open_stream();
}).toThrow("Could not resolve app config");
expect(async () => {
await app.open_stream();
}).rejects.toThrow("Could not resolve app config");
});

it("should connect to the SSE endpoint and handle messages", async () => {
app.open_stream();
await app.open_stream();

const eventsource_mock_call = app.stream_factory.mock.calls[0][0];
const eventsource_mock_call = (app.stream as Mock).mock.calls[0][0];

expect(eventsource_mock_call.href).toMatch(
/https:\/\/hmb-hello-world\.hf\.space\/queue\/data\?session_hash/
);

expect(app.stream_factory).toHaveBeenCalledWith(eventsource_mock_call);
expect(app.stream).toHaveBeenCalledWith(eventsource_mock_call);

const onMessageCallback = mock_eventsource.onmessage;
const onErrorCallback = mock_eventsource.onerror;
Expand Down
4 changes: 2 additions & 2 deletions client/js/src/utils/stream.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { BROKEN_CONNECTION_MSG } from "../constants";
import type { Client } from "../client";

export function open_stream(this: Client): void {
export async function open_stream(this: Client): Promise<void> {
let {
event_callbacks,
unclosed_events,
Expand All @@ -28,7 +28,7 @@ export function open_stream(this: Client): void {
url.searchParams.set("__sign", jwt);
}

stream = this.stream_factory(url);
stream = await this.stream(url);

if (!stream) {
console.warn("Cannot connect to SSE endpoint: " + url.toString());
Expand Down
6 changes: 3 additions & 3 deletions client/js/src/utils/submit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -372,7 +372,7 @@ export function submit(
url.searchParams.set("__sign", this.jwt);
}

stream = this.stream_factory(url);
stream = await this.stream(url);

if (!stream) {
return Promise.reject(
Expand Down Expand Up @@ -503,7 +503,7 @@ export function submit(
headers
);
});
post_data_promise.then(([response, status]: any) => {
post_data_promise.then(async ([response, status]: any) => {
if (status === 503) {
fire_event({
type: "status",
Expand Down Expand Up @@ -655,7 +655,7 @@ export function submit(
event_callbacks[event_id] = callback;
unclosed_events.add(event_id);
if (!stream_status.open) {
this.open_stream();
await this.open_stream();
}
}
});
Expand Down
2 changes: 1 addition & 1 deletion js/app/src/lite/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ export function create(options: Options): GradioAppController {
return wasm_proxied_fetch(worker_proxy, input, init);
}

stream_factory(url: URL): EventSource {
async stream(url: URL): Promise<EventSource> {
return wasm_proxied_stream_factory(worker_proxy, url);
}
}
Expand Down
2 changes: 1 addition & 1 deletion js/audio/Index.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@
{waveform_options}
{trim_region_settings}
upload={gradio.client.upload}
stream_handler={gradio.client.stream_factory}
stream_handler={gradio.client.stream}
>
<UploadText i18n={gradio.i18n} type="audio" />
</InteractiveAudio>
Expand Down
2 changes: 1 addition & 1 deletion js/audio/interactive/InteractiveAudio.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
export let editable = true;
export let max_file_size: number | null = null;
export let upload: Client["upload"];
export let stream_handler: Client["stream_factory"];
export let stream_handler: Client["stream"];
$: dispatch("drag", dragging);
Expand Down
2 changes: 1 addition & 1 deletion js/dataframe/Index.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,6 @@
{line_breaks}
{column_widths}
upload={gradio.client.upload}
stream_handler={gradio.client.stream_factory}
stream_handler={gradio.client.stream}
/>
</Block>
2 changes: 1 addition & 1 deletion js/dataframe/shared/Table.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
export let line_breaks = true;
export let column_widths: string[] = [];
export let upload: Client["upload"];
export let stream_handler: Client["stream_factory"];
export let stream_handler: Client["stream"];
let selected: false | [number, number] = false;
export let display_value: string[][] | null = null;
Expand Down
2 changes: 1 addition & 1 deletion js/file/Index.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@
{:else}
<FileUpload
upload={gradio.client.upload}
stream_handler={gradio.client.stream_factory}
stream_handler={gradio.client.stream}
{label}
{show_label}
{value}
Expand Down
2 changes: 1 addition & 1 deletion js/file/shared/FileUpload.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
export let i18n: I18nFormatter;
export let max_file_size: number | null = null;
export let upload: Client["upload"];
export let stream_handler: Client["stream_factory"];
export let stream_handler: Client["stream"];
async function handle_upload({
detail
Expand Down
2 changes: 1 addition & 1 deletion js/gallery/Index.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@
file_types={["image"]}
i18n={gradio.i18n}
upload={gradio.client.upload}
stream_handler={gradio.client.stream_factory}
stream_handler={gradio.client.stream}
on:upload={(e) => {
const files = Array.isArray(e.detail) ? e.detail : [e.detail];
value = files.map((x) => ({ image: x, caption: null }));
Expand Down
2 changes: 1 addition & 1 deletion js/image/Index.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@
max_file_size={gradio.max_file_size}
i18n={gradio.i18n}
upload={gradio.client.upload}
stream_handler={gradio.client.stream_factory}
stream_handler={gradio.client.stream}
>
{#if active_source === "upload" || !active_source}
<UploadText i18n={gradio.i18n} type="image" />
Expand Down
2 changes: 1 addition & 1 deletion js/image/shared/ImageUploader.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
export let i18n: I18nFormatter;
export let max_file_size: number | null = null;
export let upload: Client["upload"];
export let stream_handler: Client["stream_factory"];
export let stream_handler: Client["stream"];
let upload_input: Upload;
let uploading = false;
Expand Down
2 changes: 1 addition & 1 deletion js/imageeditor/Index.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@
{layers}
status={loading_status?.status}
upload={gradio.client.upload}
stream_handler={gradio.client.stream_factory}
stream_handler={gradio.client.stream}
></InteractiveImageEditor>
</Block>
{/if}
2 changes: 1 addition & 1 deletion js/imageeditor/shared/InteractiveImageEditor.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
export let canvas_size: [number, number] | undefined;
export let realtime: boolean;
export let upload: Client["upload"];
export let stream_handler: Client["stream_factory"];
export let stream_handler: Client["stream"];
const dispatch = createEventDispatcher<{
clear?: never;
Expand Down
2 changes: 1 addition & 1 deletion js/imageeditor/shared/tools/Sources.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
export let mirror_webcam = true;
export let i18n: I18nFormatter;
export let upload: Client["upload"];
export let stream_handler: Client["stream_factory"];
export let stream_handler: Client["stream"];
const { active_tool } = getContext<ToolContext>(TOOL_KEY);
const { pixi, dimensions, register_context, reset, editor_box } =
Expand Down
2 changes: 1 addition & 1 deletion js/model3D/Index.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@
i18n={gradio.i18n}
max_file_size={gradio.max_file_size}
upload={gradio.client.upload}
stream_handler={gradio.client.stream_factory}
stream_handler={gradio.client.stream}
>
<UploadText i18n={gradio.i18n} type="file" />
</Model3DUpload>
Expand Down
2 changes: 1 addition & 1 deletion js/model3D/shared/Model3DUpload.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
null
];
export let upload: Client["upload"];
export let stream_handler: Client["stream_factory"];
export let stream_handler: Client["stream"];
async function handle_upload({
detail
Expand Down
2 changes: 1 addition & 1 deletion js/multimodaltextbox/Index.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,6 @@
}}
disabled={!interactive}
upload={gradio.client.upload}
stream_handler={gradio.client.stream_factory}
stream_handler={gradio.client.stream}
/>
</Block>
2 changes: 1 addition & 1 deletion js/multimodaltextbox/shared/MultimodalTextbox.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
export let file_types: string[] | null = null;
export let max_file_size: number | null = null;
export let upload: Client["upload"];
export let stream_handler: Client["stream_factory"];
export let stream_handler: Client["stream"];
let upload_component: Upload;
let hidden_upload: HTMLInputElement;
Expand Down
2 changes: 1 addition & 1 deletion js/simpleimage/Index.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@

<ImageUploader
upload={gradio.client.upload}
stream_handler={gradio.client.stream_factory}
stream_handler={gradio.client.stream}
bind:value
{root}
on:clear={() => gradio.dispatch("clear")}
Expand Down
2 changes: 1 addition & 1 deletion js/simpleimage/shared/ImageUploader.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
export let show_label: boolean;
export let root: string;
export let upload: Client["upload"];
export let stream_handler: Client["stream_factory"];
export let stream_handler: Client["stream"];
let upload_component: Upload;
let uploading = false;
Expand Down
2 changes: 1 addition & 1 deletion js/upload/src/Upload.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
export let show_progress = true;
export let max_file_size: number | null = null;
export let upload: Client["upload"];
export let stream_handler: Client["stream_factory"];
export let stream_handler: Client["stream"];
let upload_id: string;
let file_data: FileData[];
Expand Down
Loading

0 comments on commit 22df61a

Please sign in to comment.