Compare commits
7 Commits
7c679aa0d2
...
b0c67da340
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b0c67da340 | ||
|
|
c3c332017e | ||
|
|
9aba6ebc02 | ||
|
|
3e3609f25e | ||
|
|
d5e38a8167 | ||
|
|
7d407d02ca | ||
|
|
1cc0f57eb0 |
@@ -1,4 +1,3 @@
|
|||||||
import CryptoJS from "./types/CryptoJS.d.ts"
|
|
||||||
const dataIsEmpty = !localStorage.tws_data || localStorage.tws_data == ''
|
const dataIsEmpty = !localStorage.tws_data || localStorage.tws_data == ''
|
||||||
|
|
||||||
const aes = {
|
const aes = {
|
||||||
@@ -20,6 +19,7 @@ declare global {
|
|||||||
interface Window {
|
interface Window {
|
||||||
data: {
|
data: {
|
||||||
apply: () => void
|
apply: () => void
|
||||||
|
access_token?: string
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,5 +10,6 @@ type ApiCallbackMessage = {
|
|||||||
* 501: 伺服器端不支持請求的功能
|
* 501: 伺服器端不支持請求的功能
|
||||||
*/
|
*/
|
||||||
code: 200 | 400 | 401 | 403 | 404 | 500 | 501,
|
code: 200 | 400 | 401 | 403 | 404 | 500 | 501,
|
||||||
|
data?: { [key: string]: unknown },
|
||||||
}
|
}
|
||||||
export default ApiCallbackMessage
|
export default ApiCallbackMessage
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
export type CallMethod =
|
export type CallMethod =
|
||||||
|
"User.auth" |
|
||||||
"User.register" |
|
"User.register" |
|
||||||
"User.login"
|
"User.login"
|
||||||
|
|
||||||
|
export type ClientEvent =
|
||||||
|
"Client.onMessage"
|
||||||
|
|||||||
@@ -1,21 +1,41 @@
|
|||||||
import { io, Socket } from 'https://unpkg.com/socket.io-client@4.8.1/dist/socket.io.esm.min.js'
|
import { io, Socket } from 'https://unpkg.com/socket.io-client@4.8.1/dist/socket.io.esm.min.js'
|
||||||
import { CallMethod } from './ApiDeclare.ts'
|
import { CallMethod, ClientEvent } from './ApiDeclare.ts'
|
||||||
import ApiCallbackMessage from './ApiCallbackMessage.ts'
|
import ApiCallbackMessage from './ApiCallbackMessage.ts'
|
||||||
|
|
||||||
class Client {
|
type UnknownObject = { [key: string]: unknown }
|
||||||
static socket: Socket
|
|
||||||
static connect() {
|
|
||||||
this.socket && this.socket.disconnect()
|
|
||||||
this.socket = io()
|
|
||||||
}
|
|
||||||
static call(method: CallMethod, args: {}, timeout: number = 5000) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
this.socket.timeout().emit("The_White_Silk", (err, res: ApiCallbackMessage) => {
|
|
||||||
if (err) return reject(err)
|
|
||||||
|
|
||||||
|
class Client {
|
||||||
|
static socket?: Socket
|
||||||
|
static events: { [key: string]: (data: UnknownObject) => UnknownObject } = {}
|
||||||
|
static connect() {
|
||||||
|
this.socket?.disconnect()
|
||||||
|
this.socket && delete this.socket
|
||||||
|
this.socket = io()
|
||||||
|
this.socket!.on("The_White_Silk", (name: string, data: UnknownObject, callback: (ret: UnknownObject) => void) => {
|
||||||
|
try {
|
||||||
|
if (name == null || data == null) return
|
||||||
|
const re = this.events[name]?.(data)
|
||||||
|
re && callback(re)
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
static invoke(method: CallMethod, args: UnknownObject = {}, timeout: number = 5000): Promise<ApiCallbackMessage> {
|
||||||
|
if (this.socket == null) throw new Error("客戶端未與伺服器端建立連接!")
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
this.socket!.timeout(timeout).emit("The_White_Silk", method, args, (err: string, res: ApiCallbackMessage) => {
|
||||||
|
if (err) return reject(err)
|
||||||
|
resolve(res)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
static on(eventName: ClientEvent, func: (data: UnknownObject) => UnknownObject) {
|
||||||
|
this.events[eventName] = func
|
||||||
|
}
|
||||||
|
static off(eventName: ClientEvent){
|
||||||
|
delete this.events[eventName]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Client
|
export default Client
|
||||||
|
|||||||
@@ -87,6 +87,7 @@
|
|||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div id="app"></div>
|
<div id="app"></div>
|
||||||
|
<mdui-snackbar close-on-outside-click id="public_snackbar"></mdui-snackbar>
|
||||||
|
|
||||||
<script nomodule>
|
<script nomodule>
|
||||||
alert('很抱歉, 此应用无法在较旧的浏览器运行, 请使用基于 Chromium 89+ 的浏览器(内核)使用 :(')
|
alert('很抱歉, 此应用无法在较旧的浏览器运行, 请使用基于 Chromium 89+ 的浏览器(内核)使用 :(')
|
||||||
|
|||||||
113
client/types/CryptoJS.d.ts
vendored
113
client/types/CryptoJS.d.ts
vendored
@@ -1,113 +0,0 @@
|
|||||||
// https://github.com/nozzlegear/crypto-js.d.ts/blob/master/crypto-js.d.ts
|
|
||||||
// Forked from https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/9143f1233f13692c14ae2afe7aee2d5014cba916/crypto-js/crypto-js.d.ts
|
|
||||||
|
|
||||||
declare namespace CryptoJS {
|
|
||||||
type Hash = (message: string, key?: string, ...options: any[]) => string;
|
|
||||||
interface Cipher {
|
|
||||||
encrypt(message: string, secretPassphrase: string, option?: CipherOption): WordArray;
|
|
||||||
decrypt(encryptedMessage: string | WordArray, secretPassphrase: string, option?: CipherOption): DecryptedMessage;
|
|
||||||
}
|
|
||||||
interface CipherAlgorythm {
|
|
||||||
createEncryptor(secretPassphrase: string, option?: CipherOption): Encriptor;
|
|
||||||
createDecryptor(secretPassphrase: string, option?: CipherOption): Decryptor;
|
|
||||||
}
|
|
||||||
interface Encriptor {
|
|
||||||
process(messagePart: string): string;
|
|
||||||
finalize(): string;
|
|
||||||
}
|
|
||||||
interface Decryptor {
|
|
||||||
process(messagePart: string): string;
|
|
||||||
finalize(): string;
|
|
||||||
}
|
|
||||||
interface WordArray {
|
|
||||||
iv: string;
|
|
||||||
salt: string;
|
|
||||||
ciphertext: string;
|
|
||||||
key?: string;
|
|
||||||
}
|
|
||||||
type DecryptedMessage = {
|
|
||||||
toString(encoder?: Encoder): string;
|
|
||||||
};
|
|
||||||
interface CipherOption {
|
|
||||||
iv?: string;
|
|
||||||
mode?: Mode;
|
|
||||||
padding?: Padding;
|
|
||||||
[option: string]: any;
|
|
||||||
}
|
|
||||||
interface Encoder {
|
|
||||||
parse(encodedMessage: string): any;
|
|
||||||
stringify(words: any): string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Mode {}
|
|
||||||
interface Padding {}
|
|
||||||
|
|
||||||
interface Hashes {
|
|
||||||
MD5: Hash;
|
|
||||||
SHA1: Hash;
|
|
||||||
SHA256: Hash;
|
|
||||||
SHA224: Hash;
|
|
||||||
SHA512: Hash;
|
|
||||||
SHA384: Hash;
|
|
||||||
SHA3: Hash;
|
|
||||||
RIPEMD160: Hash;
|
|
||||||
HmacMD5: Hash;
|
|
||||||
HmacSHA1: Hash;
|
|
||||||
HmacSHA256: Hash;
|
|
||||||
HmacSHA224: Hash;
|
|
||||||
HmacSHA512: Hash;
|
|
||||||
HmacSHA384: Hash;
|
|
||||||
HmacSHA3: Hash;
|
|
||||||
HmacRIPEMD160: Hash;
|
|
||||||
PBKDF2: Hash;
|
|
||||||
AES: Cipher;
|
|
||||||
DES: Cipher;
|
|
||||||
TripleDES: Cipher;
|
|
||||||
RC4: Cipher;
|
|
||||||
RC4Drop: Cipher;
|
|
||||||
Rabbit: Cipher;
|
|
||||||
RabbitLegacy: Cipher;
|
|
||||||
EvpKDF: Cipher;
|
|
||||||
algo: {
|
|
||||||
AES: CipherAlgorythm;
|
|
||||||
DES: CipherAlgorythm;
|
|
||||||
TrippleDES: CipherAlgorythm;
|
|
||||||
RC4: CipherAlgorythm;
|
|
||||||
RC4Drop: CipherAlgorythm;
|
|
||||||
Rabbit: CipherAlgorythm;
|
|
||||||
RabbitLegacy: CipherAlgorythm;
|
|
||||||
EvpKDF: CipherAlgorythm;
|
|
||||||
};
|
|
||||||
format: {
|
|
||||||
OpenSSL: any;
|
|
||||||
Hex: any;
|
|
||||||
};
|
|
||||||
enc: {
|
|
||||||
Latin1: Encoder;
|
|
||||||
Utf8: Encoder;
|
|
||||||
Hex: Encoder;
|
|
||||||
Utf16: Encoder;
|
|
||||||
Utf16LE: Encoder;
|
|
||||||
Base64: Encoder;
|
|
||||||
};
|
|
||||||
mode: {
|
|
||||||
CFB: Mode;
|
|
||||||
CTR: Mode;
|
|
||||||
CTRGladman: Mode;
|
|
||||||
OFB: Mode;
|
|
||||||
ECB: Mode;
|
|
||||||
};
|
|
||||||
pad: {
|
|
||||||
Pkcs7: Padding;
|
|
||||||
AnsiX923: Padding;
|
|
||||||
Iso10126: Padding;
|
|
||||||
Iso97971: Padding;
|
|
||||||
ZeroPadding: Padding;
|
|
||||||
NoPadding: Padding;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
declare let CryptoJS: CryptoJS.Hashes;
|
|
||||||
|
|
||||||
export default CryptoJS
|
|
||||||
@@ -1,12 +1,15 @@
|
|||||||
import Message from "./chat/Message.jsx"
|
import Client from "../api/Client.ts";
|
||||||
import MessageContainer from "./chat/MessageContainer.jsx"
|
import data from "../Data.ts";
|
||||||
|
import ChatFragment from "./chat/ChatFragment.jsx"
|
||||||
|
import LoginDialog from "./dialog/LoginDialog.jsx"
|
||||||
import ContactsListItem from "./main/ContactsListItem.jsx"
|
import ContactsListItem from "./main/ContactsListItem.jsx"
|
||||||
import RecentsListItem from "./main/RecentsListItem.jsx"
|
import RecentsListItem from "./main/RecentsListItem.jsx"
|
||||||
|
import snackbar from "./snackbar.js";
|
||||||
import useEventListener from './useEventListener.js'
|
import useEventListener from './useEventListener.js'
|
||||||
|
|
||||||
export default function App() {
|
export default function App() {
|
||||||
const [recentsList, setRecentsList] = React.useState([
|
const [recentsList, setRecentsList] = React.useState([
|
||||||
{
|
/* {
|
||||||
userId: 0,
|
userId: 0,
|
||||||
avatar: "https://www.court-records.net/mugshot/aa6-004-maya.png",
|
avatar: "https://www.court-records.net/mugshot/aa6-004-maya.png",
|
||||||
nickName: "麻油衣酱",
|
nickName: "麻油衣酱",
|
||||||
@@ -17,11 +20,11 @@ export default function App() {
|
|||||||
avatar: "https://www.court-records.net/mugshot/aa6-004-maya.png",
|
avatar: "https://www.court-records.net/mugshot/aa6-004-maya.png",
|
||||||
nickName: "Maya Fey",
|
nickName: "Maya Fey",
|
||||||
content: "我是绫里真宵, 是一名灵媒师~"
|
content: "我是绫里真宵, 是一名灵媒师~"
|
||||||
},
|
}, */
|
||||||
])
|
])
|
||||||
const [contactsMap, setContactsMap] = React.useState({
|
const [contactsMap, setContactsMap] = React.useState({
|
||||||
所有: [
|
所有: [
|
||||||
{
|
/* {
|
||||||
userId: 0,
|
userId: 0,
|
||||||
avatar: "https://www.court-records.net/mugshot/aa6-004-maya.png",
|
avatar: "https://www.court-records.net/mugshot/aa6-004-maya.png",
|
||||||
nickName: "麻油衣酱",
|
nickName: "麻油衣酱",
|
||||||
@@ -30,7 +33,7 @@ export default function App() {
|
|||||||
userId: 0,
|
userId: 0,
|
||||||
avatar: "https://www.court-records.net/mugshot/aa6-004-maya.png",
|
avatar: "https://www.court-records.net/mugshot/aa6-004-maya.png",
|
||||||
nickName: "Maya Fey",
|
nickName: "Maya Fey",
|
||||||
},
|
}, */
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
const [navigationItemSelected, setNavigationItemSelected] = React.useState('Recents')
|
const [navigationItemSelected, setNavigationItemSelected] = React.useState('Recents')
|
||||||
@@ -40,6 +43,25 @@ export default function App() {
|
|||||||
setNavigationItemSelected(event.target.value)
|
setNavigationItemSelected(event.target.value)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const [
|
||||||
|
loginDialogRef,
|
||||||
|
inputAccountRef,
|
||||||
|
inputPasswordRef,
|
||||||
|
registerButtonRef,
|
||||||
|
loginButtonRef
|
||||||
|
] = [React.useRef(null), React.useRef(null), React.useRef(null), React.useRef(null), React.useRef(null)]
|
||||||
|
|
||||||
|
React.useEffect(async () => {
|
||||||
|
Client.connect()
|
||||||
|
const re = await Client.invoke("User.auth", {
|
||||||
|
access_token: data.access_token,
|
||||||
|
})
|
||||||
|
if (re.code == 401)
|
||||||
|
loginDialogRef.current.show()
|
||||||
|
else if (re.code != 200)
|
||||||
|
snackbar("驗證失敗: " + re.msg)
|
||||||
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{
|
<div style={{
|
||||||
display: "flex",
|
display: "flex",
|
||||||
@@ -47,6 +69,12 @@ export default function App() {
|
|||||||
width: 'calc(var(--whitesilk-window-width) - 80px)',
|
width: 'calc(var(--whitesilk-window-width) - 80px)',
|
||||||
height: 'var(--whitesilk-window-height)',
|
height: 'var(--whitesilk-window-height)',
|
||||||
}}>
|
}}>
|
||||||
|
<LoginDialog
|
||||||
|
ref={loginDialogRef}
|
||||||
|
inputAccountRef={inputAccountRef}
|
||||||
|
inputPasswordRef={inputPasswordRef}
|
||||||
|
registerButtonRef={registerButtonRef}
|
||||||
|
loginButtonRef={loginButtonRef} />
|
||||||
{
|
{
|
||||||
// 移动端用 页面调试
|
// 移动端用 页面调试
|
||||||
// 換個地方弄
|
// 換個地方弄
|
||||||
@@ -122,63 +150,7 @@ export default function App() {
|
|||||||
{
|
{
|
||||||
// 聊天页面
|
// 聊天页面
|
||||||
}
|
}
|
||||||
<div style={{
|
<ChatFragment />
|
||||||
width: '100%',
|
|
||||||
height: '100%',
|
|
||||||
display: 'flex',
|
|
||||||
flexDirection: 'column',
|
|
||||||
overflowY: 'auto',
|
|
||||||
}}>
|
|
||||||
<mdui-top-app-bar style={{
|
|
||||||
position: 'sticky',
|
|
||||||
}}>
|
|
||||||
<mdui-button-icon icon="menu"></mdui-button-icon>
|
|
||||||
<mdui-top-app-bar-title>Title</mdui-top-app-bar-title>
|
|
||||||
<mdui-button-icon icon="more_vert"></mdui-button-icon>
|
|
||||||
</mdui-top-app-bar>
|
|
||||||
<div style={{
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "column",
|
|
||||||
height: "100%",
|
|
||||||
}}>
|
|
||||||
<div style={{
|
|
||||||
display: "flex",
|
|
||||||
justifyContent: "center",
|
|
||||||
}}>
|
|
||||||
<mdui-button variant="text">加載更多</mdui-button>
|
|
||||||
</div>
|
|
||||||
<MessageContainer>
|
|
||||||
<Message
|
|
||||||
nickName="Fey"
|
|
||||||
avatar="https://www.court-records.net/mugshot/aa6-004-maya.png">
|
|
||||||
Test
|
|
||||||
</Message>
|
|
||||||
</MessageContainer>
|
|
||||||
{
|
|
||||||
// 输入框
|
|
||||||
}
|
|
||||||
<div style={{
|
|
||||||
display: 'flex',
|
|
||||||
alignItems: 'center',
|
|
||||||
paddingBottom: '0.1rem',
|
|
||||||
paddingTop: '0.1rem',
|
|
||||||
height: '4rem',
|
|
||||||
position: 'sticky',
|
|
||||||
bottom: '0',
|
|
||||||
backgroundColor: 'rgb(var(--mdui-color-background))',
|
|
||||||
}}>
|
|
||||||
<mdui-text-field variant="outlined" placeholder="喵呜~" style={{
|
|
||||||
marginRight: '10px',
|
|
||||||
}}></mdui-text-field>
|
|
||||||
<mdui-button-icon slot="end-icon" icon="more_vert" style={{
|
|
||||||
marginRight: '6px',
|
|
||||||
}}></mdui-button-icon>
|
|
||||||
<mdui-button-icon icon="send" style={{
|
|
||||||
marginRight: '7px',
|
|
||||||
}}></mdui-button-icon>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -1,3 +1,64 @@
|
|||||||
export default function ChatFragment() {
|
import Message from "./Message.jsx"
|
||||||
|
import MessageContainer from "./MessageContainer.jsx"
|
||||||
|
|
||||||
|
export default function ChatFragment() {
|
||||||
|
return (
|
||||||
|
<div style={{
|
||||||
|
width: '100%',
|
||||||
|
height: '100%',
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
overflowY: 'auto',
|
||||||
|
}}>
|
||||||
|
<mdui-top-app-bar style={{
|
||||||
|
position: 'sticky',
|
||||||
|
}}>
|
||||||
|
<mdui-button-icon icon="menu"></mdui-button-icon>
|
||||||
|
<mdui-top-app-bar-title>Title</mdui-top-app-bar-title>
|
||||||
|
<mdui-button-icon icon="more_vert"></mdui-button-icon>
|
||||||
|
</mdui-top-app-bar>
|
||||||
|
<div style={{
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
height: "100%",
|
||||||
|
}}>
|
||||||
|
<div style={{
|
||||||
|
display: "flex",
|
||||||
|
justifyContent: "center",
|
||||||
|
}}>
|
||||||
|
<mdui-button variant="text">加載更多</mdui-button>
|
||||||
|
</div>
|
||||||
|
<MessageContainer>
|
||||||
|
<Message
|
||||||
|
nickName="Fey"
|
||||||
|
avatar="https://www.court-records.net/mugshot/aa6-004-maya.png">
|
||||||
|
Test
|
||||||
|
</Message>
|
||||||
|
</MessageContainer>
|
||||||
|
{
|
||||||
|
// 输入框
|
||||||
|
}
|
||||||
|
<div style={{
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
paddingBottom: '0.1rem',
|
||||||
|
paddingTop: '0.1rem',
|
||||||
|
height: '4rem',
|
||||||
|
position: 'sticky',
|
||||||
|
bottom: '0',
|
||||||
|
backgroundColor: 'rgb(var(--mdui-color-background))',
|
||||||
|
}}>
|
||||||
|
<mdui-text-field variant="outlined" placeholder="喵呜~" style={{
|
||||||
|
marginRight: '10px',
|
||||||
|
}}></mdui-text-field>
|
||||||
|
<mdui-button-icon slot="end-icon" icon="more_vert" style={{
|
||||||
|
marginRight: '6px',
|
||||||
|
}}></mdui-button-icon>
|
||||||
|
<mdui-button-icon icon="send" style={{
|
||||||
|
marginRight: '7px',
|
||||||
|
}}></mdui-button-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
21
client/ui/dialog/LoginDialog.jsx
Normal file
21
client/ui/dialog/LoginDialog.jsx
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
export default function LoginDialog({
|
||||||
|
inputAccountRef,
|
||||||
|
inputPasswordRef,
|
||||||
|
registerButtonRef,
|
||||||
|
loginButtonRef,
|
||||||
|
...prop
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<mdui-dialog headline="登录" {...prop}>
|
||||||
|
|
||||||
|
<mdui-text-field label="账号" ref={inputAccountRef}></mdui-text-field>
|
||||||
|
<div style={{
|
||||||
|
height: "10px",
|
||||||
|
}}></div>
|
||||||
|
<mdui-text-field label="密码" ref={inputPasswordRef}></mdui-text-field>
|
||||||
|
|
||||||
|
<mdui-button slot="action" variant="text" ref={registerButtonRef}>注册</mdui-button>
|
||||||
|
<mdui-button slot="action" variant="text" ref={loginButtonRef}>登录</mdui-button>
|
||||||
|
</mdui-dialog>
|
||||||
|
)
|
||||||
|
}
|
||||||
3
client/ui/snackbar.js
Normal file
3
client/ui/snackbar.js
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
export default function snackbar(text) {
|
||||||
|
$("#public_snackbar").text(text).get(0).open()
|
||||||
|
}
|
||||||
@@ -10,5 +10,6 @@ type ApiCallbackMessage = {
|
|||||||
* 501: 伺服器端不支持請求的功能
|
* 501: 伺服器端不支持請求的功能
|
||||||
*/
|
*/
|
||||||
code: 200 | 400 | 401 | 403 | 404 | 500 | 501,
|
code: 200 | 400 | 401 | 403 | 404 | 500 | 501,
|
||||||
|
data?: { [key: string]: unknown },
|
||||||
}
|
}
|
||||||
export default ApiCallbackMessage
|
export default ApiCallbackMessage
|
||||||
7
server/api/ApiDeclare.ts
Normal file
7
server/api/ApiDeclare.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
export type CallMethod =
|
||||||
|
"User.auth" |
|
||||||
|
"User.register" |
|
||||||
|
"User.login"
|
||||||
|
|
||||||
|
export type ClientEvent =
|
||||||
|
"Client.onMessage"
|
||||||
@@ -1,14 +1,15 @@
|
|||||||
import HttpServerLike from '../types/HttpServerLike.ts'
|
import HttpServerLike from '../types/HttpServerLike.ts'
|
||||||
import UserApi from "./UserApi.ts"
|
import UserApi from "./UserApi.ts"
|
||||||
import * as SocketIo from "socket.io"
|
import * as SocketIo from "socket.io"
|
||||||
import ApiCallbackMessage from "../types/ApiCallbackMessage.ts"
|
import ApiCallbackMessage from "./ApiCallbackMessage.ts"
|
||||||
import EventCallbackFunction from "../types/EventCallbackFunction.ts"
|
import EventCallbackFunction from "../types/EventCallbackFunction.ts"
|
||||||
|
import BaseApi from "./BaseApi.ts"
|
||||||
|
|
||||||
export default class ApiManager {
|
export default class ApiManager {
|
||||||
static httpServer: HttpServerLike
|
static httpServer: HttpServerLike
|
||||||
static socketIoServer: SocketIo.Server
|
static socketIoServer: SocketIo.Server
|
||||||
static event_listeners: { [key: string] : EventCallbackFunction } = {}
|
static event_listeners: { [key: string]: EventCallbackFunction } = {}
|
||||||
static apis_instance: {}
|
static apis_instance: { [key: string]: BaseApi } = {}
|
||||||
static initServer(httpServer: HttpServerLike, socketIoServer: SocketIo.Server) {
|
static initServer(httpServer: HttpServerLike, socketIoServer: SocketIo.Server) {
|
||||||
this.httpServer = httpServer
|
this.httpServer = httpServer
|
||||||
this.socketIoServer = socketIoServer
|
this.socketIoServer = socketIoServer
|
||||||
@@ -30,13 +31,17 @@ export default class ApiManager {
|
|||||||
static initEvents() {
|
static initEvents() {
|
||||||
const io = this.socketIoServer
|
const io = this.socketIoServer
|
||||||
io.on('connection', (socket) => {
|
io.on('connection', (socket) => {
|
||||||
socket.on("The_White_Silk", (name: string, args: {}, callback: (ret: ApiCallbackMessage) => void) => {
|
socket.on("The_White_Silk", (name: string, args: { [key: string]: unknown }, callback: (ret: ApiCallbackMessage) => void) => {
|
||||||
|
try {
|
||||||
if (name == null || args == null) return callback({
|
if (name == null || args == null) return callback({
|
||||||
msg: "Invalid request.",
|
msg: "Invalid request.",
|
||||||
code: 400
|
code: 400
|
||||||
})
|
})
|
||||||
|
|
||||||
return callback(this.event_listeners[name]?.(args))
|
return callback(this.event_listeners[name]?.(args))
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import EventCallbackFunction from "../types/EventCallbackFunction.ts"
|
import EventCallbackFunction from "../types/EventCallbackFunction.ts"
|
||||||
import ApiManager from "./ApiManager.ts";
|
import ApiManager from "./ApiManager.ts"
|
||||||
|
import { CallMethod } from './ApiDeclare.ts'
|
||||||
|
|
||||||
export default abstract class BaseApi {
|
export default abstract class BaseApi {
|
||||||
abstract getName(): string
|
abstract getName(): string
|
||||||
@@ -7,7 +8,8 @@ export default abstract class BaseApi {
|
|||||||
this.onInit()
|
this.onInit()
|
||||||
}
|
}
|
||||||
abstract onInit(): void
|
abstract onInit(): void
|
||||||
registerEvent(name: string, func: EventCallbackFunction) {
|
registerEvent(name: CallMethod, func: EventCallbackFunction) {
|
||||||
ApiManager.addEventListener(this.getName() + "." + name, func)
|
if (!name.startsWith(this.getName() + ".")) throw Error("注冊的事件應該與接口集合命名空間相匹配: " + name)
|
||||||
|
ApiManager.addEventListener(name, func)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import BaseApi from "./BaseApi.ts";
|
import BaseApi from "./BaseApi.ts"
|
||||||
|
|
||||||
export default class UserApi extends BaseApi {
|
export default class UserApi extends BaseApi {
|
||||||
override getName(): string {
|
override getName(): string {
|
||||||
return "User"
|
return "User"
|
||||||
}
|
}
|
||||||
override onInit(): void {
|
override onInit(): void {
|
||||||
this.registerEvent("", () => {
|
this.registerEvent("User.auth", () => {
|
||||||
return {
|
return {
|
||||||
msg: "",
|
msg: "",
|
||||||
code: 200,
|
code: 200,
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import ApiCallbackMessage from "./ApiCallbackMessage.ts"
|
import ApiCallbackMessage from "../api/ApiCallbackMessage.ts"
|
||||||
|
|
||||||
type EventCallbackFunction = (args: {}) => ApiCallbackMessage
|
type EventCallbackFunction = (args: {}) => ApiCallbackMessage
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user