add electron

This commit is contained in:
monoid 2021-01-10 03:04:30 +09:00
parent 53aebb365e
commit 05814d8a31
9 changed files with 157 additions and 88 deletions

2
.gitignore vendored
View File

@ -8,3 +8,5 @@ data/**
data/
package-lock.json
devdb.sqlite3
build/**
app/**

86
app.ts Normal file
View File

@ -0,0 +1,86 @@
import { app, BrowserWindow } from "electron";
import { get_setting } from "./src/setting";
import { create_server, start_server } from "./src/server";
const loading_html = `<!DOCTYPE html>
<html lang="ko"><head>
<meta charset="UTF-8">
<title>react-sample</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<style>
body { margin-top: 100px; background-color: #3f51b5; color: #fff; text-align:center; }
h1 {
font: 2em 'Roboto', sans-serif;
margin-bottom: 40px;
}
#loading {
display: inline-block;
width: 50px;
height: 50px;
border: 3px solid rgba(255,255,255,.3);
border-radius: 50%;
border-top-color: #fff;
animation: spin 1s linear infinite;
}
@keyframes spin {
to { transform: rotate(360deg);}
}
</style>
<body>
<h1>Loading</h1>
<div id="loading"></div>
</body>
</html>
`;
const setting = get_setting();
if (!setting.cli) {
let window: BrowserWindow | null = null;
const createWindow = async () => {
window = new BrowserWindow({
width: 800,
height: 600,
center: true,
useContentSize: true,
});
await window.loadURL(`data:text/html;base64,`+Buffer.from(loading_html).toString('base64'));
const server = await create_server();
start_server(server);
await window.loadURL(`http://localhost:${setting.port}`);
window.on("closed", () => {
window = null;
});
};
const isPrimary = app.requestSingleInstanceLock();
if (!isPrimary) {
app.quit(); //exit window
app.exit();
}
app.on("second-instance", () => {
if (window != null) {
if (window.isMinimized()) {
window.restore();
}
window.focus();
}
});
app.on("ready", (event, info) => {
createWindow();
});
app.on("window-all-closed", () => { // quit when all windows are closed
if (process.platform != "darwin") app.quit(); // (except leave MacOS app active until Cmd+Q)
});
app.on("activate", () => { // re-recreate window when dock icon is clicked and no other windows open
if (window == null) createWindow();
});
} else {
(async () => {
const server = await create_server();
start_server(server);
})();
}

View File

@ -2,14 +2,35 @@
"name": "followed",
"version": "1.0.0",
"description": "",
"main": "server.ts",
"main": "build/app.js",
"scripts": {
"test": "mocha",
"build:dev": "webpack --mode development",
"build:prod": "webpack --mode production",
"build:watch": "webpack --mode development -w",
"start": "ts-node src/server.ts",
"check-types": "tsc"
"compile": "tsc",
"compile:watch": "tsc -w",
"app": "electron build/app.js",
"app:build:win64": "electron-builder --win --x64"
},
"build": {
"asar": false,
"files":[
"build/**/*",
"node_modules/**/*",
"package.json"
],
"appId": "com.prelude.ionian.app",
"productName": "Ionian",
"win": {
"target": [
"zip"
]
},
"directories": {
"output": "app/",
"app": "."
}
},
"browserslist": {
"production": [
@ -35,8 +56,7 @@
"react": "^17.0.1",
"react-dom": "^17.0.1",
"react-router-dom": "^5.2.0",
"sqlite3": "^5.0.0",
"ts-node": "^9.1.1"
"sqlite3": "^5.0.0"
},
"devDependencies": {
"@babel/core": "^7.12.10",
@ -57,8 +77,11 @@
"babel-core": "^6.26.3",
"babel-loader": "^8.2.2",
"css-loader": "^5.0.1",
"electron": "^11.1.1",
"electron-builder": "^22.9.1",
"mini-css-extract-plugin": "^1.3.3",
"style-loader": "^2.0.0",
"ts-node": "^9.1.1",
"typescript": "^4.1.3",
"webpack": "^5.11.0",
"webpack-cli": "^4.2.0",

View File

@ -1,8 +1 @@
{
"path": [
"data"
],
"localmode": true,
"guest": false,
"jwt_secretkey": "itsRandom"
}
{"path":[],"localmode":true,"guest":false,"jwt_secretkey":"itsRandom","port":8080,"mode":"production","cli":true}

View File

@ -1,13 +1,11 @@
import { existsSync } from 'fs';
import Knex from 'knex';
import {Knex as KnexConfig} from './config';
import { get_setting } from './setting';
export async function connectDB(){
const env = process.env.NODE_ENV || 'development';
const config = KnexConfig.config;
if(env != "production" && env != "development"){
throw new Error("process unknown value in NODE_ENV: must be either \"development\" or \"production\"");
}
const env = get_setting().mode;
const init_need = !existsSync(config[env].connection.filename);
const knex = Knex(config[env]);
let tries = 0;

View File

@ -16,9 +16,11 @@ import {UserMiddleWare,createLoginMiddleware, isAdminFirst, getAdmin, LogoutMidd
import {createInterface as createReadlineInterface} from 'readline';
//let Koa = require("koa");
async function main(){
let settings = get_setting();
export async function create_server(){
let setting = get_setting();
let db = await connectDB();
if(setting.cli){
const userAdmin = await getAdmin(db);
if(await isAdminFirst(userAdmin)){
const rl = createReadlineInterface({input:process.stdin,output:process.stdout});
@ -29,6 +31,7 @@ async function main(){
});
userAdmin.reset_password(pw);
}
}
let app = new Koa();
app.use(bodyparser());
app.use(error_handler);
@ -39,8 +42,8 @@ async function main(){
let router = new Router();
let watcher = new Watcher(settings.path[0]);
await watcher.setup([]);
//let watcher = new Watcher(setting.path[0]);
//await watcher.setup([]);
const serveindex = (url:string)=>{
router.get(url, (ctx)=>{ctx.type = 'html'; ctx.body = index_html;})
}
@ -74,9 +77,11 @@ async function main(){
});
app.use(router.routes());
app.use(router.allowedMethods());
console.log("start server");
app.listen(settings.port,settings.localmode ? "127.0.0.1" : "0.0.0.0");
return app;
}
main();
export const start_server = (server: Koa)=>{
let setting = get_setting();
console.log("start server");
return server.listen(setting.port,setting.localmode ? "127.0.0.1" : "0.0.0.0");
}
export default {create_server, start_server};

View File

@ -1,6 +1,6 @@
import { Settings } from '@material-ui/icons';
import { randomBytes } from 'crypto';
import { readFileSync, writeFileSync } from 'fs';
import { existsSync, readFileSync, writeFileSync } from 'fs';
export type Setting = {
path: string[],
@ -8,6 +8,8 @@ export type Setting = {
guest: boolean,
jwt_secretkey: string,
port:number,
mode:"development"|"production",
cli:boolean,
}
const default_setting:Setting = {
path:[],
@ -15,6 +17,8 @@ const default_setting:Setting = {
guest:false,
jwt_secretkey:"itsRandom",
port:8080,
mode:"production",
cli:false
}
let setting: null|Setting = null;
@ -31,16 +35,21 @@ const setEmptyToDefault = (target:any,default_table:Setting)=>{
}
export const read_setting_from_file = ()=>{
let ret = JSON.parse(readFileSync("settings.json",{encoding:"utf8"})) as Setting;
let ret = existsSync("settings.json") ? JSON.parse(readFileSync("settings.json",{encoding:"utf8"})) : {};
const partial_occur = setEmptyToDefault(ret,default_setting);
if(partial_occur){
writeFileSync("settings.json",JSON.stringify(ret));
}
return ret;
return ret as Setting;
}
export function get_setting():Setting{
if(setting === null){
setting = read_setting_from_file();
const env = process.env.NODE_ENV || 'development';
if(env != "production" && env != "development"){
throw new Error("process unknown value in NODE_ENV: must be either \"development\" or \"production\"");
}
setting.mode = env || setting.mode;
}
return setting;
}

48
test.ts
View File

@ -1,48 +0,0 @@
import StreamZip, { ZipEntry } from 'node-stream-zip';
import {orderBy}from 'natural-orderby';
import {readZip,entriesByNaturalOrder} from './src/util/ziputil';
import {connectDB} from './src/database';
import { createKnexUserController } from './src/db/user';
import { createKnexContentsAccessor} from './src/db/contents';
console.log("on");
async function test_main1(){
let sz = await readZip("testdata/test_zip.zip");
let e = entriesByNaturalOrder(sz).filter(v=>v.name.split('.').pop() === "jpg");
console.log(e[0]);
console.log(e.map(v=>v.name));
}
async function test_main2(){
let db = await connectDB();
let user:{id:number}[] = await db.select('id').from('users');
console.log(user[0].id);
}
async function test_main3(){
let db = await connectDB();
let user_controller = createKnexUserController(db);
let bs = await user_controller.delUser("sss");
if(!bs) console.log("doesn't exist")
let retuser = await user_controller.createUser({username:"sss",password:"sss"});
let user = await user_controller.findUser("sss");
if(user !== undefined){
user.add("create");
console.log(user.username);
}
}
async function test_main4(){
let db = await connectDB();
const cntr = createKnexContentsAccessor(db);
await cntr.add({
title:"aaa",
basepath:"testdata",
content_type:"manga",
filename:"test_zip.zip",
additional:{comment:"aaab"},
tags:[]
});
const list = await cntr.findList();
console.log(list);
}
test_main4();

View File

@ -14,7 +14,7 @@
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
// "sourceMap": true, /* Generates corresponding '.map' file. */
// "outFile": "./", /* Concatenate and emit output to single file. */
// "outDir": "./", /* Redirect output structure to the directory. */
"outDir": "./build", /* Redirect output structure to the directory. */
// "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
// "composite": true, /* Enable project compilation */
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
@ -64,7 +64,8 @@
/* Advanced Options */
"skipLibCheck": true, /* Skip type checking of declaration files. */
"forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */
"forceConsistentCasingInFileNames": true, /* Disallow inconsistently-cased references to the same file. */
},
"include": ["src","./"]
"include": ["./"],
"exclude": ["src/client","app","seeds"],
}