[p2p-Magnet] 数据模型(GORM) | DHT爬虫 | 分类器

发布于:2025-08-29 ⋅ 阅读:(20) ⋅ 点赞:(0)

在这里插入图片描述

第3章:数据模型(GORM)

第2章:搜索查询引擎中,我们探索了系统如何通过高级数据库功能处理搜索请求。现在让我们深入了解这些"书籍"(种子资源)在系统"图书馆"中是如何组织和存储的。

数据模型与GORM解析

数据模型:信息蓝图

如同建筑需要设计图纸,数据模型定义了:

  • 存储内容:种子哈希值、名称、大小等核心字段
  • 结构关系:种子与文件的一对多关系
  • 外部关联:种子与影视元数据的映射关系

GORM:数据库管家

作为Go语言的ORM框架,GORM实现:

  • 对象映射:将Go结构体与数据库表自动关联
  • 关系管理:处理一对多/多对多等复杂关系
  • 语法简化:用db.First()替代复杂SQL语句

核心数据模型

系统主要包含五类核心模型:

  1. 种子模型(Torrent)
type Torrent struct {
    InfoHash  protocol.ID // 唯一标识
    Name      string      // 原始名称
    Size      uint        // 字节大小
    Files     []TorrentFile // 关联文件
}
  1. 文件模型(TorrentFile)
type TorrentFile {
    InfoHash protocol.ID // 所属种子
    Path     string      // 文件路径
    Size     uint        // 文件大小
}
  1. 标签模型(TorrentTag)
type TorrentTag {
    InfoHash protocol.ID // 所属种子
    Name     string      // 标签名称(如"4K")
}
  1. 内容分类模型(TorrentContent)
type TorrentContent {
    InfoHash    protocol.ID // 所属种子
    ContentType string      // 内容类型(movie/tv)
    ContentID   string      // 外部ID(如TMDB ID)
}
  1. 元数据模型(Content)
type Content {
    ID          string // 外部ID
    Title       string // 标准名称
    ReleaseYear int    // 发布年份
}

数据关联示意图

Torrent
TorrentFile
TorrentTag
TorrentContent
Content

实战示例:存储新种子

当系统发现《黑客帝国》种子时:

  1. 创建种子记录
newTorrent := model.Torrent{
    InfoHash: "a1b2c3...", 
    Name: "The.Matrix.1999.1080p",
    Size: 10_000_000_000
}
  1. 添加文件记录
files := []model.TorrentFile{
    {Path: "The.Matrix.mkv", Size: 9_800_000_000},
    {Path: "sample.mp4", Size: 200_000_000}
}
  1. 关联元数据
content := model.TorrentContent{
    ContentType: "movie",
    ContentID:   "tmdb_603" // TMDB ID
}
  1. 自动生成SQL
/* GORM自动生成 */
INSERT INTO torrents VALUES ('a1b2c3...', 'The.Matrix...', 10000000000);
INSERT INTO torrent_files VALUES 
    ('a1b2c3...', 0, 'The.Matrix.mkv', 9800000000),
    ('a1b2c3...', 1, 'sample.mp4', 200000000);

技术实现细节

模型自动生成

通过gorm.io/gen工具自动创建:

// internal/database/gen/gen.go
g.GenerateModel("torrents",
    gen.FieldRelate(
        field.HasMany, 
        "Files", 
        g.GenerateModel("torrent_files"),
        &field.RelateConfig{GORMTag: field.GormTag{"foreignKey":"InfoHash"}}
    )
)

数据库连接

PostgreSQL连接配置:

// internal/database/gorm.go
gorm.Open(postgres.New(postgres.Config{
    Conn: sqlDB, // 连接池
}))

总结

数据模型与GORM共同构建了系统的存储架构:

  1. 结构化存储:明确定义各类数据字段
  2. 高效关联:智能管理复杂数据关系
  3. 开发提效:简化数据库操作复杂度

下一章将揭示系统如何发现种子资源:DHT爬虫


第4章:DHT爬虫

第3章:数据模型(GORM)中,我们了解了系统如何通过"设计蓝图"和"施工队长"来组织存储种子信息。但这些种子最初是如何被发现的?系统如何不依赖传统网站或追踪器就能获取它们?

这就是DHT爬虫的职责所在!它如同系统的探险家,持续在去中心化的BitTorrent网络中搜寻新种子,构建独立的种子索引库。

DHT爬虫解析

工作原理

想象互联网是藏满宝藏的岛屿,传统方式依赖可能过时的"藏宝图"(中心化追踪器)。DHT爬虫则像装备声纳的探险船,直接探索**分布式哈希表(DHT)**网络——这个由全体BitTorrent客户端共同维护的"电话簿"。

核心功能:

  • 发现哈希值:通过询问其他客户端"你知道哪些种子?"获取信息哈希(种子的唯一指纹)
  • 获取元数据:请求种子的"配方卡"(包含名称、文件列表等)
  • 处理存储:将元数据传递给分类系统并存入数据库

操作方式

用户主要通过以下方式交互:

  1. 配置调整:可设置爬取强度(scaling_factor)或初始连接节点
  2. 状态监控:通过WebUI仪表盘查看实时指标,如bitmagnet_dht_crawler_persisted_total

技术实现细节

核心处理流程

爬虫 DHT网络 客户端 元处理器 数据库 请求已知信息哈希 返回节点列表和哈希值 过滤重复哈希 请求指定哈希的元数据 返回元数据(名称/文件列表等) 处理原始数据 结构化数据 存储新种子 确认存储 爬虫 DHT网络 客户端 元处理器 数据库

关键代码模块

  1. 控制中心(crawler.go)
type crawler struct {
    kTable       ktable.Table       // DHT网络节点表
    client       client.Client      // DHT通信客户端
    metainfoRequester metainforequester.Requester // 元数据请求器
    nodesForSampleInfoHashes chan ktable.Node     // 采样节点通道
}

func (c *crawler) start() {
    go c.runSampleInfoHashes() // 启动哈希采样协程
    go c.runPersistTorrents()  // 启动存储协程
    // ...其他工作协程...
}
  1. 哈希采样(sample_infohashes.go)
func (c *crawler) runSampleInfoHashes() {
    for node := range c.nodesForSampleInfoHashes {
        res := c.client.SampleInfoHashes(node) // 请求节点采样
        for _, hash := range res.Samples {
            if !c.ignoreHashes.testAndAdd(hash) { // 布隆过滤器去重
                c.infoHashTriage <- hash // 传递新哈希
            }
        }
    }
}
  1. 数据存储(persist.go)
func (c *crawler) runPersistTorrents() {
    for batch := range c.persistTorrents {
        c.dao.Transaction(func(tx *dao.Query) error {
            tx.Torrent.CreateInBatches(batch.torrents, 100) // 批量存储种子
            tx.TorrentFile.CreateInBatches(batch.files, 100) // 批量存储文件
            return nil
        })
    }
}

总结

DHT爬虫通过:

  1. 主动探索DHT网络
  2. 智能过滤重复项
  3. 高效批量存储
    实现系统的自给自足式种子发现。下一章将揭示如何解析种子内容:分类器

第5章:分类器

第4章:DHT爬虫中,我们看到系统如何持续探索BitTorrent网络并获取种子基础信息。但面对如"The.Matrix.1999.1080p.x264.DTS-HD.MA.5.1-GROUP"这样的原始数据,系统需要理解其实际含义——这就是分类器的使命。

分类器解析

核心功能

分类器如同智能图书管理员,能够:

  • 内容归类:识别电影/电视剧/音乐等类型
  • 特征提取:解析分辨率/音频编码等信息
  • 元数据增强:通过TMDB等API获取官方信息
  • 自定义标记:添加用户定义标签
  • 内容过滤:自动屏蔽违规资源

规则配置

通过YAML文件定义分类规则,支持:

  1. 工作流(Workflow)
workflows:
  default:
    - if_else:
        condition: "torrent.baseName.matches(keywords.banned)"
        if_action: delete
    - if_else:
        condition: "result.contentType == contentType.unknown"
        if_action: find_match
  1. 执行动作(Action)
    包含set_content_type/add_tag/delete等操作指令

  2. 条件判断(Condition)
    采用CEL表达式语言,可调用:

  • torrent对象:种子基础信息
  • result对象:当前分类结果
  • 预定义关键词列表
  1. 关键词列表(Keywords)
keywords:
  music: [music, album]
  banned: [违禁词1, 违禁词2]

实战案例

案例1:自动过滤内容

# config.yml
classifier:
  flags:
    delete_xxx: true
  keywords:
    banned: [暴力内容, 政治敏感]

案例2:自定义标签

# classifier.yml
workflows:
  my_workflow:
    - run_workflow: default
    - if_else:
        condition: "torrent.baseName.matches(keywords.classic)"
        if_action: add_tag: 经典老片

技术实现

核心处理流程

处理器 分类器 规则引擎 CEL引擎 数据库 TMDB 请求分类(种子数据) 加载YAML规则 执行条件判断 返回布尔结果 查询关联内容 返回查询结果 请求增强元数据 返回影视详情 返回分类结果 存储最终分类 处理器 分类器 规则引擎 CEL引擎 数据库 TMDB

关键代码

  1. 处理器入口(processor.go)
func (p processor) Process(ctx context.Context, torrent model.Torrent) error {
    result, err := p.classifier.Run(ctx, torrent) // 调用分类器
    if err != nil {
        return err
    }
    return p.dao.TorrentContent.Clauses(clause.OnConflict{
        UpdateAll: true,
    }).Create(&model.TorrentContent{
        InfoHash:    torrent.InfoHash,
        ContentType: result.ContentType,
        // ...其他字段...
    })
}
  1. 规则编译(compiler.go)
func (c compiler) Compile(source Source) (Runner, error) {
    workflows := make(map[string][]Action)
    for name, workflow := range source.Workflows {
        for _, action := range workflow.Actions {
            compiledAction, err := c.compileAction(action)
            workflows[name] = append(workflows[name], compiledAction)
        }
    }
    return runner{workflows: workflows}, nil
}

总结

分类器通过:

  1. 可定制规则引擎
  2. 多数据源关联
  3. 智能条件判断
    实现种子内容的深度解析。下一章将揭示任务调度机制:队列与处理器

网站公告

今日签到

点亮在社区的每一天
去签到