feat: ts APICall을 강제화.

- 오버 엔지니어링의 정석
This commit is contained in:
2021-12-29 03:55:40 +09:00
parent 0a4d568b06
commit def230bf30
16 changed files with 166 additions and 125 deletions
-34
View File
@@ -1,34 +0,0 @@
import { APIPathGen } from "./util/APIPathGen";
const apiRealPath = {
Command: {
GetReservedCommand: '',
PushCommand: '',
RepeatCommand: '',
ReserveCommand: '',
},
General: {
Join: '',
},
InheritAction: {
BuyHiddenBuff: '',
BuyRandomUnique: '',
BuySpecificUnique: '',
ResetSpecialWar: '',
ResetTurnTime: '',
SetNextSpecialWar: '',
},
Misc: { UploadImage: '' },
NationCommand: {
GetReservedCommand: '',
PushCommand: '',
RepeatCommand: '',
ReserveCommand: '',
},
Nation: {
SetNotice: '',
SetScoutMsg: '',
},
} as const;
export const APIPath = APIPathGen(apiRealPath);
+5 -6
View File
@@ -242,7 +242,6 @@ import TopBackBar from "@/components/TopBackBar.vue";
import VueTypes from "vue-types";
import { isString, range } from "lodash";
import { mb_strwidth } from "./util/mb_strwidth";
import { sammoAPI } from "./util/sammoAPI";
import { entriesWithType } from "./util/entriesWithType";
import { addMilliseconds } from "date-fns";
import { formatTime } from "./util/formatTime";
@@ -251,6 +250,7 @@ import { getNpcColor } from "./common_legacy";
import TopItem from "@/ChiefCenter/TopItem.vue";
import BottomItem from "@/ChiefCenter/BottomItem.vue";
import { ChiefResponse, OptionalFull } from "./defs";
import { SammoAPI } from "./SammoAPI";
function isDropdownChildren(e?: Event): boolean {
if (!e) {
@@ -323,7 +323,7 @@ export default defineComponent({
},
async repeatNationCommand(amount: number) {
try {
await sammoAPI(`NationCommand/RepeatCommand`, { amount });
await SammoAPI.NationCommand.RepeatCommand({ amount });
} catch (e) {
console.error(e);
alert(`실패했습니다: ${e}`);
@@ -333,7 +333,7 @@ export default defineComponent({
},
async pushNationCommand(amount: number) {
try {
await sammoAPI("NationCommand/PushCommand", { amount });
await SammoAPI.NationCommand.PushCommand({ amount });
} catch (e) {
console.error(e);
alert(`실패했습니다: ${e}`);
@@ -390,9 +390,8 @@ export default defineComponent({
async function reloadTable(): Promise<void> {
try {
const response = await sammoAPI<ChiefResponse>(
"NationCommand/GetReservedCommand"
);
const response =
await SammoAPI.NationCommand.GetReservedCommand<ChiefResponse>();
console.log(response);
for (const [key, value] of entriesWithType(response)) {
if (key === "result") {
+5 -7
View File
@@ -262,10 +262,8 @@ import "@scss/common/bootstrap5.scss";
import "@scss/game_bg.scss";
import TopBackBar from "@/components/TopBackBar.vue";
import _ from "lodash";
import { InvalidResponse } from "@/defs";
import axios from "axios";
import NumberInputWithInfo from "@/components/NumberInputWithInfo.vue";
import { sammoAPI } from "./util/sammoAPI";
import { SammoAPI } from "./SammoAPI";
type InheritanceType =
| "previous"
@@ -507,7 +505,7 @@ export default defineComponent({
}
try {
await sammoAPI("InheritAction/BuyHiddenBuff", {
await SammoAPI.InheritAction.BuyHiddenBuff({
type: buffKey,
level,
});
@@ -550,7 +548,7 @@ export default defineComponent({
}
try {
await sammoAPI(`InheritAction/${type}`, {});
await SammoAPI.InheritAction[type]({});
} catch (e) {
console.error(e);
alert(`실패했습니다: ${e}`);
@@ -584,7 +582,7 @@ export default defineComponent({
}
try {
await sammoAPI(`InheritAction/SetNextSpecialWar`, {
await SammoAPI.InheritAction.SetNextSpecialWar({
type: this.nextSpecialWar,
});
} catch (e) {
@@ -616,7 +614,7 @@ export default defineComponent({
}
try {
await sammoAPI(`InheritAction/BuySpecificUnique`, {
await SammoAPI.InheritAction.BuySpecificUnique({
item: this.specificUnique,
amount,
});
+2 -4
View File
@@ -315,10 +315,8 @@ import {
abilityRand,
} from "@util/generalStats";
import { clone, shuffle, sum } from "lodash";
import axios from "axios";
import { InvalidResponse } from "@/defs";
import NumberInputWithInfo from "@/components/NumberInputWithInfo.vue";
import { sammoAPI } from "./util/sammoAPI";
import { SammoAPI } from "./SammoAPI";
declare const nationList: {
nation: number;
@@ -536,7 +534,7 @@ export default defineComponent({
//검증은 언제 되어야 하는가?
const args = clone(this.args);
try {
await sammoAPI(["General", "Join"], args);
await SammoAPI.General.Join(args);
} catch (e) {
console.error(e);
alert(`실패했습니다: ${e}`);
+5 -4
View File
@@ -56,10 +56,9 @@ import "@scss/common_legacy.scss";
import "@scss/editor_component.scss";
import TipTap from "./components/TipTap.vue";
import { defineComponent, reactive, ref, toRefs } from "vue";
import { sammoAPI } from "./util/sammoAPI";
import { isString } from "lodash";
import { diplomacyState, NationStaticItem } from "./defs";
import { SammoAPI } from "./SammoAPI";
type NationItem = NationStaticItem & {
cityCnt: number;
diplomacy: {
@@ -123,10 +122,12 @@ export default defineComponent({
self.nationMsg = oldNationMsg;
}
console.log(SammoAPI.Nation.SetScoutMsg);
async function saveNationMsg() {
const msg = self.nationMsg;
try {
await sammoAPI("Nation/SetNotice", {
await SammoAPI.Nation.SetNotice({
msg,
});
oldNationMsg = msg;
@@ -152,7 +153,7 @@ export default defineComponent({
async function saveScoutMsg() {
const msg = self.scoutMsg;
try {
await sammoAPI("Nation/SetScoutMsg", {
await SammoAPI.Nation.SetScoutMsg({
msg,
});
oldScoutMsg = msg;
+5 -5
View File
@@ -260,9 +260,9 @@ import { joinYearMonth } from "@util/joinYearMonth";
import { mb_strwidth } from "@util/mb_strwidth";
import { parseTime } from "@util/parseTime";
import { parseYearMonth } from "@util/parseYearMonth";
import { sammoAPI } from "@util/sammoAPI";
import { convertSearch초성 } from "./util/convertSearch초성";
import DragSelect from "@/components/DragSelect.vue";
import { SammoAPI } from "./SammoAPI";
type commandItem = {
value: string;
@@ -404,7 +404,7 @@ export default defineComponent({
},
async repeatGeneralCommand(amount: number) {
try {
await sammoAPI(`Command/RepeatCommand`, { amount });
await SammoAPI.Command.RepeatCommand({ amount });
} catch (e) {
console.error(e);
alert(`실패했습니다: ${e}`);
@@ -414,7 +414,7 @@ export default defineComponent({
},
async pushGeneralCommand(amount: number) {
try {
await sammoAPI("Command/PushCommand", { amount });
await SammoAPI.Command.PushCommand({ amount });
} catch (e) {
console.error(e);
alert(`실패했습니다: ${e}`);
@@ -439,7 +439,7 @@ export default defineComponent({
async reloadCommandList() {
let result: ReservedCommandResponse;
try {
result = await sammoAPI("Command/GetReservedCommand");
result = await SammoAPI.Command.GetReservedCommand();
} catch (e) {
console.error(e);
alert(`실패했습니다: ${e}`);
@@ -524,7 +524,7 @@ export default defineComponent({
}
try {
await sammoAPI("Command/ReserveCommand", {
await SammoAPI.Command.ReserveCommand({
turnList,
action: commandName,
});
+46
View File
@@ -0,0 +1,46 @@
import { InvalidResponse } from "./defs";
import { APIPathGen } from "./util/APIPathGen";
import { callSammoAPI, ValidResponse } from "./util/callSammoAPI";
export type { ValidResponse, InvalidResponse };
async function done<ResultType extends ValidResponse>(args?: Record<string, unknown>): Promise<ResultType>;
async function done<ResultType extends ValidResponse>(args: Record<string, unknown> | undefined, returnError: false): Promise<ResultType>;
async function done<ResultType extends ValidResponse, ErrorType extends InvalidResponse>(args: Record<string, unknown> | undefined, returnError: true): Promise<ResultType | ErrorType>;
async function done<ResultType extends ValidResponse, ErrorType extends InvalidResponse>(args?: Record<string, unknown>, returnError = false): Promise<ResultType | ErrorType>{
console.error(`Can't directly call. ${args}, ${returnError}. Use auto-generated path API.`);
return callSammoAPI<ResultType, ErrorType>([], args, true);
}
const apiRealPath = {
Command: {
GetReservedCommand: done,
PushCommand: done,
RepeatCommand: done,
ReserveCommand: done,
},
General: {
Join: done,
},
InheritAction: {
BuyHiddenBuff: done,
BuyRandomUnique: done,
BuySpecificUnique: done,
ResetSpecialWar: done,
ResetTurnTime: done,
SetNextSpecialWar: done,
},
Misc: { UploadImage: done },
NationCommand: {
GetReservedCommand: done,
PushCommand: done,
RepeatCommand: done,
ReserveCommand: done,
},
Nation: {
SetNotice: done,
SetScoutMsg: done,
},
} as const;
export const SammoAPI = APIPathGen(apiRealPath);
+23
View File
@@ -0,0 +1,23 @@
import { InvalidResponse } from "./defs";
import { APIPathGen } from "./util/APIPathGen";
import { callSammoAPI, ValidResponse } from "./util/callSammoAPI";
export type { ValidResponse, InvalidResponse };
async function done<ResultType extends ValidResponse>(args?: Record<string, unknown>): Promise<ResultType>;
async function done<ResultType extends ValidResponse>(args: Record<string, unknown> | undefined, returnError: false): Promise<ResultType>;
async function done<ResultType extends ValidResponse, ErrorType extends InvalidResponse>(args: Record<string, unknown> | undefined, returnError: true): Promise<ResultType | ErrorType>;
async function done<ResultType extends ValidResponse, ErrorType extends InvalidResponse>(args?: Record<string, unknown>, returnError = false): Promise<ResultType | ErrorType>{
console.error(`Can't directly call. ${args}, ${returnError}. Use auto-generated path API.`);
return callSammoAPI<ResultType, ErrorType>([], args, true);
}
const apiRealPath = {
Login: {
LoginByID: done,
LoginByToken: done,
ReqNonce: done,
},
} as const;
export const SammoRootAPI = APIPathGen(apiRealPath);
+2 -2
View File
@@ -151,11 +151,11 @@ import { joinYearMonth } from "@util/joinYearMonth";
import { mb_strwidth } from "@util/mb_strwidth";
import { parseTime } from "@util/parseTime";
import { parseYearMonth } from "@util/parseYearMonth";
import { sammoAPI } from "@util/sammoAPI";
import { convertSearch초성 } from "@util/convertSearch초성";
import VueTypes from "vue-types";
import DragSelect from "@/components/DragSelect.vue";
import { isString } from "lodash";
import { SammoAPI } from "@/SammoAPI";
type commandItem = {
value: string;
@@ -375,7 +375,7 @@ export default defineComponent({
}
try {
await sammoAPI("NationCommand/ReserveCommand", {
await SammoAPI.NationCommand.ReserveCommand({
turnList,
action: commandName,
});
+2 -2
View File
@@ -351,9 +351,9 @@ import {
import { v4 as uuidv4 } from "uuid";
import { unwrap } from "@/util/unwrap";
import { getBase64FromFileObject } from "@/util/getBase64FromFileObject";
import { sammoAPI } from "@/util/sammoAPI";
import { isObject, isString } from "lodash";
import { AxiosError } from "axios";
import { SammoAPI } from "@/SammoAPI";
const compoment = defineComponent({
components: {
@@ -403,7 +403,7 @@ const compoment = defineComponent({
};
try {
const base64Binary = await getBase64FromFileObject(targetImage);
imageResult = await sammoAPI("Misc/UploadImage", {
imageResult = await SammoAPI.Misc.UploadImage({
imageData: base64Binary,
});
} catch (e) {
+4 -4
View File
@@ -12,8 +12,8 @@ import { InvalidResponse } from '@/defs';
import { delay } from '@util/delay';
import { Modal } from 'bootstrap';
import '@/gateway/common';
import { sammoAPI } from '@/util/sammoAPI';
import { isString } from 'lodash';
import { SammoRootAPI } from '@/SammoRootAPI';
type LoginResponse = {
result: true,
@@ -101,7 +101,7 @@ async function tryAutoLogin() {
const [tokenID, token] = tokenInfo;
const result = await sammoAPI<AutoLoginNonceResponse, AutoLoginFailed>(["Login", "ReqNonce"], {}, true);
const result = await SammoRootAPI.Login.ReqNonce<AutoLoginNonceResponse, AutoLoginFailed>({}, true);
if (!result) {
//api 에러.
@@ -116,7 +116,7 @@ async function tryAutoLogin() {
const nonce = result.loginNonce;
const hashedToken = sha512(token + nonce);
const loginResult = await sammoAPI<AutoLoginResponse, AutoLoginFailed>(["Login", "LoginByToken"], {
const loginResult = await SammoRootAPI.Login.LoginByToken<AutoLoginResponse, AutoLoginFailed>({
'hashedToken': hashedToken,
'token_id': tokenID,
}, true);
@@ -312,7 +312,7 @@ $(async function ($) {
let result: LoginResponse | LoginFailed;
try {
result = await sammoAPI<LoginResponse, LoginFailed>(["Login", "LoginByID"], {
result = await SammoRootAPI.Login.LoginByID<LoginResponse, LoginFailed>({
username: values.username,
password: hash_pw,
+29 -19
View File
@@ -1,30 +1,40 @@
type SubValue = string | { [property: string]: SubValue };
import { InvalidResponse } from "@/defs";
import { callSammoAPI, ValidResponse } from "./callSammoAPI";
const hasKey = <T extends Record<string | symbol, unknown>>(obj: T, k: string | symbol | number): k is keyof T =>
k in obj;
export type CurryCall<ResultType extends ValidResponse, ErrorType extends InvalidResponse> =
((args?: Record<string, unknown>) => Promise<ResultType>)
| ((args: Record<string, unknown> | undefined, returnError: false) => Promise<ResultType>)
| ((args: Record<string, unknown> | undefined, returnError: true) => Promise<ResultType | ErrorType>);
export function APIPathGen<K extends string, V extends SubValue>(obj: Record<K, V>, path?: string[]): Record<K, V> {
type SubValue<ResultType extends ValidResponse, ErrorType extends InvalidResponse> = CurryCall<ResultType, ErrorType> | { [property: string]: SubValue<ResultType, ErrorType> };
export function APIPathGen<ResultType extends ValidResponse, ErrorType extends InvalidResponse, T extends { [property: string]: SubValue<ResultType, ErrorType> },>(obj: T, path?: string[]): T {
return new Proxy(obj, {
get(target, key: K) {
get(target, key: string) {
let nextPath: string[];
if (path === undefined) {
path = [key];
nextPath = [key];
}
else {
path.push(key);
else{
nextPath = path;
nextPath.push(key);
}
if (hasKey(target, key)) {
const next: V = target[key];
if (typeof (next) === 'string') {
return path.join('/');
}
if (typeof (next) === 'object') {
return APIPathGen(next, path);
}
throw 'unknown';
if (!(key in target)) {
throw `${nextPath.join('/')} is not exists`;
}
throw `${path.join('/')} is not exists`;
const next = target[key];
if (typeof (next) === 'function') {
const callAPI: CurryCall<ResultType, ErrorType> = (args: Record<string, unknown> | undefined, returnError?: boolean) => {
if (returnError) {
return callSammoAPI<ResultType, ErrorType>(nextPath.join('/'), args, returnError);
}
return callSammoAPI<ResultType>(nextPath.join('/'), args, false);
}
return callAPI;
}
return APIPathGen(next, nextPath);
}
})
}
+35
View File
@@ -0,0 +1,35 @@
import axios from "axios";
import { isArray } from "lodash";
import { InvalidResponse } from '@/defs';
export type ValidResponse = {
result: true
}
export async function callSammoAPI<ResultType extends ValidResponse>(path: string | string[], args?: Record<string, unknown>): Promise<ResultType>;
export async function callSammoAPI<ResultType extends ValidResponse>(path: string | string[], args: Record<string, unknown> | undefined, returnError: false): Promise<ResultType>;
export async function callSammoAPI<ResultType extends ValidResponse, ErrorType extends InvalidResponse>(path: string | string[], args: Record<string, unknown> | undefined, returnError: true): Promise<ResultType | ErrorType>;
export async function callSammoAPI<ResultType extends ValidResponse, ErrorType extends InvalidResponse>(path: string | string[], args?: Record<string, unknown>, returnError = false): Promise<ResultType | ErrorType> {
if (isArray(path)) {
path = path.join('/');
}
const response = await axios({
url: "api.php",
method: "post",
responseType: "json",
data: {
path,
args,
},
});
const result: ErrorType | ResultType = response.data;
if (!result.result) {
if (returnError) {
return result;
}
throw result.reason;
}
return result;
}
-35
View File
@@ -1,35 +0,0 @@
import axios from "axios";
import { isArray } from "lodash";
import { InvalidResponse } from '@/defs';
export type ValidResponse = {
result: true
}
export async function sammoAPI<ResultType extends ValidResponse>(path: string | string[], args?: Record<string, unknown>): Promise<ResultType>;
export async function sammoAPI<ResultType extends ValidResponse>(path: string | string[], args: Record<string, unknown> | undefined, returnError: false): Promise<ResultType>;
export async function sammoAPI<ResultType extends ValidResponse, ErrorType extends InvalidResponse>(path: string | string[], args: Record<string, unknown> | undefined, returnError: true): Promise<ResultType | ErrorType>;
export async function sammoAPI<ResultType extends ValidResponse, ErrorType extends InvalidResponse>(path: string | string[], args?: Record<string, unknown>, returnError = false): Promise<ResultType | ErrorType> {
if (isArray(path)) {
path = path.join('/');
}
const response = await axios({
url: "api.php",
method: "post",
responseType: "json",
data: {
path,
args,
},
});
const result: ErrorType | ResultType = response.data;
if (!result.result) {
if (returnError) {
return result;
}
throw result.reason;
}
return result;
}
+3 -3
View File
@@ -9,12 +9,12 @@ import { App, createApp } from 'vue';
import { auto500px } from './util/auto500px';
import { isString } from 'lodash';
import { Args, testSubmitArgs } from './processing/args';
import { sammoAPI, ValidResponse } from './util/sammoAPI';
import { SammoAPI, ValidResponse } from './SammoAPI';
declare const turnList: number[];
async function submitCommand<T extends ValidResponse>(isChiefTurn: boolean, turnList: number[], action: string, arg: Args): Promise<T> {
const target = isChiefTurn ? 'NationCommand/ReserveCommand' : 'Command/ReserveCommand';
const targetAPI = isChiefTurn ? SammoAPI.NationCommand.ReserveCommand : SammoAPI.Command.ReserveCommand;
try {
const testResult = testSubmitArgs(arg);
@@ -22,7 +22,7 @@ async function submitCommand<T extends ValidResponse>(isChiefTurn: boolean, turn
throw new TypeError(`Invalied Type ${testResult[0]}, ${testResult[2]} should be ${testResult[1]}`);
}
console.log('trySubmit', arg);
const response = await sammoAPI(target, {
const response = await targetAPI({
action,
turnList,
arg,
View File