| FROM node:20 |
|
|
| RUN apt-get update && apt-get install -y \ |
| python3 make g++ git \ |
| && rm -rf /var/lib/apt/lists/* |
|
|
| WORKDIR /app |
|
|
| RUN git clone https://github.com/KayolEnjoy/ai-sawit.git . |
| RUN npm install --omit=dev --no-audit |
| RUN npm install mysql2 http-proxy --save |
| RUN npm run download-dist || echo "skip" |
|
|
| RUN mkdir -p /app/data && chmod -R 777 /app/data |
|
|
| RUN node -e "\ |
| var fs=require('fs'),path=require('path');\ |
| var d=path.dirname(require.resolve('mysql2'));\ |
| var f=path.join(d,'lib','connection_config.js');\ |
| var s=fs.readFileSync(f,'utf8');\ |
| fs.writeFileSync(f,s.replace(/options\.ssl\s*\|\|\s*false/g,'options.ssl||{rejectUnauthorized:false}'));\ |
| var p=path.join(d,'package.json');\ |
| var j=JSON.parse(fs.readFileSync(p,'utf8'));\ |
| delete j.exports;\ |
| fs.writeFileSync(p,JSON.stringify(j));\ |
| console.log('[PATCH] TLS+PKG OK');" |
|
|
| EXPOSE 7860 |
|
|
| RUN cat > /app/patch.js << 'PATCHEOF' |
| var C = require('mysql2/lib/connection'); |
| var _q = C.prototype.query; |
| var _e = C.prototype.execute; |
| function fix(s) { |
| if (typeof s !== 'string') return s; |
| s = s.replace(/default\s*\(('[^']*')\)/gi, 'default $1'); |
| s = s.replace(/(`\w+`\s+(?:text|tinytext|mediumtext|longtext|blob|tinyblob|mediumblob|longblob|json)(?:\s+not\s+null)?)\s+default\s+'[^']*'/gi, '$1'); |
| if (/^\s*alter\s+table\b/i.test(s) && /\bforeign\s+key\b/i.test(s)) return 'SELECT 1'; |
| s = s.replace(/,\s*(?:constraint\s+`[^`]+`\s+)?foreign\s+key\s*\([^)]+\)\s*references\s+`[^`]+`\s*\([^)]+\)(?:\s+on\s+(?:delete|update)\s+(?:cascade|restrict|set\s+null|no\s+action|set\s+default))*/gi, ''); |
| return s; |
| } |
| C.prototype.query = function(sql, values, cb) { |
| if (typeof sql === 'string') sql = fix(sql); |
| else if (sql && typeof sql.sql === 'string') sql.sql = fix(sql.sql); |
| return _q.call(this, sql, values, cb); |
| }; |
| if (_e) { |
| C.prototype.execute = function(sql, values, cb) { |
| if (typeof sql === 'string') sql = fix(sql); |
| else if (sql && typeof sql.sql === 'string') sql.sql = fix(sql.sql); |
| return _e.call(this, sql, values, cb); |
| }; |
| } |
| console.log('[SQL] patched'); |
| PATCHEOF |
|
|
| RUN cat > /app/init.js << 'INITEOF' |
| var fs = require('fs'); |
| var raw = process.env.DATABASE_URL || ''; |
| if (raw) { |
| var clean = raw.replace(/^mysql[^:]*:\/\//, ''); |
| var ai = clean.lastIndexOf('@'); |
| var creds = clean.substring(0, ai); |
| var rest = clean.substring(ai + 1); |
| var ci = creds.indexOf(':'); |
| var user = creds.substring(0, ci); |
| var pass = creds.substring(ci + 1); |
| var si = rest.indexOf('/'); |
| var hp = si !== -1 ? rest.substring(0, si) : rest; |
| var db = si !== -1 ? rest.substring(si + 1).split('?')[0] : 'uptime_kuma'; |
| var lc = hp.lastIndexOf(':'); |
| var host = lc !== -1 ? hp.substring(0, lc) : hp; |
| var port = lc !== -1 ? parseInt(hp.substring(lc + 1)) : 4000; |
| var cfg = { |
| type: 'mariadb', |
| hostname: host, |
| port: port, |
| username: user, |
| password: pass, |
| dbName: db |
| }; |
| try { fs.mkdirSync('/app/data', { recursive: true }); } catch(e) {} |
| fs.writeFileSync('/app/data/db-config.json', JSON.stringify(cfg, null, 4)); |
| console.log('[INIT] DB: ' + host + ':' + port + '/' + db + ' user=' + user); |
| } else { |
| console.log('[INIT] No DATABASE_URL'); |
| } |
| INITEOF |
|
|
| RUN cat > /app/gateway.js << 'GWEOF' |
| var http = require('http'); |
| var httpProxy = require('http-proxy'); |
| var DOMAIN = process.env.DOMAIN || ''; |
| var proxy = httpProxy.createProxyServer({ target: 'http://127.0.0.1:3001', ws: true }); |
| proxy.on('error', function(e, req, res) { |
| if (res && res.writeHead) { res.writeHead(502); res.end('502'); } |
| }); |
| function ok(req) { |
| if (!DOMAIN) return true; |
| var h = (req.headers['x-real-domain'] || '') + '|' + (req.headers['x-forwarded-host'] || '') + '|' + (req.headers['host'] || ''); |
| return h.indexOf(DOMAIN) !== -1; |
| } |
| var s = http.createServer(function(req, res) { |
| if (ok(req)) { |
| proxy.web(req, res); |
| } else { |
| res.writeHead(200, { 'Content-Type': 'text/plain' }); |
| res.end('200 OK'); |
| } |
| }); |
| s.on('upgrade', function(req, socket, head) { |
| if (ok(req)) { proxy.ws(req, socket, head); } else { socket.destroy(); } |
| }); |
| s.listen(7860, function() { console.log('[GW] 7860'); }); |
| GWEOF |
|
|
| RUN cat > /start.sh << 'SHEOF' |
| |
| node /app/init.js |
| PORT=3001 node --require /app/patch.js server/server.js --port 3001 & |
| sleep 5 |
| exec node /app/gateway.js |
| SHEOF |
|
|
| RUN chmod +x /start.sh |
| CMD ["/start.sh"] |