-
Notifications
You must be signed in to change notification settings - Fork 10
Create abstraction for communication #19
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,10 +17,6 @@ import { | |
LocalFilter, | ||
State, | ||
} from "@redux-devtools/utils"; | ||
import { | ||
DevToolsPluginClient, | ||
getDevToolsPluginClientAsync, | ||
} from "expo/devtools"; | ||
import { stringify, parse } from "jsan"; | ||
import { | ||
Action, | ||
|
@@ -31,6 +27,7 @@ import { | |
} from "redux"; | ||
|
||
import configureStore from "./configureStore"; | ||
import { ProxyClient, ProxyClientFactory } from "./types"; | ||
|
||
function async(fn: () => unknown) { | ||
setTimeout(fn, 0); | ||
|
@@ -160,12 +157,12 @@ type Message<S, A extends Action<string>> = | |
| ActionMessage | ||
| DispatchMessage<S, A>; | ||
|
||
class DevToolsEnhancer<S, A extends Action<string>> { | ||
export class DevToolsEnhancer<S, A extends Action<string>> { | ||
// eslint-disable-next-line @typescript-eslint/ban-types | ||
store!: EnhancedStore<S, A, {}>; | ||
filters: LocalFilter | undefined; | ||
instanceId?: string; | ||
devToolsPluginClient?: DevToolsPluginClient; | ||
proxyClient?: ProxyClient; | ||
sendTo?: string; | ||
instanceName: string | undefined; | ||
appInstanceId!: string; | ||
|
@@ -186,6 +183,13 @@ class DevToolsEnhancer<S, A extends Action<string>> { | |
lastAction?: unknown; | ||
paused?: boolean; | ||
locked?: boolean; | ||
createProxyClient: ProxyClientFactory; | ||
|
||
constructor( | ||
proxyClientFactory: ProxyClientFactory, | ||
) { | ||
this.createProxyClient = proxyClientFactory; | ||
} | ||
|
||
getInstanceId() { | ||
if (!this.instanceId) { | ||
|
@@ -276,7 +280,7 @@ class DevToolsEnhancer<S, A extends Action<string>> { | |
} else if (action) { | ||
message.action = action as ActionCreatorObject[]; | ||
} | ||
this.devToolsPluginClient?.sendMessage("log", message); | ||
this.proxyClient?.sendMessage("log", message); | ||
} | ||
|
||
dispatchRemotely( | ||
|
@@ -374,21 +378,19 @@ class DevToolsEnhancer<S, A extends Action<string>> { | |
stop = async () => { | ||
this.started = false; | ||
this.isMonitored = false; | ||
if (!this.devToolsPluginClient) return; | ||
await this.devToolsPluginClient.closeAsync(); | ||
this.devToolsPluginClient = undefined; | ||
if (!this.proxyClient) return; | ||
await this.proxyClient.closeAsync(); | ||
this.proxyClient = undefined; | ||
}; | ||
|
||
start = () => { | ||
if (this.started) return; | ||
|
||
(async () => { | ||
try { | ||
this.devToolsPluginClient = await getDevToolsPluginClientAsync( | ||
"redux-devtools-expo-dev-plugin", | ||
); | ||
this.proxyClient = await this.createProxyClient(); | ||
|
||
this.devToolsPluginClient.addMessageListener( | ||
this.proxyClient.addMessageListener( | ||
"respond", | ||
(data: Message<S, A>) => { | ||
this.handleMessages(data); | ||
|
@@ -505,16 +507,11 @@ class DevToolsEnhancer<S, A extends Action<string>> { | |
}; | ||
} | ||
|
||
export default <S, A extends Action<string>>( | ||
options?: Options<S, A>, | ||
): StoreEnhancer => new DevToolsEnhancer<S, A>().enhance(options); | ||
|
||
const compose = | ||
(devToolsEnhancer: DevToolsEnhancer<unknown, Action<string>>) => | ||
(options: Options<unknown, Action<string>>) => | ||
(...funcs: StoreEnhancer[]) => | ||
(...args: unknown[]) => { | ||
const devToolsEnhancer = new DevToolsEnhancer(); | ||
|
||
function preEnhancer(createStore: StoreEnhancerStoreCreator) { | ||
return <S, A extends Action<string>>( | ||
reducer: Reducer<S, A>, | ||
|
@@ -539,14 +536,25 @@ const compose = | |
); | ||
}; | ||
|
||
export function composeWithDevTools( | ||
...funcs: [Options<unknown, Action<string>>] | StoreEnhancer[] | ||
export function createComposeWithDevTools( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I changed |
||
proxyClientFactory: ProxyClientFactory, | ||
) { | ||
if (funcs.length === 0) { | ||
return new DevToolsEnhancer().enhance(); | ||
} | ||
if (funcs.length === 1 && typeof funcs[0] === "object") { | ||
return compose(funcs[0]); | ||
} | ||
return compose({})(...(funcs as StoreEnhancer[])); | ||
const devtoolsEnhancer = new DevToolsEnhancer<unknown, Action<string>>( | ||
proxyClientFactory, | ||
); | ||
return function ( | ||
...funcs: [Options<unknown, Action<string>>] | StoreEnhancer[] | ||
) { | ||
if (funcs.length === 0) { | ||
return devtoolsEnhancer.enhance(); | ||
} | ||
if (funcs.length === 1 && typeof funcs[0] === "object") { | ||
return compose(devtoolsEnhancer)(funcs[0]); | ||
} | ||
return compose(devtoolsEnhancer)({})(...(funcs as StoreEnhancer[])); | ||
}; | ||
} | ||
|
||
export const createDevToolsEnhancer = (createProxyClient: ProxyClientFactory) => <S, A extends Action<string>>( | ||
options?: Options<S, A>, | ||
): StoreEnhancer => new DevToolsEnhancer<S, A>(createProxyClient).enhance(options); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,14 +1,22 @@ | ||
/// <reference types="node" /> | ||
import { compose } from "redux"; | ||
|
||
export let composeWithDevTools: typeof import("./devtools").composeWithDevTools; | ||
let devtoolsEnhancer: typeof import("./devtools").default; | ||
export let createComposeWithDevTools: typeof import("./devtools").createComposeWithDevTools; | ||
export let composeWithDevTools: ReturnType<typeof createComposeWithDevTools>; | ||
|
||
let createDevToolsEnhancer: typeof import("./devtools").createDevToolsEnhancer; | ||
let devtoolsEnhancer: ReturnType<typeof createDevToolsEnhancer>; | ||
|
||
if (process.env.NODE_ENV !== "production") { | ||
devtoolsEnhancer = require("./devtools").default; | ||
composeWithDevTools = require("./devtools").composeWithDevTools; | ||
const getDevToolsPluginClientAsync = require('expo/devtools').getDevToolsPluginClientAsync; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I moved the import of |
||
const createDevToolsEnhancer = require("./devtools").createDevToolsEnhancer; | ||
|
||
devtoolsEnhancer = createDevToolsEnhancer(() => getDevToolsPluginClientAsync("redux-devtools-expo-dev-plugin")); | ||
createComposeWithDevTools = require("./devtools").createComposeWithDevTools; | ||
composeWithDevTools = createComposeWithDevTools(() => getDevToolsPluginClientAsync("redux-devtools-expo-dev-plugin")); | ||
} else { | ||
devtoolsEnhancer = () => (next) => next; | ||
createComposeWithDevTools = () => compose; | ||
composeWithDevTools = compose; | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
export interface ProxyClient { | ||
sendMessage: (type: string, data?: any) => void; | ||
addMessageListener: (method: string, listener: (params: any) => void) => void; | ||
closeAsync: () => Promise<void>; | ||
} | ||
|
||
export type ProxyClientFactory = () => Promise<ProxyClient>; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,23 +10,21 @@ import { | |
UPDATE_STATE, | ||
UpdateReportsRequest, | ||
} from "@redux-devtools/app-core"; | ||
import { | ||
DevToolsPluginClient, | ||
getDevToolsPluginClientAsync, | ||
} from "expo/devtools"; | ||
import { getDevToolsPluginClientAsync } from "expo/devtools"; | ||
import { stringify } from "jsan"; | ||
import { Dispatch, MiddlewareAPI } from "redux"; | ||
|
||
import { EmitAction, StoreAction } from "../actions"; | ||
import * as actions from "../constants/socketActionTypes"; | ||
import { StoreState } from "../reducers"; | ||
import { ProxyClient, ProxyClientFactory } from "./types"; | ||
import { nonReduxDispatch } from "../utils/monitorActions"; | ||
|
||
let devToolsPluginClient: DevToolsPluginClient | undefined; | ||
let proxyClient: ProxyClient | undefined; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Similarly, for the redux middleware part, I added an abstraction. Just, to allow using a different method that has the same interface as |
||
let store: MiddlewareAPI<Dispatch<StoreAction>, StoreState>; | ||
|
||
function emit({ message: type, instanceId, action, state }: EmitAction) { | ||
devToolsPluginClient?.sendMessage("respond", { | ||
proxyClient?.sendMessage("respond", { | ||
type, | ||
action, | ||
state, | ||
|
@@ -117,7 +115,7 @@ function monitoring(request: MonitoringRequest) { | |
instanceId === instances.selected && | ||
(request.type === "ACTION" || request.type === "STATE") | ||
) { | ||
devToolsPluginClient?.sendMessage("respond", { | ||
proxyClient?.sendMessage("respond", { | ||
type: "SYNC", | ||
state: stringify(instances.states[instanceId]), | ||
id: request.id, | ||
|
@@ -126,17 +124,15 @@ function monitoring(request: MonitoringRequest) { | |
} | ||
} | ||
|
||
async function connect() { | ||
async function connect(createProxyClient: ProxyClientFactory) { | ||
if (process.env.NODE_ENV === "test") return; | ||
try { | ||
devToolsPluginClient = await getDevToolsPluginClientAsync( | ||
"redux-devtools-expo-dev-plugin", | ||
); | ||
proxyClient = await createProxyClient(); | ||
|
||
const watcher = (request: UpdateReportsRequest) => { | ||
store.dispatch({ type: UPDATE_REPORTS, request }); | ||
}; | ||
devToolsPluginClient.addMessageListener("log", (data) => { | ||
proxyClient.addMessageListener("log", (data) => { | ||
monitoring(data as MonitoringRequest); | ||
watcher(data as UpdateReportsRequest); | ||
}); | ||
|
@@ -151,20 +147,24 @@ async function connect() { | |
} | ||
} | ||
|
||
export function api(inStore: MiddlewareAPI<Dispatch<StoreAction>, StoreState>) { | ||
store = inStore; | ||
connect(); | ||
export function api( | ||
createProxyClient: ProxyClientFactory = () => getDevToolsPluginClientAsync("redux-devtools-expo-dev-plugin"), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. By default it is still using |
||
) { | ||
return function (inStore: MiddlewareAPI<Dispatch<StoreAction>, StoreState>) { | ||
store = inStore; | ||
connect(createProxyClient); | ||
|
||
return (next: Dispatch<StoreAction>) => (action: StoreAction) => { | ||
const result = next(action); | ||
switch (action.type) { | ||
case actions.EMIT: | ||
if (devToolsPluginClient) emit(action); | ||
break; | ||
case LIFTED_ACTION: | ||
dispatchRemoteAction(action); | ||
break; | ||
} | ||
return result; | ||
return (next: Dispatch<StoreAction>) => (action: StoreAction) => { | ||
const result = next(action); | ||
switch (action.type) { | ||
case actions.EMIT: | ||
if (proxyClient) emit(action); | ||
break; | ||
case LIFTED_ACTION: | ||
dispatchRemoteAction(action); | ||
break; | ||
} | ||
return result; | ||
}; | ||
}; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
export interface ProxyClient { | ||
sendMessage: (type: string, data?: any) => void; | ||
addMessageListener: (method: string, listener: (params: any) => void) => void; | ||
} | ||
|
||
export type ProxyClientFactory = () => Promise<ProxyClient>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The main idea is that we abstract communication logic. As for now, the
getDevToolsPluginClientAsync
andDevToolsPluginClient
are hardcoded and tidly coupled. I wanted to allow to pass any method that returns a subset ofDevToolsPluginClient
that is used byredux-devtools-expo-dev-plugin
. I assume that if the library wants to use more features ofDevToolsPluginClient
, thenProxyClient
should be updated.