Skip to content

Commit a76a640

Browse files
committed
Added refresh method to connect and fixed bugs
1 parent 26ba958 commit a76a640

File tree

8 files changed

+112
-25
lines changed

8 files changed

+112
-25
lines changed

src/connect/http-routes/handlers/create-command.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
import { IPty, spawn } from '@homebridge/node-pty-prebuilt-multiarch';
22
import chalk from 'chalk';
33
import { Router } from 'express';
4+
import WebSocket from 'ws';
45

5-
import { ConnectOrchestrator } from '../../../orchestrators/connect.js';
66
import { Session, SocketServer } from '../../socket-server.js';
7-
import WebSocket from 'ws';
87

98
export enum ConnectCommand {
109
TERMINAL = 'terminal',
1110
APPLY = 'apply',
1211
PLAN = 'plan',
13-
IMPORT = 'import'
12+
IMPORT = 'import',
13+
REFRESH = 'refresh',
1414
}
1515

1616
interface Params {

src/connect/http-routes/handlers/import-handler.ts

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,8 @@ import { Session, SocketServer } from '../../socket-server.js';
1212
import { ConnectCommand, createCommandHandler } from './create-command.js';
1313

1414
enum ImportType {
15-
REFRESH = 'refresh',
16-
NEW_RESOURCES = 'new_resources',
17-
NEW_ALL = 'new_all',
15+
IMPORT = 'import',
16+
IMPORT_SPECIFIC = 'import_specific',
1817
}
1918

2019
const validator = ajv.compile(ConfigFileSchema);
@@ -30,8 +29,8 @@ export function importHandler() {
3029
throw new Error('Unable to parse import type');
3130
}
3231

33-
if (type === ImportType.NEW_RESOURCES && (!resourceTypes || Array.isArray(resourceTypes))) {
34-
throw new Error('For new resources import type, a list of resource types must be provided');
32+
if (type === ImportType.IMPORT_SPECIFIC && (!resourceTypes || Array.isArray(resourceTypes))) {
33+
throw new Error('For import specific, a list of resource types must be provided');
3534
}
3635

3736
if (!validator(codifyConfig)) {
@@ -46,17 +45,12 @@ export function importHandler() {
4645

4746
let args = '';
4847
switch (type as ImportType) {
49-
case ImportType.REFRESH: {
50-
break;
51-
}
52-
53-
case ImportType.NEW_RESOURCES: {
54-
args = (resourceTypes as string[]).join(' ');
48+
case ImportType.IMPORT: {
5549
break;
5650
}
5751

58-
case ImportType.NEW_ALL: {
59-
args = '*'
52+
case ImportType.IMPORT_SPECIFIC: {
53+
args = (resourceTypes as string[]).join(' ');
6054
break;
6155
}
6256
}
@@ -94,7 +88,7 @@ export function importHandler() {
9488
}
9589

9690
return createCommandHandler({
97-
name: ConnectCommand.APPLY,
91+
name: ConnectCommand.IMPORT,
9892
spawnCommand,
9993
onExit
10094
});

src/connect/http-routes/handlers/plan-handler.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ export function planHandler() {
4545
}
4646

4747
return createCommandHandler({
48-
name: ConnectCommand.APPLY,
48+
name: ConnectCommand.PLAN,
4949
spawnCommand,
5050
onExit
5151
});
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
import { spawn } from '@homebridge/node-pty-prebuilt-multiarch';
2+
import { ConfigFileSchema } from 'codify-schemas';
3+
import { diffChars } from 'diff';
4+
import fs from 'node:fs/promises';
5+
import os from 'node:os';
6+
import path from 'node:path';
7+
import { WebSocket } from 'ws';
8+
9+
import { ConnectOrchestrator } from '../../../orchestrators/connect.js';
10+
import { ajv } from '../../../utils/ajv.js';
11+
import { Session, SocketServer } from '../../socket-server.js';
12+
import { ConnectCommand, createCommandHandler } from './create-command.js';
13+
14+
enum RefreshType {
15+
REFRESH = 'refresh',
16+
REFRESH_SPECIFIC = 'refresh_specific'
17+
}
18+
19+
const validator = ajv.compile(ConfigFileSchema);
20+
21+
export function refreshHandler() {
22+
const spawnCommand = async (body: Record<string, unknown>, ws: WebSocket, session: Session) => {
23+
const { config: codifyConfig, type, resourceTypes } = body;
24+
if (!codifyConfig) {
25+
throw new Error('Unable to parse codify config');
26+
}
27+
28+
if (!type || !Object.values(RefreshType).includes(type as RefreshType)) {
29+
throw new Error('Unable to parse import type');
30+
}
31+
32+
if (type === RefreshType.REFRESH_SPECIFIC && (!resourceTypes || Array.isArray(resourceTypes))) {
33+
throw new Error('For refresh specific, a list of resource types must be provided');
34+
}
35+
36+
if (!validator(codifyConfig)) {
37+
throw new Error('Invalid codify config');
38+
}
39+
40+
const tmpDir = await fs.mkdtemp(os.tmpdir());
41+
const filePath = path.join(tmpDir, 'codify.jsonc');
42+
await fs.writeFile(filePath, JSON.stringify(codifyConfig, null, 2));
43+
session.additionalData.filePath = filePath;
44+
session.additionalData.existingFile = codifyConfig;
45+
46+
let args = '';
47+
switch (type as RefreshType) {
48+
case RefreshType.REFRESH: {
49+
break;
50+
}
51+
52+
case RefreshType.REFRESH_SPECIFIC: {
53+
args = (resourceTypes as string[]).join(' ');
54+
break;
55+
}
56+
}
57+
58+
return spawn('zsh', ['-c', `${ConnectOrchestrator.rootCommand} refresh ${args} -p ${filePath}`], {
59+
name: 'xterm-color',
60+
cols: 80,
61+
rows: 30,
62+
cwd: process.env.HOME,
63+
env: process.env
64+
});
65+
}
66+
67+
const onExit = async (exitCode: number, ws: WebSocket, session: Session) => {
68+
if (session.additionalData.filePath) {
69+
const updatedFile = await fs.readFile(session.additionalData.filePath as string, 'utf8')
70+
71+
// Changes were found
72+
if (diffChars(updatedFile, session.additionalData.existingFile as string).length > 0) {
73+
console.log('Writing imported changes to Codify dashboard');
74+
75+
const ws = SocketServer.get().getMainConnection(session.clientId);
76+
if (!ws) {
77+
throw new Error(`Unable to find client for clientId ${session.clientId}`);
78+
}
79+
80+
ws.send(JSON.stringify({ key: 'new_import', data: {
81+
updated: updatedFile,
82+
} }))
83+
}
84+
85+
86+
await fs.rm(session.additionalData.filePath as string, { recursive: true, force: true });
87+
}
88+
}
89+
90+
return createCommandHandler({
91+
name: ConnectCommand.REFRESH,
92+
spawnCommand,
93+
onExit
94+
});
95+
}

src/connect/http-routes/router.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { applyHandler } from './handlers/apply-handler.js';
44
import { importHandler } from './handlers/import-handler.js';
55
import defaultHandler from './handlers/index.js';
66
import { planHandler } from './handlers/plan-handler.js';
7+
import { refreshHandler } from './handlers/refresh-handler.js';
78
import { terminalHandler } from './handlers/terminal-handler.js';
89

910
const router = Router();
@@ -12,6 +13,7 @@ router.use('/', defaultHandler);
1213
router.use('/apply', applyHandler());
1314
router.use('/plan', planHandler())
1415
router.use('/import', importHandler());
16+
router.use('/refresh', refreshHandler());
1517
router.use('/terminal', terminalHandler());
1618

1719
export default router;

src/events/context.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ export enum ProcessName {
2424
PLAN = 'plan',
2525
DESTROY = 'destroy',
2626
IMPORT = 'import',
27+
REFRESH = 'refresh',
2728
INIT = 'init',
2829
}
2930

src/orchestrators/import.ts

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,6 @@ export class ImportOrchestrator {
3737
{ ...args, allowEmptyProject: true },
3838
reporter
3939
);
40-
const { project } = initializationResult;
41-
42-
if ((!typeIds || typeIds.length === 0) && project.isEmpty()) {
43-
throw new Error('At least one resource [type] must be specified. Ex: "codify import homebrew". Or the import command must be run in a directory with a valid codify file')
44-
}
4540

4641
await (!typeIds || typeIds.length === 0
4742
? ImportOrchestrator.autoImportAll(reporter, initializationResult)

src/orchestrators/refresh.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ export class RefreshOrchestrator {
2727
reporter: Reporter
2828
) {
2929
const typeIds = args.typeIds?.filter(Boolean)
30-
ctx.processStarted(ProcessName.IMPORT)
30+
ctx.processStarted(ProcessName.REFRESH)
3131

3232
const initializationResult = await PluginInitOrchestrator.run(
3333
{ ...args, allowEmptyProject: true },
@@ -46,7 +46,7 @@ export class RefreshOrchestrator {
4646
project.resourceConfigs.filter((r) => !typeIds || typeIds.includes(r.type))
4747
);
4848

49-
ctx.processFinished(ProcessName.IMPORT);
49+
ctx.processFinished(ProcessName.REFRESH);
5050

5151
reporter.displayImportResult(importResult, false);
5252

0 commit comments

Comments
 (0)