Commit d97349d0 authored by 神楽坂玲奈's avatar 神楽坂玲奈

Merge branch 'v3' of github.com:mycard/mycard into v3

parents 69513b55 f81a7ac0
......@@ -12,7 +12,7 @@
class="progress progress-striped progress-animated"
value="{{currentApp.status.progress}}" max="{{currentApp.status.total}}"></progress>
<div *ngIf="currentApp.status.status==='ready' && (currentApp.id != 'ygopro')">
<button (click)="startApp(currentApp)" type="button" class="btn btn-primary">运行</button>
<button (click)="runApp(currentApp)" type="button" class="btn btn-primary">运行</button>
<button type="button" data-toggle="modal" data-target="#settings-modal" class="btn btn-secondary">设置</button>
<!--<button (click)="appsService.browse(currentApp)" type="button" class="btn btn-secondary">游览本地文件</button>-->
......@@ -114,7 +114,7 @@
<div *ngIf="currentApp.isInstalled()">
<h2>本地文件</h2>
<button (click)="appsService.browse(currentApp)" type="button" class="btn btn-secondary">浏览本地文件</button>
<button (click)="uninstall(currentApp.id)" type="button" class="btn btn-secondary">
<button (click)="uninstall(currentApp)" type="button" class="btn btn-secondary">
{{'uninstall'|translate}}
</button>
</div>
......@@ -202,7 +202,8 @@
<h4>{{'additions'|translate}}</h4>
<div *ngFor="let reference of installConfig.references">
<label>
<input type="checkbox" [(ngModel)]="reference.install" name="references" value="{{reference.app.id}}">
<input type="checkbox" [(ngModel)]="reference.install" name="references"
value="{{reference.app.id}}">
{{reference.app.name}}
</label>
</div>
......
......@@ -30,11 +30,6 @@ export class AppDetailComponent implements OnInit {
}
ngOnInit() {
// this.updateInstallConfig();
ipcRenderer.on('download-message-reply', (event, arg)=> {
console.log(arg);
});
ipcRenderer.send("download-message", "ping")
}
updateInstallConfig() {
......@@ -54,14 +49,6 @@ export class AppDetailComponent implements OnInit {
return this.currentApp.news;
}
get friends() {
return false;
}
get achievement() {
return false;
}
get mods() {
// let contains = ["optional", "language", "emulator"];
//
......@@ -95,15 +82,11 @@ export class AppDetailComponent implements OnInit {
return [];
}
uninstalling: boolean;
uninstall(id: string) {
async uninstall(app: App) {
if (confirm("确认删除?")) {
this.uninstalling = true;
// this.appsService.uninstall(id).then(()=> {
// this.uninstalling = false;
// }
// );
await this.installService.uninstall(app);
this.currentApp.status.status = "init";
}
}
......@@ -148,9 +131,7 @@ export class AppDetailComponent implements OnInit {
return this.installService.add(completeApp, options);
});
}));
console.log("before")
await this.installService.getComplete(currentApp);
console.log("install complete");
currentApp.status.status = "ready";
this.ref.detectChanges();
} catch (e) {
......@@ -167,42 +148,8 @@ export class AppDetailComponent implements OnInit {
return dir[0];
}
startApp(app: App) {
let execute = path.join(app.local.path, app.actions.get("main").execute);
let args = app.actions.get("main").args;
let env = app.actions.get("main").env;
let opt = {
cwd: app.local.path,
env: env
};
let open = '';
let openApp = app.actions.get("main").open;
if (openApp) {
open = path.join(openApp.local.path, openApp.actions.get("main").execute);
args.push(execute);
} else {
//没有需要通过open启动依赖,直接启动程序
open = execute;
}
let handle = child_process.spawn(open, args, opt);
handle.stdout.on('data', (data) => {
console.log(`stdout: ${data}`);
});
handle.stderr.on('data', (data) => {
console.log(`stderr: ${data}`);
});
handle.on('close', (code) => {
console.log(`child process exited with code ${code}`);
remote.getCurrentWindow().restore();
});
remote.getCurrentWindow().minimize();
runApp(app: App) {
this.appsService.runApp(app);
}
copy(text) {
......
......@@ -55,7 +55,7 @@ export class App {
status: AppStatus;
isInstalled(): boolean {
return this.local !== undefined;
return !!this.local;
}
constructor(app) {
......
import {Injectable, ApplicationRef, NgZone} from "@angular/core";
import {Injectable, ApplicationRef} from "@angular/core";
import {Http} from "@angular/http";
import {App, AppStatus} from "./app";
import {InstallConfig} from "./install-config";
......@@ -17,24 +17,27 @@ import {AppLocal} from "./app-local";
const Aria2 = require('aria2');
const Sudo = require('electron-sudo').default;
Sudo.prototype.fork = async function (modulePath, args, options) {
let child = await this.spawn(remote.app.getPath('exe'), ['-e', modulePath].concat(args), options);
readline.createInterface({input: child.stdout}).on('line', (line) => {
child.emit('message', JSON.parse(line));
});
child.send = (message, sendHandle, options, callback)=> {
child.stdin.write(JSON.stringify(message) + os.EOL);
if (callback) {
callback()
}
};
return child
Sudo.prototype.fork = function (modulePath, args, options) {
return this.spawn(remote.app.getPath('exe'), ['-e', modulePath].concat(args), options).then((child)=> {
readline.createInterface({input: child.stdout}).on('line', (line) => {
child.emit('message', JSON.parse(line));
});
child.send = (message, sendHandle, options, callback)=> {
child.stdin.write(JSON.stringify(message) + os.EOL);
if (callback) {
callback()
}
};
return child
})
};
@Injectable()
export class AppsService {
constructor(private http: Http, private settingsService: SettingsService, private ref: ApplicationRef, private ngZong: NgZone) {
private apps: Map<string,App>;
constructor(private http: Http, private settingsService: SettingsService, private ref: ApplicationRef,) {
}
......@@ -43,7 +46,8 @@ export class AppsService {
.toPromise()
.then((response)=> {
let data = response.json();
return this.loadAppsList(data);
this.apps = this.loadAppsList(data);
return this.apps;
});
}
......@@ -122,55 +126,52 @@ export class AppsService {
return apps;
};
deleteFile(path: string): Promise<string> {
return new Promise((resolve, reject)=> {
fs.lstat(path, (err, stats)=> {
if (err) return resolve(path);
if (stats.isDirectory()) {
fs.rmdir(path, (err)=> {
resolve(path);
});
} else {
fs.unlink(path, (err)=> {
resolve(path);
});
}
});
})
findChildren(app: App): App[] {
let children = [];
for (let child of this.apps.values()) {
if (child.parent === app) {
children.push(child);
}
}
return children;
}
saveAppLocal(app: App, appLocal: AppLocal) {
localStorage.setItem(app.id, JSON.stringify(appLocal));
}
runApp(app: App) {
let children = this.findChildren(app);
let cwd = app.local.path;
let action = app.actions.get('main');
let args = [];
let env = {};
for (let child of children) {
action = child.actions.get('main');
}
let execute = path.join(cwd, action.execute);
if (action.open) {
let openAction = action.open.actions.get('main');
args = args.concat(openAction.args);
args.push(action.execute);
execute = path.join(action.open.local.path, openAction.execute);
env = Object.assign(env, openAction.env);
}
args = args.concat(action.args);
env = Object.assign(env, action.env);
let handle = child_process.spawn(execute, args, {env: env, cwd: cwd});
install(config: InstallConfig) {
let app = config.app;
}
handle.stdout.on('data', (data) => {
console.log(`stdout: ${data}`);
});
uninstall(id: string) {
// //let current = this;
// if (this.checkInstall(id)) {
// let files: string[] = this.searchApp(id).local.files.sort().reverse();
// // 删除本目录
// files.push('.');
// let install_dir = this.searchApp(id).local.path;
// return files
// .map((file)=>
// ()=>path.join(install_dir, file)
// )
// .reduce((promise: Promise<string>, task)=>
// promise.then(task).then(this.deleteFile)
// , Promise.resolve(''))
// .then((value)=> {
// this.searchApp(id).local = null;
// localStorage.setItem("localAppData", JSON.stringify(this.data));
// return Promise.resolve()
// });
// }
handle.stderr.on('data', (data) => {
console.log(`stderr: ${data}`);
});
}
handle.on('close', (code) => {
console.log(`child process exited with code ${code}`);
remote.getCurrentWindow().restore();
});
remote.getCurrentWindow().minimize();
}
browse(app: App) {
remote.shell.showItemInFolder(app.local.path);
......@@ -179,60 +180,55 @@ export class AppsService {
connections = new Map<App, {connection: WebSocket, address: string}>();
maotama;
async network(app: App, server) {
network(app: App, server) {
if (!this.maotama) {
this.maotama = new Sudo({name: 'MyCard'}).fork('maotama')
}
let child = await this.maotama;
// child.on('message', console.log);
// child.on('exit', console.log);
// child.on('error', console.log);
let connection = this.connections.get(app);
if (connection) {
connection.connection.close();
}
connection = {connection: new WebSocket(server.url), address: null};
let id;
this.connections.set(app, connection);
connection.connection.onmessage = (event)=> {
console.log(event.data);
let [action, args] = event.data.split(' ', 2);
let [address, port] = args.split(':');
switch (action) {
case 'LISTEN':
connection.address = args;
this.ref.tick();
break;
case 'CONNECT':
this.ngZong.runOutsideAngular(()=> {
this.maotama.then((child)=> {
let connection = this.connections.get(app);
if (connection) {
connection.connection.close();
}
connection = {connection: new WebSocket(server.url), address: null};
let id;
this.connections.set(app, connection);
connection.connection.onmessage = (event)=> {
console.log(event.data);
let [action, args] = event.data.split(' ', 2);
let [address, port] = args.split(':');
switch (action) {
case 'LISTEN':
connection.address = args;
this.ref.tick();
break;
case 'CONNECT':
id = setInterval(()=> {
child.send({
action: 'connect',
arguments: [app.network.port, port, address]
})
}, 200);
});
break;
case 'CONNECTED':
break;
case 'CONNECTED':
clearInterval(id);
id = null;
break;
}
};
connection.connection.onclose = (event: CloseEvent)=> {
if (id) {
clearInterval(id);
id = null;
break;
}
};
connection.connection.onclose = (event: CloseEvent)=> {
if (id) {
clearInterval(id);
}
// 如果还是在界面上显示的那个连接
if (this.connections.get(app) == connection) {
this.connections.delete(app);
if (event.code != 1000 && !connection.address) {
// 如果还没建立好就出错了,就弹窗提示这个错误
alert(`出错了 ${event.code}`);
}
// 如果还是在界面上显示的那个连接
if (this.connections.get(app) == connection) {
this.connections.delete(app);
if (event.code != 1000 && !connection.address) {
alert(`出错了 ${event.code}`);
}
}
// 如果还没建立好就出错了,就弹窗提示这个错误
this.ref.tick();
}
};
};
})
}
}
\ No newline at end of file
......@@ -14,6 +14,7 @@ import {EventEmitter} from "events";
import {AppLocal} from "./app-local";
import {Http} from "@angular/http";
import ReadableStream = NodeJS.ReadableStream;
import {AppsService} from "./apps.service";
@Injectable()
export class InstallService {
......@@ -25,7 +26,7 @@ export class InstallService {
checksumUri = "http://thief.mycard.moe/checksums/";
constructor(private http: Http) {
constructor(private http: Http, private appsService: AppsService) {
if (process.platform === "win32") {
this.tarPath = path.join(process.resourcesPath, 'bin/tar.exe');
} else {
......@@ -43,7 +44,6 @@ export class InstallService {
getComplete(app: App): Promise<App> {
return new Promise((resolve, reject)=> {
this.eventEmitter.once(app.id, (complete)=> {
console.log("receive ",app.id);
resolve();
});
});
......@@ -103,9 +103,7 @@ export class InstallService {
saveAppLocal(app: App) {
if (app.local) {
let a = JSON.stringify(app.local)
console.log(a);
localStorage.setItem(app.id, a);
localStorage.setItem(app.id, JSON.stringify(app.local));
}
}
......@@ -164,7 +162,6 @@ export class InstallService {
local.version = app.version;
app.local = local;
this.saveAppLocal(app);
console.log("send ",app.id);
this.eventEmitter.emit(app.id, 'install complete');
this.installQueue.delete(app);
this.installingQueue.delete(app);
......@@ -184,4 +181,55 @@ export class InstallService {
}
}
deleteFile(file: string): Promise<string> {
return new Promise((resolve, reject)=> {
fs.lstat(file, (err, stats)=> {
if (err) return resolve(path);
if (stats.isDirectory()) {
fs.rmdir(file, (err)=> {
resolve(file);
});
} else {
fs.unlink(file, (err)=> {
resolve(file);
});
}
});
})
}
async uninstall(app: App) {
if (!app.parent) {
let children = this.appsService.findChildren(app);
for (let child of children) {
if(child.isInstalled()) {
await this.uninstall(child);
}
}
}
let files = Array.from(app.local.files.keys()).sort().reverse();
console.log(files);
for (let file of files) {
let oldFile = file;
if (!path.isAbsolute(file)) {
oldFile = path.join(app.local.path, file);
}
await this.deleteFile(oldFile);
if (app.parent) {
let backFile = path.join(app.local.path, "backup", file);
await new Promise((resolve, reject)=> {
fs.rename(backFile, oldFile, resolve);
});
}
}
if (app.parent) {
await this.deleteFile(path.join(app.local.path, "backup"));
} else {
await this.deleteFile(app.local.path);
}
app.local = null;
localStorage.removeItem(app.id);
}
}
\ No newline at end of file
<nav class="navbar navbar-dark bg-inverse" [class.darwin]="platform == 'darwin'">
<a class="navbar-brand" href="#">MyCard 1</a>
<a class="navbar-brand" href="#">MyCard</a>
<ul class="nav navbar-nav">
<li *ngIf="!loginService.user" class="nav-item active">
<a class="nav-link" href="#">登录<span class="sr-only">(current)</span></a>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment