Skip to content

Commit 1a3bb23

Browse files
feat: use websocket for client server communication (previously enabled by EXPERIMENTAL_WS_API) (#225)
* refactor: use websocket for client server communication * chore: log deprecated feature usages * docs: update documentation * docs: rephrase Co-authored-by: Robin Le Caignec <[email protected]> --------- Co-authored-by: Robin Le Caignec <[email protected]>
1 parent bcf0faa commit 1a3bb23

File tree

8 files changed

+123
-143
lines changed

8 files changed

+123
-143
lines changed

api/README.md

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,27 @@
22

33
This API is a Node.js server that will be running on a Linux VM.
44

5-
It is composed of one endpoint:
6-
7-
- `/sconify`:
8-
9-
- Takes a public dockerhub image as input and a user auth token with push
10-
access to the image's repo in order to push the sconified image,
11-
- builds a sconified image out of it,
12-
- publishes it to dockerhub with tag suffix,
13-
- deploys an app contract on Bellecour.
14-
15-
- `/` or any other endpoint: will return a simple text (mostly to check if the
16-
server is running)
5+
The API is composed of:
6+
7+
- HTTP endpoints:
8+
9+
- 🟢 `GET /`: will return a simple text (mostly to check if the server is
10+
running)
11+
- 🟢 `GET /health`: will return a JSON object with the health status of the
12+
server and the version of the API.
13+
- 🟠 `POST /sconify`: deprecated, use Websocket API request `SCONIFY_BUILD`
14+
instead.
15+
- 🟠 `POST /sconify/build`: deprecated, use Websocket API request
16+
`SCONIFY_BUILD` instead.
17+
18+
- Websocket API requests:
19+
- 🟢 `SCONIFY_BUILD`: will take a dockerhub image and return a
20+
`sconifiedImage` and `appContractAddress` in the response.
21+
- Takes a public dockerhub image as input and a user auth token with push
22+
access to the image's repo in order to push the sconified image
23+
- builds a sconified image out of it
24+
- publishes it to dockerhub with tag suffix
25+
- 🟠 `SCONIFY`: deprecated, use `SCONIFY_BUILD` instead.
1726

1827
## Prerequisites
1928

@@ -41,3 +50,14 @@ npm run start
4150
```sh
4251
npm run dev:pretty
4352
```
53+
54+
## deprecations
55+
56+
- `POST /sconify` is deprecated, websocket API request `SCONIFY_BUILD` should be
57+
used instead.
58+
- `POST /sconify/build` is deprecated, websocket API request `SCONIFY_BUILD`
59+
should be used instead.
60+
- websocket API request `SCONIFY` is deprecated, websocket API request
61+
`SCONIFY_BUILD` should be used instead.
62+
- template `Python` is deprecated, template `Python3.13` should be used instead.
63+
- sconeVersion `v5` is deprecated, sconeVersion `v5.9` should be used instead.

api/src/constants/constants.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,14 @@ export const TEMPLATE_CONFIG: Record<
3333
JavaScript: {
3434
// node binary name does not change from one version to another
3535
binary: '/usr/local/bin/node',
36-
// for scone 5.7 this was necessary
36+
// deprecated for scone 5.7 this was necessary
3737
sconeCuratedImage:
3838
'registry.scontain.com:5050/sconecuratedimages/node:14.4.0-alpine3.11',
3939
},
4040
'Python3.13': {
4141
binary: '/usr/local/bin/python3.13',
4242
},
43-
// legacy template name Python used Python 3.8
43+
// deprecated legacy template name Python used Python 3.8
4444
Python: {
4545
binary: '/usr/local/bin/python3.8',
4646
},

api/src/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { requestIdMiddleware } from './utils/requestId.js';
1010
import { errorHandlerMiddleware } from './utils/errors.js';
1111
import { attachWebSocketServer } from './utils/websocket.js';
1212
import {
13-
sconifyBuildHttpHandler,
13+
deprecated_sconifyBuildHttpHandler,
1414
sconifyBuildWsHandler,
1515
} from './sconify/sconifyBuild.handler.js';
1616

@@ -34,7 +34,7 @@ app.use(loggerMiddleware);
3434
// deprecated endpoint, clients should use /sconify/build
3535
app.post('/sconify', deprecated_sconifyHttpHandler);
3636

37-
app.post('/sconify/build', sconifyBuildHttpHandler);
37+
app.post('/sconify/build', deprecated_sconifyBuildHttpHandler);
3838

3939
// Health endpoint
4040
app.get('/health', (req, res) => {

api/src/sconify/deprecated_sconify.handler.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { TEMPLATE_CONFIG, type TemplateName } from '../constants/constants.js';
44
import { ethereumAddressZodSchema } from '../utils/ethereumAddressZodSchema.js';
55
import { deprecated_sconify } from './deprecated_sconify.service.js';
66
import type { Request, Response } from 'express';
7+
import { logger } from '../utils/logger.js';
78

89
const bodySchema = z.object({
910
yourWalletPublicAddress: ethereumAddressZodSchema,
@@ -25,7 +26,7 @@ const bodySchema = z.object({
2526
.default('JavaScript'),
2627
});
2728

28-
async function handleSconifyRequest(requestObj: object) {
29+
async function deprecated_handleSconifyRequest(requestObj: object) {
2930
let yourWalletPublicAddress;
3031
let dockerhubImageToSconify;
3132
let dockerhubPushToken;
@@ -54,18 +55,19 @@ async function handleSconifyRequest(requestObj: object) {
5455
}
5556

5657
export async function deprecated_sconifyWsHandler(message: object) {
58+
logger.warn('deprecated feature hit: ws request SCONIFY');
5759
const { sconifiedImage, appContractAddress } =
58-
await handleSconifyRequest(message);
60+
await deprecated_handleSconifyRequest(message);
5961
return { sconifiedImage, appContractAddress };
6062
}
6163

6264
export async function deprecated_sconifyHttpHandler(
6365
req: Request,
6466
res: Response
6567
) {
66-
const { sconifiedImage, appContractAddress } = await handleSconifyRequest(
67-
req.body || {}
68-
);
68+
logger.warn('deprecated feature hit: POST /sconify');
69+
const { sconifiedImage, appContractAddress } =
70+
await deprecated_handleSconifyRequest(req.body || {});
6971
res.status(200).json({
7072
success: true,
7173
sconifiedImage,

api/src/sconify/sconifyBuild.handler.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
import { ethereumAddressZodSchema } from '../utils/ethereumAddressZodSchema.js';
99
import { sconify } from './sconifyBuild.service.js';
1010
import type { Request, Response } from 'express';
11+
import { logger } from '../utils/logger.js';
1112

1213
const bodySchema = z.object({
1314
yourWalletPublicAddress: ethereumAddressZodSchema,
@@ -51,6 +52,13 @@ async function handleSconifyRequest(requestObj: object) {
5152
}),
5253
});
5354
}
55+
if (template === 'Python') {
56+
logger.warn('Deprecated feature hit: template === "Python"');
57+
}
58+
if (sconeVersion === 'v5') {
59+
logger.warn('Deprecated feature hit: sconeVersion === "v5"');
60+
}
61+
5462
const { dockerImage, dockerImageDigest, fingerprint, entrypoint } =
5563
await sconify({
5664
dockerImageToSconify: dockerhubImageToSconify,
@@ -85,7 +93,11 @@ export async function sconifyBuildWsHandler(message: object) {
8593
};
8694
}
8795

88-
export async function sconifyBuildHttpHandler(req: Request, res: Response) {
96+
export async function deprecated_sconifyBuildHttpHandler(
97+
req: Request,
98+
res: Response
99+
) {
100+
logger.warn('Deprecated feature hit: POST /sconify/build');
89101
const {
90102
dockerImage,
91103
dockerImageDigest,

cli/src/config/config.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import { useExperimentalNetworks } from '../utils/featureFlags.js';
33
export const SCONE_TAG = ['tee', 'scone'];
44
export const DEFAULT_SCONE_VERSION = 'v5.9';
55

6-
export const SCONIFY_API_HTTP_URL = 'https://iapp-api.iex.ec';
76
export const SCONIFY_API_WS_URL = 'wss://iapp-api.iex.ec';
87

98
export const CONFIG_FILE = 'iapp.config.json';

cli/src/utils/featureFlags.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import chalk from 'chalk';
22

3-
export const useWsApi = checkFlag('EXPERIMENTAL_WS_API');
43
export const useTdx = checkFlag('EXPERIMENTAL_TDX_APP');
54
export const useExperimentalNetworks = checkFlag('EXPERIMENTAL_NETWORKS');
65

cli/src/utils/sconify.ts

Lines changed: 67 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,4 @@
1-
import {
2-
DEFAULT_SCONE_VERSION,
3-
SCONIFY_API_HTTP_URL,
4-
SCONIFY_API_WS_URL,
5-
} from '../config/config.js';
1+
import { DEFAULT_SCONE_VERSION, SCONIFY_API_WS_URL } from '../config/config.js';
62
import { getAuthToken } from './dockerhub.js';
73
import { sleep } from './sleep.js';
84
import {
@@ -11,7 +7,6 @@ import {
117
serializeData,
128
} from './websocket.js';
139
import { debug } from './debug.js';
14-
import { useWsApi } from './featureFlags.js';
1510

1611
const INITIAL_RETRY_PERIOD = 20 * 1000; // 20s
1712

@@ -56,133 +51,86 @@ export async function sconify({
5651

5752
const pushToken = await getPushToken();
5853

59-
let sconifyResult: {
54+
const sconifyResult: {
6055
dockerImage?: string;
6156
dockerImageDigest?: string;
6257
entrypoint?: string;
6358
fingerprint?: string;
6459
sconeVersion?: string;
65-
};
66-
67-
if (useWsApi) {
68-
// experimental ws connection
69-
sconifyResult = await new Promise((resolve, reject) => {
70-
createReconnectingWs(SCONIFY_API_WS_URL, {
71-
headers: {
72-
'x-wallet': walletAddress,
73-
},
74-
connectCallback: (ws) => {
75-
const handleError = (e: unknown) => {
76-
ws.close(1000); // normal ws close
77-
reject(e);
78-
};
60+
} = await new Promise((resolve, reject) => {
61+
createReconnectingWs(SCONIFY_API_WS_URL, {
62+
headers: {
63+
'x-wallet': walletAddress,
64+
},
65+
connectCallback: (ws) => {
66+
const handleError = (e: unknown) => {
67+
ws.close(1000); // normal ws close
68+
reject(e);
69+
};
7970

80-
ws.on('message', (data) => {
81-
let message;
82-
// handle communication errors
83-
try {
84-
message = deserializeData(data);
85-
debug(`ws message: ${JSON.stringify(message, undefined, 2)}`);
86-
} catch (e) {
87-
handleError(e);
88-
}
71+
ws.on('message', (data) => {
72+
let message;
73+
// handle communication errors
74+
try {
75+
message = deserializeData(data);
76+
debug(`ws message: ${JSON.stringify(message, undefined, 2)}`);
77+
} catch (e) {
78+
handleError(e);
79+
}
8980

90-
// handle server responses
91-
if (message?.type === 'RESPONSE') {
92-
if (message?.target === 'SCONIFY_BUILD') {
93-
ws.close(1000); // normal ws close
94-
if (message?.success === true && message.result) {
95-
resolve(message.result);
96-
} else {
97-
reject(Error(message.error || 'Server unknown error'));
98-
}
81+
// handle server responses
82+
if (message?.type === 'RESPONSE') {
83+
if (message?.target === 'SCONIFY_BUILD') {
84+
ws.close(1000); // normal ws close
85+
if (message?.success === true && message.result) {
86+
resolve(message.result);
87+
} else {
88+
reject(Error(message.error || 'Server unknown error'));
9989
}
10090
}
91+
}
10192

102-
// handle server requests
103-
if (message?.type === 'REQUEST') {
104-
if (message?.target === 'RENEW_PUSH_TOKEN') {
105-
getPushToken()
106-
.then((renewedPushToken) => {
107-
ws.send(
108-
serializeData({
109-
type: 'RESPONSE',
110-
target: 'RENEW_PUSH_TOKEN',
111-
result: {
112-
dockerhubPushToken: renewedPushToken,
113-
},
114-
})
115-
);
116-
})
117-
.catch(handleError);
118-
}
93+
// handle server requests
94+
if (message?.type === 'REQUEST') {
95+
if (message?.target === 'RENEW_PUSH_TOKEN') {
96+
getPushToken()
97+
.then((renewedPushToken) => {
98+
ws.send(
99+
serializeData({
100+
type: 'RESPONSE',
101+
target: 'RENEW_PUSH_TOKEN',
102+
result: {
103+
dockerhubPushToken: renewedPushToken,
104+
},
105+
})
106+
);
107+
})
108+
.catch(handleError);
119109
}
110+
}
120111

121-
// handle server info
122-
if (message?.type === 'INFO') {
123-
// TODO server feedback
124-
}
125-
});
126-
},
127-
initCallback: (ws) => {
128-
ws.send(
129-
serializeData({
130-
type: 'REQUEST',
131-
target: 'SCONIFY_BUILD', // call sconify handler
132-
template,
133-
dockerhubImageToSconify: iAppNameToSconify,
134-
dockerhubPushToken: pushToken,
135-
yourWalletPublicAddress: walletAddress,
136-
sconeVersion: DEFAULT_SCONE_VERSION,
137-
})
138-
);
139-
},
140-
errorCallback: reject,
141-
});
142-
});
143-
} else {
144-
// standard http call
145-
sconifyResult = await fetch(`${SCONIFY_API_HTTP_URL}/sconify/build`, {
146-
method: 'POST',
147-
headers: {
148-
'Content-Type': 'application/json',
149-
'x-wallet': walletAddress,
112+
// handle server info
113+
if (message?.type === 'INFO') {
114+
// TODO server feedback
115+
}
116+
});
150117
},
151-
body: JSON.stringify({
152-
template,
153-
dockerhubImageToSconify: iAppNameToSconify,
154-
dockerhubPushToken: pushToken, // used for pushing sconified image on user repo
155-
yourWalletPublicAddress: walletAddress,
156-
sconeVersion: DEFAULT_SCONE_VERSION,
157-
}),
158-
})
159-
.catch(() => {
160-
throw Error("Can't reach TEE transformation server!");
161-
})
162-
.then((res) => {
163-
if (res.ok) {
164-
return res.json().catch(() => {
165-
// failed to parse body
166-
throw Error('Unexpected server response');
167-
});
168-
}
169-
if (res.status === 429) {
170-
throw new TooManyRequestsError(
171-
'TEE transformation server is busy, retry later'
172-
);
173-
}
174-
// try getting error message from json body
175-
return res
176-
.json()
177-
.catch(() => {
178-
// failed to parse body
179-
throw Error('Unknown server error');
118+
initCallback: (ws) => {
119+
ws.send(
120+
serializeData({
121+
type: 'REQUEST',
122+
target: 'SCONIFY_BUILD', // call sconify handler
123+
template,
124+
dockerhubImageToSconify: iAppNameToSconify,
125+
dockerhubPushToken: pushToken,
126+
yourWalletPublicAddress: walletAddress,
127+
sconeVersion: DEFAULT_SCONE_VERSION,
180128
})
181-
.then(({ error }) => {
182-
throw Error(error || 'Unknown server error');
183-
});
184-
});
185-
}
129+
);
130+
},
131+
errorCallback: reject,
132+
});
133+
});
186134

187135
// Extract necessary information
188136
if (!sconifyResult.dockerImage) {

0 commit comments

Comments
 (0)