mirror of
https://github.com/AderKonstantin/aderktech-chronark.com-.git
synced 2025-06-08 21:58:41 +03:00
Compare commits
No commits in common. "181595f19541b0c01f5027ebe9d45cea0b413ed2" and "d5f36eababd10809db24c1744371a6deda7adbd4" have entirely different histories.
181595f195
...
d5f36eabab
3
.env
3
.env
@ -1,3 +0,0 @@
|
||||
REDIS_HOST=localhost
|
||||
REDIS_PORT=6379
|
||||
REDIS_PASSWORD= # если используется
|
2
.env.example
Normal file
2
.env.example
Normal file
@ -0,0 +1,2 @@
|
||||
UPSTASH_REDIS_REST_URL=
|
||||
UPSTASH_REDIS_REST_TOKEN=
|
@ -32,13 +32,13 @@ export const Navigation: React.FC = () => {
|
||||
href="/projects"
|
||||
className="duration-200 text-zinc-400 hover:text-zinc-100"
|
||||
>
|
||||
Проекты
|
||||
Projects
|
||||
</Link>
|
||||
<Link
|
||||
href="/contact"
|
||||
className="duration-200 text-zinc-400 hover:text-zinc-100"
|
||||
>
|
||||
Контакты
|
||||
Contact
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
|
@ -3,8 +3,8 @@ import React from "react";
|
||||
import Particles from "./components/particles";
|
||||
|
||||
const navigation = [
|
||||
{ name: "Проекты", href: "/projects" },
|
||||
{ name: "Контакты", href: "/contact" },
|
||||
{ name: "Projects", href: "/projects" },
|
||||
{ name: "Contact", href: "/contact" },
|
||||
];
|
||||
|
||||
export default function Home() {
|
||||
@ -29,7 +29,7 @@ export default function Home() {
|
||||
quantity={100}
|
||||
/>
|
||||
<h1 className="py-3.5 px-0.5 z-10 text-4xl text-transparent duration-1000 bg-white cursor-default text-edge-outline animate-title font-display sm:text-6xl md:text-9xl whitespace-nowrap bg-clip-text ">
|
||||
aderk.tech
|
||||
chronark
|
||||
</h1>
|
||||
|
||||
<div className="hidden w-screen h-px animate-glow md:block animate-fade-right bg-gradient-to-r from-zinc-300/0 via-zinc-300/50 to-zinc-300/0" />
|
||||
|
@ -4,7 +4,7 @@ import { Mdx } from "@/app/components/mdx";
|
||||
import { Header } from "./header";
|
||||
import "./mdx.css";
|
||||
import { ReportView } from "./view";
|
||||
import Redis from "ioredis";
|
||||
import { Redis } from "@upstash/redis";
|
||||
|
||||
export const revalidate = 60;
|
||||
|
||||
@ -14,12 +14,7 @@ type Props = {
|
||||
};
|
||||
};
|
||||
|
||||
// Настройка подключения к локальному Redis
|
||||
const redis = new Redis({
|
||||
host: process.env.REDIS_HOST || "localhost",
|
||||
port: parseInt(process.env.REDIS_PORT || "6379"),
|
||||
password: process.env.REDIS_PASSWORD,
|
||||
});
|
||||
const redis = Redis.fromEnv();
|
||||
|
||||
export async function generateStaticParams(): Promise<Props["params"][]> {
|
||||
return allProjects
|
||||
@ -37,11 +32,8 @@ export default async function PostPage({ params }: Props) {
|
||||
notFound();
|
||||
}
|
||||
|
||||
// Получаем и преобразуем значение просмотров
|
||||
const views = parseInt(
|
||||
(await redis.get(`projects:${slug}:views`)) || "0",
|
||||
10
|
||||
);
|
||||
const views =
|
||||
(await redis.get<number>(["pageviews", "projects", slug].join(":"))) ?? 0;
|
||||
|
||||
return (
|
||||
<div className="bg-zinc-50 min-h-screen">
|
||||
|
@ -4,24 +4,19 @@ import { allProjects } from "contentlayer/generated";
|
||||
import { Navigation } from "../components/nav";
|
||||
import { Card } from "../components/card";
|
||||
import { Article } from "./article";
|
||||
import Redis from "ioredis"; // Заменяем @upstash/redis на ioredis
|
||||
import { Redis } from "@upstash/redis";
|
||||
import { Eye } from "lucide-react";
|
||||
|
||||
// Создаем подключение к локальному Redis
|
||||
const redis = new Redis({
|
||||
host: process.env.REDIS_HOST || "localhost",
|
||||
port: parseInt(process.env.REDIS_PORT || "6379"),
|
||||
password: process.env.REDIS_PASSWORD, // если есть пароль
|
||||
});
|
||||
const redis = Redis.fromEnv();
|
||||
|
||||
export const revalidate = 60;
|
||||
export default async function ProjectsPage() {
|
||||
const viewsEntries = await redis.mget(
|
||||
...allProjects.map((p) => `projects:${p.slug}:views`)
|
||||
);
|
||||
|
||||
const views = allProjects.reduce((acc, project, index) => {
|
||||
acc[project.slug] = parseInt(viewsEntries[index] as string) || 0;
|
||||
const views = (
|
||||
await redis.mget<number[]>(
|
||||
...allProjects.map((p) => ["pageviews", "projects", p.slug].join(":")),
|
||||
)
|
||||
).reduce((acc, v, i) => {
|
||||
acc[allProjects[i].slug] = v ?? 0;
|
||||
return acc;
|
||||
}, {} as Record<string, number>);
|
||||
|
||||
|
@ -1,11 +0,0 @@
|
||||
---
|
||||
title: bitofgame.net
|
||||
description: bitofgame.net is an open source API Key management solution. It allows you to create, manage and validate API Keys for your users.
|
||||
date: "2025-07-01"
|
||||
url: https://unkey.dev
|
||||
published: true
|
||||
repository: chronark/unkey
|
||||
---
|
||||
|
||||
|
||||
Unkey is an open source API Key management solution. It allows you to create, manage and validate API Keys for your users. It’s built with security and speed in mind.
|
6976
package-lock.json
generated
6976
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -14,7 +14,6 @@
|
||||
"@upstash/redis": "^1.23.3",
|
||||
"contentlayer": "^0.3.4",
|
||||
"framer-motion": "^10.16.4",
|
||||
"ioredis": "^5.6.1",
|
||||
"lucide-react": "^0.284.0",
|
||||
"markdown-wasm": "^1.2.0",
|
||||
"next": "^13.5.4",
|
||||
|
@ -1,15 +1,9 @@
|
||||
import Redis from "ioredis";
|
||||
import { Redis } from "@upstash/redis";
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
|
||||
// Настройка подключения к локальному Redis
|
||||
const redis = new Redis({
|
||||
host: process.env.REDIS_HOST || "localhost",
|
||||
port: parseInt(process.env.REDIS_PORT || "6379"),
|
||||
password: process.env.REDIS_PASSWORD,
|
||||
});
|
||||
|
||||
const redis = Redis.fromEnv();
|
||||
export const config = {
|
||||
runtime: "edge", // Возможно потребуется изменить на "nodejs" если возникнут проблемы
|
||||
runtime: "edge",
|
||||
};
|
||||
|
||||
export default async function incr(req: NextRequest): Promise<NextResponse> {
|
||||
@ -21,33 +15,33 @@ export default async function incr(req: NextRequest): Promise<NextResponse> {
|
||||
}
|
||||
|
||||
const body = await req.json();
|
||||
const slug = body.slug;
|
||||
|
||||
let slug: string | undefined = undefined;
|
||||
if ("slug" in body) {
|
||||
slug = body.slug;
|
||||
}
|
||||
if (!slug) {
|
||||
return new NextResponse("Slug not found", { status: 400 });
|
||||
}
|
||||
|
||||
const ip = req.ip;
|
||||
if (ip) {
|
||||
// Хеширование IP-адреса
|
||||
// Hash the IP in order to not store it directly in your db.
|
||||
const buf = await crypto.subtle.digest(
|
||||
"SHA-256",
|
||||
new TextEncoder().encode(ip)
|
||||
new TextEncoder().encode(ip),
|
||||
);
|
||||
const hash = Array.from(new Uint8Array(buf))
|
||||
.map((b) => b.toString(16).padStart(2, "0"))
|
||||
.join("");
|
||||
|
||||
// Проверка уникальности посещения
|
||||
const key = `deduplicate:${hash}:${slug}`;
|
||||
const isNew = await redis.set(key, "1", "EX", 86400, "NX");
|
||||
|
||||
// deduplicate the ip for each slug
|
||||
const isNew = await redis.set(["deduplicate", hash, slug].join(":"), true, {
|
||||
nx: true,
|
||||
ex: 24 * 60 * 60,
|
||||
});
|
||||
if (!isNew) {
|
||||
return new NextResponse(null, { status: 202 });
|
||||
new NextResponse(null, { status: 202 });
|
||||
}
|
||||
}
|
||||
|
||||
// Увеличиваем счетчик просмотров
|
||||
await redis.incr(`projects:${slug}:views`);
|
||||
await redis.incr(["pageviews", "projects", slug].join(":"));
|
||||
return new NextResponse(null, { status: 202 });
|
||||
}
|
5094
pnpm-lock.yaml
generated
5094
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user