Skip to content

Commit

Permalink
feat: x-dr#90 Support Cloudflare R2
Browse files Browse the repository at this point in the history
  • Loading branch information
x-dr committed Sep 17, 2024
1 parent 9c8db59 commit 3f28c2d
Show file tree
Hide file tree
Showing 2 changed files with 386 additions and 0 deletions.
208 changes: 208 additions & 0 deletions src/app/api/enableauthapi/r2/route.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
export const runtime = 'edge';
import { getRequestContext } from '@cloudflare/next-on-pages';




export async function POST(request) {



const { env, cf, ctx } = getRequestContext();

if (!env.IMGRS) {
return Response.json({
status: 500,
message: `IMGRS is not Set`,
success: false
}, {
status: 500,
headers: corsHeaders,
})
}




const req_url = new URL(request.url);

if (!env.IMGRS) {
return Response.json({
status: 500,
message: `IMGRS is not Set`,
success: false
}, {
status: 500,
headers: corsHeaders,
})
}

const ip = request.headers.get('x-forwarded-for') || request.headers.get('x-real-ip') || request.socket.remoteAddress;
const clientIp = ip ? ip.split(',')[0].trim() : 'IP not found';
const Referer = request.headers.get('Referer') || "Referer";

const formData = await request.formData();
const fileType = formData.get('file').type;
const filename = formData.get('file').name;
const file = formData.get('file');

const header = new Headers()
header.set("content-type", fileType)
header.set("content-length", `${file.size}`)


const corsHeaders = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': 'Content-Type',
'Access-Control-Max-Age': '86400', // 24 hours
'Content-Type': 'application/json'
};





try {

const object = await env.IMGRS.put(filename, file, {
httpMetadata: header
})

if (object === null) {
return Response.json({
status: 404,
message: ` ${error.message}`,
success: false
}
, {
status: 404,
headers: corsHeaders,
})
}

const data = {
"url": `${req_url.origin}/api/rfile/${filename}`,
"code": 200,
"name": filename
}

if (!env.IMG) {
data.env_img = "null"
return Response.json({
...data,
msg: "1"
}, {
status: 200,
headers: corsHeaders,
})
} else {
try {
const rating_index = await getRating(env, `${req_url.origin}/api/rfile/${filename}`);
const nowTime = await get_nowTime()
await insertImageData(env.IMG, `/rfile/${filename}`, Referer, clientIp, rating_index, nowTime);

return Response.json({
...data,
msg: "2",
Referer: Referer,
clientIp: clientIp,
rating_index: rating_index,
nowTime: nowTime
}, {
status: 200,
headers: corsHeaders,
})


} catch (error) {
console.log(error);
await insertImageData(env.IMG, `/rfile/${filename}`, Referer, clientIp, -1, nowTime);


return Response.json({
"msg": error.message
}, {
status: 500,
headers: corsHeaders,
})
}
}




} catch (error) {
return Response.json({
status: 500,
message: ` ${error.message}`,
success: false
}, {
status: 500,
headers: corsHeaders,
})
}

}






async function insertImageData(env, src, referer, ip, rating, time) {
try {
const instdata = await env.prepare(
`INSERT INTO imginfo (url, referer, ip, rating, total, time)
VALUES ('${src}', '${referer}', '${ip}', ${rating}, 1, '${time}')`
).run()
} catch (error) {

};
}



async function get_nowTime() {
const options = {
timeZone: 'Asia/Shanghai',
year: 'numeric',
month: 'long',
day: 'numeric',
hour12: false,
hour: '2-digit',
minute: '2-digit',
second: '2-digit'
};
const timedata = new Date();
const formattedDate = new Intl.DateTimeFormat('zh-CN', options).format(timedata);

return formattedDate

}



async function getRating(env, url) {

try {
const apikey = env.ModerateContentApiKey
const ModerateContentUrl = apikey ? `https://api.moderatecontent.com/moderate/?key=${apikey}&` : ""

const ratingApi = env.RATINGAPI ? `${env.RATINGAPI}?` : ModerateContentUrl;

if (ratingApi) {
const res = await fetch(`${ratingApi}url=${url}`);
const data = await res.json();
const rating_index = data.hasOwnProperty('rating_index') ? data.rating_index : -1;

// return data;
return rating_index;
} else {
return 0
}


} catch (error) {
return error
}
}
178 changes: 178 additions & 0 deletions src/app/api/rfile/[name]/route.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
export const runtime = 'edge';
import { getRequestContext } from '@cloudflare/next-on-pages';
import { headers } from 'next/headers';

const corsHeaders = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': 'Content-Type',
'Access-Control-Max-Age': '86400', // 24 hours
'Content-Type': 'application/json'
};

export async function OPTIONS(request) {
return new Response(null, {
headers: corsHeaders
});
}



//https://developers.cloudflare.com/r2/examples/demo-worker/
export async function GET(request, { params }) {
const { name } = params
let { env, cf, ctx } = getRequestContext();

if(!env.IMGRS){
return Response.json({
status: 500,
message: `IMGRS is not Set`,
success: false
}, {
status: 500,
headers: corsHeaders,
})
}

const ip = request.headers.get('x-forwarded-for') || request.headers.get('x-real-ip') || request.socket.remoteAddress;
const clientIp = ip ? ip.split(',')[0].trim() : 'IP not found';
const Referer = request.headers.get('Referer') || "Referer";

const req_url = new URL(request.url);
// 构造缓存键
const cacheKey = new Request(req_url.toString(), request);
const cache = caches.default;

let rating

try {
rating = await getRating(env.IMG, `/rfile/${name}`);
if (rating === 3) {
await logRequest(env, name, Referer, clientIp);
return Response.redirect(`${req_url.origin}/img/blocked.png`, 302);
}

} catch (error) {
console.log(error);

}
// 检查缓存
let cachedResponse = await cache.match(cacheKey);
if (cachedResponse) {
await logRequest(env, name, Referer, clientIp);
// 如果缓存中存在,直接返回缓存响应
return cachedResponse
}



try {

const object = await env.IMGRS.get(name, {
range: request.headers,
onlyIf: request.headers,
})

if (object === null) {
return Response.json({
status: 404,
message: ` ${error.message}`,
success: false
}
, {
status: 404,
headers: corsHeaders,
})

}
const headers = new Headers()
object.writeHttpMetadata(headers)
headers.set('etag', object.httpEtag)

if (object.range) {
headers.set("content-range", `bytes ${object.range.offset}-${object.range.end ?? object.size - 1}/${object.size}`)
}

const status = object.body ? (request.headers.get("range") !== null ? 206 : 200) : 304

let response_img = new Response(object.body, {
headers,
status
})
if (status === 200) {
await cache.put(cacheKey, response_img.clone());
}




if (Referer == req_url.origin + "/admin" || Referer == req_url.origin + "/list" || Referer == req_url.origin + "/" || !env.IMG) {
return response_img
} else {
await logRequest(env, name, Referer, clientIp);
return response_img
}

} catch (error) {
return Response.json({
status: 500,
message: ` ${error.message}`,
success: false
}
, {
status: 500,
headers: corsHeaders,
})
}

}




// 插入 tgimglog 记录
async function insertTgImgLog(DB, url, referer, ip, time) {
const iImglog = await DB.prepare('INSERT INTO tgimglog (url, referer, ip, time) VALUES (?, ?, ?, ?)')
.bind(url, referer, ip, time)
.run();
}

// 异步日志记录
async function logRequest(env, name, referer, ip) {
try {
const nowTime = await get_nowTime()
await insertTgImgLog(env.IMG, `/rfile/${name}`, referer, ip, nowTime);
const setData = await env.IMG.prepare(`UPDATE imginfo SET total = total +1 WHERE url = '/rfile/${name}';`).run()
} catch (error) {
console.error('Error logging request:', error);
}
}



// 从数据库获取鉴黄信息
async function getRating(DB, url) {
const ps = DB.prepare(`SELECT rating FROM imginfo WHERE url='${url}'`);
const result = await ps.first();
return result ? result.rating : null;
}




async function get_nowTime() {
const options = {
timeZone: 'Asia/Shanghai',
year: 'numeric',
month: 'long',
day: 'numeric',
hour12: false,
hour: '2-digit',
minute: '2-digit',
second: '2-digit'
};
const timedata = new Date();
const formattedDate = new Intl.DateTimeFormat('zh-CN', options).format(timedata);

return formattedDate

}

0 comments on commit 3f28c2d

Please sign in to comment.