add batch game info request
This commit is contained in:
parent
f6d40b8f2e
commit
d916014872
@ -44,6 +44,19 @@ async fn get_game(
|
|||||||
games.iter().find(|g| g.title == title).cloned()
|
games.iter().find(|g| g.title == title).cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[post("/games/batch", data = "<req>")]
|
||||||
|
async fn get_games_batch(
|
||||||
|
_token: auth::Token,
|
||||||
|
game_list: &rocket::State<Mutex<Vec<Game>>>,
|
||||||
|
req: proto_utils::Proto<items::GetGameInfoRequest>,
|
||||||
|
) -> items::GameList {
|
||||||
|
let games = game_list.lock().await;
|
||||||
|
let req = req.into_inner();
|
||||||
|
let mut games = games.clone();
|
||||||
|
games.retain(|g| req.games.contains(&g.title));
|
||||||
|
items::GameList { games }
|
||||||
|
}
|
||||||
|
|
||||||
#[get("/games")]
|
#[get("/games")]
|
||||||
async fn get_games(
|
async fn get_games(
|
||||||
_token: auth::Token,
|
_token: auth::Token,
|
||||||
@ -319,7 +332,8 @@ async fn main() -> Result<(), std::io::Error> {
|
|||||||
add_opinion,
|
add_opinion,
|
||||||
remove_opinion,
|
remove_opinion,
|
||||||
add_game,
|
add_game,
|
||||||
get_game_thumbnail
|
get_game_thumbnail,
|
||||||
|
get_games_batch
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
.mount(
|
.mount(
|
||||||
|
|||||||
@ -116,6 +116,14 @@ export interface RemoveOpinionRequest {
|
|||||||
gameTitle: string;
|
gameTitle: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface GetGameInfoRequest {
|
||||||
|
games: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface GameInfoResponse {
|
||||||
|
games: Game[];
|
||||||
|
}
|
||||||
|
|
||||||
function createBasePerson(): Person {
|
function createBasePerson(): Person {
|
||||||
return { name: "", opinion: [] };
|
return { name: "", opinion: [] };
|
||||||
}
|
}
|
||||||
@ -1213,6 +1221,122 @@ export const RemoveOpinionRequest: MessageFns<RemoveOpinionRequest> = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function createBaseGetGameInfoRequest(): GetGameInfoRequest {
|
||||||
|
return { games: [] };
|
||||||
|
}
|
||||||
|
|
||||||
|
export const GetGameInfoRequest: MessageFns<GetGameInfoRequest> = {
|
||||||
|
encode(message: GetGameInfoRequest, writer: BinaryWriter = new BinaryWriter()): BinaryWriter {
|
||||||
|
for (const v of message.games) {
|
||||||
|
writer.uint32(10).string(v!);
|
||||||
|
}
|
||||||
|
return writer;
|
||||||
|
},
|
||||||
|
|
||||||
|
decode(input: BinaryReader | Uint8Array, length?: number): GetGameInfoRequest {
|
||||||
|
const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
|
||||||
|
const end = length === undefined ? reader.len : reader.pos + length;
|
||||||
|
const message = createBaseGetGameInfoRequest();
|
||||||
|
while (reader.pos < end) {
|
||||||
|
const tag = reader.uint32();
|
||||||
|
switch (tag >>> 3) {
|
||||||
|
case 1: {
|
||||||
|
if (tag !== 10) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
message.games.push(reader.string());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((tag & 7) === 4 || tag === 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
reader.skip(tag & 7);
|
||||||
|
}
|
||||||
|
return message;
|
||||||
|
},
|
||||||
|
|
||||||
|
fromJSON(object: any): GetGameInfoRequest {
|
||||||
|
return { games: globalThis.Array.isArray(object?.games) ? object.games.map((e: any) => globalThis.String(e)) : [] };
|
||||||
|
},
|
||||||
|
|
||||||
|
toJSON(message: GetGameInfoRequest): unknown {
|
||||||
|
const obj: any = {};
|
||||||
|
if (message.games?.length) {
|
||||||
|
obj.games = message.games;
|
||||||
|
}
|
||||||
|
return obj;
|
||||||
|
},
|
||||||
|
|
||||||
|
create<I extends Exact<DeepPartial<GetGameInfoRequest>, I>>(base?: I): GetGameInfoRequest {
|
||||||
|
return GetGameInfoRequest.fromPartial(base ?? ({} as any));
|
||||||
|
},
|
||||||
|
fromPartial<I extends Exact<DeepPartial<GetGameInfoRequest>, I>>(object: I): GetGameInfoRequest {
|
||||||
|
const message = createBaseGetGameInfoRequest();
|
||||||
|
message.games = object.games?.map((e) => e) || [];
|
||||||
|
return message;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
function createBaseGameInfoResponse(): GameInfoResponse {
|
||||||
|
return { games: [] };
|
||||||
|
}
|
||||||
|
|
||||||
|
export const GameInfoResponse: MessageFns<GameInfoResponse> = {
|
||||||
|
encode(message: GameInfoResponse, writer: BinaryWriter = new BinaryWriter()): BinaryWriter {
|
||||||
|
for (const v of message.games) {
|
||||||
|
Game.encode(v!, writer.uint32(10).fork()).join();
|
||||||
|
}
|
||||||
|
return writer;
|
||||||
|
},
|
||||||
|
|
||||||
|
decode(input: BinaryReader | Uint8Array, length?: number): GameInfoResponse {
|
||||||
|
const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
|
||||||
|
const end = length === undefined ? reader.len : reader.pos + length;
|
||||||
|
const message = createBaseGameInfoResponse();
|
||||||
|
while (reader.pos < end) {
|
||||||
|
const tag = reader.uint32();
|
||||||
|
switch (tag >>> 3) {
|
||||||
|
case 1: {
|
||||||
|
if (tag !== 10) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
message.games.push(Game.decode(reader, reader.uint32()));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((tag & 7) === 4 || tag === 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
reader.skip(tag & 7);
|
||||||
|
}
|
||||||
|
return message;
|
||||||
|
},
|
||||||
|
|
||||||
|
fromJSON(object: any): GameInfoResponse {
|
||||||
|
return { games: globalThis.Array.isArray(object?.games) ? object.games.map((e: any) => Game.fromJSON(e)) : [] };
|
||||||
|
},
|
||||||
|
|
||||||
|
toJSON(message: GameInfoResponse): unknown {
|
||||||
|
const obj: any = {};
|
||||||
|
if (message.games?.length) {
|
||||||
|
obj.games = message.games.map((e) => Game.toJSON(e));
|
||||||
|
}
|
||||||
|
return obj;
|
||||||
|
},
|
||||||
|
|
||||||
|
create<I extends Exact<DeepPartial<GameInfoResponse>, I>>(base?: I): GameInfoResponse {
|
||||||
|
return GameInfoResponse.fromPartial(base ?? ({} as any));
|
||||||
|
},
|
||||||
|
fromPartial<I extends Exact<DeepPartial<GameInfoResponse>, I>>(object: I): GameInfoResponse {
|
||||||
|
const message = createBaseGameInfoResponse();
|
||||||
|
message.games = object.games?.map((e) => Game.fromPartial(e)) || [];
|
||||||
|
return message;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
/** Authentication service */
|
/** Authentication service */
|
||||||
export interface AuthService {
|
export interface AuthService {
|
||||||
Login(request: LoginRequest): Promise<LoginResponse>;
|
Login(request: LoginRequest): Promise<LoginResponse>;
|
||||||
@ -1255,6 +1379,7 @@ export interface MainService {
|
|||||||
GetGames(request: GetGamesRequest): Promise<GameList>;
|
GetGames(request: GetGamesRequest): Promise<GameList>;
|
||||||
AddGame(request: Game): Promise<Game>;
|
AddGame(request: Game): Promise<Game>;
|
||||||
AddOpinion(request: AddOpinionRequest): Promise<Person>;
|
AddOpinion(request: AddOpinionRequest): Promise<Person>;
|
||||||
|
GetGameInfo(request: GetGameInfoRequest): Promise<GameInfoResponse>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const MainServiceServiceName = "items.MainService";
|
export const MainServiceServiceName = "items.MainService";
|
||||||
@ -1268,6 +1393,7 @@ export class MainServiceClientImpl implements MainService {
|
|||||||
this.GetGames = this.GetGames.bind(this);
|
this.GetGames = this.GetGames.bind(this);
|
||||||
this.AddGame = this.AddGame.bind(this);
|
this.AddGame = this.AddGame.bind(this);
|
||||||
this.AddOpinion = this.AddOpinion.bind(this);
|
this.AddOpinion = this.AddOpinion.bind(this);
|
||||||
|
this.GetGameInfo = this.GetGameInfo.bind(this);
|
||||||
}
|
}
|
||||||
GetGame(request: GameRequest): Promise<Game> {
|
GetGame(request: GameRequest): Promise<Game> {
|
||||||
const data = GameRequest.encode(request).finish();
|
const data = GameRequest.encode(request).finish();
|
||||||
@ -1292,6 +1418,12 @@ export class MainServiceClientImpl implements MainService {
|
|||||||
const promise = this.rpc.request(this.service, "AddOpinion", data);
|
const promise = this.rpc.request(this.service, "AddOpinion", data);
|
||||||
return promise.then((data) => Person.decode(new BinaryReader(data)));
|
return promise.then((data) => Person.decode(new BinaryReader(data)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GetGameInfo(request: GetGameInfoRequest): Promise<GameInfoResponse> {
|
||||||
|
const data = GetGameInfoRequest.encode(request).finish();
|
||||||
|
const promise = this.rpc.request(this.service, "GetGameInfo", data);
|
||||||
|
return promise.then((data) => GameInfoResponse.decode(new BinaryReader(data)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Rpc {
|
interface Rpc {
|
||||||
|
|||||||
@ -3,6 +3,8 @@ import {
|
|||||||
Person,
|
Person,
|
||||||
PersonList as PersonListProto,
|
PersonList as PersonListProto,
|
||||||
Game as GameProto,
|
Game as GameProto,
|
||||||
|
GetGameInfoRequest,
|
||||||
|
GameInfoResponse,
|
||||||
} from "../items";
|
} from "../items";
|
||||||
import { apiFetch } from "./api";
|
import { apiFetch } from "./api";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
@ -72,31 +74,38 @@ export function GameFilter() {
|
|||||||
.filter(([, players]) => players.size === 0)
|
.filter(([, players]) => players.size === 0)
|
||||||
.map(([game]) => game);
|
.map(([game]) => game);
|
||||||
|
|
||||||
const games = game_titles.map(async (title) => {
|
let games = game_titles.filter((title) => metaData[title]).map((title) => metaData[title]);
|
||||||
if (metaData[title]) {
|
const gamesToFetch = GetGameInfoRequest.encode(
|
||||||
console.log("returned cached metadata");
|
GetGameInfoRequest.create({
|
||||||
return metaData[title];
|
games: game_titles.filter((title) => !metaData[title]),
|
||||||
}
|
})
|
||||||
return await apiFetch(`/api/game/${encodeURIComponent(title)}`)
|
).finish();
|
||||||
.then((res) => res.arrayBuffer())
|
|
||||||
.then((buffer) => {
|
|
||||||
const game = GameProto.decode(new Uint8Array(buffer)) as GameProto;
|
|
||||||
metaData[title] = game;
|
|
||||||
return game;
|
|
||||||
})
|
|
||||||
.catch((err) => console.error("Failed to fetch game:", err));
|
|
||||||
});
|
|
||||||
|
|
||||||
Promise.all(games).then((games) => {
|
apiFetch("/api/games/batch", {
|
||||||
const filteredGames = games.filter((g) => {
|
method: "POST",
|
||||||
const game = g as GameProto;
|
headers: {
|
||||||
return (
|
"Content-Type": "application/octet-stream",
|
||||||
game.maxPlayers >= selectedPeople.size &&
|
},
|
||||||
game.minPlayers <= selectedPeople.size
|
body: gamesToFetch,
|
||||||
);
|
})
|
||||||
|
.then((res) => res.arrayBuffer())
|
||||||
|
.then((buffer) => {
|
||||||
|
const list = GameInfoResponse.decode(new Uint8Array(buffer));
|
||||||
|
games = games.concat(list.games);
|
||||||
|
|
||||||
|
games.forEach((game) => {
|
||||||
|
metaData[game.title] = game;
|
||||||
|
});
|
||||||
|
|
||||||
|
const filteredGames = games.filter((g) => {
|
||||||
|
const game = g as GameProto;
|
||||||
|
return (
|
||||||
|
game.maxPlayers >= selectedPeople.size &&
|
||||||
|
game.minPlayers <= selectedPeople.size
|
||||||
|
);
|
||||||
|
});
|
||||||
|
setFilteredGames(filteredGames.map((g) => (g as GameProto).title));
|
||||||
});
|
});
|
||||||
setFilteredGames(filteredGames.map((g) => (g as GameProto).title));
|
|
||||||
});
|
|
||||||
}, [selectedPeople, people, metaData]);
|
}, [selectedPeople, people, metaData]);
|
||||||
|
|
||||||
const togglePerson = (name: string) => {
|
const togglePerson = (name: string) => {
|
||||||
|
|||||||
@ -459,7 +459,7 @@ export function GameList({ onShowToast }: Props) {
|
|||||||
"Content-Type": "application/octet-stream",
|
"Content-Type": "application/octet-stream",
|
||||||
},
|
},
|
||||||
body: RemoveOpinionRequest.encode(
|
body: RemoveOpinionRequest.encode(
|
||||||
AddOpinionRequest.create({
|
RemoveOpinionRequest.create({
|
||||||
gameTitle: title,
|
gameTitle: title,
|
||||||
})
|
})
|
||||||
).finish(),
|
).finish(),
|
||||||
|
|||||||
@ -3,31 +3,32 @@ syntax = "proto3";
|
|||||||
package items;
|
package items;
|
||||||
|
|
||||||
message Person {
|
message Person {
|
||||||
string name = 1;
|
string name = 1;
|
||||||
repeated Opinion opinion = 2;
|
repeated Opinion opinion = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message Opinion {
|
message Opinion {
|
||||||
string title = 1;
|
string title = 1;
|
||||||
bool would_play = 2;
|
bool would_play = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message Game {
|
message Game {
|
||||||
reserved 3;
|
reserved 3;
|
||||||
string title = 1;
|
string title = 1;
|
||||||
Source source = 2;
|
Source source = 2;
|
||||||
uint32 min_players = 4;
|
uint32 min_players = 4;
|
||||||
uint32 max_players = 5;
|
uint32 max_players = 5;
|
||||||
uint32 price = 6;
|
uint32 price = 6;
|
||||||
uint64 remote_id = 7;
|
uint64 remote_id = 7;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Source {
|
enum Source {
|
||||||
STEAM = 0;
|
STEAM = 0;
|
||||||
ROBLOX = 1;
|
ROBLOX = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
message PersonList { repeated Person person = 1; }
|
message PersonList { repeated Person person = 1; }
|
||||||
|
|
||||||
message GameList { repeated Game games = 1; }
|
message GameList { repeated Game games = 1; }
|
||||||
|
|
||||||
// Authentication messages
|
// Authentication messages
|
||||||
@ -37,24 +38,24 @@ message LoginRequest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
message LoginResponse {
|
message LoginResponse {
|
||||||
string token = 1;
|
string token = 1;
|
||||||
bool success = 2;
|
bool success = 2;
|
||||||
string message = 3;
|
string message = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
message LogoutRequest { string token = 1; }
|
message LogoutRequest { string token = 1; }
|
||||||
|
|
||||||
message LogoutResponse {
|
message LogoutResponse {
|
||||||
bool success = 1;
|
bool success = 1;
|
||||||
string message = 2;
|
string message = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message AuthStatusRequest { string token = 1; }
|
message AuthStatusRequest { string token = 1; }
|
||||||
|
|
||||||
message AuthStatusResponse {
|
message AuthStatusResponse {
|
||||||
bool authenticated = 1;
|
bool authenticated = 1;
|
||||||
string username = 2;
|
string username = 2;
|
||||||
string message = 3;
|
string message = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Authentication service
|
// Authentication service
|
||||||
@ -65,18 +66,28 @@ service AuthService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
message GameRequest { string title = 1; }
|
message GameRequest { string title = 1; }
|
||||||
|
|
||||||
message GetGamesRequest {}
|
message GetGamesRequest {}
|
||||||
|
|
||||||
message AddOpinionRequest {
|
message AddOpinionRequest {
|
||||||
string game_title = 1;
|
string game_title = 1;
|
||||||
bool would_play = 2;
|
bool would_play = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message RemoveOpinionRequest { string game_title = 1; }
|
message RemoveOpinionRequest { string game_title = 1; }
|
||||||
|
|
||||||
|
message GetGameInfoRequest {
|
||||||
|
repeated string games = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GameInfoResponse {
|
||||||
|
repeated Game games = 1;
|
||||||
|
}
|
||||||
|
|
||||||
service MainService {
|
service MainService {
|
||||||
rpc GetGame(GameRequest) returns (Game);
|
rpc GetGame(GameRequest) returns (Game);
|
||||||
rpc GetGames(GetGamesRequest) returns (GameList);
|
rpc GetGames(GetGamesRequest) returns (GameList);
|
||||||
rpc AddGame(Game) returns (Game);
|
rpc AddGame(Game) returns (Game);
|
||||||
rpc AddOpinion(AddOpinionRequest) returns (Person);
|
rpc AddOpinion(AddOpinionRequest) returns (Person);
|
||||||
|
rpc GetGameInfo(GetGameInfoRequest) returns (GameInfoResponse);
|
||||||
}
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user