Skip to content

Commit

Permalink
Merge pull request #1040 from neet/dispose-streaming-client
Browse files Browse the repository at this point in the history
feat: Implement Disposable for mastodon.streaming.Client
  • Loading branch information
neet committed Feb 22, 2024
2 parents 7a04c56 + d926649 commit 1744996
Show file tree
Hide file tree
Showing 9 changed files with 48 additions and 11 deletions.
5 changes: 3 additions & 2 deletions examples/timeline-with-streaming.ts
@@ -1,14 +1,15 @@
import { createStreamingAPIClient } from "masto";

const subscribe = async (): Promise<void> => {
const masto = createStreamingAPIClient({
using masto = createStreamingAPIClient({
streamingApiUrl: "<STREAMING API URL>",
accessToken: "<TOKEN>",
});

using events = masto.hashtag.subscribe({ tag: "mastojs" });
console.log("subscribed to #mastojs");

for await (const event of masto.hashtag.subscribe({ tag: "mastojs" })) {
for await (const event of events) {
switch (event.event) {
case "update": {
console.log("new post", event.payload.content);
Expand Down
1 change: 1 addition & 0 deletions jest.config.js
Expand Up @@ -6,6 +6,7 @@ export default {
testEnvironment: "node",
testMatch: ["<rootDir>/src/**/*.spec.ts"],
transform: { "^.+\\.tsx?$": "ts-jest" },
setupFilesAfterEnv: ["<rootDir>/test-utils/jest-setup-after-env-unit.ts"],
},
{
displayName: "e2e",
Expand Down
16 changes: 15 additions & 1 deletion src/adapters/action/dispatcher-ws.spec.ts
Expand Up @@ -22,6 +22,20 @@ describe("DispatcherWs", () => {
data: undefined,
meta: {},
});
}).toThrowError(MastoUnexpectedError);
}).toThrow(MastoUnexpectedError);
});

it("can be disposed", () => {
const connector = new WebSocketConnectorImpl({
constructorParameters: ["wss://example.com"],
});
const dispatcher = new WebSocketActionDispatcher(
connector,
new SerializerNativeImpl(),
createLogger("error"),
);

dispatcher[Symbol.dispose]();
expect(connector.canAcquire()).toBe(false);
});
});
4 changes: 4 additions & 0 deletions src/adapters/action/dispatcher-ws.ts
Expand Up @@ -45,4 +45,8 @@ export class WebSocketActionDispatcher
{ ...data },
) as T;
}

[Symbol.dispose](): void {
this.connector.close();
}
}
14 changes: 14 additions & 0 deletions src/adapters/action/proxy.spec.ts
Expand Up @@ -102,4 +102,18 @@ describe("RequestBuilder", () => {
expect(() => api()).toThrow(TypeError);
expect(() => api.close()).not.toThrow(TypeError);
});

it("can be disposed", () => {
const dispatcher = {
dispatch: async <T>(_: AnyAction) => {
return {} as T;
},
[Symbol.dispose]: jest.fn(),
};
const api: any = createActionProxy(dispatcher, { context: ["root"] });

api[Symbol.dispose]();

expect(dispatcher[Symbol.dispose]).toHaveBeenCalled();
});
});
3 changes: 3 additions & 0 deletions src/adapters/action/proxy.ts
Expand Up @@ -60,6 +60,9 @@ const get =
if (typeof property === "string" && SPECIAL_PROPERTIES.has(property)) {
return;
}
if (property === Symbol.dispose) {
return actionDispatcher[Symbol.dispose];
}
if (typeof property === "symbol") {
return;
}
Expand Down
1 change: 1 addition & 0 deletions src/interfaces/action.ts
Expand Up @@ -12,6 +12,7 @@ export type AnyAction = Action<string>;

export interface ActionDispatcher<T extends AnyAction> {
dispatch<U>(action: T): U | Promise<U>;
[Symbol.dispose]?(): void;
}

export interface ActionDispatcherHook<T extends AnyAction, U = unknown> {
Expand Down
11 changes: 3 additions & 8 deletions src/mastodon/streaming/client.ts
Expand Up @@ -8,18 +8,13 @@ export interface SubscribeHashtagParams {
readonly tag: string;
}

export interface Subscription {
unsubscribe(): void;
export interface Subscription extends AsyncIterable<Event>, Disposable {
values(): AsyncIterableIterator<Event>;
[Symbol.asyncIterator](): AsyncIterator<Event, undefined>;

/**
* @experimental This is an experimental API.
*/
[Symbol.dispose](): void;
unsubscribe(): void;
}

export interface Client {
export interface Client extends Disposable {
public: {
subscribe(): Subscription;
media: {
Expand Down
4 changes: 4 additions & 0 deletions test-utils/jest-setup-after-env-unit.ts
@@ -0,0 +1,4 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
(Symbol as any).dispose ??= Symbol("Symbol.dispose");
(Symbol as any).asyncDispose ??= Symbol("Symbol.asyncDispose");
/* eslint-enable @typescript-eslint/no-explicit-any */

0 comments on commit 1744996

Please sign in to comment.