1- import { existsSync , mkdirSync , mkdtempSync , rmSync , writeFileSync } from 'node:fs'
2- import { tmpdir } from 'node:os'
3- import { join , resolve } from 'node:path'
4-
51import { defineConfig } from 'vite'
62
73import { resolvePort } from './composables/resolvePort'
4+ import { SessionManager } from './plugin/sessionManager'
85import type { StartedEvent , StartRequest } from './types'
96
107export { resolvePort }
118
12- const DEFAULT_PORT = 9000
13- const DEFAULT_START_TIMEOUT_MS = 30_000
14-
159let previousSigintHandler : ( ( ) => void ) | null = null
1610let previousSigtermHandler : ( ( ) => void ) | null = null
1711let previousExitHandler : ( ( ) => void ) | null = null
@@ -22,19 +16,9 @@ export default defineConfig({
2216 name : 'slidev-addon-livecode' ,
2317
2418 configureServer ( server ) {
25- const root = server . config . root
26- const COLOR_THEMES = {
27- dark : 'Default Dark Modern' ,
28- light : 'Default Light Modern' ,
29- } as const
30-
31- const sessions = new Map <
32- string ,
33- { close : ( ) => Promise < void > ; port : number ; url : string ; userDataDir ?: string }
34- > ( )
35- const usedPorts = new Set < number > ( )
19+ const manager = new SessionManager ( )
3620
37- const sendStartedEvent = (
21+ const send = (
3822 session : string ,
3923 url : string ,
4024 state : 'running' | 'error' ,
@@ -43,98 +27,15 @@ export default defineConfig({
4327 server . ws . send ( 'livecode:started' , { error, session, state, url } satisfies StartedEvent )
4428 }
4529
46- server . ws . on ( 'livecode:start' , async ( request : StartRequest ) => {
47- const {
48- colorScheme,
49- defaultFolder,
50- defaultPort = DEFAULT_PORT ,
51- fontSize,
52- hideActivityBar,
53- hideMinimap,
54- hideStatusBar,
55- port : requestedPort ,
56- session,
57- startTimeout = DEFAULT_START_TIMEOUT_MS ,
58- } = request
59-
60- const existing = sessions . get ( session )
61- if ( existing ) {
62- sendStartedEvent ( session , existing . url , 'running' )
63- return
64- }
65-
66- const port = resolvePort ( usedPorts , requestedPort , defaultPort )
67- usedPorts . add ( port )
68-
69- try {
70- const { startCodeServer } = await import ( 'coderaft' )
71-
72- const absoluteFolder = defaultFolder ? resolve ( root , defaultFolder ) : root
73- const resolvedFolder = existsSync ( absoluteFolder ) ? absoluteFolder : root
74-
75- const settings : Record < string , unknown > = { }
76- if ( colorScheme ) settings [ 'workbench.colorTheme' ] = COLOR_THEMES [ colorScheme ]
77- if ( fontSize ) settings [ 'editor.fontSize' ] = fontSize
78- if ( hideMinimap ) settings [ 'editor.minimap.enabled' ] = false
79- if ( hideActivityBar ) settings [ 'workbench.activityBar.location' ] = 'hidden'
80- if ( hideStatusBar ) settings [ 'workbench.statusBar.visible' ] = false
81-
82- let userDataDir : string | undefined
83- if ( Object . keys ( settings ) . length > 0 ) {
84- userDataDir = mkdtempSync ( join ( tmpdir ( ) , 'livecode-' ) )
85- mkdirSync ( join ( userDataDir , 'User' ) , { recursive : true } )
86- writeFileSync ( join ( userDataDir , 'User' , 'settings.json' ) , JSON . stringify ( settings ) )
87- }
88-
89- const handle = await Promise . race ( [
90- startCodeServer ( {
91- defaultFolder : resolvedFolder ,
92- host : '127.0.0.1' ,
93- port,
94- ...( userDataDir ? { vscode : { 'user-data-dir' : userDataDir } } : { } ) ,
95- } ) ,
96- new Promise < never > ( ( _ , reject ) =>
97- setTimeout (
98- ( ) => reject ( new Error ( `timeout after ${ startTimeout } ms` ) ) ,
99- startTimeout ,
100- ) ,
101- ) ,
102- ] )
103-
104- sessions . set ( session , {
105- close : ( ) => handle . close ( ) ,
106- port,
107- url : handle . url ,
108- userDataDir,
109- } )
110- console . log ( `[livecode] Session "${ session } " running at ${ handle . url } ` )
111- sendStartedEvent ( session , handle . url , 'running' )
112- } catch ( err ) {
113- usedPorts . delete ( port )
114- const message = err instanceof Error ? err . message : String ( err )
115- console . error ( `[livecode] Failed to start session "${ session } ": ${ message } ` )
116- sendStartedEvent ( session , '' , 'error' , message )
117- }
30+ server . ws . on ( 'livecode:start' , ( request : StartRequest ) => {
31+ manager . start ( request , server . config . root , send )
11832 } )
11933
12034 server . ws . on ( 'livecode:stop' , ( { session } : { session : string } ) => {
121- const entry = sessions . get ( session )
122- if ( ! entry ) return
123- entry . close ( ) . catch ( ( ) => { } )
124- if ( entry . userDataDir ) rmSync ( entry . userDataDir , { recursive : true , force : true } )
125- sessions . delete ( session )
126- usedPorts . delete ( entry . port )
127- console . log ( `[livecode] Session "${ session } " stopped` )
35+ manager . stop ( session )
12836 } )
12937
130- const cleanup = ( ) => {
131- for ( const [ , entry ] of sessions ) {
132- entry . close ( ) . catch ( ( ) => { } )
133- if ( entry . userDataDir ) rmSync ( entry . userDataDir , { recursive : true , force : true } )
134- }
135- sessions . clear ( )
136- usedPorts . clear ( )
137- }
38+ const cleanup = ( ) => manager . cleanup ( )
13839
13940 const sigintHandler = ( ) => {
14041 cleanup ( )
0 commit comments