Add endpoints on pusher to resolve wokas

This commit is contained in:
Alexis Faizeau
2022-02-17 15:02:11 +01:00
committed by David Négrier
parent f993aa4f5a
commit 2161a40e05
12 changed files with 1880 additions and 1 deletions
+2
View File
@@ -6,6 +6,7 @@ import { PrometheusController } from "./Controller/PrometheusController";
import { DebugController } from "./Controller/DebugController";
import { AdminController } from "./Controller/AdminController";
import { OpenIdProfileController } from "./Controller/OpenIdProfileController";
import { WokaListController } from "./Controller/WokaListController";
import HyperExpress from "hyper-express";
import { cors } from "./Middleware/Cors";
@@ -29,6 +30,7 @@ class App {
new DebugController(webserver);
new AdminController(webserver);
new OpenIdProfileController(webserver);
new WokaListController(webserver);
}
}
@@ -69,7 +69,7 @@ export class AuthenticateController extends BaseHttpController {
//if not nonce and code, user connected in anonymous
//get data with identifier and return token
if (!code && !nonce) {
return res.json(JSON.stringify({ ...resUserData, authToken: token }));
return res.json({ ...resUserData, authToken: token });
}
console.error("Token cannot to be check on OpenId provider");
res.status(500);
@@ -0,0 +1,47 @@
import { hasToken } from "../Middleware/HasToken";
import { BaseHttpController } from "./BaseHttpController";
import { ADMIN_API_URL } from "../Enum/EnvironmentVariable";
import { adminWokaService } from "..//Services/AdminWokaService";
import { localWokaService } from "..//Services/LocalWokaService";
import { WokaServiceInterface } from "src/Services/WokaServiceInterface";
import { Server } from "hyper-express";
export class WokaListController extends BaseHttpController {
private wokaService: WokaServiceInterface;
constructor(app: Server) {
super(app);
this.wokaService = ADMIN_API_URL ? adminWokaService : localWokaService;
}
routes() {
// eslint-disable-next-line @typescript-eslint/no-misused-promises
this.app.get("/woka-list", { middlewares: [hasToken] }, async (req, res) => {
const token = req.header("Authorization");
const wokaList = await this.wokaService.getWokaList(token);
if (!wokaList) {
return res.status(500).send("Error on getting woka list");
}
return res.status(200).json(wokaList);
});
// eslint-disable-next-line @typescript-eslint/no-misused-promises
this.app.post("/woka-details", async (req, res) => {
const body = await req.json();
if (!body || !body.textureIds) {
return res.status(400);
}
const textureIds = body.textureIds;
const wokaDetails = await this.wokaService.fetchWokaDetails(textureIds);
if (!wokaDetails) {
return res.json({ details: [] });
}
return res.json(wokaDetails);
});
}
}
+64
View File
@@ -0,0 +1,64 @@
import * as tg from "generic-type-guard";
//The list of all the player textures, both the default models and the partial textures used for customization
export const isWokaTexture = new tg.IsInterface()
.withProperties({
id: tg.isString,
name: tg.isString,
url: tg.isString,
position: tg.isNumber,
})
.withOptionalProperties({
tags: tg.isArray(tg.isString),
tintable: tg.isBoolean,
})
.get();
export type WokaTexture = tg.GuardedType<typeof isWokaTexture>;
export const isWokaTextureCollection = new tg.IsInterface()
.withProperties({
name: tg.isString,
position: tg.isNumber,
textures: tg.isArray(isWokaTexture),
})
.get();
export type WokaTextureCollection = tg.GuardedType<typeof isWokaTextureCollection>;
export const isWokaPartType = new tg.IsInterface()
.withProperties({
collections: tg.isArray(isWokaTextureCollection),
})
.withOptionalProperties({
required: tg.isBoolean,
})
.get();
export type WokaPartType = tg.GuardedType<typeof isWokaPartType>;
export const isWokaList = new tg.IsInterface().withStringIndexSignature(isWokaPartType).get();
export type WokaList = tg.GuardedType<typeof isWokaList>;
export const wokaPartNames = ["woka", "body", "eyes", "hair", "clothes", "hat", "accessory"];
export const isWokaDetail = new tg.IsInterface()
.withProperties({
id: tg.isString,
})
.withOptionalProperties({
texture: tg.isString,
})
.get();
export type WokaDetail = tg.GuardedType<typeof isWokaDetail>;
export const isWokaDetailsResult = new tg.IsInterface()
.withProperties({
details: tg.isArray(isWokaDetail),
})
.get();
export type WokaDetailsResult = tg.GuardedType<typeof isWokaDetailsResult>;
+16
View File
@@ -0,0 +1,16 @@
import Request from "hyper-express/types/components/http/Request";
import Response from "hyper-express/types/components/http/Response";
import { MiddlewareNext, MiddlewarePromise } from "hyper-express/types/components/router/Router";
export function hasToken(req: Request, res: Response, next?: MiddlewareNext): MiddlewarePromise {
const authorizationHeader = req.header("Authorization");
if (!authorizationHeader) {
res.status(401).send("Undefined authorization header");
return;
}
if (next) {
next();
}
}
+71
View File
@@ -0,0 +1,71 @@
import axios from "axios";
import { ADMIN_API_TOKEN, ADMIN_API_URL } from "../Enum/EnvironmentVariable";
import { isWokaDetailsResult, isWokaList, WokaDetailsResult, WokaList } from "../Enum/PlayerTextures";
import { WokaServiceInterface } from "./WokaServiceInterface";
class AdminWokaService implements WokaServiceInterface {
/**
* Returns the list of all available Wokas for the current user.
*/
getWokaList(token: string): Promise<WokaList | undefined> {
return axios
.get(`${ADMIN_API_URL}/api/woka-list/${token}`, {
headers: { Authorization: `${ADMIN_API_TOKEN}` },
})
.then((res) => {
if (isWokaList(res.data)) {
throw new Error("Bad response format provided by woka list endpoint");
}
return res.data;
})
.catch((err) => {
console.error(`Cannot get woka list from admin API with token: ${token}`, err);
return undefined;
});
}
/**
* Returns the URL of all the images for the given texture ids.
*
* Key: texture id
* Value: URL
*
* If one of the textures cannot be found, undefined is returned
*/
fetchWokaDetails(textureIds: string[]): Promise<WokaDetailsResult | undefined> {
return axios
.post(
`${ADMIN_API_URL}/api/woka-details`,
{
textureIds,
},
{
headers: { Authorization: `${ADMIN_API_TOKEN}` },
}
)
.then((res) => {
if (isWokaDetailsResult(res.data)) {
throw new Error("Bad response format provided by woka detail endpoint");
}
const result: WokaDetailsResult = res.data;
if (result.details.length !== textureIds.length) {
return undefined;
}
for (const detail of result.details) {
if (!detail.texture) {
return undefined;
}
}
return res.data;
})
.catch((err) => {
console.error(`Cannot get woka details from admin API with ids: ${textureIds}`, err);
return undefined;
});
}
}
export const adminWokaService = new AdminWokaService();
+64
View File
@@ -0,0 +1,64 @@
import { WokaDetail, WokaDetailsResult, WokaList, wokaPartNames } from "../Enum/PlayerTextures";
import { WokaServiceInterface } from "./WokaServiceInterface";
class LocalWokaService implements WokaServiceInterface {
/**
* Returns the list of all available Wokas & Woka Parts for the current user.
*/
async getWokaList(token: string): Promise<WokaList | undefined> {
const wokaData: WokaList = await require("../../data/woka.json");
if (!wokaData) {
return undefined;
}
return wokaData;
}
/**
* Returns the URL of all the images for the given texture ids.
*
* Key: texture id
* Value: URL
*
* If one of the textures cannot be found, undefined is returned (and the user should be redirected to Woka choice page!)
*/
async fetchWokaDetails(textureIds: string[]): Promise<WokaDetailsResult | undefined> {
const wokaData: WokaList = await require("../../data/woka.json");
const textures = new Map<string, string>();
const searchIds = new Set(textureIds);
for (const part of wokaPartNames) {
const wokaPartType = wokaData[part];
if (!wokaPartType) {
continue;
}
for (const collection of wokaPartType.collections) {
for (const id of searchIds) {
const texture = collection.textures.find((texture) => texture.id === id);
if (texture) {
textures.set(id, texture.url);
searchIds.delete(id);
}
}
}
}
if (textureIds.length !== textures.size) {
return undefined;
}
const details: WokaDetail[] = [];
textures.forEach((value, key) => {
details.push({
id: key,
texture: value,
});
});
return { details };
}
}
export const localWokaService = new LocalWokaService();
@@ -0,0 +1,18 @@
import { WokaDetailsResult, WokaList } from "../Enum/PlayerTextures";
export interface WokaServiceInterface {
/**
* Returns the list of all available Wokas for the current user.
*/
getWokaList(token: string): Promise<WokaList | undefined>;
/**
* Returns the URL of all the images for the given texture ids.
*
* Key: texture id
* Value: URL
*
* If one of the textures cannot be found, undefined is returned (and the user should be redirected to Woka choice page!)
*/
fetchWokaDetails(textureIds: string[]): Promise<WokaDetailsResult | undefined>;
}