Skip to content

Commit 238bed9

Browse files
committed
1. Update Linux Support
1 parent dfc6d58 commit 238bed9

File tree

24 files changed

+313
-75
lines changed

24 files changed

+313
-75
lines changed

DEV.md

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,7 @@ This guide outlines the project's file structure, architecture, and interface st
55

66
## Branches
77
The project has three branches, each corresponding to a different platform:
8-
- **master**: macOS
9-
- **Win**: Windows
10-
- **Linux**: Linux
8+
- **master**: macOS & Windows & Linux
119

1210
Please select the appropriate branch based on your development environment.
1311

Linux.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
make g++

build/helper.js

Lines changed: 11 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

configs/esbuild.config.win.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,24 @@ const distFork: BuildOptions = {
5151
drop: ['debugger', 'console']
5252
}
5353

54+
const devHelper: BuildOptions = {
55+
platform: 'node',
56+
entryPoints: ['src/helper/index.ts'],
57+
outfile: 'dist/helper/helper.js',
58+
minify: true,
59+
bundle: true,
60+
loader: {
61+
'.node': 'file'
62+
},
63+
plugins: [],
64+
external: [],
65+
drop: ['debugger', 'console']
66+
}
67+
5468
export default {
5569
dev,
5670
dist,
5771
devFork,
58-
distFork
72+
distFork,
73+
devHelper
5974
}

scripts/dev-runner.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,12 @@ function buildMainProcess() {
6060
} else if (isWindows()) {
6161
console.log('isWindows !!!')
6262
const config = (await import('../configs/esbuild.config.win')).default
63-
promise = Promise.all([build(config.dev), build(config.devFork), ElectronKillWin()])
63+
promise = Promise.all([
64+
build(config.dev),
65+
build(config.devFork),
66+
build(config.devHelper),
67+
ElectronKillWin()
68+
])
6469
}
6570
if (!promise) {
6671
building = false

src/fork/module/Minio.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ class Minio extends Base {
5454
if (isMacOS()) {
5555
const bin = join(global.Server.AppDir!, `minio`, 'minio')
5656
const zip = join(global.Server.Cache!, 'minio')
57-
const arch = global.Server.isAppleSilicon ? 'arm64' : 'amd64'
57+
const arch = global.Server.isArmArch ? 'arm64' : 'amd64'
5858
const all: any[] = [
5959
{
6060
url: `https://dl.min.io/server/minio/release/darwin-${arch}/minio`,

src/fork/module/Node.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ class Manager extends Base {
247247
current
248248
})
249249
} else {
250-
const arch = global.Server.isAppleSilicon ? 'arm64' : 'x64'
250+
const arch = global.Server.isArmArch ? 'arm64' : 'x64'
251251
const url = `https://nodejs.org/dist/v${version}/node-v${version}-darwin-${arch}.tar.xz`
252252
const destDir = join(global.Server.AppDir!, `nodejs/v${version}`)
253253
if (existsSync(destDir)) {

src/global.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ export interface ServerType {
1010
BrewError?: string
1111
Password?: string
1212
Proxy?: { [key: string]: string }
13-
isAppleSilicon?: boolean
13+
isArmArch?: boolean
1414
Static?: string
1515
Cache?: string
1616
RedisDir?: string

src/helper/module/Host.ts

Lines changed: 150 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,167 @@
11
import { BaseManager } from './Base'
2-
import { execPromise } from '../util'
2+
import { execPromise, isLinux, isMacOS } from '../util'
3+
import { join } from 'node:path'
34

45
class Manager extends BaseManager {
5-
sslAddTrustedCert(cwd: string, caName: string): Promise<boolean> {
6-
return new Promise(async (resolve, reject) => {
6+
async sslAddTrustedCert(cwd: string, caName: string): Promise<boolean> {
7+
if (isMacOS()) {
8+
await execPromise(
9+
`security add-trusted-cert -d -r trustRoot -k "/Library/Keychains/System.keychain" "${caName}"`,
10+
{
11+
cwd
12+
}
13+
)
14+
} else if (isLinux()) {
15+
const caFile = join(cwd, caName)
16+
// 检查常见的 CA 信任目录
17+
const debianUbuntuPath = `/usr/local/share/ca-certificates/${caName}`
18+
const centosFedoraPath = `/etc/pki/ca-trust/source/anchors/${caName}`
19+
20+
let error = false
721
try {
8-
await execPromise(
9-
`security add-trusted-cert -d -r trustRoot -k "/Library/Keychains/System.keychain" "${caName}"`,
10-
{
11-
cwd
12-
}
13-
)
14-
} catch (e) {
15-
reject(e)
16-
return
22+
// 尝试复制到 Debian/Ubuntu 风格的路径
23+
await execPromise(`sudo cp "${caFile}" "${debianUbuntuPath}"`)
24+
// 更新证书
25+
await execPromise('sudo update-ca-certificates')
26+
} catch {
27+
error = true
28+
}
29+
if (error) {
30+
try {
31+
await execPromise(`sudo cp "${caFile}" "${centosFedoraPath}"`)
32+
// 更新证书
33+
await execPromise('sudo update-ca-trust extract')
34+
} catch {}
1735
}
18-
resolve(true)
19-
})
36+
}
37+
return true
2038
}
2139

22-
sslFindCertificate(cwd: string) {
23-
return new Promise(async (resolve, reject) => {
24-
try {
25-
const res = await execPromise(`security find-certificate -c "FlyEnv-Root-CA"`, {
40+
async sslFindCertificate(
41+
cwd: string,
42+
commonName: string = 'FlyEnv-Root-CA'
43+
): Promise<{ stdout: string; stderr: string }> {
44+
try {
45+
if (isMacOS()) {
46+
const res = await execPromise(`security find-certificate -c "${commonName}"`, {
2647
cwd
2748
})
28-
resolve({
49+
return {
2950
stdout: res.stdout,
3051
stderr: res.stderr
31-
})
32-
} catch (e) {
33-
reject(e)
52+
}
53+
} else if (isLinux()) {
54+
// Linux 查找证书比较复杂,通常需要遍历目录和解析证书文件
55+
// 这是一个非常简化的实现,它会检查常见的CA目录中是否存在文件,
56+
// 并尝试使用 openssl x509 -text 来查找 Common Name
57+
const commonCaPaths = [
58+
'/etc/ssl/certs/',
59+
'/usr/local/share/ca-certificates/',
60+
'/etc/pki/ca-trust/extracted/pem/', // CentOS/RHEL/Fedora 提取的路径
61+
'/etc/pki/tls/certs/'
62+
]
63+
64+
let foundCertPath = ''
65+
66+
for (const dir of commonCaPaths) {
67+
try {
68+
// 尝试列出目录中的所有 .crt 文件
69+
const { stdout: files } = await execPromise(
70+
`find "${dir}" -name "*.crt" -print 2>/dev/null`
71+
)
72+
const certFiles = files
73+
.split('\n')
74+
.map((s) => s.trim())
75+
.filter((s) => !!s)
76+
77+
for (const filePath of certFiles) {
78+
try {
79+
// 使用 openssl 检查证书的 Common Name
80+
const { stdout: certInfo } = await execPromise(
81+
`openssl x509 -in "${filePath}" -text -noout`
82+
)
83+
if (certInfo.includes(`CN = ${commonName}`)) {
84+
foundCertPath = filePath
85+
break // 找到后跳出内层循环
86+
}
87+
} catch {}
88+
}
89+
if (foundCertPath) break // 找到后跳出外层循环
90+
} catch {}
91+
}
92+
93+
if (foundCertPath) {
94+
return {
95+
stdout: `Found certificate: ${foundCertPath}\n`,
96+
stderr: ''
97+
}
98+
} else {
99+
return {
100+
stdout: '',
101+
stderr: `Certificate with CN "${commonName}" not found on Linux.`
102+
}
103+
}
34104
}
35-
})
105+
return { stdout: '', stderr: '' } // 如果不是 macOS 或 Linux,返回空
106+
} catch (e: any) {
107+
return { stdout: '', stderr: `${e}` }
108+
}
36109
}
37110

38-
dnsRefresh() {
39-
return new Promise(async (resolve) => {
40-
try {
41-
await execPromise(`dscacheutil -flushcache`)
42-
} catch {}
43-
try {
44-
await execPromise(`killall -HUP mDNSResponder`)
45-
} catch {}
46-
resolve(true)
47-
})
111+
/**
112+
* 刷新系统 DNS 缓存。
113+
* 注意:Linux 上 DNS 刷新方法因使用的 DNS 解析器而异。
114+
* @returns Promise<boolean> 操作成功返回 true。
115+
*/
116+
async dnsRefresh(): Promise<boolean> {
117+
try {
118+
if (isMacOS()) {
119+
try {
120+
await execPromise(`dscacheutil -flushcache`)
121+
} catch (e) {
122+
console.warn(`Error flushing dscacheutil: ${e}`)
123+
}
124+
try {
125+
await execPromise(`killall -HUP mDNSResponder`)
126+
} catch (e) {
127+
console.warn(`Error killing mDNSResponder: ${e}`)
128+
}
129+
} else if (isLinux()) {
130+
// 尝试常见的 Linux DNS 刷新方法
131+
// 1. systemd-resolved (新版系统,如 Ubuntu 18.04+, Fedora, CentOS 7+)
132+
try {
133+
await execPromise(`sudo systemctl restart systemd-resolved.service`)
134+
console.log('systemd-resolved restarted.')
135+
return true // 如果成功,直接返回
136+
} catch (e) {
137+
console.warn(`systemd-resolved not found or restart failed: ${e}`)
138+
}
139+
140+
// 2. nscd (Name Service Cache Daemon)
141+
try {
142+
await execPromise(`sudo systemctl restart nscd.service`)
143+
console.log('nscd restarted.')
144+
return true // 如果成功,直接返回
145+
} catch (e) {
146+
console.warn(`nscd not found or restart failed: ${e}`)
147+
}
148+
149+
// 3. dnsmasq (如果作为本地 DNS 缓存服务)
150+
try {
151+
await execPromise(`sudo systemctl restart dnsmasq.service`)
152+
console.log('dnsmasq restarted.')
153+
return true // 如果成功,直接返回
154+
} catch (e) {
155+
console.warn(`dnsmasq not found or restart failed: ${e}`)
156+
}
157+
158+
// 如果以上都没有成功,可能没有特定的 DNS 缓存服务或需要手动清除
159+
console.warn(
160+
'Could not determine or refresh system DNS cache on Linux. Manual intervention might be needed.'
161+
)
162+
}
163+
} catch {}
164+
return true
48165
}
49166
}
50167

src/helper/module/Mailpit.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
import { existsSync } from 'node:fs'
22
import { BaseManager } from './Base'
3-
import { execPromise } from '../util'
3+
import { execPromise, isMacOS } from '../util'
44

55
class Manager extends BaseManager {
66
binFixed(bin: string): Promise<boolean> {
77
return new Promise(async (resolve) => {
8-
if (existsSync(bin)) {
9-
try {
10-
await execPromise(`xattr -dr "com.apple.quarantine" "${bin}"`)
11-
} catch {}
8+
if (isMacOS()) {
9+
if (existsSync(bin)) {
10+
try {
11+
await execPromise(`xattr -dr "com.apple.quarantine" "${bin}"`)
12+
} catch {}
13+
}
1214
}
1315
resolve(true)
1416
})

0 commit comments

Comments
 (0)