Loading save files done.

This commit is contained in:
2025-03-11 19:03:11 -05:00
parent 85f643ef10
commit 60db15e932
19 changed files with 489 additions and 76 deletions

13
src/pages/404.tsx Normal file
View File

@@ -0,0 +1,13 @@
export type Error404Props = {
error:404;
};
export const Error404:React.FC<Error404Props> = props => {
return (
<div>
<h1>Error 404</h1>
</div>
);
}
export default Error404;

14
src/pages/500.tsx Normal file
View File

@@ -0,0 +1,14 @@
export type Error500Props = {
code:500;
};
export const Error500:React.FC<Error500Props> = props => {
console.log('props', props);
return (
<div>
<h1>Error 500</h1>
</div>
)
}
export default Error500;

View File

@@ -1,8 +1,8 @@
import { typeDefs, resolvers } from "@/graphql/schema";
import { typeDefs, schema } from "@/graphql/schema";
import { ApolloServer } from "apollo-server-micro";
import { NextApiRequest, NextApiResponse } from "next";
const apolloServer = new ApolloServer({ typeDefs, resolvers });
const apolloServer = new ApolloServer({ typeDefs, schema });
export const config = {
api: {

44
src/pages/api/v1/save.ts Normal file
View File

@@ -0,0 +1,44 @@
import { NextApiHandler } from "next";
import * as fs from 'fs';
import * as path from 'path';
const PATH_SAVES = path.resolve('.', 'data', 'saves');
const handler:NextApiHandler = async (req, res) => {
if (req.method !== 'GET') {
res.setHeader('Allow', ['GET']);
res.status(405).end(`Method Not Allowed`);
return;
}
// ID query param
if(!req.query.id || typeof req.query.id !== 'string') {
res.status(404).end(`Not Found`);
return;
}
const { id } = req.query;
if(!id) {
res.status(404).end(`Not Found`);
return;
}
// Does rom exist?
const pathSave = path.resolve(PATH_SAVES, `${id}.zip`);
if(!fs.existsSync(pathSave)) {
res.status(404).end(`Not Found`);
return;
}
// Read save
try {
const romStream = fs.createReadStream(pathSave);
res.setHeader('Content-Type', 'application/octet-stream');
res.setHeader('Content-Disposition', `attachment; filename="${id}.zip"`);
romStream.pipe(res);
} catch (error) {
res.status(500).end(`Internal Server Error`);
}
};
export default handler;

View File

@@ -1,4 +1,9 @@
import { GetServerSideProps, GetStaticPaths, GetStaticProps } from 'next';
import { apiClientGet } from '@/lib/apiClient';
import { includeFragment, extendFragment } from '@/lib/fragment';
import { GameHeavy, GameLightFragment } from '@/lib/game';
import { Error500, Error500Props } from '@/pages/500';
import { gql } from 'apollo-server-micro';
import { GetServerSideProps } from 'next';
import Link from 'next/link';
type PageParams = {
@@ -6,31 +11,48 @@ type PageParams = {
}
type PageProps = {
id:string;
}
game:GameHeavy;
} | Error500Props;
export const getServerSideProps:GetServerSideProps<> = async ({ params }) => {
const { id } = params as PageParams;
export const getServerSideProps:GetServerSideProps<PageProps, PageParams> = async ({ params }) => {
try {
if(!params || !params.id) return { notFound: true };
// if(id !== '0') {
// return {
// notFound: true
// };
// }
const client = await apiClientGet();
const res = await client.query<{ game:GameHeavy }>({
variables: { id: params.id },
query: gql`
${includeFragment(GameLightFragment)}
return {
props: {
id
},
};
query getGame($id: ID!) {
game(id: $id) {
${extendFragment(GameLightFragment)}
}
}
`,
});
if(!res.data.game) return { notFound: true };
return { props: { ...res.data } };
} catch(e) {
console.error('Error', e);
return { props: { code: 500 } };
}
};
export const Page:React.FC<PageProps> = ({ id }) => {
export const Page:React.FC<PageProps> = props => {
if('code' in props) {
if(props.code === 500) return <Error500 {...props} />;
return null;
}
const { game } = props;
return (
<div>
<h1>Viewing Game ID: {id}</h1>
<h1>{ game.name }</h1>
<Link href={`/games/${id}/play`}>
<Link href={`/games/${game.id}/play`}>
Play Game
</Link>
</div>

View File

@@ -27,7 +27,9 @@ export const Page:React.FC<PageProps> = ({ id }) => {
<div className={styles.play__emulator}>
<Emulator
system='gbc'
system="gbc"
gameId="0"
gameName="Pokemon Crystal Version"
/>
</div>
</div>

View File

@@ -1,25 +1,73 @@
import { GetServerSideProps, GetStaticPaths, GetStaticProps } from 'next';
import { GetServerSideProps } from 'next';
import Link from 'next/link';
import { apiClientGet } from '@/lib/apiClient';
import { gql } from 'apollo-server-micro';
import { GameLight, GameLightFragment } from '@/lib/game';
import Error500, { Error500Props } from '../500';
import { extendFragment, includeFragment } from '@/lib/fragment';
import { Paginated, paginationQuery } from '@/lib/page';
type PageProps = {
}
export const getServerSideProps:GetServerSideProps = async ({ params }) => {
return {
props: {
},
};
type Game = {
id: string;
name: string;
system: string;
};
export const Page:React.FC<PageProps> = ({ }) => {
type PageProps = {
games:Paginated<GameLight>|null;
} | Error500Props;
export const getServerSideProps: GetServerSideProps<PageProps> = async () => {
try {
const client = await apiClientGet();
const res = await client.query<{ games:Paginated<GameLight> }>({
variables: { },
query: gql`
${includeFragment(GameLightFragment)}
query getGames {
games(first: 100) {
${paginationQuery(extendFragment(GameLightFragment))}
}
}
`,
});
if(!res || !res.data || !res.data.games) {
return { props: { games:null } };
}
return { props: { games: res.data.games } };
} catch (e) {
console.error('Error', e);
return { props: { code: 500 } };
}
};
export const Page: React.FC<PageProps> = props => {
if ('code' in props) {
if (props.code === 500) return <Error500 {...props} />;
return null;
}
const { games } = props;
if(!games) {
return <div>No games found</div>;
}
return (
<div>
<h1>Games</h1>
<div>
<Link href="/games/0">
Test Game
</Link>
</div>
<ul>
{games.edges.map(({ node }) => {
return (
<li key={node.id}>
<Link href={`/games/${node.id}`}>
{node.name} ({node.system})
</Link>
</li>
);
})}
</ul>
</div>
);
};

View File

@@ -4,9 +4,11 @@ import { GetServerSideProps } from 'next';
import { apiClientGet } from '@/lib/apiClient';
import { ApolloQueryResult, gql } from '@apollo/client';
import Link from 'next/link';
import { GameLightFragment, GameLight } from '@/lib/game';
import { extendFragment, includeFragment } from '@/lib/fragment';
type PageData = {
hello:string;
game:GameLight;
}
type PageProps = ApolloQueryResult<PageData>
@@ -16,10 +18,17 @@ export const getServerSideProps:GetServerSideProps<PageProps> = async () => {
const res = await client.query<PageData>({
query: gql`
query {
hello
${includeFragment(GameLightFragment)}
query getGame($id: ID!) {
game(id: $id) {
${extendFragment(GameLightFragment)}
}
}
`
`,
variables: {
id: '0'
}
});
return {
@@ -34,11 +43,10 @@ const HomePage: React.FC<PageProps> = props => {
<title>HomePlay, your personal video game library</title>
</Head>
<Link href="/game/1/play">
Play Game
<Link href="/games">
Games
</Link>
{ props.data?.hello }
{ JSON.stringify(props) }
</div>
);
}