@efffrida/rpc 0.0.27 → 0.0.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/dist/frida/FridaRpcClient.d.ts +4 -29
  2. package/dist/frida/FridaRpcClient.d.ts.map +1 -1
  3. package/dist/frida/FridaRpcClient.js +47 -83
  4. package/dist/frida/FridaRpcClient.js.map +1 -1
  5. package/dist/frida/FridaRpcServer.d.ts +7 -7
  6. package/dist/frida/FridaRpcServer.d.ts.map +1 -1
  7. package/dist/frida/FridaRpcServer.js +37 -49
  8. package/dist/frida/FridaRpcServer.js.map +1 -1
  9. package/dist/node/FridaRpcClient.d.ts +6 -10
  10. package/dist/node/FridaRpcClient.d.ts.map +1 -1
  11. package/dist/node/FridaRpcClient.js +67 -46
  12. package/dist/node/FridaRpcClient.js.map +1 -1
  13. package/dist/node/FridaRpcServer.d.ts +10 -3
  14. package/dist/node/FridaRpcServer.d.ts.map +1 -1
  15. package/dist/node/FridaRpcServer.js +63 -64
  16. package/dist/node/FridaRpcServer.js.map +1 -1
  17. package/dist/shared/{constants.d.ts → Constants.d.ts} +7 -3
  18. package/dist/shared/Constants.d.ts.map +1 -0
  19. package/dist/shared/Constants.js +10 -0
  20. package/dist/shared/Constants.js.map +1 -0
  21. package/dist/shared/index.d.ts +10 -0
  22. package/dist/shared/index.d.ts.map +1 -0
  23. package/dist/shared/index.js +10 -0
  24. package/dist/shared/index.js.map +1 -0
  25. package/package.json +12 -20
  26. package/src/frida/FridaRpcClient.ts +61 -141
  27. package/src/frida/FridaRpcServer.ts +47 -54
  28. package/src/node/FridaRpcClient.ts +84 -71
  29. package/src/node/FridaRpcServer.ts +92 -80
  30. package/src/shared/Constants.ts +13 -0
  31. package/src/shared/index.ts +10 -0
  32. package/dist/shared/constants.d.ts.map +0 -1
  33. package/dist/shared/constants.js +0 -7
  34. package/dist/shared/constants.js.map +0 -1
  35. package/dist/shared/predicates.d.ts +0 -10
  36. package/dist/shared/predicates.d.ts.map +0 -1
  37. package/dist/shared/predicates.js +0 -12
  38. package/dist/shared/predicates.js.map +0 -1
  39. package/src/shared/constants.ts +0 -11
  40. package/src/shared/predicates.ts +0 -19
@@ -7,119 +7,121 @@
7
7
 
8
8
  import type * as Scope from "effect/Scope";
9
9
 
10
- import * as RpcMessage from "@effect/rpc/RpcMessage";
11
- import * as RpcSerialization from "@effect/rpc/RpcSerialization";
12
- import * as RpcServer from "@effect/rpc/RpcServer";
13
- import * as FridaScript from "@efffrida/frida-tools/FridaScript";
14
- import * as Console from "effect/Console";
15
10
  import * as Effect from "effect/Effect";
16
11
  import * as Function from "effect/Function";
17
- import * as Mailbox from "effect/Mailbox";
12
+ import * as Layer from "effect/Layer";
18
13
  import * as Option from "effect/Option";
19
14
  import * as Predicate from "effect/Predicate";
20
- import * as Schema from "effect/Schema";
15
+ import * as Queue from "effect/Queue";
21
16
  import * as Stream from "effect/Stream";
22
17
  import * as String from "effect/String";
23
- import * as Tuple from "effect/Tuple";
18
+ import * as RpcMessage from "effect/unstable/rpc/RpcMessage";
19
+ import * as RpcSerialization from "effect/unstable/rpc/RpcSerialization";
20
+ import * as RpcServer from "effect/unstable/rpc/RpcServer";
21
+
22
+ import * as FridaScript from "@efffrida/frida-tools/FridaScript";
24
23
 
25
- import * as constants from "../shared/constants.ts";
26
- import * as predicates from "../shared/predicates.ts";
24
+ import * as constants from "../shared/Constants.ts";
27
25
 
28
26
  /**
29
27
  * @since 1.0.0
30
28
  * @category Protocol
31
29
  */
32
30
  export const makeProtocolFrida = (): Effect.Effect<
33
- unknown,
31
+ RpcServer.Protocol["Service"],
34
32
  never,
35
33
  FridaScript.FridaScript | RpcSerialization.RpcSerialization | Scope.Scope
36
34
  > =>
37
35
  Effect.gen(function* () {
38
- const encoder = new TextEncoder();
39
- const script = yield* FridaScript.FridaScript;
40
36
  const serialization = yield* RpcSerialization.RpcSerialization;
37
+ const script = yield* FridaScript.FridaScript;
38
+
39
+ const disconnects = yield* Queue.unbounded<number>();
40
+ const parser = serialization.makeUnsafe();
41
+ const encoder = new TextEncoder();
41
42
 
42
43
  let clientId = 0;
43
44
  const clientIds = new Set<number>();
44
- const parser = serialization.unsafeMake();
45
- const disconnects = yield* Mailbox.make<number>();
46
-
47
- let writeRequest!: (clientId: number, message: RpcMessage.FromClientEncoded) => Effect.Effect<void>;
45
+ const clientIdsByExports = new Map<string, number>();
46
+ const clients = new Map<
47
+ number,
48
+ {
49
+ readonly write: (bytes: RpcMessage.FromServerEncoded) => void;
50
+ }
51
+ >();
48
52
 
49
- // Listen for new clients
50
- yield* script.stream.pipe(
51
- Stream.filterMap(({ message }) => {
52
- if (predicates.newClientPredicate(message)) {
53
- const stripPrefix = String.replace(constants.nodeRpcClientConnectionRequestMessagePrefix, "");
54
- return Option.some(stripPrefix(message));
55
- } else {
56
- return Option.none();
57
- }
58
- }),
59
- Stream.runForEach((exportName) => {
60
- const id = clientId++;
61
- clientIds.add(id);
62
- return script.callExport(exportName, Schema.Void)(clientId++);
63
- }),
64
- Stream.tapError(Console.error),
65
- Stream.runDrain,
66
- Effect.forkScoped
53
+ const stripPrefix = String.replace(constants.nodeRpcClientConnectionRequestMessagePrefix, "");
54
+ const newClientPredicate: Predicate.Refinement<unknown, string> = Predicate.compose(
55
+ Predicate.isString,
56
+ String.startsWith(constants.nodeRpcClientConnectionRequestMessagePrefix)
57
+ );
58
+ const clientMessagePredicate: Predicate.Refinement<unknown, string> = Predicate.compose(
59
+ Predicate.isString,
60
+ (message) => clientIdsByExports.has(message)
67
61
  );
68
62
 
69
- // Listen for messages from connected clients
70
- yield* script.stream.pipe(
71
- Stream.filterMap(({ data: maybeData, message }) => {
72
- if (predicates.isTaggedForAnyClient(message)) {
73
- return Option.map(maybeData, (data) => Tuple.make(message.clientId, data));
74
- } else {
75
- return Option.none();
76
- }
77
- }),
78
- Stream.runForEach(([clientId, data]) => {
63
+ let writeRequest!: (clientId: number, message: RpcMessage.FromClientEncoded) => Effect.Effect<void>;
64
+ const makeRawWriter =
65
+ (exportName: string) =>
66
+ (data: string | Uint8Array): Effect.Effect<void> => {
67
+ const transformed = typeof data === "string" ? encoder.encode(data) : data;
68
+ return script.callExport(exportName)(transformed).pipe(Effect.orDie);
69
+ };
70
+
71
+ const onClientConnect = (message: string): Effect.Effect<void> => {
72
+ const writeRaw = makeRawWriter(stripPrefix(message));
73
+ const write = (response: RpcMessage.FromServerEncoded): Effect.Effect<void> => {
79
74
  try {
80
- const decoded = parser.decode(data) as ReadonlyArray<RpcMessage.FromClientEncoded>;
81
- if (decoded.length === 0) return Effect.void;
82
- let i = 0;
83
- return Effect.whileLoop({
84
- while: () => i < decoded.length,
85
- body() {
86
- const message = decoded[i++];
87
- return writeRequest(clientId, message);
88
- },
89
- step: Function.constVoid,
90
- });
75
+ const encoded = parser.encode(response);
76
+ if (encoded === undefined) return Effect.void;
77
+ return writeRaw(encoded);
91
78
  } catch (cause) {
92
- return Effect.sync(() => {
93
- const encoded = parser.encode(RpcMessage.ResponseDefectEncoded(cause))!;
94
- const transformed = typeof encoded === "string" ? encoder.encode(encoded) : encoded;
95
- script.script.post({ clientId }, Buffer.from(transformed));
96
- });
79
+ const encoded = parser.encode(RpcMessage.ResponseDefectEncoded(cause))!;
80
+ return writeRaw(encoded);
97
81
  }
98
- }),
99
- Stream.tapError(Console.error),
100
- Stream.runDrain,
101
- Effect.forkScoped
102
- );
82
+ };
83
+
84
+ const id = ++clientId;
85
+ clientIdsByExports.set(stripPrefix(message), id);
86
+ clients.set(id, { write });
87
+ clientIds.add(id);
88
+ return Effect.void;
89
+ };
90
+
91
+ const onMessage = (exportName: string, data: Uint8Array): Effect.Effect<void> => {
92
+ try {
93
+ const id = clientIdsByExports.get(exportName)!;
94
+ const decoded = parser.decode(data) as ReadonlyArray<RpcMessage.FromClientEncoded>;
95
+ if (decoded.length === 0) return Effect.void;
96
+ let i = 0;
97
+ return Effect.whileLoop({
98
+ while: () => i < decoded.length,
99
+ step: Function.constVoid,
100
+ body() {
101
+ const message = decoded[i++];
102
+ return writeRequest(id, message);
103
+ },
104
+ });
105
+ } catch (cause) {
106
+ const writeRaw = makeRawWriter(exportName);
107
+ return writeRaw(parser.encode(RpcMessage.ResponseDefectEncoded(cause))!);
108
+ }
109
+ };
110
+
111
+ yield* Stream.runForEach(script.stream, ({ message, data }) => {
112
+ if (newClientPredicate(message)) return onClientConnect(message);
113
+ if (clientMessagePredicate(message) && Option.isSome(data)) return onMessage(message, data.value);
114
+ return Effect.void;
115
+ }).pipe(Effect.forkScoped);
103
116
 
104
117
  return yield* RpcServer.Protocol.make((_writeRequest) => {
105
118
  writeRequest = _writeRequest;
106
119
  return Effect.succeed({
107
120
  disconnects,
108
121
  send: (clientId, response) => {
109
- const writeRaw = (data: string | Uint8Array) => {
110
- const transformed = typeof data === "string" ? encoder.encode(data) : data;
111
- script.script.post({ clientId }, Buffer.from(transformed));
112
- return Effect.void;
113
- };
114
-
115
- try {
116
- const encoded = parser.encode(response);
117
- if (Predicate.isNotUndefined(encoded)) return writeRaw(encoded);
118
- else return Effect.void;
119
- } catch (cause) {
120
- const encoded = parser.encode(RpcMessage.ResponseDefectEncoded(cause))!;
121
- return writeRaw(encoded);
122
- }
122
+ const client = clients.get(clientId);
123
+ if (!client) return Effect.void;
124
+ return Effect.sync(() => client.write(response));
123
125
  },
124
126
  end(_clientId) {
125
127
  return Effect.void;
@@ -132,3 +134,13 @@ export const makeProtocolFrida = (): Effect.Effect<
132
134
  });
133
135
  });
134
136
  });
137
+
138
+ /**
139
+ * @since 1.0.0
140
+ * @category Layer
141
+ */
142
+ export const layerProtocolFrida: Layer.Layer<
143
+ RpcServer.Protocol,
144
+ never,
145
+ FridaScript.FridaScript | RpcSerialization.RpcSerialization
146
+ > = Layer.effect(RpcServer.Protocol, makeProtocolFrida());
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Constants for working with RPC servers and clients.
3
+ *
4
+ * @since 1.0.0
5
+ */
6
+
7
+ export const defaultServerMainExportName = "rpc";
8
+ export const generateServerExportNameForClient = (clientId: number): string =>
9
+ `@efffrida/rpc/FridaServerRpcListenerForClient/${clientId}`;
10
+
11
+ export const nodeRpcClientConnectionRequestMessagePrefix = "@efffrida/rpc/NodeRpcClientConnectionRequest/";
12
+ export const nodeRpcClientMakeConnectionRequestForServer = (exportName: string) =>
13
+ `${nodeRpcClientConnectionRequestMessagePrefix}${exportName}`;
@@ -0,0 +1,10 @@
1
+ /**
2
+ * @since 1.0.0
3
+ */
4
+
5
+ /**
6
+ * Constants for working with RPC servers and clients.
7
+ *
8
+ * @since 1.0.0
9
+ */
10
+ export * as Constants from "./Constants.ts"
@@ -1 +0,0 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/shared/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,2BAA2B,QAAQ,CAAC;AACjD,eAAO,MAAM,iCAAiC,GAAI,UAAU,MAAM,KAAG,MACN,CAAC;AAGhE,eAAO,MAAM,yCAAyC,QAAO,MACY,CAAC;AAE1E,eAAO,MAAM,2CAA2C,8BAA8B,CAAC;AACvF,eAAO,MAAM,2CAA2C,GAAI,YAAY,MAAM,WACZ,CAAC"}
@@ -1,7 +0,0 @@
1
- export const defaultServerMainExportName = "rpc";
2
- export const generateServerExportNameForClient = clientId => `@efffrida/rpc/FridaServerRpcListenerForClient/${clientId}`;
3
- let exportIdForClientCallback = 0;
4
- export const generateClientCallbackExportNameForServer = () => `@efffrida/rpc/FridaClientRpcCallback/${exportIdForClientCallback++}`;
5
- export const nodeRpcClientConnectionRequestMessagePrefix = "client id request message";
6
- export const nodeRpcClientMakeConnectionRequestForServer = exportName => `${nodeRpcClientConnectionRequestMessagePrefix}:${exportName}`;
7
- //# sourceMappingURL=constants.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"constants.js","names":["defaultServerMainExportName","generateServerExportNameForClient","clientId","exportIdForClientCallback","generateClientCallbackExportNameForServer","nodeRpcClientConnectionRequestMessagePrefix","nodeRpcClientMakeConnectionRequestForServer","exportName"],"sources":["../../src/shared/constants.ts"],"sourcesContent":[null],"mappings":"AAAA,OAAO,MAAMA,2BAA2B,GAAG,KAAK;AAChD,OAAO,MAAMC,iCAAiC,GAAIC,QAAgB,IAC9D,iDAAiDA,QAAQ,EAAE;AAE/D,IAAIC,yBAAyB,GAAW,CAAC;AACzC,OAAO,MAAMC,yCAAyC,GAAGA,CAAA,KACrD,wCAAwCD,yBAAyB,EAAE,EAAE;AAEzE,OAAO,MAAME,2CAA2C,GAAG,2BAA2B;AACtF,OAAO,MAAMC,2CAA2C,GAAIC,UAAkB,IAC1E,GAAGF,2CAA2C,IAAIE,UAAU,EAAE","ignoreList":[]}
@@ -1,10 +0,0 @@
1
- import * as Predicate from "effect/Predicate";
2
- export declare const isClientId: (clientId: number) => Predicate.Refinement<unknown, number>;
3
- export declare const isTaggedForClient: (clientId: number) => Predicate.Refinement<unknown, {
4
- readonly clientId: number;
5
- }>;
6
- export declare const isTaggedForAnyClient: Predicate.Refinement<unknown, {
7
- readonly clientId: number;
8
- }>;
9
- export declare const newClientPredicate: Predicate.Refinement<unknown, string>;
10
- //# sourceMappingURL=predicates.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"predicates.d.ts","sourceRoot":"","sources":["../../src/shared/predicates.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,SAAS,MAAM,kBAAkB,CAAC;AAK9C,eAAO,MAAM,UAAU,GAAI,UAAU,MAAM,0CAAmE,CAAC;AAE/G,eAAO,MAAM,iBAAiB,GAAI,UAAU,MAAM;;EAC8C,CAAC;AAEjG,eAAO,MAAM,oBAAoB;;EAGhC,CAAC;AAEF,eAAO,MAAM,kBAAkB,uCAG9B,CAAC"}
@@ -1,12 +0,0 @@
1
- import * as Predicate from "effect/Predicate";
2
- import * as String from "effect/String";
3
- import * as constants from "./constants.js";
4
- export const isClientId = clientId => Predicate.compose(Predicate.isNumber, id => id === clientId);
5
- export const isTaggedForClient = clientId => Predicate.compose(Predicate.isUnknown, Predicate.struct({
6
- clientId: isClientId(clientId)
7
- }));
8
- export const isTaggedForAnyClient = /*#__PURE__*/Predicate.compose(Predicate.isUnknown, /*#__PURE__*/Predicate.struct({
9
- clientId: Predicate.isNumber
10
- }));
11
- export const newClientPredicate = /*#__PURE__*/Predicate.compose(Predicate.isString, /*#__PURE__*/String.startsWith(constants.nodeRpcClientConnectionRequestMessagePrefix));
12
- //# sourceMappingURL=predicates.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"predicates.js","names":["Predicate","String","constants","isClientId","clientId","compose","isNumber","id","isTaggedForClient","isUnknown","struct","isTaggedForAnyClient","newClientPredicate","isString","startsWith","nodeRpcClientConnectionRequestMessagePrefix"],"sources":["../../src/shared/predicates.ts"],"sourcesContent":[null],"mappings":"AAAA,OAAO,KAAKA,SAAS,MAAM,kBAAkB;AAC7C,OAAO,KAAKC,MAAM,MAAM,eAAe;AAEvC,OAAO,KAAKC,SAAS,MAAM,gBAAgB;AAE3C,OAAO,MAAMC,UAAU,GAAIC,QAAgB,IAAKJ,SAAS,CAACK,OAAO,CAACL,SAAS,CAACM,QAAQ,EAAGC,EAAE,IAAKA,EAAE,KAAKH,QAAQ,CAAC;AAE9G,OAAO,MAAMI,iBAAiB,GAAIJ,QAAgB,IAC9CJ,SAAS,CAACK,OAAO,CAACL,SAAS,CAACS,SAAS,EAAET,SAAS,CAACU,MAAM,CAAC;EAAEN,QAAQ,EAAED,UAAU,CAACC,QAAQ;AAAC,CAAE,CAAC,CAAC;AAEhG,OAAO,MAAMO,oBAAoB,gBAAGX,SAAS,CAACK,OAAO,CACjDL,SAAS,CAACS,SAAS,eACnBT,SAAS,CAACU,MAAM,CAAC;EAAEN,QAAQ,EAAEJ,SAAS,CAACM;AAAQ,CAAE,CAAC,CACrD;AAED,OAAO,MAAMM,kBAAkB,gBAAGZ,SAAS,CAACK,OAAO,CAC/CL,SAAS,CAACa,QAAQ,eAClBZ,MAAM,CAACa,UAAU,CAACZ,SAAS,CAACa,2CAA2C,CAAC,CAC3E","ignoreList":[]}
@@ -1,11 +0,0 @@
1
- export const defaultServerMainExportName = "rpc";
2
- export const generateServerExportNameForClient = (clientId: number): string =>
3
- `@efffrida/rpc/FridaServerRpcListenerForClient/${clientId}`;
4
-
5
- let exportIdForClientCallback: number = 0;
6
- export const generateClientCallbackExportNameForServer = (): string =>
7
- `@efffrida/rpc/FridaClientRpcCallback/${exportIdForClientCallback++}`;
8
-
9
- export const nodeRpcClientConnectionRequestMessagePrefix = "client id request message";
10
- export const nodeRpcClientMakeConnectionRequestForServer = (exportName: string) =>
11
- `${nodeRpcClientConnectionRequestMessagePrefix}:${exportName}`;
@@ -1,19 +0,0 @@
1
- import * as Predicate from "effect/Predicate";
2
- import * as String from "effect/String";
3
-
4
- import * as constants from "./constants.ts";
5
-
6
- export const isClientId = (clientId: number) => Predicate.compose(Predicate.isNumber, (id) => id === clientId);
7
-
8
- export const isTaggedForClient = (clientId: number) =>
9
- Predicate.compose(Predicate.isUnknown, Predicate.struct({ clientId: isClientId(clientId) }));
10
-
11
- export const isTaggedForAnyClient = Predicate.compose(
12
- Predicate.isUnknown,
13
- Predicate.struct({ clientId: Predicate.isNumber })
14
- );
15
-
16
- export const newClientPredicate = Predicate.compose(
17
- Predicate.isString,
18
- String.startsWith(constants.nodeRpcClientConnectionRequestMessagePrefix)
19
- );