This commit is contained in:
sx1989827 2021-09-05 20:36:51 +08:00
parent dbf05b7319
commit 490cd96425
83 changed files with 857 additions and 203 deletions

View File

@ -0,0 +1,9 @@
export interface ICommon_Model_Admin {
id:bigint,
name:string,
password:string,
description:string,
created_time:Date,
modified_time:Date
}
export const Table_Admin="admin"

View File

@ -1,10 +1,10 @@
export default interface IServer_DB_Model_Comment {
export interface ICommon_Model_Comment {
id:bigint,
type:number,
type_id:bigint,
user_id:bigint,
content:string,
created_time:number,
modified_time:number
created_time:Date,
modified_time:Date
}
export const Table_Comment="comment"

View File

@ -1,10 +1,10 @@
export default interface IServer_DB_Model_Field {
export interface ICommon_Model_Field {
id:bigint,
type_id:bigint,
system:number,
description:string,
created_time:number,
modified_time:number,
created_time:Date,
modified_time:Date,
created_by:bigint,
modified_by:bigint,
name:string

View File

@ -1,8 +1,8 @@
export default interface IServer_DB_Model_Field_Component {
export interface ICommon_Model_Field_Component {
id:bigint,
description:string,
created_time:number,
modified_time:number,
created_time:Date,
modified_time:Date,
created_by:bigint,
modified_by:bigint,
name:string

View File

@ -1,10 +1,10 @@
export default interface IServer_DB_Model_Field_Component_Field {
export interface ICommon_Model_Field_Component_Field {
id:bigint,
type_id:bigint,
system:number,
description:string,
created_time:number,
modified_time:number,
created_time:Date,
modified_time:Date,
created_by:bigint,
modified_by:bigint,
name:string

View File

@ -1,4 +1,4 @@
export default interface IServer_DB_Model_Field_Config_Value {
export interface ICommon_Model_Field_Config_Value {
id: bigint,
field_id :bigint,
value :string,

View File

@ -1,7 +1,7 @@
export default interface IServer_DB_Model_Field_Solution {
export interface ICommon_Model_Field_Solution {
id :bigint,
created_time :number,
modified_time :number ,
created_time :Date,
modified_time :Date ,
created_by :bigint,
modified_by: bigint,
name :string,

View File

@ -1,4 +1,4 @@
export default interface IServer_DB_Model_Field_Solution_Config_Or_Field {
export interface ICommon_Model_Field_Solution_Config_Or_Field {
id :bigint,
type :number,
field_solution_id :bigint,

View File

@ -1,4 +1,4 @@
export default interface IServer_DB_Model_Field_Solution_Workflow {
export interface ICommon_Model_Field_Solution_Workflow {
id: bigint,
field_solution_id :bigint,
workflow_id :bigint,

View File

@ -1,4 +1,4 @@
export default interface IServer_DB_Model_Field_Solution_Workflow_Action {
export interface ICommon_Model_Field_Solution_Workflow_Action {
id :bigint,
field_solution :bigint ,
workflow_action_id :bigint ,

View File

@ -1,4 +1,4 @@
export default interface IServer_DB_Model_Field_Type {
export interface ICommon_Model_Field_Type {
id :bigint,
name :string,
icon :bigint,

View File

@ -1,11 +1,11 @@
export default interface IServer_DB_Model_File {
export interface ICommon_Model_File {
id :bigint,
user_id :bigint,
project_id :bigint ,
size: bigint ,
filename :string,
type :string,
created_time :number,
created_time :Date,
path :string,
}
export const Table_File="file"

View File

@ -0,0 +1,8 @@
export interface ICommon_Model_Group {
id :bigint ,
name :string,
created_time :Date,
modified_time :Date,
created_by :bigint ,
}
export const Table_Group="group"

View File

@ -1,4 +1,4 @@
export default interface IServer_DB_Model_Issue_Type {
export interface ICommon_Model_Issue_Type {
id:bigint,
name:string,
icon:bigint,

View File

@ -1,10 +1,10 @@
export default interface IServer_DB_Model_Issue_Type_Solution {
export interface ICommon_Model_Issue_Type_Solution {
id :bigint ,
name :string,
description :string,
system :number,
created_time :number,
modify_time :number,
created_time :Date,
modified_time :Date,
created_by :bigint ,
modified_by :bigint ,
}

View File

@ -1,4 +1,4 @@
export default interface IServer_DB_Model_Issue_Type {
export interface ICommon_Model_Issue_Type {
id :bigint ,
issue_type_id :bigint,
issue_type_solution_id :bigint,

View File

@ -1,8 +1,8 @@
export default interface IServer_DB_Model_Permission {
export interface ICommon_Model_Permission {
id: bigint,
name :string,
created_time :number,
modified_time :number,
created_time :Date,
modified_time :Date,
type :number,
value :number,
}

View File

@ -1,4 +1,4 @@
export default interface IServer_DB_Model_Permission_Target {
export interface ICommon_Model_Permission_Target {
id :bigint,
permission_id: bigint,
target_id :bigint,

View File

@ -1,9 +1,9 @@
export default interface IServer_DB_Model_Project {
export interface ICommon_Model_Project {
id :bigint,
key :string,
name :string,
created_time :number,
modified_time :number,
created_time :Date,
modified_time :Date,
image :bigint,
created_by :bigint ,
description :string,

View File

@ -1,4 +1,4 @@
export default interface IServer_DB_Model_Project_Field_Solution {
export interface ICommon_Model_Project_Field_Solution {
id: bigint,
project_id :bigint ,
field_solution_id :bigint ,

View File

@ -1,8 +1,8 @@
export default interface IServer_DB_Model_Project_Issue {
export interface ICommon_Model_Project_Issue {
unique_id :number,
id :bigint ,
created_time :number,
modified_time :number,
created_time :Date,
modified_time :Date,
created_by :bigint ,
modified_by :bigint ,
project_id :bigint ,

View File

@ -1,4 +1,4 @@
export default interface IServer_DB_Model_Project_Issue_Description {
export interface ICommon_Model_Project_Issue_Description {
id :bigint,
project_issue_id :bigint,
content:string

View File

@ -1,4 +1,4 @@
export default interface IServer_DB_Model_Project_Issue_Field_Value {
export interface ICommon_Model_Project_Issue_Field_Value {
id :bigint,
project_issue_id :bigint,
field_id :bigint,

View File

@ -1,4 +1,4 @@
export default interface IServer_DB_Model_Project_Issue_Parent {
export interface ICommon_Model_Project_Issue_Parent {
id :bigint,
parent_id :bigint,
child_id:bigint

View File

@ -1,4 +1,4 @@
export default interface IServer_DB_Model_Project_Issue_Related {
export interface ICommon_Model_Project_Issue_Related {
id :bigint,
project_issue_1_id :bigint,
project_issue_2_id:bigint

View File

@ -1,4 +1,4 @@
export default interface IServer_DB_Model_Project_Issue_Solution {
export interface ICommon_Model_Project_Issue_Solution {
id :bigint,
project_id :bigint,
issue_solution_id:bigint

View File

@ -1,4 +1,4 @@
export default interface IServer_DB_Model_Project_Lable {
export interface ICommon_Model_Project_Lable {
id :bigint,
name:string
}

View File

@ -1,4 +1,4 @@
export default interface IServer_DB_Model_Project_Lable_Issue {
export interface ICommon_Model_Project_Lable_Issue {
id :bigint,
project_label_id:bigint,
project_issue_id:bigint

View File

@ -1,4 +1,4 @@
export default interface IServer_DB_Model_Project_Module {
export interface ICommon_Model_Project_Module {
id :bigint,
name:string
}

View File

@ -1,4 +1,4 @@
export default interface IServer_DB_Model_Project_Module_Issue {
export interface ICommon_Model_Project_Module_Issue {
id :bigint,
project_module_id:bigint,
project_issue_id:bigint

View File

@ -1,4 +1,4 @@
export default interface IServer_DB_Model_Project_Module_Parent {
export interface ICommon_Model_Project_Module_Parent {
id :bigint,
parent_id:bigint,
child_id:bigint

View File

@ -1,11 +1,11 @@
export default interface IServer_DB_Model_Project_Release {
export interface ICommon_Model_Project_Release {
id :bigint ,
name :string,
start_time :number,
release_time :number,
description :string,
created_time :number,
modify_time :number,
created_time :Date,
modified_time :Date,
created_by :bigint ,
modified_by :bigint,
status :number,

View File

@ -1,4 +1,4 @@
export default interface IServer_DB_Model_Project_Release_Issue {
export interface ICommon_Model_Project_Release_Issue {
id :bigint ,
project_release_id :bigint,
project_issue_id:bigint

View File

@ -1,8 +1,8 @@
export default interface IServer_DB_Model_Project_User {
export interface ICommon_Model_Project_User {
id :bigint,
permission :bigint ,
created_time :number,
modified_time :number,
created_time :Date,
modified_time :Date,
project_id :bigint ,
user_id :bigint ,
}

View File

@ -1,4 +1,4 @@
export default interface IServer_DB_Model_Project_Workflow_Solution {
export interface ICommon_Model_Project_Workflow_Solution {
id :bigint,
project_id :bigint ,
workflow_solution_id :bigint ,

View File

@ -0,0 +1,7 @@
export interface ICommon_Model_Role {
id :bigint,
name :string,
created_time :Date,
modified_time :Date,
}
export const Table_Role="role"

View File

@ -1,4 +1,4 @@
export default interface IServer_DB_Model_Role_Permission {
export interface ICommon_Model_Role_Permission {
role_id :bigint,
permission_id :bigint,
id :bigint ,

View File

@ -1,10 +1,10 @@
export default interface IServer_DB_Model_User {
export interface ICommon_Model_User {
id :bigint,
username :string,
email :string,
phone :string,
created_time :number,
modified_time :number,
created_time :Date,
modified_time :Date,
password :string,
sign :string,
location :string,

View File

@ -1,4 +1,4 @@
export default interface IServer_DB_Model_User_Has_Group {
export interface ICommon_Model_User_Has_Group {
user_id :bigint,
group_id :bigint,
id :bigint ,

View File

@ -1,4 +1,4 @@
export default interface IServer_DB_Model_User_Role {
export interface ICommon_Model_User_Role {
user_id :bigint,
role_id :bigint,
id :bigint ,

View File

@ -1,10 +1,10 @@
export default interface IServer_DB_Model_User_Setting {
export interface ICommon_Model_User_Setting {
id :bigint ,
key :string,
value :string,
type :number,
created_time :number,
modified_time :number,
created_time :Date,
modified_time :Date,
user_id :bigint,
}
export const Table_User_Setting="user_setting"

View File

@ -1,10 +1,10 @@
export default interface IServer_DB_Model_Workflow {
export interface ICommon_Model_Workflow {
id :bigint ,
name :string,
description :string,
system :number,
created_time :number,
modified_time :number,
created_time :Date,
modified_time :Date,
created_by :bigint ,
modified_by :bigint ,
}

View File

@ -1,4 +1,4 @@
export default interface IServer_DB_Model_Workflow_Action {
export interface ICommon_Model_Workflow_Action {
id :bigint ,
name :string,
system :number,

View File

@ -1,4 +1,4 @@
export default interface IServer_DB_Model_Workflow_Node {
export interface ICommon_Model_Workflow_Node {
id :bigint ,
name :string,
description :string,

View File

@ -1,7 +1,7 @@
export default interface IServer_DB_Model_Workflow_Solution {
export interface ICommon_Model_Workflow_Solution {
id :bigint ,
created_time :number,
modified_time :number,
created_time :Date,
modified_time :Date,
created_by :bigint ,
modified_by :bigint,
system :number,

View File

@ -1,4 +1,4 @@
export default interface IServer_DB_Model_Workflow_Solution_Issue_Type {
export interface ICommon_Model_Workflow_Solution_Issue_Type {
id :bigint,
workflow_solution_id :bigint,
workflow_id :bigint ,

View File

@ -0,0 +1,3 @@
export enum ECommon_Permission_Issue {
}

View File

@ -0,0 +1,3 @@
export enum ECommon_Permission_Project {
}

View File

@ -0,0 +1,3 @@
export enum ECommon_Permission_User {
}

View File

View File

@ -1,19 +1,73 @@
import { ICommon_Model_Admin } from './../model/admin';
import { ICommon_Model_User } from './../model/user';
import { ECommon_Services } from './../types';
import { ICommon_Http_User_Test_Res } from "./userRes";
import {ECommon_HttpApi_Method, ICommon_HttpApi} from "./types"
const api={
baseUrl:"/user",
service:ECommon_Services.User,
routes:{
test:{
login:{
method:ECommon_HttpApi_Method.POST,
path:"/test",
path:"/login",
req:<{
name:string,
age:number
username:string,
password:string
}>{},
res:<ICommon_Http_User_Test_Res>{},
res:<Omit<ICommon_Model_User,"password">>{},
ignoreValidate:true
},
checkUser:{
method:ECommon_HttpApi_Method.GET,
path:"/check_user",
req:<{
name:string
}>{},
res:{},
ignoreValidate:true
},
logout:{
method:ECommon_HttpApi_Method.POST,
path:"/logout",
req:{},
res:{},
},
loginAdmin:{
method:ECommon_HttpApi_Method.POST,
path:"/admin_login",
req:<{
username:string,
password:string
}>{},
res:<Omit<ICommon_Model_Admin,"password">>{},
},
refresh:{
method:ECommon_HttpApi_Method.GET,
path:"/refresh",
req:{},
res:<Omit<ICommon_Model_User,"password"> | Omit<ICommon_Model_Admin,"password">>{},
},
update:{
method:ECommon_HttpApi_Method.PUT,
path:"/item",
req:<Partial<Omit<ICommon_Model_User,"id" | "password" | "created_time" | "modified_time">>>{},
res:<Omit<ICommon_Model_User,"password">>{},
},
create:{
method:ECommon_HttpApi_Method.POST,
path:"/item",
req:<Partial<Omit<ICommon_Model_User,"id" | "created_time" | "modified_time">> & {
username:string,
password:string
}>{},
res:<Omit<ICommon_Model_User,"password">>{},
},
remove:{
method:ECommon_HttpApi_Method.DELETE,
path:"/item",
req:{},
res:{},
}
}
}
export=api

View File

@ -1,4 +0,0 @@
export interface ICommon_Http_User_Test_Res {
name:string,
age:number
}

View File

@ -1,6 +1,63 @@
export default {
overUploadFileSize:{
code:1,
msg:"over up;oad file size"
export namespace Err {
export abstract class BaseError {
abstract code:number
msg:string
}
}
export namespace Common {
export class ParamError extends BaseError {
code=0
override msg="param error"
}
export class MysqlError extends BaseError {
code=1
override msg:string
constructor(msg?:string) {
super()
this.msg=msg?msg:"mysql error"
}
}
}
export namespace User {
export class UserNotFound extends BaseError {
code=1000
override msg="user not found"
}
export class UserExists extends BaseError {
code=1001
override msg="user exists"
}
export class UserIdNotExists extends BaseError {
code=1002
override msg="user id not exists"
}
export class UserNameNotExists extends BaseError {
code=1003
override msg="user name not exists"
}
export class UserPasswordWrong extends BaseError {
code=1004
override msg="user password wrong"
}
export class NotAuth extends BaseError {
code=1005
override msg="user not auth"
}
}
export namespace Http {
export class OverFileSize extends BaseError {
code=2000
override msg="over file size"
}
}
}

View File

@ -1,3 +1,4 @@
import { getRedisInstance, Redis } from "../redis";
class RedisBaseKey<T> {
protected redis:InstanceType<typeof Redis>=getRedisInstance()
@ -7,6 +8,13 @@ class RedisBaseKey<T> {
this.name=name,
this.type=type
}
async getTTL():Promise<number> {
let ret=await this.redis.getTTL(this.name)
return ret;
}
async setTTL(seconds:number):Promise<void> {
await this.redis.setTTL(this.name,seconds)
}
}
export class RedisStringKey<T> extends RedisBaseKey<T> {
@ -20,4 +28,8 @@ export class RedisStringKey<T> extends RedisBaseKey<T> {
async set(value:T,ttl?:number){
await this.redis.set(this.name,value,ttl);
}
}
async scan():Promise<T[]>{
let ret=await this.redis.scan<T>(this.name,this.type);
return ret
}
}

View File

@ -5,10 +5,14 @@ import {cacheRedisType} from "../../types/cache"
import StringUtil from "../../util/string"
export namespace REDIS_GATEWAY {
let INSTANCE_KEY=`${ECommon_Services.GateWay}:instance:{0}`
export function instance(key:string)
let INSTANCES_KEY=`${ECommon_Services.GateWay}:instance:*`
export function instances(key:string)
{
let obj=new RedisStringKey(StringUtil.format(INSTANCE_KEY,key),cacheRedisType<IServer_Common_Nacos_Instance[]>().Object)
return obj
}
export function allInstances() {
let obj=new RedisStringKey(INSTANCES_KEY,cacheRedisType<IServer_Common_Nacos_Instance[]>().Object);
return obj;
}
}

13
code/server/common/cache/keys/user.ts vendored Normal file
View File

@ -0,0 +1,13 @@
import { ECommon_Services } from '../../../../common/types';
import { IServer_Common_Nacos_Instance } from './../../types/nacos';
import { RedisStringKey } from './base';
import {cacheRedisType} from "../../types/cache"
import StringUtil from "../../util/string"
export namespace REDIS_USER {
let USER_TOKEN_KEY=`${ECommon_Services.User}:user:{0}:token`
export function token(userId:bigint)
{
let obj=new RedisStringKey(StringUtil.format(USER_TOKEN_KEY,userId),cacheRedisType<string>().String)
return obj
}
}

View File

@ -6,6 +6,40 @@ export function getRedisInstance(){
}
export class Redis {
private redis:InstanceType<typeof IORedis>
private parseType(value:any,type:any){
let t=typeof type;
if(value==null)
{
return null
}
if(t=="boolean")
{
if(value=="true")
{
return true;
}
else
{
return false
}
}
else if(t=="number")
{
return Number(value)
}
else if(t=="object")
{
try{
return JSON.parse(value)
}catch(err){
return null
}
}
else
{
return value
}
}
constructor(info:IServer_Common_Config_Redis){
this.redis=new IORedis({
port:info.port,
@ -17,39 +51,7 @@ export class Redis {
}
async get<T>(key:string,type:T):Promise<T> {
let ret=await this.redis.get(key)
let value:any=null;
let t=typeof type;
if(ret==null)
{
value=null
}
if(t=="boolean")
{
if(ret=="true")
{
value=true;
}
else
{
value=false
}
}
else if(t=="number")
{
value=Number(ret)
}
else if(t=="object")
{
try{
value=JSON.parse(ret)
}catch(err){
value=null
}
}
else
{
value=ret
}
let value=this.parseType(ret,type);
return value
}
async set(key:string,value:any,ttl?:number)
@ -67,4 +69,22 @@ export class Redis {
await this.redis.set(key,String(value),"EX",ttl)
}
}
async scan<T>(key:string,type:T):Promise<T[]> {
let index=0,values=<T[]><unknown>[]
do {
let ret=await this.redis.scan(index,"match",key);
index=Number(ret[0])
values=values.concat(ret[1].map(item=>{
return this.parseType(item,type)
}));
} while(index!=0)
return values;
}
async getTTL(key:string):Promise<number> {
let ret=await this.redis.ttl(key);
return ret;
}
async setTTL(key:string,seconds:number):Promise<void> {
await this.redis.expire(key,seconds);
}
}

View File

@ -1,8 +0,0 @@
import IServer_DB_Model_Issue_Type, { Table_Issue_Type } from './../model/mysql/issue_type';
import { getMysqlInstance } from "../mysql";
export async function getIssueTypeListMapper() {
var mysql=getMysqlInstance()
var ret=await mysql.execute<IServer_DB_Model_Issue_Type[]>(`select * from ${Table_Issue_Type}`)
return ret
}

View File

@ -1,8 +0,0 @@
export default interface IServer_DB_Model_Group {
id :bigint ,
name :string,
created_time :number,
modified_time :number,
created_by :bigint ,
}
export const Table_Group="group"

View File

@ -1,7 +0,0 @@
export default interface IServer_DB_Model_Role {
id :bigint,
name :string,
created_time :number,
modified_time :number,
}
export const Table_Role="role"

View File

@ -1,8 +1,10 @@
import { IServer_Common_Config_Mysql } from './../types/config';
import "reflect-metadata"
import * as mysql from "mysql2"
import {Pool as PromisePool} from "mysql2/promise"
import { Err } from '../../../common/status/error';
var g_mysqlConnection:InstanceType<typeof Mysql>
export function getMysqlInstance(){
return g_mysqlConnection;
@ -38,7 +40,8 @@ export default class Mysql {
}
} catch(err){
return null
console.error("mysql error:",err,sqlText)
throw new Err.Common.MysqlError
}
}
}

View File

@ -0,0 +1,28 @@
export abstract class Entity<T> {
protected item:T;
getId():bigint{
if(this.item) {
return (<any>this.item).id
} else {
return null;
}
}
setItem(item:T) {
this.item=item
}
assignItem(item:any) {
if(typeof(item)=="object") {
this.item=<T>{}
for(let key in item) {
this.item[key]=item[key]
}
}
}
getItem():T {
return this.item;
}
abstract create():Promise<T>;
abstract update():Promise<T>;
abstract delete();
abstract loadItem():Promise<T>;
}

View File

@ -0,0 +1,21 @@
import { EServer_Common_Event_Types } from "./types"
var g_events=<{
[param:string]: ((...args: any[]) =>any)[]
}>{
}
export async function getEventsFunc(){
return g_events
}
export function DEventListener(eventName: EServer_Common_Event_Types.Types) {
return function (target, propertyKey: string, desc: PropertyDescriptor) {
let handle = desc.value.bind(target)
if(!g_events[eventName]) {
g_events[eventName]=[]
}
g_events[eventName].push(handle);
}
}

View File

@ -0,0 +1,6 @@
export namespace EServer_Common_Event_Types {
export type Types= User
export enum User {
DELETE="delete user" //userId:string
}
}

View File

@ -97,7 +97,7 @@ export function DHttpContext(target: Object, propertyKey: string, parameterIndex
name:null,
index:parameterIndex,
type:type,
category:EServer_Common_Http_Structure_HandleParam_Category.Content
category:EServer_Common_Http_Structure_HandleParam_Category.Context
}
if(!g_objParam[key]){
g_objParam[key]=[]

View File

@ -59,6 +59,9 @@ export default class Nacos<T extends IServer_Common_Config_Base> {
port: this.objConfigCurrentService.port,
});
}
get serviceName():string {
return this.name;
}
get serverPort():number {
return this.objConfigCurrentService.port
}
@ -96,6 +99,7 @@ export default class Nacos<T extends IServer_Common_Config_Base> {
if(element.valid)
{
ele.push({
name:element.serviceName,
ip:element.ip,
port:element.port
})

View File

@ -1,7 +1,9 @@
export interface IAAA {
name:string,
age:number
import { EServer_Common_User_Type } from "../../types/user";
export interface IServer_Common_RPC_User_CheckSession {
userId:string,
type:EServer_Common_User_Type
}
export default interface IServer_Common_RPC_User {
a?(obj:IAAA):Promise<IAAA>
checkSession?(token:string):Promise<IServer_Common_RPC_User_CheckSession>
}

View File

@ -1,12 +1,14 @@
import { IServer_Common_Http_Proxy } from './../types/http';
import { IServer_Common_Nacos_Instance } from './../types/nacos';
import { ECommon_Services } from '../../../common/types';
import { Redis } from '../cache/redis';
import { EServer_Common_Event_Types } from '../event/types';
import * as sio from "socket.io"
import * as ioClient from "socket.io-client"
import { REDIS_GATEWAY } from '../cache/keys/gateway';
import * as http from 'http';
import { getHttpRoutes, handleHttpCall } from '../http/http';
import {getEventsFunc} from "../event/event"
import { getNacosInstance } from '../nacos/nacos';
interface ISocketStruct {
name:string,
args:any[]
@ -50,7 +52,6 @@ export class Rpc{
objRes.msg=err.msg;
callback(objRes)
}
}
})
socket.on("http-call",async (arg:IServer_Common_Http_Proxy,callback)=>{
@ -58,20 +59,43 @@ export class Rpc{
let objRoute=getHttpRoutes()
for(let keyRoute in objRoute) {
if(key==keyRoute){
let ret=await handleHttpCall(objRoute[keyRoute],arg)
callback(ret)
return
try {
let ret=await handleHttpCall(objRoute[keyRoute],arg)
callback(ret)
return
} catch (err) {
let obj:IServer_Common_Http_Proxy=<IServer_Common_Http_Proxy>{}
obj.status=500
obj.data={
code:err.code,
msg:err.msg??err.message
}
callback(obj)
return
}
}
}
let obj:IServer_Common_Http_Proxy=<IServer_Common_Http_Proxy>{}
obj.status=404
callback(obj)
})
socket.on("event-call",async (arg:ISocketStruct,callback)=>{
let name=arg.name
let obj=arg.args;
let objFunc=getEventsFunc()
for(let key in objFunc) {
if(key==name) {
for(let func of objFunc[key]) {
func(obj)
}
}
}
})
})
}
static async validInstance(name:string):Promise<IServer_Common_Nacos_Instance>
{
let objRedis=REDIS_GATEWAY.instance(name)
let objRedis=REDIS_GATEWAY.instances(name)
let ret=await objRedis.get()
return ret?ret[0]:null
}
@ -94,14 +118,22 @@ export async function proxyRequest(objProxy:IServer_Common_Http_Proxy,targetServ
g_Socket[targetServer]=socket
socket.on("connect",()=>{
socket.emit("http-call",objProxy,(res:IServer_Common_Http_Proxy)=>{
resolve(res)
if(res.status<200 || res.status>=300) {
reject(res)
} else {
resolve(res)
}
})
})
}
else
{
g_Socket[targetServer].emit("http-call",objProxy,(res:IServer_Common_Http_Proxy)=>{
resolve(res)
if(res.status<200 || res.status>=300) {
reject(res)
} else {
resolve(res)
}
})
}
})
@ -175,4 +207,58 @@ export function DRPCRecieve(target: Object, propertyName: string, descriptor: Ty
{
g_RevieveInstance[propertyName]=target
}
}
async function validInstances(): Promise<string[]> {
let objRedis = REDIS_GATEWAY.allInstances()
let ret = await objRedis.scan()
return ret.map(item => {
return item[0].name ?? ""
}).filter(item => {
if (item) {
return true
}
})
}
export async function emitServiceEvent(event: EServer_Common_Event_Types.Types, obj: any,exceptMe:boolean=false) {
let arrServiceName = await validInstances()
arrServiceName=arrServiceName.filter(item=>{
return getNacosInstance().serviceName!=item
})
if(!exceptMe) {
let objFunc = getEventsFunc()
for (let key in objFunc) {
if (key == event) {
for (let func of objFunc[key]) {
func(obj)
}
}
}
}
for (let serviceName of arrServiceName) {
if (!g_Socket[serviceName] || !g_Socket[serviceName].connected) {
if (g_Socket[serviceName] && !g_Socket[serviceName].connected) {
g_Socket[serviceName].close()
}
let instance = await Rpc.validInstance(serviceName)
if (!instance) {
return
}
let socket = ioClient.io(`ws://${instance.ip}:${instance.port}`)
g_Socket[serviceName] = socket
socket.on("connect", () => {
socket.emit("event-call", <ISocketStruct>{
name: event,
args: obj
})
})
}
else {
g_Socket[serviceName].emit("event-call", <ISocketStruct>{
name: event,
args: obj
})
}
}
}

View File

@ -25,5 +25,5 @@ export interface IServer_Common_Config {
mysql:IServer_Common_Config_Mysql
}
export interface IServer_Common_Global_Config {
jwt:string
}

View File

@ -1,5 +1,6 @@
export interface IServer_Common_Nacos_Instance {
name:string,
ip:string,
port:number
}

View File

@ -0,0 +1,4 @@
export enum EServer_Common_User_Type {
USER,
ADMIN
}

View File

@ -0,0 +1,110 @@
import{ UniqueID } from 'nodejs-snowflake';
const uid = new UniqueID({
returnNumber: true
});
type EXPR={
[key:string]:string|number|boolean|bigint|{
value?:string|number|boolean|string[]|[number,number]|bigint,
exp?:"="|">="|"<="|">"|"<"|"<>"|"is null"|"in"|"is not null"|"between"|"%like"|"like%"|"%like%"
}
}
export async function generateSnowId() {
let id =await uid.asyncGetUniqueID()
return id as bigint
}
function generateExp(objExpr?:EXPR,exprMode?:"and"|"or"):string{
let expr="",arrExpr=[]
if(objExpr) {
for(let key in objExpr) {
let value=objExpr[key]
if(typeof(value)!="object") {
let val=typeof(value)=="number"?value:typeof(value)=="boolean"?(value?1:0):("'"+value+"'")
arrExpr.push(`${key}=${val}`)
} else {
if (value.exp == "=" || value.exp=="<=" || value.exp==">" || value.exp=="<" || value.exp=="<>" || !value.exp) {
if(!value.exp) {
value.exp="="
}
let val = typeof (value.value) == "number" ? value.value : typeof (value.value) == "boolean" ? (value.value ? 1 : 0) : ("'" + value.value + "'")
arrExpr.push(`${key}${value.exp}${val}`)
} else if(value.exp=="is null") {
arrExpr.push(`${key} is null`)
} else if(value.exp=="in") {
arrExpr.push(`${key} in (${(<string[] | number[]>value.value).map((item)=>{
return typeof(item)=="number"?item:("'"+item+"'")
}).join(",")})`)
} else if(value.exp=="is not null") {
arrExpr.push(`${key} is not null`)
} else if(value.exp=="between") {
let val=value.value as [number,number];
arrExpr.push(`${key} between ${val[0]} and ${val[1]}`)
} else if(value.exp=="%like") {
arrExpr.push(`${key} like '%${value.value}'`)
} else if(value.exp=="like%") {
arrExpr.push(`${key} like '${value.value}%'`)
} else if(value.exp=="%like%") {
arrExpr.push(`${key} like '%${value.value}%'`)
}
}
}
expr=arrExpr.join(` ${exprMode?exprMode:"and"} `)
}
return expr;
}
export function generateCreateSql(table:string,obj:any):string {
let keys="",values=""
for(let key in obj) {
let value=obj[key]
keys+=key+","
values+=((value!==null && value!==undefined)?("'"+value+"'"):"")+","
}
if(keys[keys.length-1]==","){
keys=keys.substring(0,keys.length-1);
}
if(values[values.length-1]==","){
values=values.substring(0,values.length-1);
}
return `insert into ${table} (${keys}) values (${values})`
}
export function generateQuerySql(table:string,columns:string[],objExpr?:EXPR,exprMode?:"and"|"or"):string {
let column=""
if(Array.isArray(columns) && columns.length>0) {
column=columns.join(",")
} else {
column="*"
}
let expr=generateExp(objExpr,exprMode);
return `select ${column} from ${table}${expr?(" where "+expr):""}`
}
export function generateUpdateSql(table:string,obj:any,objExpr?:EXPR,exprMode?:"and"|"or"):string {
let arrVal=[];
for(let key in obj) {
let value=obj[key]
let val;
if(value===null) {
val="null"
} else if(value===undefined) {
continue
} else if (typeof(value)=="number") {
val=String(value)
} else if(typeof(value)=="boolean") {
val=value?1:0+""
} else {
val="'"+value+"'"
}
arrVal.push(`key=${val}`)
}
let expr=generateExp(objExpr,exprMode);
return `update ${table} set ${arrVal.join(",")}${expr?(" where "+expr):""}`
}
export function generateDeleteSql(table:string,objExpr?:EXPR,exprMode?:"and"|"or"):string {
let expr=generateExp(objExpr,exprMode);
return `delete from ${table}${expr?(" where "+expr):""}`
}

View File

@ -1,18 +1,19 @@
import * as Koa from "koa"
import * as body from 'koa-bodyparser';
import * as http from "http"
import userCall from "../rpc/user"
import userRpcApi from '../rpc/user';
import Application from "../../common/app/app"
import { getNacosInstance } from "../../common/nacos/nacos";
import { CacheService } from './../cache/service';
import {generateHttpErrorResponse} from "../../common/util/http"
import ERROR from "../../../common/status/error"
import * as userApi from "../../../common/routes/user"
import { ICommon_HttpApi } from "../../../common/routes/types";
import { EServer_Common_Http_Body_Type, IServer_Common_Http_Proxy, IServer_Common_Http_Req_File } from "../../common/types/http";
import { parseFormData } from "../util/util";
import { PassThrough } from "stream";
import { proxyRequest } from "../../common/rpc/rpc";
import { Err } from "../../../common/status/error";
import { ECommon_Services } from "../../../common/types";
var apis:ICommon_HttpApi[]=[userApi];
var app = new Koa();
var pipe=function (from,to) :Promise<string>{
@ -40,7 +41,14 @@ export default class GateWay extends Application {
await this.initKoa();
}
async initKoa() {
let apiMap={}
let apiMap=<{
[param:string]:{
[parem:string]:{
service:string,
ignoreValidate:boolean
}
}
}>{}
for(let obj of apis){
let baseUrl=obj.baseUrl.substr(1)
if(!apiMap[baseUrl])
@ -49,14 +57,17 @@ export default class GateWay extends Application {
}
for(let key in obj.routes) {
let objApi=obj.routes[key];
apiMap[baseUrl][objApi.method+" "+objApi.path]=obj.service;
apiMap[baseUrl][objApi.method+" "+objApi.path]={
service:obj.service,
ignoreValidate:!!objApi.ignoreValidate
};
}
}
app.use(async (ctx, next) => {
if (ctx.headers['content-type'] && ctx.headers['content-type'].split(';')[0] === 'multipart/form-data') {
const maxLength = 1024 * 1024 * 5;
if (ctx.headers && ctx.headers['content-length'] && Number(ctx.headers['content-length']) > maxLength) {
ctx.body = generateHttpErrorResponse(ERROR.overUploadFileSize)
ctx.body = generateHttpErrorResponse(new Err.Http.OverFileSize)
return;
}
let stream=new PassThrough()
@ -83,8 +94,11 @@ export default class GateWay extends Application {
})
app.use(body());
app.use(async (ctx, next) => {
ctx.state.apiMap=apiMap;
await next()
try {
await next()
} catch (err) {
ctx.body = generateHttpErrorResponse(err.data??err)
}
})
app.use(async function (ctx, next) {
let path = ctx.path
@ -93,8 +107,19 @@ export default class GateWay extends Application {
let method = ctx.req.method;
let baseUrl = path.substring(1, path.indexOf("/", 1))
let apiPath = path.substr(1 + baseUrl.length)
if (ctx.state.apiMap[baseUrl] && ctx.state.apiMap[baseUrl][method + " " + apiPath]) {
let microServer = ctx.state.apiMap[baseUrl][method + " " + apiPath]
if (apiMap[baseUrl] && apiMap[baseUrl][method + " " + apiPath]) {
let microServer = apiMap[baseUrl][method + " " + apiPath].service
let ignoreValidate = apiMap[baseUrl][method + " " + apiPath].ignoreValidate
if(!ignoreValidate) {
let authorization = ctx.get("Authorization")
if(!authorization) {
throw new Err.User.NotAuth
}
let ret= await userRpcApi.checkSession(authorization.substr(7))
if(!ret) {
throw new Err.User.NotAuth
}
}
let obj = <IServer_Common_Http_Proxy>{}
if (ctx.req.method == "POST" || ctx.req.method == "PUT" || ctx.req.method == "PATCH") {
if (!ctx.state.p) {
@ -111,7 +136,7 @@ export default class GateWay extends Application {
if (ctx.state.formData) {
obj.bodyType = EServer_Common_Http_Body_Type.FORMDATA
}
let ret = await proxyRequest(obj, microServer)
let ret = await proxyRequest(obj, microServer as ECommon_Services)
ctx.response.status = ret.status;
for (let key in ret.headers) {
if (key == "set-cookie") {
@ -134,14 +159,6 @@ export default class GateWay extends Application {
})
http.createServer(app.callback()).listen(getNacosInstance().serverPort,function(){
console.log(`start`);
setTimeout(async () => {
var obj=new userCall()
let ret=await obj.a({
name:"dd",
age:23
})
console.log(ret)
}, 2000);
})
}
}

View File

@ -25,7 +25,7 @@ export class CacheService {
for(let key in ret) {
let obj=ret[key]
this.instanceMap[key]=obj[0].ip
let objRedis=REDIS_GATEWAY.instance(key)
let objRedis=REDIS_GATEWAY.instances(key)
await objRedis.set(obj,this.instanceTTL)
}
this.timer=setTimeout(this.handle.bind(this),this.timerCount)

View File

@ -0,0 +1,8 @@
import { Table_Issue_Type ,ICommon_Model_Issue_Type} from '../../../common/model/issue_type';
import { getMysqlInstance } from "../../common/db/mysql";
export async function getIssueTypeListMapper() {
var mysql=getMysqlInstance()
var ret=await mysql.execute<ICommon_Model_Issue_Type[]>(`select * from ${Table_Issue_Type}`)
return ret
}

View File

@ -1,9 +1,10 @@
import { ECommon_Services } from '../../../common/types';
import IServer_Common_RPC_User, { IAAA } from "../../common/rpc/api/user";
import IServer_Common_RPC_User, { IServer_Common_RPC_User_CheckSession } from "../../common/rpc/api/user";
import {DRPCSend} from "../../common/rpc/rpc"
export default class RpcUserApi implements IServer_Common_RPC_User {
class RpcUserApi implements IServer_Common_RPC_User {
@DRPCSend(ECommon_Services.User)
async a(obj:IAAA):Promise<IAAA> {
async checkSession(token:string):Promise<IServer_Common_RPC_User_CheckSession> {
return null
}
}
}
export default new RpcUserApi

View File

@ -14,6 +14,7 @@
"fs-extra": "^9.1.0",
"got": "^11.8.1",
"ioredis": "^4.22.0",
"jsonwebtoken": "^8.5.1",
"koa": "^2.7.0",
"koa-better-body": "^3.0.4",
"koa-bodyparser": "^4.2.1",
@ -26,6 +27,7 @@
"mongodb": "^3.6.4",
"mysql2": "^2.2.5",
"nacos": "^2.0.1",
"nodejs-snowflake": "^1.6.2",
"socket.io": "^3.1.1",
"socket.io-client": "^3.1.1",
"yargs": "^16.2.0"
@ -33,6 +35,7 @@
"devDependencies": {
"@types/fs-extra": "^9.0.7",
"@types/ioredis": "^4.19.4",
"@types/jsonwebtoken": "^8.5.5",
"@types/koa": "^2.11.8",
"@types/koa-bodyparser": "^4.3.0",
"@types/node": "^14.14.27",

View File

@ -3,6 +3,7 @@ import * as body from 'koa-bodyparser';
import Application from "../../common/app/app"
import "../http/user"
import "../rpc/user"
export default class User extends Application {
override async config() {

View File

@ -1,15 +1,32 @@
import { IServer_Common_Http_Req_File } from './../../common/types/http';
import { DHttpApi, DHttpContext, DHttpReqParam, DHttpReqParamFile,DHttpContent } from "../../common/http/http"
import { DHttpApi, DHttpContext, DHttpReqParam, DHttpReqParamFile,DHttpContent, DHttpReqParamRequired } from "../../common/http/http"
import * as userApi from "../../../common/routes/user"
import { ICommon_Http_User_Test_Res } from "../../../common/routes/userRes"
import HttpContext from "../../common/http/context"
import UserService from "../service/user"
import { Err } from "../../../common/status/error"
class UserController {
@DHttpApi(userApi.routes.test)
async test(@DHttpContent content:typeof userApi.routes.test.req,@DHttpContext ctx:HttpContext):Promise<ICommon_Http_User_Test_Res>{
console.log(content)
return {
name:"",
age:11,
@DHttpApi(userApi.routes.create)
async create(@DHttpContent content:typeof userApi.routes.create.req):Promise<typeof userApi.routes.create.res>{
let user=new UserService()
user.assignItem(content);
let obj=await user.create()
delete obj.password
return obj
}
@DHttpApi(userApi.routes.login)
async login(@DHttpReqParamRequired("username") username:string,@DHttpReqParamRequired("password") password:string,@DHttpContext ctx:HttpContext):Promise<typeof userApi.routes.login.res> {
let user=await UserService.getItemByName(username)
if(!user) {
throw new Err.User.UserNotFound
}
if(user.getItem().password===password) {
let token=await user.startSession()
let ret=user.getItem()
delete ret.password
ctx.setHeader("token",token)
return ret
} else {
throw new Err.User.UserPasswordWrong
}
}
}

View File

@ -0,0 +1,65 @@
import { Table_User, ICommon_Model_User } from './../../../common/model/user';
import { getMysqlInstance } from "../../common/db/mysql"
import {Err} from "../../../common/status/error"
import {generateCreateSql, generateDeleteSql, generateQuerySql, generateUpdateSql} from "../../common/util/sql"
export namespace userMapper {
export async function checkUserValid(username:string):Promise<boolean> {
if(!username){
return false
}
var mysql=getMysqlInstance()
let ret=await mysql.execute<{
username:string
}>(generateQuerySql(Table_User,["username"],{
username:username
}),true)
if(ret instanceof Err.Common.MysqlError) {
throw new Err.Common.MysqlError;
}
return !!ret
}
export async function createUser(info:ICommon_Model_User):Promise<void> {
if(!info || !info.username || !info.password ||!info.id){
throw new Err.Common.ParamError
}
var mysql=getMysqlInstance()
await mysql.execute<Extract<typeof createUser,ICommon_Model_User>>(generateCreateSql(Table_User,info))
}
export async function getUserById(id:bigint):Promise<ICommon_Model_User> {
if(!id) {
throw new Err.User.UserIdNotExists
}
var mysql=getMysqlInstance();
let ret=await mysql.execute<ICommon_Model_User>(generateQuerySql(Table_User,[],{id}),true)
return ret
}
export async function getUserByName(name:string):Promise<ICommon_Model_User> {
if(!name) {
throw new Err.User.UserNameNotExists
}
var mysql=getMysqlInstance();
let ret=await mysql.execute<ICommon_Model_User>(generateQuerySql(Table_User,[],{username:name}),true)
return ret
}
export async function updateUser(info:ICommon_Model_User):Promise<void> {
if(!info.id) {
throw new Err.User.UserIdNotExists
}
var mysql=getMysqlInstance();
let id=info.id;
delete info.id,info.created_time,info.modified_time
await mysql.execute(generateUpdateSql(Table_User,info,{id}))
}
export async function deleteUser(id):Promise<void> {
if(!id) {
throw new Err.User.UserIdNotExists
}
var mysql=getMysqlInstance();
await mysql.execute(generateDeleteSql(Table_User,{id}))
}
}

View File

@ -1,12 +1,36 @@
import IServer_Common_RPC_User, { IAAA } from "../../common/rpc/api/user";
import IServer_Common_RPC_User, { IServer_Common_RPC_User_CheckSession } from "../../common/rpc/api/user";
import {DRPCRecieve} from "../../common/rpc/rpc"
export default class RpcUserApi implements IServer_Common_RPC_User {
import * as jwt from "jsonwebtoken"
import { getNacosInstance } from "../../common/nacos/nacos";
import { REDIS_USER } from "../../common/cache/keys/user";
class RpcUserApi implements IServer_Common_RPC_User {
@DRPCRecieve
async a(obj:IAAA):Promise<IAAA> {
return {
name:obj.name+"xxx",
age:obj.age+100
async checkSession(token:string):Promise<IServer_Common_RPC_User_CheckSession> {
if(!token) {
return null;
}
let secret=getNacosInstance().globalConfig.jwt;
return new Promise(function(resolve){
jwt.verify(token,secret,async function(err,decoded) {
if(err) {
resolve(null);
} else {
let session=REDIS_USER.token(decoded.userId)
let tokenFromCache = await session.get()
if(token==tokenFromCache) {
await session.setTTL(3600);
resolve({
userId:decoded.userId,
type:decoded.type
})
} else {
resolve(null);
}
}
})
})
}
}
}
export default new RpcUserApi;

View File

@ -0,0 +1,87 @@
import { EServer_Common_User_Type } from './../../common/types/user';
import { ICommon_Model_User } from './../../../common/model/user';
import {Entity} from "../../common/entity/entity"
import { userMapper } from '../mapper/user';
import { Err } from '../../../common/status/error';
import { generateSnowId } from '../../common/util/sql';
import { emitServiceEvent } from '../../common/rpc/rpc';
import { EServer_Common_Event_Types } from '../../common/event/types';
import * as jwt from "jsonwebtoken"
import { getNacosInstance } from '../../common/nacos/nacos';
import {REDIS_USER} from "../../common/cache/keys/user"
export default class User extends Entity<ICommon_Model_User> {
async create():Promise<ICommon_Model_User>{
if(!this.item) {
throw new Err.User.UserNotFound;
} else if(this.item.id) {
throw new Err.User.UserExists;
}
this.item.id=await generateSnowId()
await userMapper.createUser(this.item)
await this.loadItem();
return this.item;
}
async update():Promise<ICommon_Model_User>{
if(!this.item || !this.item.id) {
throw new Err.User.UserNotFound;
}
await userMapper.updateUser(this.item)
return this.item;
}
async delete(){
await userMapper.deleteUser(this.item.id);
emitServiceEvent(EServer_Common_Event_Types.User.DELETE,this.item.id);
}
async loadItem():Promise<ICommon_Model_User> {
if(!this.item || !this.item.id) {
throw new Err.User.UserNotFound;
}
let obj = await userMapper.getUserById(this.item.id);
this.item=obj;
return this.item;
}
static async getItemById(id:bigint):Promise<InstanceType<typeof User>>{
let obj = await userMapper.getUserById(id);
if(obj) {
let user = new User;
user.setItem(obj);
return user;
} else {
return null;
}
}
static async getItemByName(name:string):Promise<InstanceType<typeof User>>{
let obj = await userMapper.getUserByName(name);
if(obj) {
let user = new User;
user.setItem(obj);
return user;
} else {
return null;
}
}
async startSession():Promise<string>{
let secret=getNacosInstance().globalConfig.jwt;
if(!this.item || !this.item.id) {
throw new Err.User.UserNotFound
}
return new Promise(async (resolve,reject)=>{
jwt.sign({
userId:this.item.id,
type:EServer_Common_User_Type.USER
},secret,async (err,token)=>{
if(err) {
reject(err)
return
} else {
let session=REDIS_USER.token(this.item.id)
await session.set(token,3600);
resolve(token)
}
})
})
}
}

View File

@ -17,7 +17,7 @@
},
"include": [
"./**/*"
],
, "../gateway/mapper/gateway.ts" ],
"exclude": [
"node_modules"
]