on 8d566ea help sign in
bridge/src/store/lib/useHostingStore.js
238 lines 6.3 kB history raw
1import { useState, useCallback, useMemo } from 'react';
2import { Just, Nothing } from 'folktale/maybe';
3import * as ob from 'urbit-ob';
5import { getVaneName, getVaneNumber } from 'lib/hosting';
6import SolarisClient from 'lib/SolarisClient';
7// import { usePointCursor } from 'store/pointCursor';
8import useKeyfileGenerator from 'lib/useKeyfileGenerator';
9const STATE = {
10 // container states
11 UNKNOWN: 'UNKNOWN',
12 MISSING: 'MISSING',
13 RUNNING: 'RUNNING',
14 PENDING: 'PENDING',
15};
17function useHostingStore(url) {
18 const client = new SolarisClient(url);
20 // const { pointCursor } = usePointCursor();
21 //
22 const pointCursor = Just(ob.patp2dec('~wicdev-wisryt'));
24 const [bootProgress, setBootProgress] = useState(0);
25 const [bootMessage, setBootMessage] = useState('Assembling Urbit');
26 const [startTime] = useState(Date.now());
28 const [status, _setStatus] = useState(STATE.UNKNOWN);
29 const setStatus = useCallback(
30 s => {
31 console.log(s);
32 _setStatus(s);
33 },
34 [_setStatus]
35 );
37 const [sysEvents, setSysEvents] = useState([]);
38 const [newEvents, setNewEvents] = useState([]);
39 const [runEvents, setRunEvents] = useState([]);
41 const [error, _setError] = useState();
42 const setError = useCallback(
43 error => {
44 _setError(error);
45 if (error) {
46 setStatus(STATE.UNKNOWN);
47 console.error(error);
48 }
49 },
50 [_setError, setStatus]
51 );
53 const unknown = status === STATE.UNKNOWN;
54 const missing = status === STATE.MISSING;
55 const running = status === STATE.RUNNING;
56 const pending = status === STATE.PENDING;
58 let syncStatus;
60 const resetEvents = useCallback(() => {
61 setSysEvents([]);
62 setNewEvents([]);
63 setRunEvents([]);
64 }, [setSysEvents, setNewEvents, setRunEvents]);
66 const getEvents = useCallback(() => {
67 try {
68 if (Nothing.hasInstance(pointCursor)) {
69 return;
70 }
71 const patp = ob.patp(pointCursor.value);
72 setError(undefined);
74 resetEvents();
76 const url = client.getShipsByPatpUrl(patp) + '/events';
77 const source = new EventSource(url);
79 // source.onerror = () => setStatus(STATE.UNKNOWN);
80 // source.onmessage = console.log;
82 source.addEventListener('sys', event => {
83 // console.log(event);
84 const sysEvent = JSON.parse(event.data);
85 const time = new Date(sysEvent.object.firstTimestamp).getTime();
86 if (time > startTime) {
87 console.log(sysEvent);
88 setSysEvents(previous => [...previous, sysEvent]);
89 }
90 });
92 source.addEventListener('new', event => {
93 // console.log(event);
94 const elapsed = (Date.now() - startTime) / 1000;
95 if (event.data !== '') {
96 setNewEvents(previous => [...previous, event.data]);
97 }
98 if (event.data === '1-b') {
99 setBootMessage('Compiling Hoon');
100 setBootProgress(0.2);
101 console.log(`${elapsed}: compiling Hoon`);
102 } else if (event.data === '1-c') {
103 setBootProgress(0.25);
104 } else if (event.data === '%arvo-assembly') {
105 setBootMessage('Compiling Urbit OS');
106 setBootProgress(0.3);
107 } else if (event.data.startsWith('[%vane %')) {
108 const vane = getVaneName(event.data.slice(8, 9));
109 setBootMessage(`Compiling vane: ${vane}`);
110 setBootProgress(0.3 + 0.05 * getVaneNumber(event.data.slice(8, 9)));
111 } else if (event.data === 'pier: boot complete') {
112 setBootMessage('Ship starting');
113 setBootProgress(0.85);
114 }
115 });
117 source.addEventListener('run', event => {
118 if (event.data === 'goad: recompiling all apps') {
119 setBootProgress(1.0);
120 setBootMessage('Ship Launched');
121 syncStatus();
122 }
123 if (event.data !== '') {
124 setRunEvents(previous => [...previous, event.data]);
125 }
126 });
127 } catch (error) {
128 setError(error);
129 }
130 }, [
131 setError,
132 resetEvents,
133 client,
134 pointCursor,
135 setBootMessage,
136 startTime,
137 syncStatus,
138 ]);
140 syncStatus = useCallback(async () => {
141 try {
142 if (Nothing.hasInstance(pointCursor)) {
143 return;
144 }
145 const patp = ob.patp(pointCursor.value);
146 setError(undefined);
148 resetEvents();
150 const response = await client.getShipsByPatp(patp);
152 if (response.status === 404) {
153 setStatus(STATE.MISSING);
154 } else if (!response.ok) {
155 setError(response.statusText);
156 } else {
157 const ship = await response.json();
159 if (ship.status === 'Pending') {
160 setStatus(STATE.PENDING);
161 getEvents();
162 } else if (ship.status === 'Running') {
163 setStatus(STATE.RUNNING);
164 } else {
165 setError(ship);
166 }
167 }
168 } catch (error) {
169 setError(error);
170 }
171 }, [client, getEvents, pointCursor, resetEvents, setError, setStatus]);
173 const hostedShipUrl = useMemo(
174 () =>
175 `http://${ob.patp(pointCursor.getOrElse('')).slice(1)}.liam.tlon.network`,
176 [pointCursor]
177 );
179 const create = useCallback(
180 async keyfile => {
181 try {
182 if (Nothing.hasInstance(pointCursor)) {
183 return;
184 }
185 keyfile =
186 '0wnE.Z56pm.i2HLZ.6Pf1R.tAVZH.65R~C.Zgy6y.caI5Z.bZ2vV.09M5A.QP5-p.29UfR.35h2U.2k8-D.QP~~p.6bL62.~x3Em.t9h0x.0y01N.w80c1';
187 const patp = ob.patp(pointCursor.value).slice(1);
188 setError(undefined);
190 const start = Date.now();
191 console.log(start);
192 setStatus(STATE.PENDING);
193 setBootProgress(0.1);
195 const response = await client.postShips({
196 patp,
197 key: keyfile,
198 debug: true,
199 fake: false,
200 });
202 if (!response.ok) {
203 setError(response.statusText);
204 } else {
205 getEvents();
206 }
207 } catch (error) {
208 setError(error);
209 }
210 },
211 [pointCursor, setError, setStatus, client, getEvents]
212 );
214 return {
215 error,
216 unknown,
217 missing,
218 running,
219 pending,
220 url: hostedShipUrl,
222 sysEvents,
223 newEvents,
224 runEvents,
226 syncStatus,
227 getEvents,
228 create,
230 bootProgress,
231 bootMessage,
233 // debugging
234 status,
235 };
238export default useHostingStore;