Files
devstar-vscode/src/home.ts

377 lines
14 KiB
TypeScript
Raw Normal View History

2024-07-02 12:15:39 +08:00
import * as vscode from 'vscode';
import * as os from 'os';
import RemoteContainer from './remote-container';
import User from './user';
import * as utils from './utils'
2024-07-02 12:15:39 +08:00
export default class DSHome {
private context: vscode.ExtensionContext;
private remoteContainer: RemoteContainer;
private user: User;
2025-11-10 08:45:19 +00:00
private devstarDomain: string | undefined;
/**
* devstarDomain
* @param context
* @param user
*/
constructor(context: vscode.ExtensionContext, user: User)
/**
* open with vscode链接提供devstarDomain
* @param context
* @param user
* @param devstarDomain
*/
constructor(context: vscode.ExtensionContext, user: User, devstarDomain: string)
constructor(context: vscode.ExtensionContext, user: User, devstarDomain?: string) {
this.context = context;
2025-03-24 16:29:55 +08:00
this.user = user;
this.remoteContainer = new RemoteContainer(user);
if (devstarDomain != undefined && devstarDomain != "") {
2025-11-10 08:45:19 +00:00
this.devstarDomain = devstarDomain.endsWith('/') ? devstarDomain.slice(0, -1) : devstarDomain;
} else {
2025-11-10 08:45:19 +00:00
const devstarDomainFromConfig = utils.devstarDomain();
if (devstarDomainFromConfig != undefined && devstarDomainFromConfig != "") {
2025-11-10 08:45:19 +00:00
this.devstarDomain = devstarDomainFromConfig.endsWith('/') ? devstarDomainFromConfig.slice(0, -1) : devstarDomainFromConfig;
} else {
2025-11-10 08:45:19 +00:00
this.devstarDomain = "https://devstar.cn";
}
}
2024-07-02 12:15:39 +08:00
}
setUser(user: User) {
2025-11-10 08:45:19 +00:00
this.user = user;
}
setRemoteContainer(remoteContainer: RemoteContainer) {
2025-11-10 08:45:19 +00:00
this.remoteContainer = remoteContainer;
}
setDevstarDomainAndHomePageURL(devstarDomain: string) {
if (devstarDomain != undefined && devstarDomain != "") {
2025-11-10 08:45:19 +00:00
this.devstarDomain = devstarDomain.endsWith('/') ? devstarDomain.slice(0, -1) : devstarDomain;
} else {
2025-11-10 08:45:19 +00:00
console.error("devstarDomain is undefined or null");
}
}
2025-11-10 08:45:19 +00:00
async toggle() {
2024-07-02 12:15:39 +08:00
const panel = vscode.window.createWebviewPanel(
2024-09-18 20:46:25 +08:00
'homeWebview',
2025-04-22 22:32:06 +08:00
vscode.l10n.t('Home'),
2024-07-02 12:15:39 +08:00
vscode.ViewColumn.One,
{
enableScripts: true,
retainContextWhenHidden: true,
}
2024-07-02 12:15:39 +08:00
);
2025-11-10 08:45:19 +00:00
panel.webview.html = await this.getWebviewContent();
2024-07-02 12:15:39 +08:00
panel.webview.onDidReceiveMessage(
async (message) => {
2025-11-10 08:45:19 +00:00
const data = message.data;
const need_return = message.need_return;
if (need_return) {
// ================= need return ====================
switch (message.command) {
// ----------------- frequent -----------------------
2025-04-22 20:58:09 +08:00
case 'getHomeConfig':
const config = {
language: vscode.env.language
2025-11-10 08:45:19 +00:00
};
panel.webview.postMessage({ command: 'getHomeConfig', data: { homeConfig: config } });
break;
case 'getUserToken':
2025-11-10 08:45:19 +00:00
const userToken = this.user.getUserTokenFromLocal();
if (userToken === undefined) {
2025-11-10 08:45:19 +00:00
panel.webview.postMessage({ command: 'getUserToken', data: { userToken: '' } });
} else {
2025-11-10 08:45:19 +00:00
panel.webview.postMessage({ command: 'getUserToken', data: { userToken: userToken } });
}
2025-11-10 08:45:19 +00:00
break;
case 'getUsername':
2025-11-10 08:45:19 +00:00
const username = this.user.getUsernameFromLocal();
if (username === undefined) {
2025-11-10 08:45:19 +00:00
panel.webview.postMessage({ command: 'getUsername', data: { username: '' } });
} else {
2025-11-10 08:45:19 +00:00
panel.webview.postMessage({ command: 'getUsername', data: { username: username } });
}
2025-11-10 08:45:19 +00:00
break;
case 'firstOpenRemoteFolder':
// data.host - project name
2025-11-10 08:45:19 +00:00
await this.remoteContainer.firstOpenProject(data.host, data.hostname, data.port, data.username, data.path, this.context);
break;
case 'openRemoteFolder':
this.remoteContainer.openRemoteFolder(data.host, data.port, data.username, data.path);
break;
case 'getDevstarDomain':
2025-11-10 08:45:19 +00:00
panel.webview.postMessage({ command: 'getDevstarDomain', data: { devstarDomain: this.devstarDomain } });
break;
// ----------------- not frequent -----------------------
case 'setUserToken':
2025-11-10 08:45:19 +00:00
this.user.setUserTokenToLocal(data.userToken);
if (data.userToken === this.user.getUserTokenFromLocal()) {
2025-11-10 08:45:19 +00:00
panel.webview.postMessage({ command: 'setUserToken', data: { ok: true } });
} else {
2025-11-10 08:45:19 +00:00
panel.webview.postMessage({ command: 'setUserToken', data: { ok: false } });
}
2025-11-10 08:45:19 +00:00
break;
case 'setUsername':
this.user.setUsernameToLocal(data.username);
if (data.username === this.user.getUsernameFromLocal()) {
panel.webview.postMessage({ command: 'setUsername', data: { ok: true } });
} else {
panel.webview.postMessage({ command: 'setUsername', data: { ok: false } });
}
2025-11-10 08:45:19 +00:00
break;
case 'getUserPublicKey':
2025-11-10 08:45:19 +00:00
let userPublicKey = '';
if (this.user.existUserPrivateKey()) {
userPublicKey = this.user.getUserPublicKey();
}
2025-11-10 08:45:19 +00:00
panel.webview.postMessage({ command: 'getUserPublicKey', data: { userPublicKey: userPublicKey } });
break;
case 'createUserPublicKey':
await this.user.createUserSSHKey();
if (this.user.existUserPublicKey()) {
2025-11-10 08:45:19 +00:00
panel.webview.postMessage({ command: 'createUserPublicKey', data: { ok: true } });
} else {
2025-11-10 08:45:19 +00:00
panel.webview.postMessage({ command: 'createUserPublicKey', data: { ok: false } });
}
2025-11-10 08:45:19 +00:00
break;
case 'getMachineName':
const machineName = os.hostname();
2025-11-10 08:45:19 +00:00
panel.webview.postMessage({ command: 'getMachineName', data: { machineName: machineName } });
break;
}
} else {
// ================= don't need return ==============
// frequent
switch (message.command) {
// ----------------- frequent -----------------------
case 'showInformationNotification':
vscode.window.showInformationMessage(data.message);
break;
case 'showWarningNotification':
2025-11-10 08:45:19 +00:00
vscode.window.showWarningMessage(data.message);
break;
case 'showErrorNotification':
2025-11-10 08:45:19 +00:00
await utils.showErrorNotification(data.message);
break;
2025-11-10 11:51:55 +00:00
case 'openExternalUrl':
// 修复:直接从 message 中获取 url而不是从 data
const url = message.url || (data && data.url);
if (url) {
try {
await vscode.env.openExternal(vscode.Uri.parse(url));
vscode.window.showInformationMessage(`已在浏览器中打开: ${url}`);
} catch (error) {
vscode.window.showErrorMessage(`打开链接失败: ${url}`);
console.error('打开外部链接失败:', error);
}
} else {
console.error('openExternalUrl: url is undefined', message);
vscode.window.showErrorMessage('打开链接失败: 链接地址无效');
}
break;
}
2024-07-02 12:15:39 +08:00
}
},
undefined,
this.context.subscriptions
2024-07-02 12:15:39 +08:00
);
2025-11-10 08:45:19 +00:00
this.context.subscriptions.push(panel);
2024-07-02 12:15:39 +08:00
}
2025-11-10 08:45:19 +00:00
async getWebviewContent(): Promise<string> {
return `
2025-11-10 08:45:19 +00:00
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>DevStar Home</title>
<style>
body {
margin: 0;
padding: 20px;
font-family: var(--vscode-font-family);
background-color: var(--vscode-editor-background);
color: var(--vscode-editor-foreground);
}
.header {
text-align: center;
margin-bottom: 30px;
}
.feature-list {
list-style: none;
padding: 0;
}
.feature-item {
padding: 10px;
margin: 10px 0;
background-color: var(--vscode-button-background);
border-radius: 4px;
cursor: pointer;
text-align: center;
}
.feature-item:hover {
background-color: var(--vscode-button-hoverBackground);
}
.login-status {
padding: 10px;
margin: 10px 0;
border-radius: 4px;
text-align: center;
}
.logged-in {
background-color: var(--vscode-inputValidation-infoBackground);
border: 1px solid var(--vscode-inputValidation-infoBorder);
}
.logged-out {
background-color: var(--vscode-inputValidation-warningBackground);
border: 1px solid var(--vscode-inputValidation-warningBorder);
}
.hidden {
display: none;
}
</style>
</head>
<body>
<div class="header">
<h1>🚀 DevStar Home</h1>
<p>使 DevStar </p>
</div>
<!-- 登录状态显示 -->
<div id="loginStatus" class="login-status hidden">
<span id="statusText"></span>
<span id="usernameDisplay"></span>
</div>
<ul class="feature-list">
<li class="feature-item" onclick="handleMainAction()" id="mainActionButton">
</li>
</ul>
<script>
const vscode = acquireVsCodeApi();
let isLoggedIn = false;
let username = '';
function vscodePostMessage(command, data) {
vscode.postMessage({
command: command,
need_return: false,
data: data
});
}
2025-11-10 08:45:19 +00:00
async function communicateVSCode(command, data) {
return new Promise((resolve, reject) => {
vscode.postMessage({ command: command, need_return: true, data: data });
2025-11-10 08:45:19 +00:00
function handleResponse(event) {
const jsonData = event.data;
if (jsonData.command === command) {
window.removeEventListener('message', handleResponse);
resolve(jsonData.data);
}
}
2025-11-10 08:45:19 +00:00
window.addEventListener('message', handleResponse);
2025-11-10 08:45:19 +00:00
setTimeout(() => {
window.removeEventListener('message', handleResponse);
reject('timeout');
}, 5000);
});
}
2025-11-10 08:45:19 +00:00
// 检查登录状态
async function checkLoginStatus() {
try {
const userTokenResult = await communicateVSCode('getUserToken', {});
const usernameResult = await communicateVSCode('getUsername', {});
const userToken = userTokenResult.userToken;
username = usernameResult.username;
isLoggedIn = !!(userToken && userToken.trim() !== '' && username && username.trim() !== '');
updateUI();
} catch (error) {
console.error('检查登录状态失败:', error);
isLoggedIn = false;
updateUI();
}
2025-11-10 08:45:19 +00:00
}
2025-11-10 08:45:19 +00:00
// 更新UI显示
function updateUI() {
const loginStatus = document.getElementById('loginStatus');
const statusText = document.getElementById('statusText');
const usernameDisplay = document.getElementById('usernameDisplay');
const mainActionButton = document.getElementById('mainActionButton');
loginStatus.classList.remove('hidden');
if (isLoggedIn) {
loginStatus.classList.remove('logged-out');
loginStatus.classList.add('logged-in');
statusText.textContent = '已登录';
usernameDisplay.textContent = username ? ' - 用户: ' + username : '';
mainActionButton.textContent = '跳转到本地服务 (端口 80)';
} else {
loginStatus.classList.remove('logged-in');
loginStatus.classList.add('logged-out');
statusText.textContent = '未登录';
usernameDisplay.textContent = '';
mainActionButton.textContent = '跳转到 DevStar 官网';
}
2025-11-10 08:45:19 +00:00
}
2025-11-10 11:51:55 +00:00
// 处理主要功能点击 - 修复消息发送格式
2025-11-10 08:45:19 +00:00
function handleMainAction() {
if (isLoggedIn) {
// 已登录跳转到本地80端口
vscodePostMessage('showInformationNotification', {message: '跳转到本地服务 http://localhost:80'});
2025-11-10 11:51:55 +00:00
// 修复:直接发送包含 url 的消息
vscode.postMessage({
command: 'openExternalUrl',
need_return: false,
url: 'http://localhost:80'
});
2025-11-10 08:45:19 +00:00
} else {
// 未登录:跳转到 DevStar 官网
vscodePostMessage('showInformationNotification', {message: '跳转到 DevStar 官网'});
2025-11-10 11:51:55 +00:00
// 修复:直接发送包含 url 的消息
vscode.postMessage({
command: 'openExternalUrl',
need_return: false,
url: 'https://devstar.cn'
});
}
2025-11-10 08:45:19 +00:00
}
2025-11-10 08:45:19 +00:00
// 页面加载时检查登录状态
window.addEventListener('load', async () => {
await checkLoginStatus();
});
2025-11-10 08:45:19 +00:00
// 可选:添加重新检查登录状态的功能
function refreshLoginStatus() {
checkLoginStatus();
vscodePostMessage('showInformationNotification', {message: '登录状态已刷新'});
}
</script>
</body>
</html>`;
2024-07-02 12:15:39 +08:00
}
2025-11-10 08:45:19 +00:00
}