Skip to content

Commit b974313

Browse files
committed
add config to use rabbitmq for remote runtime
1 parent 4797ba2 commit b974313

File tree

5 files changed

+169
-48
lines changed

5 files changed

+169
-48
lines changed

README.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,24 @@ npm install -g ijavascript
9898
ijsinstall
9999
```
100100

101+
# Using remote runtime
102+
103+
In the runtime section in the sidebar, you can add a new runtime. For the runtime, you need to specify the two addresses: the websocket address for sending code to server, and the MQ address for receiving output. If MQ address is empty, the websocket will be used.
104+
105+
The default runtime is the local runtime, which is `localhost:14321`
106+
107+
To start the server, on the server machine, you need to setup the kernels. Then, you need to clone this repo, go into the cpkernel folder, and do:
108+
109+
1. `docker-compose up -d`. This will setup a rabbitmq server. The MQ address is `:15674`
110+
2. `npm run kernel-server`. This will run the server. The websocket address is `:14321`
111+
112+
So to use this server, enter:
113+
114+
- `<your-server-ip>:14321` for the socket address
115+
- `<your-server-ip>:15674` for the MQ address
116+
117+
We can spawn a docker container on the server for the kernels. However, it will be tricky to access files and install packages. One has to install packages for every restart of the kernel, and one has to mount a volume to exchange files between the server and the container. Thus we think it is a better experience to use the bare-metal server.
118+
101119
# Development Scripts
102120

103121
Develop

ui/src/components/repo/sidebar.js

Lines changed: 137 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -118,13 +118,133 @@ function SidebarSession() {
118118
);
119119
}
120120

121+
function RuntimeItem({ socketAddress, mqAddress }) {
122+
const [edit, setEdit] = useState(false);
123+
const [addr1, setAddr1] = useState(socketAddress);
124+
const [addr2, setAddr2] = useState(mqAddress);
125+
const dispatch = useDispatch();
126+
const activeRuntime = useSelector((state) => state.repo.activeRuntime);
127+
let reponame = useSelector((state) => state.repo.reponame);
128+
const repoConfig = useSelector((state) => state.repo.repoConfig);
129+
const [updateRepoConfig, {}] = useMutation(
130+
gql`
131+
mutation UpdateRepoConfig($reponame: String, $config: String) {
132+
updateRepoConfig(name: $reponame, config: $config)
133+
}
134+
`,
135+
{ refetchQueries: ["RepoConfig"] }
136+
);
137+
return (
138+
<Stack key={socketAddress} direction="row" alignItems="center">
139+
<Radio
140+
checked={
141+
JSON.stringify([socketAddress, mqAddress]) ==
142+
JSON.stringify(activeRuntime)
143+
}
144+
onChange={() => {
145+
dispatch(wsActions.wsDisconnect());
146+
dispatch(
147+
repoSlice.actions.activateRuntime([socketAddress, mqAddress])
148+
);
149+
// dispatch(wsActions.wsConnect());
150+
}}
151+
value="a"
152+
name="radio-buttons"
153+
inputProps={{ "aria-label": "A" }}
154+
/>
155+
{edit ? (
156+
<Box sx={{ display: "flex", flexDirection: "column" }}>
157+
<TextField
158+
size="small"
159+
value={addr1}
160+
onChange={(e) => {
161+
setAddr1(e.target.value);
162+
}}
163+
></TextField>
164+
<TextField
165+
size="small"
166+
value={addr2}
167+
onChange={(e) => {
168+
setAddr2(e.target.value);
169+
}}
170+
></TextField>
171+
<Button
172+
onClick={() => {
173+
updateRepoConfig({
174+
variables: {
175+
reponame,
176+
config: JSON.stringify({
177+
runtimes: produce(repoConfig.runtimes, (draft) => {
178+
let idx = draft.findIndex(
179+
([addr1, addr2]) => addr1 === socketAddress
180+
);
181+
draft[idx] = [addr1, addr2];
182+
}),
183+
}),
184+
},
185+
});
186+
setEdit(false);
187+
}}
188+
>
189+
Save
190+
</Button>
191+
<Button
192+
onClick={() => {
193+
setAddr1(socketAddress);
194+
setAddr2(mqAddress);
195+
setEdit(false);
196+
}}
197+
>
198+
Cancel
199+
</Button>
200+
</Box>
201+
) : (
202+
<Box>
203+
<Box fontSize="small">{socketAddress}</Box>
204+
{mqAddress && <Box fontSize="small">{mqAddress}</Box>}
205+
</Box>
206+
)}
207+
208+
{!edit && socketAddress !== "localhost:14321" && (
209+
<Box>
210+
<IconButton
211+
// onClick={() => {
212+
// updateRepoConfig({
213+
// variables: {
214+
// reponame,
215+
// config: JSON.stringify({
216+
// runtimes: produce(repoConfig.runtimes, (draft) => {
217+
// let idx = draft.findIndex(
218+
// ([addr1, addr2]) => addr1 === socketAddress
219+
// );
220+
// draft.splice(idx, 1);
221+
// }),
222+
// }),
223+
// },
224+
// });
225+
// }}
226+
>
227+
<DeleteForeverTwoToneIcon sx={{ fontSize: 15, color: "red" }} />
228+
</IconButton>
229+
<Button
230+
onClick={() => {
231+
setEdit(true);
232+
}}
233+
>
234+
Edit
235+
</Button>
236+
</Box>
237+
)}
238+
</Stack>
239+
);
240+
}
241+
121242
function SidebarRuntime() {
122243
const sessionRuntime = useSelector((state) => state.repo.sessionRuntime);
123244
const runtimeConnected = useSelector((state) => state.repo.runtimeConnected);
124245
// const runtimes = useSelector((state) => state.repo.runtimes);
125-
const activeRuntime = useSelector((state) => state.repo.activeRuntime);
126-
let reponame = useSelector((state) => state.repo.reponame);
127246

247+
let reponame = useSelector((state) => state.repo.reponame);
128248
const [updateRepoConfig, {}] = useMutation(
129249
gql`
130250
mutation UpdateRepoConfig($reponame: String, $config: String) {
@@ -151,54 +271,28 @@ function SidebarRuntime() {
151271
variables: {
152272
reponame,
153273
config: JSON.stringify({
154-
runtimes: Object.assign(
155-
{ [value]: true },
156-
repoConfig.runtimes
157-
),
274+
runtimes: produce(repoConfig.runtimes, (draft) => {
275+
draft[value] = true;
276+
}),
158277
}),
159278
},
160279
});
161280
}}
162281
>
163282
Add
164283
</ClickInputButton>
165-
{/* <Box>{JSON.stringify(runtimes)}</Box> */}
166-
{Object.entries(
167-
Object.assign({ "localhost:14321": false }, repoConfig?.runtimes)
168-
).map(([address, canDelete]) => (
169-
<Stack key={address} direction="row" alignItems="center">
170-
<Radio
171-
checked={address === activeRuntime}
172-
onChange={() => {
173-
dispatch(wsActions.wsDisconnect());
174-
dispatch(repoSlice.actions.activateRuntime(address));
175-
// dispatch(wsActions.wsConnect());
176-
}}
177-
value="a"
178-
name="radio-buttons"
179-
inputProps={{ "aria-label": "A" }}
180-
/>
181-
<Box fontSize="small">{address}</Box>
182-
{canDelete && (
183-
<IconButton
184-
onClick={() => {
185-
updateRepoConfig({
186-
variables: {
187-
reponame,
188-
config: JSON.stringify({
189-
runtimes: produce(repoConfig.runtimes, (draft) => {
190-
delete draft[address];
191-
}),
192-
}),
193-
},
194-
});
195-
}}
196-
>
197-
<DeleteForeverTwoToneIcon sx={{ fontSize: 15, color: "red" }} />
198-
</IconButton>
199-
)}
200-
</Stack>
201-
))}
284+
<Button
285+
onClick={() => {
286+
dispatch(repoSlice.actions.addRuntime());
287+
}}
288+
>
289+
+
290+
</Button>
291+
{[["localhost:14321", ""]]
292+
.concat(repoConfig?.runtimes || [])
293+
.map(([address, mqAddress]) => (
294+
<RuntimeItem socketAddress={address} mqAddress={mqAddress} />
295+
))}
202296
</Box>
203297
<Box>
204298
Runtime connected?{" "}

ui/src/lib/reducers/runtime.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,15 @@ export default {
1212
state.pods[id].error = null;
1313
});
1414
},
15-
1615
setRunning: (state, action) => {
1716
let id = action.payload;
1817
state.pods[id].running = true;
1918
},
2019
activateRuntime: (state, action) => {
2120
state.activeRuntime = action.payload;
2221
},
22+
addRuntime: (state, action) => {
23+
// socket address, MQ address, editing
24+
state.repoConfig.runtimes.push(["", ""]);
25+
},
2326
};

ui/src/lib/store.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ const initialState = {
132132
// sessionId: nanoid(),
133133
sessionId: null,
134134
sessionRuntime: {},
135-
activeRuntime: "localhost:14321",
135+
activeRuntime: ["localhost:14321", ""],
136136
runtimeConnected: false,
137137
kernels: {
138138
julia: {

ui/src/lib/ws/middleware.js

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -531,7 +531,7 @@ const socketMiddleware = () => {
531531
// socket_url = `ws://localhost:14321`;
532532
// socket_url = `ws://192.168.1.142:14321`;
533533
// FIXME variable not ready?
534-
socket_url = `ws://${store.getState().repo.activeRuntime}`;
534+
socket_url = `ws://${store.getState().repo.activeRuntime[0]}`;
535535
} else if (window.location.protocol === "http:") {
536536
socket_url = `ws://${window.location.host}/ws`;
537537
} else {
@@ -541,9 +541,12 @@ const socketMiddleware = () => {
541541
socket = new WebSocket(socket_url);
542542
// socket.emit("spawn", state.sessionId, lang);
543543

544-
if (!window.codepodio) {
544+
if (!store.getState().repo.activeRuntime[1]) {
545+
// If the mqAddress is not supplied, use the websocket
545546
socket.onmessage = onMessage(store);
546547
} else {
548+
// otherwise, use the mqAddress
549+
547550
// if (mq_client) {
548551
// mq_client.disconnect()
549552
// }
@@ -554,10 +557,13 @@ const socketMiddleware = () => {
554557
// "ws://codepod.test/ws"
555558
// "ws://mq.codepod.test/ws"
556559
// FIXME why have to use /ws suffix?
557-
mq_url = `ws://mq.${window.location.host}/ws`;
560+
// mq_url = `ws://mq.${window.location.host}/ws`;
561+
// mq_url = `ws://192.168.1.142:15674/ws`;
562+
mq_url = `ws://${store.getState().repo.activeRuntime[1]}/ws`;
558563
} else {
559564
mq_url = `wss://mq.${window.location.host}/ws`;
560565
}
566+
console.log("connecting to MQ:", mq_url);
561567
mq_client = Stomp.over(new WebSocket(mq_url));
562568
// remove debug messages
563569
mq_client.debug = () => {};

0 commit comments

Comments
 (0)