migrate-oss-shanghai.js 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. // OSS Migration: Hangzhou → Shanghai (internal endpoint)
  2. // Server is in cn-shanghai, bucket must be same region for internal access
  3. const OSS = require('ali-oss');
  4. const mysql = require('mysql2/promise');
  5. const AK = 'LTAI5tBn4G5HMo8PqMdNsqHd';
  6. const SK = 'f0R5nOQf6E1lIGESENKiK8cNzFl8wd';
  7. const OLD_BUCKET = 'aaaa33dfsf32rfsf';
  8. const OLD_REGION = 'oss-cn-hangzhou';
  9. const NEW_BUCKET = 'aaaa33dfsf32rfsf-sh';
  10. const NEW_REGION = 'oss-cn-shanghai';
  11. async function main() {
  12. // Source: Hangzhou PUBLIC endpoint (internal is broken cross-region)
  13. const src = new OSS({
  14. region: OLD_REGION,
  15. accessKeyId: AK,
  16. accessKeySecret: SK,
  17. bucket: OLD_BUCKET,
  18. secure: true,
  19. internal: false, // public endpoint
  20. });
  21. // Dest: Shanghai INTERNAL endpoint
  22. const dst = new OSS({
  23. region: NEW_REGION,
  24. accessKeyId: AK,
  25. accessKeySecret: SK,
  26. bucket: NEW_BUCKET,
  27. secure: true,
  28. internal: true,
  29. });
  30. console.log('[1/4] Listing objects in Hangzhou bucket...');
  31. let allObjects = [];
  32. let marker = null;
  33. do {
  34. const result = await src.list({ 'max-keys': 100, marker });
  35. if (result.objects) allObjects.push(...result.objects);
  36. marker = result.nextMarker;
  37. } while (marker);
  38. console.log(` Found ${allObjects.length} objects`);
  39. if (allObjects.length === 0) {
  40. console.log(' No objects to migrate!');
  41. return;
  42. }
  43. console.log('[2/4] Copying objects to Shanghai bucket...');
  44. let copied = 0, failed = 0;
  45. for (const obj of allObjects) {
  46. try {
  47. // Download from Hangzhou public
  48. const data = await src.get(obj.name);
  49. // Upload to Shanghai internal (ACL inherited from bucket)
  50. await dst.put(obj.name, data.content, {
  51. mime: data.res?.headers?.['content-type'] || 'audio/mpeg',
  52. });
  53. copied++;
  54. if (copied % 20 === 0) console.log(` Progress: ${copied}/${allObjects.length}`);
  55. } catch (e) {
  56. failed++;
  57. console.error(` FAIL ${obj.name}: ${e.message?.slice(0,80)}`);
  58. }
  59. }
  60. console.log(` Done: ${copied} copied, ${failed} failed`);
  61. // Update env
  62. console.log('[3/4] Updating environment config...');
  63. const fs = require('fs');
  64. const envPath = '/data/ai/audio/server/.env';
  65. let env = fs.readFileSync(envPath, 'utf-8');
  66. // Replace bucket name in OSS endpoints
  67. env = env.replace(/OSS_ENDPOINT=oss-cn-hangzhou/g, 'OSS_ENDPOINT=oss-cn-shanghai');
  68. env = env.replace(/OSS_INTERNAL_ENDPOINT=oss-cn-hangzhou-internal/g, 'OSS_INTERNAL_ENDPOINT=oss-cn-shanghai-internal');
  69. env = env.replace(new RegExp(OLD_BUCKET, 'g'), NEW_BUCKET);
  70. fs.writeFileSync(envPath, env, 'utf-8');
  71. fs.writeFileSync(envPath + '.bak', env, 'utf-8'); // backup too
  72. console.log(' Updated .env with Shanghai endpoints & new bucket name');
  73. // Update DB audioUrl references
  74. console.log('[4/4] Updating database audioUrl references...');
  75. const db = await mysql.createConnection('mysql://root:123456@127.0.0.1:3306/audio_book');
  76. const oldPrefix = `https://${OLD_BUCKET}.${OLD_REGION}.aliyuncs.com/`;
  77. const newPrefix = `https://${NEW_BUCKET}.${NEW_REGION}.aliyuncs.com/`;
  78. const [chCount] = await db.execute(
  79. `UPDATE BookChapter SET audioUrl = REPLACE(audioUrl, ?, ?) WHERE audioUrl LIKE ?`,
  80. [oldPrefix, newPrefix, `%${OLD_BUCKET}.${OLD_REGION}.aliyuncs.com%`]
  81. );
  82. console.log(` BookChapter: ${chCount.changedRows || 0} rows updated`);
  83. const [arCount] = await db.execute(
  84. `UPDATE AudioRecord SET audioUrl = REPLACE(audioUrl, ?, ?) WHERE audioUrl LIKE ?`,
  85. [oldPrefix, newPrefix, `%${OLD_BUCKET}.${OLD_REGION}.aliyuncs.com%`]
  86. );
  87. console.log(` AudioRecord: ${arCount.changedRows || 0} rows updated`);
  88. await db.end();
  89. console.log('\n=== Migration complete ===');
  90. console.log(`Copied: ${copied} files`);
  91. console.log(`Env updated: ${envPath}`);
  92. console.log(`Restart required: pm2 restart server`);
  93. }
  94. main().catch(e => { console.error('FATAL:', e); process.exit(1); });