yasarefe commited on
Commit
0396645
·
1 Parent(s): 766f6d6

Add async API with job tracking for APK builds

Browse files
Files changed (3) hide show
  1. Dockerfile +8 -1
  2. app.js +92 -44
  3. package.json +2 -1
Dockerfile CHANGED
@@ -3,9 +3,16 @@ FROM node:20
3
  # Install Java and basic tools
4
  RUN apt-get update && apt-get install -y openjdk-17-jdk wget unzip
5
 
6
- # Set Android environment
7
  ENV ANDROID_HOME=/opt/android-sdk
8
  ENV PATH=${PATH}:${ANDROID_HOME}/cmdline-tools/latest/bin:${ANDROID_HOME}/platform-tools
 
 
 
 
 
 
 
9
 
10
  # Copy app
11
  COPY . /app
 
3
  # Install Java and basic tools
4
  RUN apt-get update && apt-get install -y openjdk-17-jdk wget unzip
5
 
6
+ # Install Android SDK
7
  ENV ANDROID_HOME=/opt/android-sdk
8
  ENV PATH=${PATH}:${ANDROID_HOME}/cmdline-tools/latest/bin:${ANDROID_HOME}/platform-tools
9
+ RUN mkdir -p ${ANDROID_HOME}/cmdline-tools && \
10
+ cd ${ANDROID_HOME}/cmdline-tools && \
11
+ wget -q https://dl.google.com/android/repository/commandlinetools-linux-9477386_latest.zip -O cmdline-tools.zip && \
12
+ unzip -q cmdline-tools.zip && \
13
+ mv cmdline-tools cmdline-tools-latest && \
14
+ rm -f cmdline-tools.zip && \
15
+ yes | ${ANDROID_HOME}/cmdline-tools/latest/bin/sdkmanager --licenses
16
 
17
  # Copy app
18
  COPY . /app
app.js CHANGED
@@ -2,10 +2,17 @@ const express = require('express');
2
  const { exec } = require('child_process');
3
  const fs = require('fs');
4
  const path = require('path');
 
5
 
6
  const app = express();
7
  const PORT = 7860;
8
 
 
 
 
 
 
 
9
  // Web arayüzü
10
  app.get('/', (req, res) => {
11
  res.send(`
@@ -19,26 +26,10 @@ app.get('/', (req, res) => {
19
  </style>
20
  </head>
21
  <body>
22
- <h1>APK Build Service</h1>
23
- <p>Web uygulamanızı APK'ya dönüştürün.</p>
24
- <button onclick="startBuild()">APK Build Başlat</button>
25
- <div id="status"></div>
26
- <script>
27
- function startBuild() {
28
- document.getElementById('status').innerHTML = 'Build başlatılıyor...';
29
- fetch('/build', { method: 'POST' })
30
- .then(response => response.json())
31
- .then(data => {
32
- document.getElementById('status').innerHTML = data.message;
33
- if (data.success) {
34
- document.getElementById('status').innerHTML += '<br><a href="/download">APK İndir</a>';
35
- }
36
- })
37
- .catch(error => {
38
- document.getElementById('status').innerHTML = 'Hata: ' + error;
39
- });
40
- }
41
- </script>
42
  </body>
43
  </html>
44
  `);
@@ -46,11 +37,72 @@ app.get('/', (req, res) => {
46
 
47
  // Build endpoint
48
  app.post('/build', (req, res) => {
49
- console.log('Build başlatıldı');
 
 
 
 
50
 
51
- // GitHub'dan web uygulamasını çek
52
- const repoUrl = 'https://github.com/nyx47rd/AIStudioToApp2.git';
53
- const buildDir = '/tmp/build';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
54
 
55
  // Temizle
56
  if (fs.existsSync(buildDir)) {
@@ -58,47 +110,43 @@ app.post('/build', (req, res) => {
58
  }
59
 
60
  // Klonla
61
- exec(`git clone ${repoUrl} ${buildDir}`, (error, stdout, stderr) => {
62
  if (error) {
63
  console.error('Klonlama hatası:', error);
64
- return res.json({ success: false, message: 'Repo klonlanamadı: ' + error.message });
 
 
65
  }
66
 
67
  // Build işlemi
68
- exec('npm install && npm run build && npx cap init "AIStudioToApp2" "com.example.aistudiotoapp2" --web-dir dist && npx cap add android && npx cap sync android && cd android && chmod +x gradlew && ./gradlew assembleDebug',
69
- { cwd: buildDir },
70
  (error, stdout, stderr) => {
71
  if (error) {
72
  console.error('Build hatası:', error);
73
- return res.json({ success: false, message: 'Build başarısız: ' + error.message });
 
 
74
  }
75
 
76
  // APK'yı kopyala
77
  const apkPath = path.join(buildDir, 'android/app/build/outputs/apk/debug/app-debug.apk');
78
- const destPath = '/tmp/app-debug.apk';
79
 
80
  if (fs.existsSync(apkPath)) {
81
  fs.copyFileSync(apkPath, destPath);
82
  console.log('APK oluşturuldu:', destPath);
83
- res.json({ success: true, message: 'APK başarıyla oluşturuldu!' });
 
84
  } else {
85
- res.json({ success: false, message: 'APK dosyası bulunamadı.' });
 
86
  }
87
  }
88
  );
89
  });
90
- });
91
-
92
- // APK indirme endpoint
93
- app.get('/download', (req, res) => {
94
- const apkPath = '/tmp/app-debug.apk';
95
- if (fs.existsSync(apkPath)) {
96
- res.download(apkPath, 'app-debug.apk');
97
- } else {
98
- res.status(404).send('APK dosyası bulunamadı. Önce build yapın.');
99
- }
100
- });
101
 
102
  app.listen(PORT, () => {
103
- console.log(`Sunucu ${PORT} portunda çalışıyor`);
104
  });
 
2
  const { exec } = require('child_process');
3
  const fs = require('fs');
4
  const path = require('path');
5
+ const { v4: uuidv4 } = require('uuid');
6
 
7
  const app = express();
8
  const PORT = 7860;
9
 
10
+ // JSON body parser
11
+ app.use(express.json());
12
+
13
+ // Job storage
14
+ const jobs = {};
15
+
16
  // Web arayüzü
17
  app.get('/', (req, res) => {
18
  res.send(`
 
26
  </style>
27
  </head>
28
  <body>
29
+ <h1>APK Build Service API</h1>
30
+ <p>POST /build - Build başlat (appName, packageId, repoUrl)</p>
31
+ <p>GET /status/:jobId - Durum sorgula</p>
32
+ <p>GET /download/:jobId - APK indir</p>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
  </body>
34
  </html>
35
  `);
 
37
 
38
  // Build endpoint
39
  app.post('/build', (req, res) => {
40
+ const { appName, packageId, repoUrl } = req.body;
41
+
42
+ if (!appName || !packageId || !repoUrl) {
43
+ return res.status(400).json({ success: false, message: 'appName, packageId ve repoUrl gerekli' });
44
+ }
45
 
46
+ const jobId = uuidv4();
47
+ jobs[jobId] = {
48
+ status: 'pending',
49
+ appName,
50
+ packageId,
51
+ repoUrl,
52
+ createdAt: new Date(),
53
+ apkPath: null
54
+ };
55
+
56
+ // Build işlemini arka planda başlat
57
+ buildAPK(jobId);
58
+
59
+ res.json({ success: true, jobId, message: 'Build başlatıldı' });
60
+ });
61
+
62
+ // Durum sorgulama
63
+ app.get('/status/:jobId', (req, res) => {
64
+ const { jobId } = req.params;
65
+ const job = jobs[jobId];
66
+
67
+ if (!job) {
68
+ return res.status(404).json({ success: false, message: 'Job bulunamadı' });
69
+ }
70
+
71
+ res.json({
72
+ success: true,
73
+ jobId,
74
+ status: job.status,
75
+ appName: job.appName,
76
+ createdAt: job.createdAt
77
+ });
78
+ });
79
+
80
+ // APK indirme
81
+ app.get('/download/:jobId', (req, res) => {
82
+ const { jobId } = req.params;
83
+ const job = jobs[jobId];
84
+
85
+ if (!job) {
86
+ return res.status(404).json({ success: false, message: 'Job bulunamadı' });
87
+ }
88
+
89
+ if (job.status !== 'completed') {
90
+ return res.status(400).json({ success: false, message: 'APK henüz hazır değil' });
91
+ }
92
+
93
+ if (job.apkPath && fs.existsSync(job.apkPath)) {
94
+ res.download(job.apkPath, `${job.appName}-debug.apk`);
95
+ } else {
96
+ res.status(404).json({ success: false, message: 'APK dosyası bulunamadı' });
97
+ }
98
+ });
99
+
100
+ // Build fonksiyonu
101
+ function buildAPK(jobId) {
102
+ const job = jobs[jobId];
103
+ job.status = 'building';
104
+
105
+ const buildDir = `/tmp/build-${jobId}`;
106
 
107
  // Temizle
108
  if (fs.existsSync(buildDir)) {
 
110
  }
111
 
112
  // Klonla
113
+ exec(`git clone ${job.repoUrl} ${buildDir}`, (error, stdout, stderr) => {
114
  if (error) {
115
  console.error('Klonlama hatası:', error);
116
+ job.status = 'failed';
117
+ job.error = error.message;
118
+ return;
119
  }
120
 
121
  // Build işlemi
122
+ exec(`npm install && npm run build && npx cap init "${job.appName}" "${job.packageId}" --web-dir dist && npx cap add android && npx cap sync android && cd android && chmod +x gradlew && ./gradlew assembleDebug`,
123
+ { cwd: buildDir, timeout: 600000 }, // 10 dakika timeout
124
  (error, stdout, stderr) => {
125
  if (error) {
126
  console.error('Build hatası:', error);
127
+ job.status = 'failed';
128
+ job.error = error.message;
129
+ return;
130
  }
131
 
132
  // APK'yı kopyala
133
  const apkPath = path.join(buildDir, 'android/app/build/outputs/apk/debug/app-debug.apk');
134
+ const destPath = `/tmp/${job.appName}-${jobId}-debug.apk`;
135
 
136
  if (fs.existsSync(apkPath)) {
137
  fs.copyFileSync(apkPath, destPath);
138
  console.log('APK oluşturuldu:', destPath);
139
+ job.status = 'completed';
140
+ job.apkPath = destPath;
141
  } else {
142
+ job.status = 'failed';
143
+ job.error = 'APK dosyası bulunamadı';
144
  }
145
  }
146
  );
147
  });
148
+ }
 
 
 
 
 
 
 
 
 
 
149
 
150
  app.listen(PORT, () => {
151
+ console.log(`APK Build Service ${PORT} portunda çalışıyor`);
152
  });
package.json CHANGED
@@ -7,6 +7,7 @@
7
  "start": "node app.js"
8
  },
9
  "dependencies": {
10
- "express": "^4.18.2"
 
11
  }
12
  }
 
7
  "start": "node app.js"
8
  },
9
  "dependencies": {
10
+ "express": "^4.18.2",
11
+ "uuid": "^9.0.0"
12
  }
13
  }