@@ -1,62 +1,73 @@
1import { useCallback, useState } from 'react';
1import { useCallback, useState } from 'react';
2−import ob from 'urbit-ob';
4−import SolarisClient from 'lib/SolarisClient';
5−import useDeepEqualReference from './useDeepEqualReference';
7const STATE = {
3const STATE = {
8− NOT_FOUND: 'NOT_FOUND',
4+ // container states
9 RUNNING: 'RUNNING',
7 RUNNING: 'RUNNING',
10+ QUERYING: 'QUERYING',
10 BOOTING: 'BOOTING',
11 BOOTING: 'BOOTING',
11 CONNECTING: 'CONNECTING',
12 CONNECTING: 'CONNECTING',
12 CONNECTED: 'CONNECTED',
14 CONNECTED: 'CONNECTED',
16−export function useHostedShip(point, endpoint = 'http://localhost:3030') {
17+export function useHostedShip(client, patp) {
17− const patp = ob.patp(point.value);
18− const client = new SolarisClient(endpoint);
20 const [state, setState] = useState(STATE.UNKNOWN);
18 const [state, setState] = useState(STATE.UNKNOWN);
21− const [events, setEvents] = useState([]);
22− const [error, _setError] = useState();
20+ const [sysEvents, setSysEvents] = useState([]);
21+ const [newEvents, setNewEvents] = useState([]);
22+ const [runEvents, setRunEvents] = useState([]);
24+ const [error, _setError] = useState();
24 const setError = useCallback(
25 const setError = useCallback(
25 error => {
26 error => {
26 _setError(error);
27 _setError(error);
27− setState(STATE.UNKNOWN);
28 if (error) {
28 if (error) {
29+ setState(STATE.UNKNOWN);
29 console.error(error);
30 console.error(error);
32− [_setError]
33+ [_setError, setState]
35− const addEvent = event => {
36+ const unknown = state === STATE.UNKNOWN;
36− setEvents(current => current.push(event));
39− const notFound = state === STATE.NOT_FOUND;
37+ const missing = state === STATE.MISSING;
40 const running = state === STATE.RUNNING;
38 const running = state === STATE.RUNNING;
39+ const pending = state === STATE.PENDING;
40+ const querying = state === STATE.QUERYING;
41 const booting = state === STATE.BOOTING;
41 const booting = state === STATE.BOOTING;
42 const connecting = state === STATE.CONNECTING;
42 const connecting = state === STATE.CONNECTING;
43 const connected = state === STATE.CONNECTED;
43 const connected = state === STATE.CONNECTED;
44− const unknown = state === STATE.UNKNOWN;
45+ const resetEvents = useCallback(() => {
46− const checkShipExists = useCallback(async () => {
51+ const getStatus = useCallback(async () => {
48 setError(undefined);
53 setError(undefined);
57+ setState(STATE.QUERYING);
50 const response = await client.getShipsByPatp(patp);
59 const response = await client.getShipsByPatp(patp);
52 if (response.status === 404) {
61 if (response.status === 404) {
53− setState(STATE.NOT_FOUND);
62+ setState(STATE.MISSING);
54 } else if (!response.ok) {
63 } else if (!response.ok) {
55 setError(response.statusText);
64 setError(response.statusText);
57 const ship = await response.json();
66 const ship = await response.json();
59− if (ship.status === 'Running') {
68+ if (ship.status === 'Pending') {
69+ setState(STATE.PENDING);
70+ } else if (ship.status === 'Running') {
60 setState(STATE.RUNNING);
71 setState(STATE.RUNNING);
62 setError(ship);
73 setError(ship);
@@ -65,44 +76,47 @@ export function useHostedShip(point, endpoint = 'http://localhost:3030') {
65 } catch (error) {
76 } catch (error) {
66 setError(error);
77 setError(error);
68− }, [client, patp, setError]);
79+ }, [client, patp, resetEvents, setError]);
70− const getShipEvents = useCallback(async () => {
81+ const getEvents = useCallback(() => {
72 setError(undefined);
83 setError(undefined);
73− setState(STATE.CONNECTING);
75− const response = await client.getShipsByPatpEvents(patp);
85+ resetEvents();
77− if (!response.ok) {
87+ setState(STATE.CONNECTING);
78− setError(response.statusText);
88+
79− } else {
89+ const url = client.getShipsByPatpUrl(patp) + '/events';
80− const reader = response.body.getReader();
90+ const source = new EventSource(url);
82− reader.read().then(function yieldEvent({ done, value }) {
83− setState(STATE.CONNECTED);
92+ source.onopen = () => setState(STATE.CONNECTED);
93+ // source.onerror = () => setState(STATE.UNKNOWN);
94+ // source.onmessage = console.log;
85− // Result objects contain two properties:
96+ source.addEventListener('sys', event => {
86− // done - true if the stream has already given you all its data.
97+ setSysEvents(previous => [...previous, JSON.parse(event.data)]);
87− // value - some data. Always undefined when done is true.
92− addEvent(JSON.parse(value));
100+ source.addEventListener('new', event => {
101+ if (event.data !== '') {
102+ setNewEvents(previous => [...previous, event.data]);
94− // Read some more, and call this function again
106+ source.addEventListener('run', event => {
95− return reader.read().then(yieldEvent);
107+ if (event.data !== '') {
108+ setRunEvents(previous => [...previous, event.data]);
98 } catch (error) {
111 } catch (error) {
99 setError(error);
112 setError(error);
101− }, [client, patp, setError]);
114+ }, [setError, resetEvents, client, patp, setState]);
103− const createNewShip = useCallback(async () => {
116+ const create = useCallback(async () => {
105 setError(undefined);
118 setError(undefined);
106 setState(STATE.BOOTING);
120 setState(STATE.BOOTING);
108 const response = await client.postShips({
122 const response = await client.postShips({
@@ -113,26 +127,33 @@ export function useHostedShip(point, endpoint = 'http://localhost:3030') {
113 if (!response.ok) {
127 if (!response.ok) {
114 setError(response.statusText);
128 setError(response.statusText);
116− checkShipExists();
130+ getEvents();
118 } catch (error) {
132 } catch (error) {
119 setError(error);
133 setError(error);
121− }, [checkShipExists, client, patp, setError]);
135+ }, [setError, client, patp, getEvents]);
123− const values = useDeepEqualReference({
137+ return {
125− notFound,
139+ unknown,
128 connecting,
145 connecting,
129 connected,
146 connected,
137− return { ...values, bind: values };
148+ sysEvents,