Spaces:
newtext
/
No application file

yxzx commited on
Commit
e6c3c17
·
verified ·
1 Parent(s): d60f9b2

Create app.js

Browse files
Files changed (1) hide show
  1. app.js +189 -0
app.js ADDED
@@ -0,0 +1,189 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { Webhooks, createNodeMiddleware } from '@octokit/webhooks'
2
+ import { exec as execute, spawn } from 'node:child_process'
3
+ import { promisify } from 'node:util'
4
+ import morgan from 'morgan'
5
+ import express from 'express'
6
+ import ini from 'ini'
7
+
8
+ const exec = promisify(execute)
9
+
10
+ const {
11
+ GIT_URL,
12
+ WEBHOOK_SECRET,
13
+ PORT = 7860,
14
+ } = process.env
15
+
16
+ const CONFIG_FILE = 'hf.conf' //TODO: mv to env
17
+ const REPO_NAME = extractRepoName(GIT_URL)
18
+
19
+ let childProcess = null
20
+ let config = null
21
+ let env = {}
22
+
23
+ const webhooks = new Webhooks({ secret: WEBHOOK_SECRET })
24
+ const logApp = createLogger('App')
25
+ const logWebhook = createLogger('Webhook')
26
+
27
+ if (!REPO_NAME) {
28
+ logApp('error', 'Please provide $GIT_URL environment variable.')
29
+ process.exit(1)
30
+ }
31
+
32
+ if (!WEBHOOK_SECRET) {
33
+ logApp('error', 'Please provide $WEBHOOK_SECRET environment variable.')
34
+ process.exit(1)
35
+ }
36
+
37
+ function extractRepoName(url) {
38
+ if (!url) return null
39
+ const name = url.split('/').pop()
40
+ return name.endsWith('.git') ? name.slice(0, -4) : name
41
+ }
42
+
43
+ function formatDate(date) {
44
+ const options = {
45
+ year: 'numeric',
46
+ month: '2-digit',
47
+ day: '2-digit',
48
+ hour: '2-digit',
49
+ minute: '2-digit',
50
+ hour12: true
51
+ }
52
+ return new Date(date).toLocaleString('en-US', options).replace(',', '')
53
+ }
54
+
55
+ function createLogger(context) {
56
+ return (level, message) => {
57
+ const timestamp = formatDate(new Date())
58
+ console.log(`[${timestamp}] [${level.toUpperCase()}] [${context}] ${message}`)
59
+ }
60
+ }
61
+
62
+ async function executeCommand(command, cwd = REPO_NAME) {
63
+ try {
64
+ logApp('info', `Executing: ${command}`)
65
+ const { stdout, stderr } = await exec(command, { cwd })
66
+ if (stdout) console.log(stdout)
67
+ if (stderr) console.error(stderr)
68
+ return true
69
+ } catch (error) {
70
+ logApp('error', `Command failed: ${command} - ${error.message}`)
71
+ return false
72
+ }
73
+ }
74
+
75
+ async function cloneRepository() {
76
+ logApp('info', 'Cloning repository...')
77
+ return await executeCommand(`git clone ${GIT_URL}`, '.')
78
+ }
79
+
80
+ async function pullLatestChanges() {
81
+ logApp('info', 'Pulling latest changes...')
82
+ return await executeCommand('git pull')
83
+ }
84
+
85
+ async function runSetupScripts(scripts) {
86
+ logApp('info', 'Running setup scripts...')
87
+ for (const script of scripts) {
88
+ const success = await executeCommand(script)
89
+ if (!success) return false
90
+ }
91
+ return true
92
+ }
93
+
94
+ async function buildApplication() {
95
+ logApp('info', 'Building application...')
96
+ if (!config) {
97
+ logApp('error', 'Configuration not loaded. Please clone the repository before building the application.')
98
+ return false
99
+ }
100
+ if (!(await pullLatestChanges())) return false
101
+ if (!(await runSetupScripts(config.script))) return false
102
+ return true
103
+ }
104
+
105
+ function validateConfig(config) {
106
+ if (!config) throw new Error("No config found in config file.")
107
+ if (!config.command) throw new Error("No Command found in config file.")
108
+ if (!config.script) throw new Error("No script for setup installation found in config file.")
109
+ }
110
+
111
+ async function loadConfiguration(filename) {
112
+ try {
113
+ const { stdout } = await exec(`cat ${filename}`, { cwd: REPO_NAME })
114
+ const obj = ini.parse(stdout)
115
+ validateConfig(obj.config)
116
+ config = obj.config
117
+ env = obj.env || {}
118
+ return true
119
+ } catch (error) {
120
+ logApp('error', `Failed to load configuration from ${filename}: ${error.message}`)
121
+ return false
122
+ }
123
+ }
124
+
125
+ async function startApplication(build = false) {
126
+ if (childProcess) {
127
+ logApp('info', 'Restarting application...')
128
+ childProcess.kill()
129
+ childProcess = null
130
+ } else {
131
+ logApp('info', 'Starting application...')
132
+ if (!(await cloneRepository())) return
133
+ }
134
+
135
+ if (build) {
136
+ if (!(await loadConfiguration(CONFIG_FILE))) return
137
+ if (!(await buildApplication())) return
138
+ }
139
+
140
+ const [command, ...args] = config.command.split(' ')
141
+ logApp('info', `Executing command: ${config.command}`)
142
+
143
+ childProcess = spawn(command, args, {
144
+ env: { ...process.env, ...env },
145
+ cwd: REPO_NAME,
146
+ stdio: ['inherit', 'inherit', 'inherit', 'ipc'],
147
+ })
148
+
149
+ childProcess.on('message', async (msg) => {
150
+ const action = msg.trim()
151
+ if (action === 'reset') {
152
+ await startApplication()
153
+ } else if (action === 'build') {
154
+ await startApplication(true)
155
+ } else if (action === 'pull') {
156
+ await pullLatestChanges()
157
+ } else if (action === 'setup') {
158
+ await runSetupScripts(config.script)
159
+ }
160
+ })
161
+
162
+ }
163
+
164
+ webhooks.onAny((event) => {
165
+ logWebhook('info', `Received event: ${event.name} with ID: ${event.id}`)
166
+ if (childProcess && event.name === 'push') {
167
+ childProcess.send('push='+JSON.stringify(event))
168
+ childProcess.emit('message', 'build')
169
+ }
170
+ })
171
+
172
+ function initializeServer() {
173
+ const app = express()
174
+ const middleware = createNodeMiddleware(webhooks, { path: '/webhook' })
175
+
176
+ app.use(morgan('combined'))
177
+ app.use(middleware)
178
+
179
+ app.get('/', (req, res) => {
180
+ res.json({ status: 'active', message: { greeting: "Elysia is Running" }})
181
+ })
182
+
183
+ app.listen(PORT, () => {
184
+ logApp('info', `Server listening on port ${PORT}`)
185
+ })
186
+ }
187
+
188
+ initializeServer()
189
+ startApplication(true)