@@ -0,0 +1,138 @@
1+import { useCallback, useState } from 'react';
2+import ob from 'urbit-ob';
3+
4+import SolarisClient from 'lib/SolarisClient';
5+import useDeepEqualReference from './useDeepEqualReference';
6+
7+const STATE = {
8+ NOT_FOUND: 'NOT_FOUND',
9+ RUNNING: 'RUNNING',
10+ BOOTING: 'BOOTING',
11+ CONNECTING: 'CONNECTING',
12+ CONNECTED: 'CONNECTED',
13+ UNKNOWN: 'UNKNOWN',
14+};
15+
16+export function useHostedShip(point, endpoint = 'http://localhost:3030') {
17+ const patp = ob.patp(point.value);
18+ const client = new SolarisClient(endpoint);
19+
20+ const [state, setState] = useState(STATE.UNKNOWN);
21+ const [events, setEvents] = useState([]);
22+ const [error, _setError] = useState();
23+
24+ const setError = useCallback(
25+ error => {
26+ _setError(error);
27+ setState(STATE.UNKNOWN);
28+ if (error) {
29+ console.error(error);
30+ }
31+ },
32+ [_setError]
33+ );
34+
35+ const addEvent = event => {
36+ setEvents(current => current.push(event));
37+ };
38+
39+ const notFound = state === STATE.NOT_FOUND;
40+ const running = state === STATE.RUNNING;
41+ const booting = state === STATE.BOOTING;
42+ const connecting = state === STATE.CONNECTING;
43+ const connected = state === STATE.CONNECTED;
44+ const unknown = state === STATE.UNKNOWN;
45+
46+ const checkShipExists = useCallback(async () => {
47+ try {
48+ setError(undefined);
49+
50+ const response = await client.getShipsByPatp(patp);
51+
52+ if (response.status === 404) {
53+ setState(STATE.NOT_FOUND);
54+ } else if (!response.ok) {
55+ setError(response.statusText);
56+ } else {
57+ const ship = await response.json();
58+
59+ if (ship.status === 'Running') {
60+ setState(STATE.RUNNING);
61+ } else {
62+ setError(ship);
63+ }
64+ }
65+ } catch (error) {
66+ setError(error);
67+ }
68+ }, [client, patp, setError]);
69+
70+ const getShipEvents = useCallback(async () => {
71+ try {
72+ setError(undefined);
73+ setState(STATE.CONNECTING);
74+
75+ const response = await client.getShipsByPatpEvents(patp);
76+
77+ if (!response.ok) {
78+ setError(response.statusText);
79+ } else {
80+ const reader = response.body.getReader();
81+
82+ reader.read().then(function yieldEvent({ done, value }) {
83+ setState(STATE.CONNECTED);
84+
85+ // Result objects contain two properties:
86+ // done - true if the stream has already given you all its data.
87+ // value - some data. Always undefined when done is true.
88+ if (done) {
89+ return;
90+ }
91+
92+ addEvent(JSON.parse(value));
93+
94+ // Read some more, and call this function again
95+ return reader.read().then(yieldEvent);
96+ });
97+ }
98+ } catch (error) {
99+ setError(error);
100+ }
101+ }, [client, patp, setError]);
102+
103+ const createNewShip = useCallback(async () => {
104+ try {
105+ setError(undefined);
106+ setState(STATE.BOOTING);
107+
108+ const response = await client.postShips({
109+ patp,
110+ key: '123',
111+ });
112+
113+ if (!response.ok) {
114+ setError(response.statusText);
115+ } else {
116+ checkShipExists();
117+ }
118+ } catch (error) {
119+ setError(error);
120+ }
121+ }, [checkShipExists, client, patp, setError]);
122+
123+ const values = useDeepEqualReference({
124+ error,
125+ notFound,
126+ running,
127+ booting,
128+ connecting,
129+ connected,
130+ unknown,
131+ events,
132+ checkShipExists,
133+ getShipEvents,
134+ createNewShip,
135+ });
136+
137+ return { ...values, bind: values };
138+}