Skip to content

Commit 9c3daeb

Browse files
committed
allow async plugins
1 parent 18af9ab commit 9c3daeb

File tree

4 files changed

+83
-26
lines changed

4 files changed

+83
-26
lines changed

plugins/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
import * as allPlugins from "./plugins";
22

33
export const plugins = allPlugins;
4-
export {IPlugin, IPluginContext, DType} from "./plugin";
4+
export * from "./plugin";

plugins/plugin.ts

+24-4
Original file line numberDiff line numberDiff line change
@@ -15,18 +15,38 @@ export interface IPlugin<PostType> {
1515
this: IPluginContext<IPlugin<PostType>, PostType>,
1616
req: puppeteer.Request,
1717
overrides: puppeteer.Overrides,
18-
): void;
18+
): Promise<void>;
1919

2020
responseEvent?(
2121
this: IPluginContext<IPlugin<PostType>, PostType>,
2222
res: puppeteer.Response,
2323
data: {[key: string]: any},
24-
): void;
24+
): Promise<void>;
2525

2626
postPageEvent?(
2727
this: IPluginContext<IPlugin<PostType>, PostType>,
2828
data: PostType,
29-
): void;
29+
): Promise<void>;
3030

31-
graftingEvent?(this: IPluginContext<IPlugin<PostType>, PostType>): void;
31+
graftingEvent?(
32+
this: IPluginContext<IPlugin<PostType>, PostType>,
33+
): Promise<void>;
34+
}
35+
36+
export enum AsyncPluginEvents {
37+
browser,
38+
grafting,
39+
postPage,
40+
request,
41+
response,
42+
}
43+
44+
export type AsyncPluginEventsType = keyof typeof AsyncPluginEvents;
45+
46+
export enum SyncPluginEvents {
47+
construction,
3248
}
49+
50+
export type SyncPluginEventsType = keyof typeof SyncPluginEvents;
51+
52+
export type PluginEventsType = SyncPluginEventsType | AsyncPluginEventsType;

plugins/plugins/largeFirst.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ export class LargeFirst<PostType> implements IPlugin<PostType> {
1010
this.state.jumpSize = 150;
1111
}
1212

13-
public requestEvent(req: Request, overrides: Overrides): void {
13+
public async requestEvent(req: Request, overrides: Overrides) {
1414
const url = overrides["url"] ? overrides["url"] : req.url();
1515
const parsedUrl = urlParse(url);
1616
const query = querystring.parse(parsedUrl.query);

src/api/instagram.ts

+57-20
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import AwaitLock from "await-lock";
22
import chalk from "chalk";
3-
import {EventEmitter} from "events";
43
import {isLeft} from "fp-ts/lib/Either";
54
import {Type} from "io-ts";
65
import {PathReporter} from "io-ts/lib/PathReporter";
@@ -16,14 +15,22 @@ import {
1615
Response,
1716
} from "puppeteer";
1817
import * as winston from "winston";
19-
import {IPlugin, IPluginContext} from "../../plugins";
18+
import {
19+
AsyncPluginEvents,
20+
AsyncPluginEventsType,
21+
IPlugin,
22+
IPluginContext,
23+
PluginEventsType,
24+
SyncPluginEvents,
25+
SyncPluginEventsType,
26+
} from "../../plugins";
2027
import {IOptions} from "./api";
2128
import {PostIdSet} from "./postIdSet";
2229

2330
/**
2431
* Instagram API wrapper
2532
*/
26-
export class Instagram<PostType> extends EventEmitter {
33+
export class Instagram<PostType> {
2734
/**
2835
* Apply defaults to undefined options
2936
*/
@@ -153,6 +160,25 @@ export class Instagram<PostType> extends EventEmitter {
153160
// Location of chromium / chrome binary executable
154161
private readonly executablePath: string;
155162

163+
// Plugins to be run
164+
private pluginFunctions: {
165+
[key in keyof typeof AsyncPluginEvents]: Array<
166+
(...args: any[]) => Promise<void>
167+
>;
168+
} &
169+
{
170+
[key in keyof typeof SyncPluginEvents]: Array<
171+
(...args: any[]) => void
172+
>;
173+
} = {
174+
browser: [],
175+
construction: [],
176+
grafting: [],
177+
postPage: [],
178+
request: [],
179+
response: [],
180+
};
181+
156182
/**
157183
* Create API wrapper instance
158184
* @param endpoint the url for the type of resource to scrape
@@ -170,7 +196,6 @@ export class Instagram<PostType> extends EventEmitter {
170196
options: IOptions = {},
171197
validator: Type<unknown>,
172198
) {
173-
super();
174199
this.id = id;
175200
this.postIds = new PostIdSet();
176201
this.url = endpoint.replace("[id]", id);
@@ -192,7 +217,7 @@ export class Instagram<PostType> extends EventEmitter {
192217
this.validator = options.validator || validator;
193218

194219
this.addPlugins(options["plugins"]);
195-
this.emit("construction");
220+
this.executePlugins("construction");
196221
}
197222

198223
/**
@@ -268,6 +293,7 @@ export class Instagram<PostType> extends EventEmitter {
268293
public async start() {
269294
// Build page and visit url
270295
await this.constructPage();
296+
await this.executePlugins("browser");
271297

272298
this.started = true;
273299

@@ -358,7 +384,7 @@ export class Instagram<PostType> extends EventEmitter {
358384
headers: this.graftHeaders,
359385
url: this.graftURL,
360386
};
361-
this.emit("request", req, overrides);
387+
await this.executePlugins("request", req, overrides);
362388
await req.continue(overrides);
363389

364390
// Reset grafting data
@@ -372,7 +398,7 @@ export class Instagram<PostType> extends EventEmitter {
372398
break;
373399
} else {
374400
const overrides = {};
375-
this.emit("request", req, overrides);
401+
this.executePlugins("request", req, overrides);
376402
await req.continue(overrides);
377403
}
378404
}
@@ -410,7 +436,7 @@ export class Instagram<PostType> extends EventEmitter {
410436
}
411437

412438
// Emit event
413-
this.emit("response", res, data);
439+
this.executePlugins("response", res, data);
414440

415441
// Check for rate limiting
416442
if (data && "status" in data && data["status"] === "fail") {
@@ -519,7 +545,7 @@ export class Instagram<PostType> extends EventEmitter {
519545
if (!parsed) {
520546
return;
521547
}
522-
this.emit("postPage", parsed);
548+
await this.executePlugins("postPage", parsed);
523549
await this.addToPostBuffer(parsed);
524550
}
525551

@@ -841,7 +867,7 @@ export class Instagram<PostType> extends EventEmitter {
841867

842868
await this.progress(Progress.GRAFTING);
843869

844-
this.emit("grafting");
870+
this.executePlugins("grafting");
845871

846872
// Enable grafting
847873
this.graft = true;
@@ -886,28 +912,39 @@ export class Instagram<PostType> extends EventEmitter {
886912
return;
887913
}
888914

889-
const events = [
890-
"construction",
891-
"request",
892-
"response",
893-
"postPage",
894-
"grafting",
895-
];
896-
897915
for (const plugin of plugins) {
898-
for (const event of events) {
916+
for (const event of Object.keys(this.pluginFunctions)) {
899917
const pluginEvent = plugin[event + "Event"];
900918
if (pluginEvent) {
901919
const context: IPluginContext<typeof plugin, PostType> = {
902920
plugin,
903921
state: this,
904922
};
905923

906-
this.on(event, pluginEvent.bind(context));
924+
this.pluginFunctions[event].push(pluginEvent.bind(context));
907925
}
908926
}
909927
}
910928
}
929+
930+
private executePlugins(event: SyncPluginEventsType, ...args): void;
931+
private executePlugins(
932+
event: AsyncPluginEventsType,
933+
...args
934+
): Promise<unknown>;
935+
private executePlugins(event: PluginEventsType, ...args) {
936+
if (event in SyncPluginEvents) {
937+
for (const pluginFunction of this.pluginFunctions["construction"]) {
938+
pluginFunction();
939+
}
940+
return;
941+
}
942+
943+
// @ts-ignore
944+
return Promise.all(
945+
this.pluginFunctions[event].map((cb) => cb(...args)),
946+
);
947+
}
911948
}
912949

913950
/**

0 commit comments

Comments
 (0)