导言

最近做一个 Rails (RoR) 项目,需要将文件上传保存到 MEGA 云盘。MEGA 云盘是一个类似于 Dropbox、Google Drive 的云存储服务,提供了大容量的免费存储空间和端到端加密保护用户隐私。MEGA 没有提供官方的 Ruby SDK,但它提供了一个命令行工具 MEGA CMD 来简化文件操作。通过这个工具,我们可以在 Rails 应用中使用 system 或 `cmd` 轻松集成 MEGA 的文件上传和下载功能。

使用方式

安装 MEGA CMD

提示:不要安装 Ubuntu 仓库中的版本,因为它太旧了。可以直接从 MEGA 官网下载最新版 MEGA CMD

MEGA官网下载页面

我的系统是 Ubuntu 24.04,所以下载对应的 deb 包:

wget https://mega.nz/linux/repo/xUbuntu_24.04/amd64/megacmd-xUbuntu_24.04_amd64.deb && sudo apt install "$PWD/megacmd-xUbuntu_24.04_amd64.deb"

安装成功后,可以通过 mega-cmd 命令来使用 MEGA CMD 工具。

MEGA CMD 命令行界面

登录 MEGA 账号

登录 MEGA 账号

MEGA CMD> login [email protected] your_password

登录成功后,可以使用 ls 命令列出 MEGA 云盘的文件列表。

[email protected]:/$ ls
欢迎使用 MEGA.pdf

MEGA CMD 提供了丰富的命令行操作,可以通过 help 命令查看所有可用命令。还可以查看用户手册:https://github.com/meganz/MEGAcmd/blob/master/UserGuide.md

RoR 中集成 MEGA CMD,实现文件上传和分享

class UploadToMegaJob < ApplicationJob
  queue_as :default

  def perform(batch_upload_id)
    batch_upload = BatchUpload.find(batch_upload_id)
    batch_upload.uploading!
    Rails.logger.info("Starting upload for BatchUpload ID: #{batch_upload_id}")
    batch_upload.files.each do |file|
      temp_path = ActiveStorage::Blob.service.path_for(file.key)
      remote_path = "#{ENV['MEGA_CLOUD_DIR']}#{batch_upload.id}/#{file.filename}"
      if system("mega-put '-c' '#{temp_path}' '#{remote_path}'")
        stock = Stock.create!(
          service: batch_upload.service,
          batch_upload: batch_upload,
          order: nil,
          filename: file.filename,
          mega_path: remote_path,
          mega_link: mega_link(remote_path),
          state: :available
        )
        Rails.logger.info("Uploaded #{file.filename} to MEGA and created stock record with ID #{stock.id}")
      else
        Rails.logger.error("Failed to upload #{file.filename} to MEGA")
      end
    end
    batch_upload.completed!
    Rails.logger.info("Completed upload for BatchUpload ID: #{batch_upload_id}")
  rescue StandardError => e
    batch_upload.failed!
    Rails.logger.error("Failed to upload BatchUpload ID: #{batch_upload_id} with error: #{e.message}")
  end

  private

  def mega_link(path)
    megacmd_output = `mega-export -a "#{path}"`
    Rails.logger.info("MEGA command output: #{megacmd_output}")
    # export -a /STOCK/1/t2.png的输出格式为:
    # Exported /STOCK/1/t2.png: https://mega.nz/file/bxxynKxZ#BGIDsuMDlNZywyO_uF2INgxyjiGCAttozehrc1DmfBE

    if $?.success?
      # 解析 megacmd 输出以获取链接
      mega_link = megacmd_output.match(/https:\/\/mega\.nz\/file\/[a-zA-Z0-9]+#[a-zA-Z0-9_-]+/)[0]
      Rails.logger.info("Fetched MEGA link for #{path}: #{mega_link}")
      mega_link
    else
      Rails.logger.error("Failed to fetch MEGA link for #{path}")
    end
  end
end

结语

通过 Ruby 的 system 方法,我们可以轻松地在 Rails 应用中集成 MEGA CMD,实现文件的上传和分享功能。MEGA CMD 提供了丰富的命令行操作,可以满足大部分文件管理需求。还可以通过自定义 ActiveStorage 的服务来封装 MEGA CMD 的操作,使其更符合 Rails 的惯例。