diff --git a/launcher/Cargo.lock b/launcher/Cargo.lock index 7c815e7..881a2fe 100644 --- a/launcher/Cargo.lock +++ b/launcher/Cargo.lock @@ -323,11 +323,19 @@ dependencies = [ "cfg-if 1.0.0", ] +[[package]] +name = "itoa" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" + [[package]] name = "launcher" version = "0.1.0" dependencies = [ "notify-rust", + "serde", + "serde_json", "winres", ] @@ -585,6 +593,12 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "ryu" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" + [[package]] name = "scoped-tls" version = "1.0.0" @@ -611,6 +625,17 @@ dependencies = [ "syn 1.0.77", ] +[[package]] +name = "serde_json" +version = "1.0.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f690853975602e1bfe1ccbf50504d67174e3bcf340f23b5ea9992e0587a52d8" +dependencies = [ + "itoa", + "ryu", + "serde", +] + [[package]] name = "serde_repr" version = "0.1.7" diff --git a/launcher/Cargo.toml b/launcher/Cargo.toml index 7ee2df4..71c15e8 100644 --- a/launcher/Cargo.toml +++ b/launcher/Cargo.toml @@ -7,6 +7,8 @@ edition = '2018' target-dir = "dist" [dependencies] +serde_json = "1.0.68" +serde = "1.0.130" notify-rust = "4" [target.'cfg(windows)'.build-dependencies] diff --git a/launcher/src/main.rs b/launcher/src/main.rs index 6d60005..017e7f1 100644 --- a/launcher/src/main.rs +++ b/launcher/src/main.rs @@ -1,37 +1,62 @@ #![cfg_attr(not(debug_assertions),windows_subsystem = "windows")] use std::process::Command; use std::os::windows::process::CommandExt; -use std::path::Path; +use serde::{Deserialize, Serialize}; use notify_rust::Notification; +use std::path::Path; +use serde_json; + +#[derive(Serialize, Deserialize)] +struct Config { + clear_tmp: Option, + clear_output: Option, +} fn main() { + // //是否缺少檔案 if !Path::new("core.exe").is_file() { // core not found Notification::new() - .summary("找不到 core.exe") - .body("相同目錄缺少檔案\"core.exe\"") - .show().unwrap(); + .summary("找不到 core.exe") + .body("相同目錄缺少檔案\"core.exe\"") + .show().unwrap(); panic!("core.exe not found"); } - - + // //是否缺少檔案,缺少的話創建新的 let config = "config.json"; - if !Path::new(&config).is_file() { + let config_path = Path::new(&config); + if !config_path.is_file() { println!("create {}", &config); std::fs::write(config, "{}").unwrap(); }; - + + // //是否缺少檔案,缺少的話創建新的 let tmp = "tmp"; - if !Path::new(&tmp).is_dir() { + let tmp_path = Path::new(&tmp); + if !tmp_path.is_dir() { println!("create {}", &tmp); std::fs::create_dir(tmp).unwrap(); }; + //運行軟體 if cfg!(target_os = "windows") { const CREATE_NO_WINDOW: u32 = 0x08000000; let mut open_core = Command::new("core.exe"); let log = open_core.arg("run").creation_flags(CREATE_NO_WINDOW).output().expect("can't open core"); println!("{}", String::from_utf8_lossy(&log.stdout)); } + + //如果設定有,刪除暫存檔 + let config_json = std::fs::read_to_string(config_path).expect("can't read config"); + let config:Config = serde_json::from_str(&config_json[..]).expect("can't parse config"); + if config.clear_tmp == Some(true) && tmp_path.is_dir(){ + std::fs::remove_dir_all(tmp_path).unwrap(); + } + + //如果設定有,刪除輸出檔 + let output_path = Path::new("output"); + if config.clear_output == Some(true) && output_path.is_dir(){ + std::fs::remove_dir_all(output_path).unwrap(); + } } \ No newline at end of file diff --git a/tools/build.js b/tools/build.js index d97a12d..837147a 100644 --- a/tools/build.js +++ b/tools/build.js @@ -15,7 +15,7 @@ const fs = $fs.promises; const promise = [] promise.push( exec("tsc -p " + "./server/tsconfig.json").then($done), - exec(`npx vue-cli-service build --mode production --dest ../build/www --target app --modern --fix`,{cwd:"./view"}).then($done), + exec(`npm run lint && npx vue-cli-service build --mode production --dest ../build/www --target app --modern --fix`,{cwd:"./view"}).then($done), fs.readdir("./lib").then((files)=>{ files.map(file => { return fs.copyFile("./lib/" + file, "./build/lib/" + file) diff --git a/types/config/index.d.ts b/types/config/index.d.ts index c1ca2e9..c64d0a4 100644 --- a/types/config/index.d.ts +++ b/types/config/index.d.ts @@ -1,3 +1,5 @@ export default interface Config { - thread_count: number; + thread_count: number + clear_output:boolean + clear_tmp:boolean } \ No newline at end of file diff --git a/view/.eslintrc.js b/view/.eslintrc.js index a62473d..4efa478 100644 --- a/view/.eslintrc.js +++ b/view/.eslintrc.js @@ -14,8 +14,8 @@ module.exports = { ecmaVersion: 2020, }, rules: { - "no-console": process.env.NODE_ENV === "production" ? "warn" : "off", - "no-debugger": process.env.NODE_ENV === "production" ? "warn" : "off", + "no-console": "off", + "no-debugger": "off", "@typescript-eslint/no-this-alias": ["off"], }, }; diff --git a/view/src/App.vue b/view/src/App.vue index 0acbee4..4114ddd 100644 --- a/view/src/App.vue +++ b/view/src/App.vue @@ -27,13 +27,13 @@ export default defineComponent({ SidebarTemplate: Sidebar, LoggerTemplate: Logger, }, - setup(){ - const loading = toRef(useStore().state, "loading") + setup() { + const loading = toRef(useStore().state, "loading"); return { - loading + loading, }; }, -}) +}); \ No newline at end of file + diff --git a/view/src/components/choose_files.vue b/view/src/components/choose_files.vue index 840fa60..79abba8 100644 --- a/view/src/components/choose_files.vue +++ b/view/src/components/choose_files.vue @@ -1,82 +1,84 @@ \ No newline at end of file + diff --git a/view/src/components/logger.vue b/view/src/components/logger.vue index 0a33825..b9eff6f 100644 --- a/view/src/components/logger.vue +++ b/view/src/components/logger.vue @@ -1,29 +1,28 @@ \ No newline at end of file + diff --git a/view/src/components/sidebar.vue b/view/src/components/sidebar.vue index c9de66d..0d14a7b 100644 --- a/view/src/components/sidebar.vue +++ b/view/src/components/sidebar.vue @@ -12,17 +12,17 @@ \ No newline at end of file + diff --git a/view/src/components/view_files.vue b/view/src/components/view_files.vue index 51ef011..1e51d50 100644 --- a/view/src/components/view_files.vue +++ b/view/src/components/view_files.vue @@ -36,9 +36,9 @@
@@ -47,15 +47,14 @@ \ No newline at end of file + diff --git a/view/src/main.ts b/view/src/main.ts index 7c26c59..0729d5d 100644 --- a/view/src/main.ts +++ b/view/src/main.ts @@ -1,20 +1,18 @@ import { createApp } from "vue"; import App from "./App.vue"; -import {router} from "./router"; -import { store , key} from "./store"; +import { router } from "./router"; +import { store, key } from "./store"; import _ws from "./websocket"; -addEventListener("resize",()=>window.resizeTo(1200,600));window.resizeTo(1200,600) +addEventListener("resize", () => window.resizeTo(1200, 600)); +window.resizeTo(1200, 600); -const ws = window.ws = new _ws() +const ws = (window.ws = new _ws()); -console.log("啟動GUI") -const app = createApp(App) +console.log("啟動GUI"); +const app = createApp(App); -const app_prop = app.config.globalProperties -app_prop.$ws = ws +const app_prop = app.config.globalProperties; +app_prop.$ws = ws; -app - .use(store,key) - .use(router) - .mount("#root") \ No newline at end of file +app.use(store, key).use(router).mount("#root"); diff --git a/view/src/router/index.ts b/view/src/router/index.ts index 27e4ba7..ca9c56c 100644 --- a/view/src/router/index.ts +++ b/view/src/router/index.ts @@ -1,8 +1,9 @@ import { createRouter, createWebHistory, RouteRecordRaw } from "vue-router"; import Home from "../views/home.vue"; - -function import_vue(name:string){return ()=>import(`../views/${name}.vue`)} +function import_vue(name: string) { + return () => import(`../views/${name}.vue`); +} const routes: Array = [ { path: "/", @@ -22,12 +23,12 @@ const router = createRouter({ routes, }); -const list = [] as {path:string,name:string,}[] +const list = [] as { path: string; name: string }[]; for (const item of routes) { list.push({ - path:item.path, - name:(item.name as string), - }) + path: item.path, + name: item.name as string, + }); } -export {router,list} \ No newline at end of file +export { router, list }; diff --git a/view/src/store/index.ts b/view/src/store/index.ts index 9e91baa..be45a04 100644 --- a/view/src/store/index.ts +++ b/view/src/store/index.ts @@ -1,38 +1,50 @@ -import { InjectionKey } from 'vue' -import { createStore, useStore as baseUseStore, Store, mapMutations as mapMutations, mapState, mapActions } from 'vuex' +import { InjectionKey } from "vue"; +import { + createStore, + useStore as baseUseStore, + Store, + mapMutations as mapMutations, + mapActions, +} from "vuex"; export interface State { - console_opened: boolean - loading: boolean - logger:{title:string,content:string}[] + console_opened: boolean; + loading: boolean; + logger: { title: string; content: string }[]; } -export const key: InjectionKey> = Symbol() +export const key: InjectionKey> = Symbol(); const $store = { state: { console_opened: false, - loading:false, - logger:[], - }, - actions: { - + loading: false, + logger: [], }, + actions: {}, mutations: { - log(state:State,payload:{title:string,content:string}) {state.logger.push(payload)}, - loading(state:State,payload:boolean){state.loading=payload}, - } -} + log(state: State, payload: { title: string; content: string }) { + state.logger.push(payload); + }, + loading(state: State, payload: boolean) { + state.loading = payload; + }, + }, +}; -export const store = createStore($store) +export const store = createStore($store); export const mixin = { methods: { - ...mapActions(Object.keys($store.actions) as Array), - ...mapMutations(Object.keys($store.mutations) as Array) - } -} + ...mapActions( + Object.keys($store.actions) as Array + ), + ...mapMutations( + Object.keys($store.mutations) as Array + ), + }, +}; -export function useStore () { - return baseUseStore(key) -} \ No newline at end of file +export function useStore(): Store { + return baseUseStore(key); +} diff --git a/view/src/store/vuex.d.ts b/view/src/store/vuex.d.ts index 56b9ed7..4a04b82 100644 --- a/view/src/store/vuex.d.ts +++ b/view/src/store/vuex.d.ts @@ -1,11 +1,12 @@ -import { ComponentCustomProperties } from 'vue' -import { State } from '.' -import ws from '@/websocket' +/* eslint-disable */ +import { ComponentCustomProperties } from "vue"; +import { State } from "."; +import ws from "@/websocket"; -declare module '@vue/runtime-core' { +declare module "@vue/runtime-core" { interface ComponentCustomProperties { - $router: Router, - $store: State, - $ws: ws + $router: Router; + $store: State; + $ws: ws; } -} \ No newline at end of file +} diff --git a/view/src/types/global.d.ts b/view/src/types/global.d.ts index d041a8d..1968b3e 100644 --- a/view/src/types/global.d.ts +++ b/view/src/types/global.d.ts @@ -1,7 +1,7 @@ -import ws from '@/websocket' +import ws from "@/websocket"; declare global { - interface Window { - ws : ws + interface Window { + ws: ws; } -} \ No newline at end of file +} diff --git a/view/src/views/home.vue b/view/src/views/home.vue index 4a3ab05..d43cec9 100644 --- a/view/src/views/home.vue +++ b/view/src/views/home.vue @@ -54,12 +54,15 @@ ,直接複製網址。 - +

自動切割

+ :data-checked="edit_setting.auto_cut" + > + 自動切割 +

@@ -71,12 +74,11 @@ \ No newline at end of file + diff --git a/view/src/views/settings.vue b/view/src/views/settings.vue index 5f64501..f683d60 100644 --- a/view/src/views/settings.vue +++ b/view/src/views/settings.vue @@ -1,140 +1,191 @@ \ No newline at end of file + diff --git a/view/src/websocket.ts b/view/src/websocket.ts index e88b9ad..3d736aa 100644 --- a/view/src/websocket.ts +++ b/view/src/websocket.ts @@ -1,95 +1,138 @@ -import { DataType } from 'VS/protocol'; +/* eslint-disable @typescript-eslint/explicit-module-boundary-types */ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { DataType } from "VS/protocol"; export default class { - constructor() { - this.ws = new WebSocket("ws://localhost:" + location.port) - this.ws.addEventListener("message", (event) => { - const $data = JSON.parse(event.data) as WebSocketEvent["sender"] | WebSocketEvent["receiver"] - switch ($data.type) { - case "get": //發送請求 - case "send": { - let promise_data: any = null - if (typeof this.event[$data.key] === "undefined") console.warn(this._info + $data.key + "|未註冊") - else promise_data = this.event[$data.key]($data) + constructor() { + this.ws = new WebSocket("ws://localhost:" + location.port); + this.ws.addEventListener("message", (event) => { + const $data = JSON.parse(event.data) as + | WebSocketEvent["sender"] + | WebSocketEvent["receiver"]; + switch ($data.type) { + case "get": //發送請求 + case "send": { + let promise_data: any = null; + if (typeof this.event[$data.key] === "undefined") + console.warn(this._info + $data.key + "|未註冊"); + else promise_data = this.event[$data.key]($data); - if ($data.type === "get") { - const req = JSON.stringify({ key: $data.key, data: promise_data, hash: $data.hash, type: "receive" } as WebSocketEvent["receiver"]) - if (this.ws.readyState === 0) this._wait_send.push(req) - else this.ws.send(req) - } - break; - } - case "receive": { //取得請求 - this._sync_list[$data.hash]($data as WebSocketEvent["receiver"]) - delete this._sync_list[$data.hash] - break; - } - } - }) - this.ws.addEventListener("open", () => { - console.debug(this._info + "已連線") - this._wait_send.forEach(req => this.ws.send(req)) - this._wait_send = [] - }) - this.ws.addEventListener("close", () => { - console.error(this._info + "已斷線") - close() //如果無法close,嘗試重新連線 - console.warn(this._info + "無法關閉") - setTimeout(() => { - const mode = process.env.NODE_ENV - if (mode === "development") location.reload() - else alert("無法關閉,請檢查是否已被啟動") - }, 500) - }) - } - - on(key: T, fun: (data: WebSocketEvent["sender"]) => DataType[T]["resolve"]|Promise): void - on(key: string, fun: (data: WebSocketEvent["sender"]) => any) { - if (this.event[key]) console.warn(this._info + key + "|重複註冊") - else { - this.event[key] = fun - console.log(this._info + key + "|註冊成功") + if ($data.type === "get") { + const req = JSON.stringify({ + key: $data.key, + data: promise_data, + hash: $data.hash, + type: "receive", + } as WebSocketEvent["receiver"]); + if (this.ws.readyState === 0) this._wait_send.push(req); + else this.ws.send(req); + } + break; } - } - - off(key: T): void - off(key: string) { - if (!this.event[key]) console.warn(this._info + key + "|嘗試刪除未註冊") - else { - delete this.event[key] - console.log(this._info + key + "|刪除註冊") + case "receive": { + //取得請求 + this._sync_list[$data.hash]($data as WebSocketEvent["receiver"]); + delete this._sync_list[$data.hash]; + break; } + } + }); + this.ws.addEventListener("open", () => { + console.debug(this._info + "已連線"); + this._wait_send.forEach((req) => this.ws.send(req)); + this._wait_send = []; + }); + this.ws.addEventListener("close", () => { + console.error(this._info + "已斷線"); + close(); //如果無法close,嘗試重新連線 + console.warn(this._info + "無法關閉"); + setTimeout(() => { + const mode = process.env.NODE_ENV; + if (mode === "development") location.reload(); + else alert("無法關閉,請檢查是否已被啟動"); + }, 500); + }); + } + + on( + key: T, + fun: ( + data: WebSocketEvent["sender"] + ) => DataType[T]["resolve"] | Promise + ): void; + on(key: string, fun: (data: WebSocketEvent["sender"]) => any) { + if (this.event[key]) console.warn(this._info + key + "|重複註冊"); + else { + this.event[key] = fun; + console.log(this._info + key + "|註冊成功"); } - send(key: T, data: DataType[T]["req"]): void - send(key: string, data: any) { - const req = JSON.stringify({ key: key, data: data, type: "send" } as WebSocketEvent["sender"]) - if (this.ws.readyState === 0) this._wait_send.push(req) - else this.ws.send(req) + } + + off(key: T): void; + off(key: string) { + if (!this.event[key]) console.warn(this._info + key + "|嘗試刪除未註冊"); + else { + delete this.event[key]; + console.log(this._info + key + "|刪除註冊"); } + } + send(key: T, data: DataType[T]["req"]): void; + send(key: string, data: any): void { + const req = JSON.stringify({ + key: key, + data: data, + type: "send", + } as WebSocketEvent["sender"]); + if (this.ws.readyState === 0) this._wait_send.push(req); + else this.ws.send(req); + } - //========================================== - // sync 互動 - //========================================== + //========================================== + // sync 互動 + //========================================== - get(key: T, data:DataType[T]["req"]): Promise["receiver"]> - async get(key: string, data: any) { - const hash = this._hash() - const req = JSON.stringify({ key: key, data: data, type: "get", hash } as WebSocketEvent["sender"]) - if (this.ws.readyState === 0) { - this._wait_send.push(req) - } - else this.ws.send(req) - return new Promise((resolve, reject) => this._sync_list[hash] = resolve) - } + get( + key: T, + data: DataType[T]["req"] + ): Promise["receiver"]>; + async get(key: string, data: any): Promise["receiver"]> { + const hash = this._hash(); + const req = JSON.stringify({ + key: key, + data: data, + type: "get", + hash, + } as WebSocketEvent["sender"]); + if (this.ws.readyState === 0) { + this._wait_send.push(req); + } else this.ws.send(req); + return new Promise((resolve) => (this._sync_list[hash] = resolve)); + } - ws: WebSocket - event: { [key: string]: (enevt: WebSocketEvent["sender"]) => any } = {} - private _info = "|websocket|" - private _wait_send: string[] = [] - private _sync_list: { [hash: string]: (req: WebSocketEvent["receiver"]) => void } = {} - private _hash() { let result = ''; const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; for (let i = 0; i < 12; i++)result += characters.charAt(Math.floor(Math.random() * 62)); return result } + ws: WebSocket; + event: { [key: string]: (enevt: WebSocketEvent["sender"]) => any } = {}; + private _info = "|websocket|"; + private _wait_send: string[] = []; + private _sync_list: { + [hash: string]: (req: WebSocketEvent["receiver"]) => void; + } = {}; + private _hash() { + let result = ""; + const characters = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + for (let i = 0; i < 12; i++) + result += characters.charAt(Math.floor(Math.random() * 62)); + return result; + } } interface WebSocketEvent { - sender: { key: string, data: DataType[T]["req"], type: "send" } | { key: string, data: DataType[T]["req"], hash: string, type: "get" } - receiver: { key: string, data: DataType[T]["resolve"], hash: string, type: "receive" } -} \ No newline at end of file + sender: + | { key: string; data: DataType[T]["req"]; type: "send" } + | { key: string; data: DataType[T]["req"]; hash: string; type: "get" }; + receiver: { + key: string; + data: DataType[T]["resolve"]; + hash: string; + type: "receive"; + }; +}