Skip to content

Commit 51c1a4b

Browse files
committed
create endpoint and show sample image
1 parent 94c5a1c commit 51c1a4b

File tree

4 files changed

+145
-19
lines changed

4 files changed

+145
-19
lines changed

app/lib/redis.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export function getRedisClient(env: Env) {
99
return client;
1010
}
1111

12-
interface GameState {
12+
export interface GameState {
1313
kyoku: number;
1414
junme: number;
1515
haiyama: Hai[];
@@ -123,3 +123,17 @@ export const jikyoku = async (
123123
};
124124
await setGameState(client, userId, newGameState);
125125
};
126+
127+
export const getCurrentGameState = async (
128+
client: ReturnType<typeof createClient>,
129+
userId: string,
130+
): Promise<GameState | null> => {
131+
return await getGameState(client, userId);
132+
};
133+
134+
export const deleteGameState = async (
135+
client: ReturnType<typeof createClient>,
136+
userId: string,
137+
) => {
138+
await client.del(`user:${userId}:game`);
139+
};

app/routes/play.tedashi.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { getAuth } from "~/lib/auth";
2+
import { type GameState, getRedisClient, tedashi } from "~/lib/redis";
3+
import type { Route } from "./+types/play.tedashi";
4+
5+
export async function action({
6+
context,
7+
request,
8+
}: Route.ActionArgs): Promise<GameState> {
9+
const { env } = context.cloudflare;
10+
const auth = getAuth(env);
11+
const session = await auth.api.getSession({ headers: request.headers });
12+
13+
if (!session?.user?.id) {
14+
throw new Response("Unauthorized", { status: 401 });
15+
}
16+
const userId = session.user.id;
17+
18+
const formData = await request.formData();
19+
const index = Number(formData.get("index"));
20+
21+
if (isNaN(index)) {
22+
throw new Response("Invalid index", { status: 400 });
23+
}
24+
25+
const redisClient = getRedisClient(env);
26+
await redisClient.connect();
27+
28+
try {
29+
await tedashi(redisClient, userId, index);
30+
const gameStateJSON = await redisClient.get(`user:${userId}:game`);
31+
const gameState = gameStateJSON ? JSON.parse(gameStateJSON) : null;
32+
33+
await redisClient.quit();
34+
return gameState;
35+
} catch (error) {
36+
await redisClient.quit();
37+
const errorMessage = error instanceof Error ? error.message : String(error);
38+
throw new Response(errorMessage, { status: 400 });
39+
}
40+
}

app/routes/play.tsumogiri.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { getAuth } from "~/lib/auth";
2+
import { type GameState, getRedisClient, tsumogiri } from "~/lib/redis";
3+
import type { Route } from "./+types/play.tsumogiri";
4+
5+
export async function action({
6+
context,
7+
request,
8+
}: Route.ActionArgs): Promise<GameState> {
9+
const { env } = context.cloudflare;
10+
const auth = getAuth(env);
11+
const session = await auth.api.getSession({ headers: request.headers });
12+
13+
if (!session?.user?.id) {
14+
throw new Response("Unauthorized", { status: 401 });
15+
}
16+
const userId = session.user.id;
17+
18+
const redisClient = getRedisClient(env);
19+
await redisClient.connect();
20+
21+
try {
22+
await tsumogiri(redisClient, userId);
23+
const gameStateJSON = await redisClient.get(`user:${userId}:game`);
24+
const gameState = gameStateJSON ? JSON.parse(gameStateJSON) : null;
25+
26+
await redisClient.quit();
27+
return gameState;
28+
} catch (error) {
29+
await redisClient.quit();
30+
const errorMessage = error instanceof Error ? error.message : String(error);
31+
throw new Response(errorMessage, { status: 400 });
32+
}
33+
}

app/routes/play.tsx

Lines changed: 57 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,43 +3,82 @@ import { getAuth } from "~/lib/auth";
33
import { getDB } from "~/lib/db";
44
import { hai, haiyama } from "~/lib/db/schema";
55
import { dbHaiToHai } from "~/lib/hai";
6+
import { type GameState, getRedisClient, init } from "~/lib/redis";
67
import type { Route } from "./+types/play";
78

8-
export async function loader({ context, request }: Route.LoaderArgs) {
9+
export async function loader({
10+
context,
11+
request,
12+
}: Route.LoaderArgs): Promise<GameState> {
913
const { env } = context.cloudflare;
1014
const db = getDB(env);
1115
const auth = getAuth(env);
1216
const session = await auth.api.getSession({ headers: request.headers });
17+
1318
if (!session?.user?.id) {
1419
throw new Response("Unauthorized", { status: 401 });
1520
}
1621
const userId = session.user.id;
1722

18-
const randomHaiyama = await db
19-
.select()
20-
.from(haiyama)
21-
.orderBy(sql`RANDOM()`)
22-
.limit(1);
23+
// Check if game state already exists in Redis
24+
const redisClient = getRedisClient(env);
25+
await redisClient.connect();
26+
27+
try {
28+
const existingGameState = await redisClient.get(`user:${userId}:game`);
29+
30+
if (existingGameState) {
31+
// Return existing game state from Redis
32+
await redisClient.quit();
33+
return JSON.parse(existingGameState);
34+
}
35+
36+
// No existing game state, so initialize from PostgreSQL
37+
const randomHaiyama = await db
38+
.select()
39+
.from(haiyama)
40+
.orderBy(sql`RANDOM()`)
41+
.limit(1);
42+
43+
if (randomHaiyama.length === 0) {
44+
await redisClient.quit();
45+
throw new Response("No haiyama found", { status: 404 });
46+
}
47+
48+
const selectedHaiyama = randomHaiyama[0];
49+
const rawHaiData = await db
50+
.select()
51+
.from(hai)
52+
.where(sql`${hai.haiyamaId} = ${selectedHaiyama.id}`)
53+
.orderBy(hai.order);
54+
55+
const haiData = rawHaiData.map((hai) => dbHaiToHai(hai));
56+
57+
// Initialize game state in Redis
58+
await init(redisClient, userId, haiData);
59+
60+
// Get the initialized game state to return
61+
const gameStateJSON = await redisClient.get(`user:${userId}:game`);
62+
const gameState = gameStateJSON ? JSON.parse(gameStateJSON) : null;
2363

24-
if (randomHaiyama.length === 0) {
25-
throw new Response("No haiyama found", { status: 404 });
64+
await redisClient.quit();
65+
return gameState;
66+
} catch (error) {
67+
await redisClient.quit();
68+
throw error instanceof Error ? error : new Error(String(error));
2669
}
27-
const selectedHaiyama = randomHaiyama[0];
28-
const rawHaiData = await db
29-
.select()
30-
.from(hai)
31-
.where(sql`${hai.haiyamaId} = ${selectedHaiyama.id}`)
32-
.orderBy(hai.order);
33-
const haiData = rawHaiData.map((hai) => dbHaiToHai(hai));
34-
//TODO: store data in redis
35-
return haiData;
3670
}
3771

3872
export default function Page({ loaderData }: Route.ComponentProps) {
39-
console.log(loaderData);
73+
const exampleHai = loaderData.haiyama[0];
4074
return (
4175
<>
4276
<p>Play Page</p>
77+
<img
78+
src={`/hai/${exampleHai.kind}_${exampleHai.value}.png`}
79+
alt={`${hai.kind} ${hai.value}`}
80+
className="cursor-pointer"
81+
/>
4382
</>
4483
);
4584
}

0 commit comments

Comments
 (0)