Skip to content

Commit d926649

Browse files
committed
feat: Implement Disposable for mastodon.streaming.Client
1 parent 7a04c56 commit d926649

9 files changed

Lines changed: 48 additions & 11 deletions

File tree

examples/timeline-with-streaming.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
import { createStreamingAPIClient } from "masto";
22

33
const subscribe = async (): Promise<void> => {
4-
const masto = createStreamingAPIClient({
4+
using masto = createStreamingAPIClient({
55
streamingApiUrl: "<STREAMING API URL>",
66
accessToken: "<TOKEN>",
77
});
88

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

11-
for await (const event of masto.hashtag.subscribe({ tag: "mastojs" })) {
12+
for await (const event of events) {
1213
switch (event.event) {
1314
case "update": {
1415
console.log("new post", event.payload.content);

jest.config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ export default {
66
testEnvironment: "node",
77
testMatch: ["<rootDir>/src/**/*.spec.ts"],
88
transform: { "^.+\\.tsx?$": "ts-jest" },
9+
setupFilesAfterEnv: ["<rootDir>/test-utils/jest-setup-after-env-unit.ts"],
910
},
1011
{
1112
displayName: "e2e",

src/adapters/action/dispatcher-ws.spec.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,20 @@ describe("DispatcherWs", () => {
2222
data: undefined,
2323
meta: {},
2424
});
25-
}).toThrowError(MastoUnexpectedError);
25+
}).toThrow(MastoUnexpectedError);
26+
});
27+
28+
it("can be disposed", () => {
29+
const connector = new WebSocketConnectorImpl({
30+
constructorParameters: ["wss://example.com"],
31+
});
32+
const dispatcher = new WebSocketActionDispatcher(
33+
connector,
34+
new SerializerNativeImpl(),
35+
createLogger("error"),
36+
);
37+
38+
dispatcher[Symbol.dispose]();
39+
expect(connector.canAcquire()).toBe(false);
2640
});
2741
});

src/adapters/action/dispatcher-ws.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,4 +45,8 @@ export class WebSocketActionDispatcher
4545
{ ...data },
4646
) as T;
4747
}
48+
49+
[Symbol.dispose](): void {
50+
this.connector.close();
51+
}
4852
}

src/adapters/action/proxy.spec.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,4 +102,18 @@ describe("RequestBuilder", () => {
102102
expect(() => api()).toThrow(TypeError);
103103
expect(() => api.close()).not.toThrow(TypeError);
104104
});
105+
106+
it("can be disposed", () => {
107+
const dispatcher = {
108+
dispatch: async <T>(_: AnyAction) => {
109+
return {} as T;
110+
},
111+
[Symbol.dispose]: jest.fn(),
112+
};
113+
const api: any = createActionProxy(dispatcher, { context: ["root"] });
114+
115+
api[Symbol.dispose]();
116+
117+
expect(dispatcher[Symbol.dispose]).toHaveBeenCalled();
118+
});
105119
});

src/adapters/action/proxy.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@ const get =
6060
if (typeof property === "string" && SPECIAL_PROPERTIES.has(property)) {
6161
return;
6262
}
63+
if (property === Symbol.dispose) {
64+
return actionDispatcher[Symbol.dispose];
65+
}
6366
if (typeof property === "symbol") {
6467
return;
6568
}

src/interfaces/action.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ export type AnyAction = Action<string>;
1212

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

1718
export interface ActionDispatcherHook<T extends AnyAction, U = unknown> {

src/mastodon/streaming/client.ts

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,13 @@ export interface SubscribeHashtagParams {
88
readonly tag: string;
99
}
1010

11-
export interface Subscription {
12-
unsubscribe(): void;
11+
export interface Subscription extends AsyncIterable<Event>, Disposable {
1312
values(): AsyncIterableIterator<Event>;
14-
[Symbol.asyncIterator](): AsyncIterator<Event, undefined>;
1513

16-
/**
17-
* @experimental This is an experimental API.
18-
*/
19-
[Symbol.dispose](): void;
14+
unsubscribe(): void;
2015
}
2116

22-
export interface Client {
17+
export interface Client extends Disposable {
2318
public: {
2419
subscribe(): Subscription;
2520
media: {
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
/* eslint-disable @typescript-eslint/no-explicit-any */
2+
(Symbol as any).dispose ??= Symbol("Symbol.dispose");
3+
(Symbol as any).asyncDispose ??= Symbol("Symbol.asyncDispose");
4+
/* eslint-enable @typescript-eslint/no-explicit-any */

0 commit comments

Comments
 (0)