index.ts 5.58 KB
Newer Older
duanjinfei's avatar
duanjinfei committed
1 2 3 4 5 6 7 8
// Follow this setup guide to integrate the Deno language server with your editor:
// https://deno.land/manual/getting_started/setup_your_environment
// This enables autocomplete, go to definition, etc.

// Setup type definitions for built-in Supabase Runtime APIs
import "jsr:@supabase/functions-js/edge-runtime.d.ts"
import { createClient } from 'jsr:@supabase/supabase-js@2'

duanjinfei's avatar
duanjinfei committed
9 10 11 12 13 14 15 16 17
// 分页查询函数
async function fetchAllData(supabase, table: string, pageSize: number = 1000) {
  let allData: any[] = [];
  let offset = 0;

  while (true) {
    const { data, error } = await supabase
      .from(table)
      .select('*') // 可以根据需要调整字段
duanjinfei's avatar
duanjinfei committed
18
      .eq('is_show', true)
duanjinfei's avatar
duanjinfei committed
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
      .order('created_at', { ascending: true }) // 按照创建时间排序
      .range(offset, offset + pageSize - 1); // 分页范围

    if (error) {
      console.error(`Error fetching data from ${table}:`, error);
      throw error;
    }

    if (data && data.length > 0) {
      allData = allData.concat(data); // 合并当前页数据
      offset += pageSize; // 移动到下一页
    } else {
      break; // 如果没有更多数据,则退出循环
    }
  }

  return allData;
}

duanjinfei's avatar
duanjinfei committed
38
const getTimestampForMidnight3AM = () => {
duanjinfei's avatar
duanjinfei committed
39 40
  const timestamp = Math.floor(Date.now() / 3600000) * 3600; // 计算整点的时间戳
  return timestamp
duanjinfei's avatar
duanjinfei committed
41

duanjinfei's avatar
duanjinfei committed
42
};
duanjinfei's avatar
duanjinfei committed
43

duanjinfei's avatar
duanjinfei committed
44
Deno.serve(async (req) => {
duanjinfei's avatar
duanjinfei committed
45 46 47
  if (req.method === 'OPTIONS') {
    return new Response('ok', { headers: corsHeaders })
  }
duanjinfei's avatar
duanjinfei committed
48 49 50 51 52 53 54 55 56
  try {
    // const { name } = await req.json()
    const supabase = createClient(
      Deno.env.get('SUPABASE_URL') ?? '',
      Deno.env.get('SUPABASE_ANON_KEY') ?? '',
      { global: { headers: { Authorization: req.headers.get('Authorization')! } } }
    )

    // 获取所有 app 数据
duanjinfei's avatar
duanjinfei committed
57
    const allApps = await fetchAllData(supabase, 'app');
duanjinfei's avatar
duanjinfei committed
58
    // 获取当前时间的整点时间戳
duanjinfei's avatar
duanjinfei committed
59
    const timestamp = getTimestampForMidnight3AM();
duanjinfei's avatar
duanjinfei committed
60 61

    // 上传所有 app 数据到 storage
duanjinfei's avatar
duanjinfei committed
62
    const directory = `app-category/${timestamp}`;
duanjinfei's avatar
duanjinfei committed
63
    const bucketName = 'cache'; // 替换为存储桶名称
duanjinfei's avatar
duanjinfei committed
64 65 66 67 68 69 70
    // 分页参数
    const pageSize = 30;
    const totalCount = allApps.length;
    const paginatedApps = [];
    for (let i = 0; i < totalCount; i += pageSize) {
      paginatedApps.push(allApps.slice(i, i + pageSize));
    }
duanjinfei's avatar
duanjinfei committed
71

duanjinfei's avatar
duanjinfei committed
72 73 74 75 76 77
    // 遍历分页后的数据并上传
    for (let pageNum = 1; pageNum <= paginatedApps.length; pageNum++) {
      const pageApps = paginatedApps[pageNum - 1];
      const pageJson = JSON.stringify({
        total_count: totalCount,
        apps: pageApps,
duanjinfei's avatar
duanjinfei committed
78 79
      });

duanjinfei's avatar
duanjinfei committed
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
      const pageFileName = `${directory}/app_all_${pageNum}.json`;

      const { error: pageUploadError } = await supabase.storage
        .from(bucketName)
        .upload(pageFileName, new Blob([pageJson]), {
          contentType: 'application/json',
          upsert: true,
        });

      if (pageUploadError) {
        console.error(`Error uploading page ${pageNum} JSON:`, pageUploadError);
        return new Response(
          JSON.stringify({ error: `Failed to upload app_all_${pageNum}.json` }),
          { status: 500 }
        );
      }
duanjinfei's avatar
duanjinfei committed
96 97 98 99 100 101 102 103 104 105 106 107
    }

    // 按 category_id 分组
    const groupedData: Record<string, any[]> = {};
    allApps.forEach((app) => {
      if (!groupedData[app.category_id]) {
        groupedData[app.category_id] = [];
      }
      groupedData[app.category_id].push(app);
    });

    // 上传每个 category_id 的数据
duanjinfei's avatar
duanjinfei committed
108
    // 上传每个 category_id 的分页数据
duanjinfei's avatar
duanjinfei committed
109
    for (const [categoryId, apps] of Object.entries(groupedData)) {
duanjinfei's avatar
duanjinfei committed
110 111 112 113 114 115
      const totalCount = apps.length; // 当前分类的总数
      const pageSize = 30;
      const paginatedApps = [];
      for (let i = 0; i < totalCount; i += pageSize) {
        paginatedApps.push(apps.slice(i, i + pageSize));
      }
duanjinfei's avatar
duanjinfei committed
116

duanjinfei's avatar
duanjinfei committed
117 118 119 120 121 122
      // 遍历分页数据并上传
      for (let pageNum = 1; pageNum <= paginatedApps.length; pageNum++) {
        const pageApps = paginatedApps[pageNum - 1];
        const pageJson = JSON.stringify({
          total_count: totalCount,
          apps: pageApps,
duanjinfei's avatar
duanjinfei committed
123 124
        });

duanjinfei's avatar
duanjinfei committed
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
        // 文件名格式:{categoryId}_{pageNum}.json
        const categoryPageFileName = `${directory}/${categoryId}_${pageNum}.json`;

        const { error: categoryPageUploadError } = await supabase.storage
          .from(bucketName)
          .upload(categoryPageFileName, new Blob([pageJson]), {
            contentType: 'application/json',
            upsert: true,
          });

        if (categoryPageUploadError) {
          console.error(
            `Error uploading category ${categoryId} page ${pageNum} JSON:`,
            categoryPageUploadError
          );
          return new Response(
            JSON.stringify({
              error: `Failed to upload category ${categoryId} page ${pageNum} JSON`,
            }),
            { status: 500 }
          );
        }
duanjinfei's avatar
duanjinfei committed
147 148 149 150 151
      }
    }
    return new Response(
      JSON.stringify({
        message: 'All data uploaded successfully',
duanjinfei's avatar
duanjinfei committed
152
        fileName: allAppsFileName,
duanjinfei's avatar
duanjinfei committed
153
      }),
duanjinfei's avatar
duanjinfei committed
154 155 156 157
      {
        headers: { 'Content-Type': 'application/json' },
        status: 200
      }
duanjinfei's avatar
duanjinfei committed
158 159 160 161
    );
  } catch (err) {
    console.error('Unexpected error:', err);
    return new Response(JSON.stringify({ error: 'Internal server error' }), {
duanjinfei's avatar
duanjinfei committed
162
      headers: { 'Content-Type': 'application/json' },
duanjinfei's avatar
duanjinfei committed
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
      status: 500,
    });
  }
})




/* To invoke locally:

  1. Run `supabase start` (see: https://supabase.com/docs/reference/cli/supabase-start)
  2. Make an HTTP request:

  curl -i --location --request POST 'http://127.0.0.1:54321/functions/v1/hello-world' \
    --header 'Authorization: Bearer ' \
    --header 'Content-Type: application/json' \
    --data '{"name":"Functions"}'

*/