Skip to content

Commit e5383b4

Browse files
feat(overmind-devtools): handle mutiple client sockets and convert runtime to connection indicator
BREAKING CHANGE: no more direct app connection
1 parent 2b3b647 commit e5383b4

File tree

19 files changed

+172
-299
lines changed

19 files changed

+172
-299
lines changed

packages/node_modules/overmind-devtools-client/DevtoolBackend.js

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ const WebSocket = require('ws')
33
class DevtoolBackend {
44
constructor(options) {
55
this.options = options
6+
this.clientSockets = {}
67
this.onClientConnection = this.onClientConnection.bind(this)
78
this.onDevtoolConnection = this.onDevtoolConnection.bind(this)
89
this.onConnection = this.onConnection.bind(this)
@@ -23,12 +24,26 @@ class DevtoolBackend {
2324
close() {
2425
this.devtoolServer.close()
2526
}
27+
getQuery(url) {
28+
return url
29+
.split('?')[1]
30+
.split(',')
31+
.reduce((aggr, part) => {
32+
const parts = part.split('=')
33+
34+
return Object.assign(aggr, {
35+
[parts[0]]: decodeURIComponent(parts[1]),
36+
})
37+
}, {})
38+
}
2639
onConnection(ws, req) {
40+
const query = this.getQuery(req.url)
41+
2742
// devtools connects with ?devtools=1 in url
28-
if (req.url.indexOf('devtools') !== -1) {
43+
if (query.devtools) {
2944
this.onDevtoolConnection(ws, req)
3045
} else {
31-
this.onClientConnection(ws, req)
46+
this.onClientConnection(query.name, ws)
3247
}
3348
}
3449

@@ -62,12 +77,32 @@ class DevtoolBackend {
6277
this.options.onRelaunch()
6378
break
6479
default:
65-
this.clientSocket.send(JSON.stringify(parsedMessage.data))
80+
this.clientSockets[parsedMessage.appName].send(
81+
JSON.stringify(parsedMessage.data)
82+
)
6683
}
6784
}
68-
onClientConnection(ws) {
69-
this.clientSocket = ws
70-
this.clientSocket.on('message', this.onClientMessage)
85+
onClientConnection(name, ws) {
86+
if (this.clientSockets[name]) {
87+
this.clientSockets[name].terminate()
88+
}
89+
90+
this.clientSockets[name] = ws
91+
92+
ws.on('message', this.onClientMessage)
93+
94+
const self = this
95+
ws.on('close', function onClose() {
96+
ws.removeEventListener('message', self.onClientMessage)
97+
ws.removeEventListener('close', onClose)
98+
99+
self.devtoolSocket.send(
100+
JSON.stringify({
101+
type: 'disconnect',
102+
data: name,
103+
})
104+
)
105+
})
71106
}
72107
onClientMessage(message) {
73108
this.devtoolSocket.send(`

packages/node_modules/overmind-devtools-client/src/BackendConnector.ts

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -85,15 +85,12 @@ class WebsocketConnector {
8585
}
8686

8787
export class BackendConnector extends WebsocketConnector {
88-
port: string
89-
messageCallback: MessageCallback
90-
constructor() {
91-
super()
92-
}
9388
onMessage = (onMessage: MessageCallback) => {
94-
this.messageCallback = onMessage
9589
this.on('message', (message) => onMessage(message))
9690
}
91+
onDisconnect = (onDisconnect: (name: string) => void) => {
92+
this.on('disconnect', (name) => onDisconnect(name))
93+
}
9794
sendMessage(appName: string, eventName: string, payload: object = null) {
9895
this.send('message', {
9996
appName,

packages/node_modules/overmind-devtools-client/src/components/Devtools/index.tsx

Lines changed: 6 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@ import Input from '../common/Input'
66
import Button from '../common/Button'
77
import Workspace from '../Workspace'
88
import { css } from 'emotion'
9-
import Runtime from '../Runtime'
10-
import { colors } from '../../theme'
119

1210
const Devtools: FunctionComponent = () => {
1311
const { state, actions } = useOvermind()
@@ -64,35 +62,12 @@ const Devtools: FunctionComponent = () => {
6462
)
6563
}
6664

67-
return (
68-
<Fragment>
69-
{state.isConnecting ? (
70-
<div className={styles.wrapper}>
71-
<h1>Waiting for an app to connect...</h1>
72-
<h2>or</h2>
73-
<input
74-
autoFocus
75-
disabled={state.runtimeHost && state.runtimeLoading}
76-
className={styles.input}
77-
defaultValue={
78-
state.runtimeHost ? state.runtimeHost.split('?')[0] : ''
79-
}
80-
placeholder="Connect to app..."
81-
style={{
82-
borderColor: state.runtimeError ? colors.red : 'transparent',
83-
}}
84-
onKeyDown={(event) => {
85-
if (event.keyCode === 13) {
86-
actions.setRuntimeHost(event.currentTarget.value)
87-
}
88-
}}
89-
/>
90-
</div>
91-
) : (
92-
<Workspace />
93-
)}
94-
<Runtime />
95-
</Fragment>
65+
return state.isConnecting ? (
66+
<div className={styles.wrapper}>
67+
<h1>Waiting for an app to connect...</h1>
68+
</div>
69+
) : (
70+
<Workspace />
9671
)
9772
}
9873

packages/node_modules/overmind-devtools-client/src/components/Runtime/index.tsx

Lines changed: 0 additions & 45 deletions
This file was deleted.

packages/node_modules/overmind-devtools-client/src/components/Runtime/styles.ts

Lines changed: 0 additions & 5 deletions
This file was deleted.

packages/node_modules/overmind-devtools-client/src/components/RuntimeConfig/index.tsx

Lines changed: 5 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -5,46 +5,18 @@ import { colors } from '../../theme'
55

66
const RuntimeConfig: FunctionComponent = () => {
77
const { state, actions } = useOvermind()
8-
const currentHost = state.runtimeHost.split('?')[0]
9-
const [host, setHost] = useState(currentHost)
108

119
return (
1210
<div className={styles.wrapper}>
1311
<div
1412
className={styles.overlay}
1513
onClick={() => actions.toggleRuntimeConfig()}
1614
/>
17-
<form
18-
className={styles.contentWrapper}
19-
onSubmit={(event) => {
20-
event.preventDefault()
21-
host === currentHost
22-
? actions.disconnectRuntime()
23-
: actions.setRuntimeHost(host)
24-
}}
25-
>
26-
<input
27-
autoFocus
28-
value={host}
29-
onChange={(event) => setHost(event.currentTarget.value)}
30-
className={styles.input}
31-
/>
32-
<button
33-
type="submit"
34-
className={styles.button}
35-
disabled={!host.length}
36-
style={{
37-
color: host && host === currentHost ? colors.white : colors.dark,
38-
backgroundColor: host
39-
? host === currentHost
40-
? colors.red
41-
: colors.green
42-
: colors.gray,
43-
}}
44-
>
45-
{host && host === currentHost ? 'disconnect' : 'connect'}
46-
</button>
47-
</form>
15+
<div className={styles.contentWrapper}>
16+
<strong>{state.currentApp.connectionState}</strong>
17+
<span style={{ margin: '0 5px' }}>on port</span>
18+
<strong>{state.port}</strong>
19+
</div>
4820
</div>
4921
)
5022
}

packages/node_modules/overmind-devtools-client/src/components/RuntimeConfig/styles.ts

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -24,25 +24,11 @@ export const contentWrapper = css({
2424
height: '100%',
2525
padding: '0.5rem',
2626
boxSizing: 'border-box',
27+
whiteSpace: 'nowrap',
2728
display: 'flex',
29+
alignItems: 'center',
2830
backgroundColor: colors.dark,
2931
borderRadiusTopRight: 3,
3032
borderRadiusBottomRight: 3,
3133
boxShadow: '5px 5px 20px 5px rgba(0,0,0,0.10)',
3234
})
33-
34-
export const input = css({
35-
border: 0,
36-
outline: 'none',
37-
padding: '0.5rem',
38-
fontSize: 18,
39-
borderRadius: 3,
40-
})
41-
42-
export const button = css({
43-
border: 0,
44-
borderRadius: 3,
45-
outline: 'none',
46-
cursor: 'pointer',
47-
marginLeft: '0.5rem',
48-
})

packages/node_modules/overmind-devtools-client/src/components/Tabs/index.tsx

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,8 @@ const Tabs: FunctionComponent = () => {
2121
const { state, actions } = useOvermind()
2222

2323
function getRuntimeColor() {
24-
if (!state.runtimeHost) return colors.white
25-
if (state.runtimeError) return colors.red
26-
if (state.runtimeLoading) return colors.yellow
24+
if (state.currentApp.connectionState === 'disconnected') return colors.red
25+
if (state.currentApp.connectionState === 'pending') return colors.yellow
2726

2827
return colors.green
2928
}
@@ -34,10 +33,7 @@ const Tabs: FunctionComponent = () => {
3433
<div className={styles.divider} />
3534
<div className={styles.runtimeWrapper}>
3635
<button
37-
className={css(
38-
styles.button,
39-
Boolean(state.runtimeHost) && styles.activeButton
40-
)}
36+
className={css(styles.button, styles.activeButton)}
4137
onClick={() => actions.toggleRuntimeConfig()}
4238
>
4339
<FaChrome
@@ -46,18 +42,20 @@ const Tabs: FunctionComponent = () => {
4642
}}
4743
/>
4844
</button>
49-
{state.isShowingRuntimeConfig ? <RuntimeConfig /> : null}
45+
{state.isShowingRuntime ? <RuntimeConfig /> : null}
5046
</div>
5147
<div className={styles.divider} />
52-
<button
53-
className={css(
54-
styles.button,
55-
state.currentTab === Tab.State && styles.activeButton
56-
)}
57-
onClick={() => actions.changeTab(Tab.State)}
58-
>
59-
<FaDatabase />
60-
</button>
48+
<Tooltip text="State">
49+
<button
50+
className={css(
51+
styles.button,
52+
state.currentTab === Tab.State && styles.activeButton
53+
)}
54+
onClick={() => actions.changeTab(Tab.State)}
55+
>
56+
<FaDatabase />
57+
</button>
58+
</Tooltip>
6159
<Tooltip text="Actions">
6260
<button
6361
className={css(

0 commit comments

Comments
 (0)